1 /*++
2
3
4 Copyright (c) Microsoft. All rights reserved.
5
6 Module Name:
7
8 FxPkgPnp.cpp
9
10 Abstract:
11
12 This module implements the pnp IRP handlers for the driver framework.
13
14 Author:
15
16
17
18 Environment:
19
20 Both kernel and user mode
21
22 Revision History:
23
24
25
26
27
28 --*/
29
30 #include "pnppriv.hpp"
31
32 #include <initguid.h>
33 #include <wdmguid.h>
34
35 extern "C" {
36
37 #if defined(EVENT_TRACING)
38 #include "FxPkgPnp.tmh"
39 #endif
40
41 }
42
43 /* dc7a8e51-49b3-4a3a-9e81-625205e7d729 */
44 const GUID FxPkgPnp::GUID_POWER_THREAD_INTERFACE = {
45 0xdc7a8e51, 0x49b3, 0x4a3a, { 0x9e, 0x81, 0x62, 0x52, 0x05, 0xe7, 0xd7, 0x29 }
46 };
47
FxPkgPnp(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in CfxDevice * Device,__in WDFTYPE Type)48 FxPkgPnp::FxPkgPnp(
49 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
50 __in CfxDevice* Device,
51 __in WDFTYPE Type
52 ) :
53 FxPackage(FxDriverGlobals, Device, Type)
54 {
55 ULONG i;
56
57 m_DmaEnablerList = NULL;
58 m_RemovalDeviceList = NULL;
59 m_UsageDependentDeviceList = NULL;
60
61 //
62 // Initialize the structures to the default state and then override the
63 // non WDF std default values to the unsupported / off values.
64 //
65 m_PnpStateAndCaps.Value =
66 FxPnpStateDisabledUseDefault |
67 FxPnpStateDontDisplayInUIUseDefault |
68 FxPnpStateFailedUseDefault |
69 FxPnpStateNotDisableableUseDefault |
70 FxPnpStateRemovedUseDefault |
71 FxPnpStateResourcesChangedUseDefault |
72
73 FxPnpCapLockSupportedUseDefault |
74 FxPnpCapEjectSupportedUseDefault |
75 FxPnpCapRemovableUseDefault |
76 FxPnpCapDockDeviceUseDefault |
77 FxPnpCapUniqueIDUseDefault |
78 FxPnpCapSilentInstallUseDefault |
79 FxPnpCapSurpriseRemovalOKUseDefault |
80 FxPnpCapHardwareDisabledUseDefault |
81 FxPnpCapNoDisplayInUIUseDefault
82 ;
83
84 m_PnpCapsAddress = (ULONG) -1;
85 m_PnpCapsUINumber = (ULONG) -1;
86
87 RtlZeroMemory(&m_PowerCaps, sizeof(m_PowerCaps));
88 m_PowerCaps.Caps =
89 FxPowerCapDeviceD1UseDefault |
90 FxPowerCapDeviceD2UseDefault |
91 FxPowerCapWakeFromD0UseDefault |
92 FxPowerCapWakeFromD1UseDefault |
93 FxPowerCapWakeFromD2UseDefault |
94 FxPowerCapWakeFromD3UseDefault
95 ;
96
97 m_PowerCaps.DeviceWake = PowerDeviceMaximum;
98 m_PowerCaps.SystemWake = PowerSystemMaximum;
99
100 m_PowerCaps.D1Latency = (ULONG) -1;
101 m_PowerCaps.D2Latency = (ULONG) -1;
102 m_PowerCaps.D3Latency = (ULONG) -1;
103
104 m_PowerCaps.States = 0;
105 for (i = 0; i < PowerSystemMaximum; i++) {
106 _SetPowerCapState(i, PowerDeviceMaximum, &m_PowerCaps.States);
107 }
108
109 RtlZeroMemory(&m_D3ColdInterface, sizeof(m_D3ColdInterface));
110 RtlZeroMemory(&m_SpecialSupport[0], sizeof(m_SpecialSupport));
111 RtlZeroMemory(&m_SpecialFileCount[0], sizeof(m_SpecialFileCount));
112
113 m_PowerThreadInterface.Interface.Size = sizeof(m_PowerThreadInterface);
114 m_PowerThreadInterface.Interface.Version = 1;
115 m_PowerThreadInterface.Interface.Context = this;
116 m_PowerThreadInterface.Interface.InterfaceReference = &FxPkgPnp::_PowerThreadInterfaceReference;
117 m_PowerThreadInterface.Interface.InterfaceDereference = &FxPkgPnp::_PowerThreadInterfaceDereference;
118 m_PowerThreadInterface.PowerThreadEnqueue = &FxPkgPnp::_PowerThreadEnqueue;
119 m_PowerThread = NULL;
120 m_HasPowerThread = FALSE;
121 m_PowerThreadInterfaceReferenceCount = 1;
122 m_PowerThreadEvent = NULL;
123
124 m_DeviceStopCount = 0;
125 m_CapsQueried = FALSE;
126 m_InternalFailure = FALSE;
127 m_FailedAction = WdfDeviceFailedUndefined;
128
129 //
130 // We only set the pending child count to 1 once we know we have successfully
131 // created an FxDevice and initialized it fully. If we delete an FxDevice
132 // which is half baked, it cannot have any FxChildLists which have any
133 // pending children on them.
134 //
135 m_PendingChildCount = 0;
136
137 m_QueryInterfaceHead.Next = NULL;
138
139 m_DeviceInterfaceHead.Next = NULL;
140 m_DeviceInterfacesCanBeEnabled = FALSE;
141
142 m_Failed = FALSE;
143 m_SetDeviceRemoveProcessed = FALSE;
144
145 m_SystemPowerState = PowerSystemWorking;
146 m_DevicePowerState = WdfPowerDeviceD3Final;
147 m_DevicePowerStateOld = WdfPowerDeviceD3Final;
148
149 m_PendingPnPIrp = NULL;
150 m_PendingSystemPowerIrp = NULL;
151 m_PendingDevicePowerIrp = NULL;
152 m_SystemPowerAction = (UCHAR) PowerActionNone;
153
154 m_PnpStateCallbacks = NULL;
155 m_PowerStateCallbacks = NULL;
156 m_PowerPolicyStateCallbacks = NULL;
157
158 m_SelfManagedIoMachine = NULL;
159
160 m_EnumInfo = NULL;
161
162 m_Resources = NULL;
163 m_ResourcesRaw = NULL;
164
165 InitializeListHead(&m_InterruptListHead);
166 m_InterruptObjectCount = 0;
167 m_WakeInterruptCount = 0;
168 m_WakeInterruptPendingAckCount = 0;
169 m_SystemWokenByWakeInterrupt = FALSE;
170 m_WakeInterruptsKeepConnected = FALSE;
171 m_AchievedStart = FALSE;
172
173 m_SharedPower.m_WaitWakeIrp = NULL;
174 m_SharedPower.m_WaitWakeOwner = FALSE;
175 m_SharedPower.m_ExtendWatchDogTimer = FALSE;
176
177 m_DeviceRemoveProcessed = NULL;
178
179 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
180 //
181 // Interrupt APIs for Vista and forward
182 //
183 m_IoConnectInterruptEx = FxLibraryGlobals.IoConnectInterruptEx;
184 m_IoDisconnectInterruptEx = FxLibraryGlobals.IoDisconnectInterruptEx;
185
186 //
187 // Interrupt APIs for Windows 8 and forward
188 //
189 m_IoReportInterruptActive = FxLibraryGlobals.IoReportInterruptActive;
190 m_IoReportInterruptInactive = FxLibraryGlobals.IoReportInterruptInactive;
191
192 #endif
193
194 m_ReleaseHardwareAfterDescendantsOnFailure = FALSE;
195
196 MarkDisposeOverride(ObjectDoNotLock);
197 }
198
~FxPkgPnp()199 FxPkgPnp::~FxPkgPnp()
200 {
201 PSINGLE_LIST_ENTRY ple;
202
203 Mx::MxAssert(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
204
205 //
206 // We should either have zero pending children or we never made it out of
207 // the init state during a failed WDFDEVICE create or failed EvtDriverDeviceAdd
208 //
209 Mx::MxAssert(m_PendingChildCount == 0 ||
210 m_Device->GetDevicePnpState() == WdfDevStatePnpInit);
211
212
213 ple = m_DeviceInterfaceHead.Next;
214 while (ple != NULL) {
215 FxDeviceInterface* pDI;
216
217 pDI = FxDeviceInterface::_FromEntry(ple);
218
219 //
220 // Advance to the next before deleting the current
221 //
222 ple = ple->Next;
223
224 //
225 // No longer in the list
226 //
227 pDI->m_Entry.Next = NULL;
228
229 delete pDI;
230 }
231 m_DeviceInterfaceHead.Next = NULL;
232
233 if (m_DmaEnablerList != NULL) {
234 delete m_DmaEnablerList;
235 m_DmaEnablerList = NULL;
236 }
237
238 if (m_RemovalDeviceList != NULL) {
239 delete m_RemovalDeviceList;
240 m_RemovalDeviceList = NULL;
241 }
242
243 if (m_UsageDependentDeviceList != NULL) {
244 delete m_UsageDependentDeviceList;
245 m_UsageDependentDeviceList = NULL;
246 }
247
248 if (m_PnpStateCallbacks != NULL) {
249 delete m_PnpStateCallbacks;
250 }
251
252 if (m_PowerStateCallbacks != NULL) {
253 delete m_PowerStateCallbacks;
254 }
255
256 if (m_PowerPolicyStateCallbacks != NULL) {
257 delete m_PowerPolicyStateCallbacks;
258 }
259
260 if (m_SelfManagedIoMachine != NULL) {
261 delete m_SelfManagedIoMachine;
262 m_SelfManagedIoMachine = NULL;
263 }
264
265 if (m_EnumInfo != NULL) {
266 delete m_EnumInfo;
267 m_EnumInfo = NULL;
268 }
269
270 if (m_Resources != NULL) {
271 m_Resources->RELEASE(this);
272 m_Resources = NULL;
273 }
274
275 if (m_ResourcesRaw != NULL) {
276 m_ResourcesRaw->RELEASE(this);
277 m_ResourcesRaw = NULL;
278 }
279
280 ASSERT(IsListEmpty(&m_InterruptListHead));
281 }
282
283 BOOLEAN
Dispose(VOID)284 FxPkgPnp::Dispose(
285 VOID
286 )
287 {
288 PSINGLE_LIST_ENTRY ple;
289
290 //
291 // All of the interrupts were freed during this object's dispose path. This
292 // is because all of the interrupts were attached as children to this object.
293 //
294 // It is safe to just reinitialize the list head.
295 //
296 InitializeListHead(&m_InterruptListHead);
297
298 m_QueryInterfaceLock.AcquireLock(GetDriverGlobals());
299
300 //
301 // A derived class can insert an embedded FxQueryInterface into the QI list,
302 // so clear out the list before the destructor chain runs. (The derived
303 // class will be destructed first, as such, the embedded FxQueryInterface
304 // will also destruct first and complain it is still in a list.
305 //
306 ple = m_QueryInterfaceHead.Next;
307
308 //
309 // Clear out the head while holding the lock so that we synchronize against
310 // processing a QI while deleting the list.
311 //
312 m_QueryInterfaceHead.Next = NULL;
313
314 m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals());
315
316 while (ple != NULL) {
317 FxQueryInterface* pQI;
318
319 pQI = FxQueryInterface::_FromEntry(ple);
320
321 //
322 // Advance before we potentiall free the structure
323 //
324 ple = ple->Next;
325
326 //
327 // FxQueryInterface's destructor requires Next be NULL
328 //
329 pQI->m_Entry.Next = NULL;
330
331 if (pQI->m_EmbeddedInterface == FALSE) {
332 delete pQI;
333 }
334 }
335
336 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
337 DropD3ColdInterface();
338 #endif
339
340 //
341 // Call up the hierarchy
342 //
343 return FxPackage::Dispose(); // __super call
344 }
345
346
347 _Must_inspect_result_
348 NTSTATUS
Initialize(__in PWDFDEVICE_INIT DeviceInit)349 FxPkgPnp::Initialize(
350 __in PWDFDEVICE_INIT DeviceInit
351 )
352
353 /*++
354
355 Routine Description:
356
357 This function initializes state associated with an instance of FxPkgPnp.
358 This differs from the constructor because it can do operations which
359 will fail, and can return failure. (Constructors can't fail, they can
360 only throw exceptions, which we can't deal with in this kernel mode
361 environment.)
362
363 Arguments:
364
365 DeviceInit - Struct that the driver initialized that contains defaults.
366
367 Returns:
368
369 NTSTATUS
370
371 --*/
372
373 {
374 PFX_DRIVER_GLOBALS pFxDriverGlobals;
375 NTSTATUS status;
376
377 pFxDriverGlobals = GetDriverGlobals();
378
379 m_ReleaseHardwareAfterDescendantsOnFailure = (DeviceInit->ReleaseHardwareOrderOnFailure ==
380 WdfReleaseHardwareOrderOnFailureAfterDescendants);
381
382 status = m_QueryInterfaceLock.Initialize();
383 if (!NT_SUCCESS(status)) {
384 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR,
385 TRACINGPNP,
386 "Could not initialize QueryInterfaceLock for "
387 "WDFDEVICE %p, %!STATUS!",
388 m_Device->GetHandle(), status);
389 return status;
390 }
391
392 status = m_DeviceInterfaceLock.Initialize();
393 if (!NT_SUCCESS(status)) {
394 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR,
395 TRACINGPNP,
396 "Could not initialize DeviceInterfaceLock for "
397 "WDFDEVICE %p, %!STATUS!",
398 m_Device->GetHandle(), status);
399 return status;
400 }
401
402 //
403 // Initialize preallocated events for UM
404 // (For KM, events allocated on stack are used since event initialization
405 // doesn't fail in KM)
406 //
407 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
408
409 status = m_CleanupEventUm.Initialize();
410 if (!NT_SUCCESS(status)) {
411 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR,
412 TRACINGPNP,
413 "Could not initialize cleanup event for "
414 "WDFDEVICE %p, %!STATUS!",
415 m_Device->GetHandle(), status);
416 return status;
417 }
418
419 status = m_RemoveEventUm.Initialize(SynchronizationEvent, FALSE);
420 if (!NT_SUCCESS(status)) {
421 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR,
422 TRACINGPNP,
423 "Could not initialize remove event for "
424 "WDFDEVICE %p, %!STATUS!",
425 m_Device->GetHandle(), status);
426 return status;
427 }
428 #endif
429
430 if (DeviceInit->IsPwrPolOwner()) {
431 m_PowerPolicyMachine.m_Owner = new (pFxDriverGlobals)
432 FxPowerPolicyOwnerSettings(this);
433
434 if (m_PowerPolicyMachine.m_Owner == NULL) {
435 return STATUS_INSUFFICIENT_RESOURCES;
436 }
437
438 status = m_PowerPolicyMachine.m_Owner->Init();
439 if (!NT_SUCCESS(status)) {
440 return status;
441 }
442
443 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
444 QueryForD3ColdInterface();
445 #endif
446 }
447
448 //
449 // we will change the access flags on the object later on when we build up
450 // the list from the wdm resources
451 //
452 status = FxCmResList::_CreateAndInit(&m_Resources,
453 pFxDriverGlobals,
454 m_Device,
455 WDF_NO_OBJECT_ATTRIBUTES,
456 FxResourceNoAccess);
457 if (!NT_SUCCESS(status)) {
458 return status;
459 }
460
461 status = m_Resources->Commit(WDF_NO_OBJECT_ATTRIBUTES,
462 WDF_NO_HANDLE,
463 m_Device);
464
465 //
466 // This should never fail
467 //
468 ASSERT(NT_SUCCESS(status));
469 if (!NT_SUCCESS(status)) {
470 m_Resources->DeleteFromFailedCreate();
471 m_Resources = NULL;
472 return status;
473 }
474
475 m_Resources->ADDREF(this);
476
477 //
478 // we will change the access flags on the object later on when we build up
479 // the list from the wdm resources
480 //
481 status = FxCmResList::_CreateAndInit(&m_ResourcesRaw,
482 pFxDriverGlobals,
483 m_Device,
484 WDF_NO_OBJECT_ATTRIBUTES,
485 FxResourceNoAccess);
486 if (!NT_SUCCESS(status)) {
487 return status;
488 }
489
490 status = m_ResourcesRaw->Commit(WDF_NO_OBJECT_ATTRIBUTES,
491 WDF_NO_HANDLE,
492 m_Device);
493
494 //
495 // This should never fail
496 //
497 ASSERT(NT_SUCCESS(status));
498 if (!NT_SUCCESS(status)) {
499 m_ResourcesRaw->DeleteFromFailedCreate();
500 m_ResourcesRaw = NULL;
501 return status;
502 }
503
504 m_ResourcesRaw->ADDREF(this);
505
506 status = RegisterCallbacks(&DeviceInit->PnpPower.PnpPowerEventCallbacks);
507 if (!NT_SUCCESS(status)) {
508 return status;
509 }
510
511 if (IsPowerPolicyOwner()) {
512 RegisterPowerPolicyCallbacks(&DeviceInit->PnpPower.PolicyEventCallbacks);
513 }
514
515 return status;
516 }
517
518 _Must_inspect_result_
519 NTSTATUS
Dispatch(__in MdIrp Irp)520 FxPkgPnp::Dispatch(
521 __in MdIrp Irp
522 )
523
524 /*++
525
526 Routine Description:
527
528 This is the main dispatch handler for the pnp package. This method is
529 called by the framework manager when a PNP or Power IRP enters the driver.
530 This function will dispatch the IRP to a function designed to handle the
531 specific IRP.
532
533 Arguments:
534
535 Device - a pointer to the FxDevice
536
537 Irp - a pointer to the FxIrp
538
539 Returns:
540
541 NTSTATUS
542
543 --*/
544
545 {
546 NTSTATUS status;
547 FxIrp irp(Irp);
548
549 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
550 FX_TRACK_DRIVER(GetDriverGlobals());
551 #endif
552
553 if (irp.GetMajorFunction() == IRP_MJ_PNP) {
554
555 switch (irp.GetMinorFunction()) {
556 case IRP_MN_START_DEVICE:
557 case IRP_MN_QUERY_REMOVE_DEVICE:
558 case IRP_MN_REMOVE_DEVICE:
559 case IRP_MN_CANCEL_REMOVE_DEVICE:
560 case IRP_MN_STOP_DEVICE:
561 case IRP_MN_QUERY_STOP_DEVICE:
562 case IRP_MN_CANCEL_STOP_DEVICE:
563 case IRP_MN_SURPRISE_REMOVAL:
564 case IRP_MN_EJECT:
565 case IRP_MN_QUERY_PNP_DEVICE_STATE:
566 DoTraceLevelMessage(
567 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
568 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p",
569 m_Device->GetHandle(),
570 m_Device->GetDeviceObject(),
571 irp.GetMinorFunction(), irp.GetIrp());
572 break;
573
574 case IRP_MN_QUERY_DEVICE_RELATIONS:
575 DoTraceLevelMessage(
576 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
577 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! "
578 "type %!DEVICE_RELATION_TYPE! IRP 0x%p",
579 m_Device->GetHandle(),
580 m_Device->GetDeviceObject(),
581 irp.GetMinorFunction(),
582 irp.GetParameterQDRType(), irp.GetIrp());
583 break;
584
585 default:
586 DoTraceLevelMessage(
587 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
588 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p",
589 m_Device->GetHandle(),
590 m_Device->GetDeviceObject(),
591 irp.GetMinorFunction(), irp.GetIrp());
592 break;
593 }
594
595 if (irp.GetMinorFunction() <= IRP_MN_SURPRISE_REMOVAL) {
596 status = (*GetDispatchPnp()[irp.GetMinorFunction()])(this, &irp);
597 }
598 else {
599 //
600 // For Pnp IRPs we don't understand, just forget about them
601 //
602 status = FireAndForgetIrp(&irp);
603 }
604 }
605 else {
606 //
607 // If this isn't a PnP Irp, it must be a power irp.
608 //
609 switch (irp.GetMinorFunction()) {
610 case IRP_MN_WAIT_WAKE:
611 case IRP_MN_SET_POWER:
612 if (irp.GetParameterPowerType() == SystemPowerState) {
613 DoTraceLevelMessage(
614 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
615 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! "
616 "IRP 0x%p for %!SYSTEM_POWER_STATE! (S%d)",
617 m_Device->GetHandle(),
618 m_Device->GetDeviceObject(),
619 irp.GetMinorFunction(), irp.GetIrp(),
620 irp.GetParameterPowerStateSystemState(),
621 irp.GetParameterPowerStateSystemState() - 1);
622 }
623 else {
624 DoTraceLevelMessage(
625 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
626 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! "
627 "IRP 0x%p for %!DEVICE_POWER_STATE!",
628 m_Device->GetHandle(),
629 m_Device->GetDeviceObject(),
630 irp.GetMinorFunction(), irp.GetIrp(),
631 irp.GetParameterPowerStateDeviceState());
632 }
633 break;
634
635 default:
636 DoTraceLevelMessage(
637 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
638 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! IRP 0x%p",
639 m_Device->GetHandle(),
640 m_Device->GetDeviceObject(),
641 irp.GetMinorFunction(), irp.GetIrp());
642 break;
643 }
644
645 Mx::MxAssert(irp.GetMajorFunction() == IRP_MJ_POWER);
646
647 if (irp.GetMinorFunction() <= IRP_MN_QUERY_POWER) {
648 status = (*GetDispatchPower()[irp.GetMinorFunction()])(this, &irp);
649 }
650 else {
651 //
652 // For Power IRPs we don't understand, just forget about them
653 //
654 status = FireAndForgetIrp(&irp);
655 }
656 }
657
658 return status;
659 }
660
661 PNP_DEVICE_STATE
HandleQueryPnpDeviceState(__in PNP_DEVICE_STATE PnpDeviceState)662 FxPkgPnp::HandleQueryPnpDeviceState(
663 __in PNP_DEVICE_STATE PnpDeviceState
664 )
665
666 /*++
667
668 Routine Description:
669
670 This function handled IRP_MN_QUERY_DEVICE_STATE. Most of the bits are
671 just copied from internal Framework state.
672
673 Arguments:
674
675 PnpDeviceState - Bitfield that will be returned to the sender of the IRP.
676
677 Returns:
678
679 NTSTATUS
680
681 --*/
682
683 {
684 LONG state;
685
686 state = GetPnpStateInternal();
687
688 //
689 // Return device state set by driver.
690 //
691 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
692 PNP_DEVICE_DISABLED,
693 state,
694 Disabled);
695 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
696 PNP_DEVICE_DONT_DISPLAY_IN_UI,
697 state,
698 DontDisplayInUI);
699 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
700 PNP_DEVICE_FAILED,
701 state,
702 Failed);
703 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
704 PNP_DEVICE_NOT_DISABLEABLE,
705 state,
706 NotDisableable);
707 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
708 PNP_DEVICE_REMOVED,
709 state,
710 Removed);
711 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
712 PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED,
713 state,
714 ResourcesChanged);
715
716 if ((state & FxPnpStateDontDisplayInUIMask) == FxPnpStateDontDisplayInUIUseDefault) {
717 LONG caps;
718
719 //
720 // Mask off all caps except for NoDispalyInUI
721 //
722 caps = GetPnpCapsInternal() & FxPnpCapNoDisplayInUIMask;
723
724 //
725 // If the driver didn't specify pnp state, see if they specified no
726 // display as a capability. For raw PDOs and just usability, it is not
727 // always clear to the driver writer that they must set both the pnp cap
728 // and the pnp state for the no display in UI property to stick after
729 // the device has been started.
730 //
731 if (caps == FxPnpCapNoDisplayInUITrue) {
732 PnpDeviceState |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
733 }
734 else if (caps == FxPnpCapNoDisplayInUIFalse) {
735 PnpDeviceState &= ~PNP_DEVICE_DONT_DISPLAY_IN_UI;
736 }
737 }
738
739 //
740 // Return device state maintained by frameworks.
741 //
742 if (IsInSpecialUse()) {
743 PnpDeviceState |= PNP_DEVICE_NOT_DISABLEABLE;
744 }
745
746 //
747 // If there is an internal failure, then indicate that up to pnp.
748 //
749 if (m_InternalFailure || m_Failed) {
750 PnpDeviceState |= PNP_DEVICE_FAILED;
751 }
752
753 return PnpDeviceState;
754 }
755
756 _Must_inspect_result_
757 NTSTATUS
HandleQueryBusRelations(__inout FxIrp * Irp)758 FxPkgPnp::HandleQueryBusRelations(
759 __inout FxIrp* Irp
760 )
761 /*++
762
763 Routine Description:
764 Handles a query device relations for the bus relations type (all other types
765 are handled by HandleQueryDeviceRelations). This function will call into
766 each of the device's FxChildList objects to process the request.
767
768 Arguments:
769 Irp - the request contain the query device relations
770
771 Return Value:
772 NTSTATUS
773
774 --*/
775 {
776 FxWaitLockTransactionedList* pList;
777 PDEVICE_RELATIONS pRelations;
778 FxTransactionedEntry* ple;
779 NTSTATUS status, listStatus;
780 BOOLEAN changed;
781
782 //
783 // Before we do anything, callback into the driver
784 //
785 m_DeviceRelationsQuery.Invoke(m_Device->GetHandle(), BusRelations);
786
787 //
788 // Default to success unless list processing fails
789 //
790 status = STATUS_SUCCESS;
791
792 //
793 // Keep track of changes made by any list object. If anything changes,
794 // remember it for post-processing.
795 //
796 changed = FALSE;
797
798 pRelations = (PDEVICE_RELATIONS) Irp->GetInformation();
799
800 if (m_EnumInfo != NULL) {
801 pList = &m_EnumInfo->m_ChildListList;
802
803 pList->LockForEnum(GetDriverGlobals());
804 }
805 else {
806 pList = NULL;
807 }
808
809 ple = NULL;
810 while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) {
811 FxChildList* pChildList;
812
813 pChildList = FxChildList::_FromEntry(ple);
814
815 //
816 // ProcessBusRelations will free and reallocate pRelations if necessary
817 //
818 listStatus = pChildList->ProcessBusRelations(&pRelations);
819
820 //
821 // STATUS_NOT_SUPPORTED is a special value. It indicates that the call
822 // to ProcessBusRelations did not modify pRelations in any way.
823 //
824 if (listStatus == STATUS_NOT_SUPPORTED) {
825 continue;
826 }
827
828
829 if (!NT_SUCCESS(listStatus)) {
830 DoTraceLevelMessage(
831 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
832 "WDFDEVICE %p, WDFCHILDLIST %p returned %!STATUS! from "
833 "processing bus relations",
834 m_Device->GetHandle(), pChildList->GetHandle(), listStatus);
835 status = listStatus;
836 break;
837 }
838
839 //
840 // We updated pRelations, change the status later
841 //
842 changed = TRUE;
843 }
844
845 //
846 // By checking for NT_SUCCESS(status) below we account for
847 // both the cases - list changed, as well as list unchanged but possibly
848 // children being reported missing (that doesn't involve list change).
849 //
850 if (NT_SUCCESS(status)) {
851
852 ple = NULL;
853 while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) {
854 FxChildList* pChildList;
855
856 pChildList = FxChildList::_FromEntry(ple);
857
858 //
859 // invoke the ReportedMissing callback for for children that are
860 // being reporte missing
861 //
862 pChildList->InvokeReportedMissingCallback();
863 }
864 }
865
866 if (pList != NULL) {
867 pList->UnlockFromEnum(GetDriverGlobals());
868 }
869
870 if (NT_SUCCESS(status) && changed == FALSE) {
871 //
872 // Went through the entire list of FxChildList objects, but no object
873 // modified the pRelations, so restore the caller's NTSTATUS.
874 //
875 status = Irp->GetStatus();
876 }
877
878 //
879 // Re-set the relations into the structure so that any changes that any call
880 // to FxChildList::ProcessBusRelations takes effect and is reported.
881 //
882 Irp->SetInformation((ULONG_PTR) pRelations);
883 Irp->SetStatus(status);
884
885 DoTraceLevelMessage(
886 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
887 "WDFDEVICE %p, returning %!STATUS! from processing bus relations",
888 m_Device->GetHandle(), status
889 );
890
891 if (NT_SUCCESS(status) && pRelations != NULL) {
892 ULONG i;
893
894 DoTraceLevelMessage(
895 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
896 "WDFDEVICE %p returning %d devices in relations %p",
897 m_Device->GetHandle(), pRelations->Count, pRelations
898 );
899
900 //
901 // Try to not consume an IFR entry per DO reported. Instead, report up
902 // to 4 at a time.
903 //
904 for (i = 0; i < pRelations->Count && GetDriverGlobals()->FxVerboseOn; i += 4) {
905 if (i + 3 < pRelations->Count) {
906 DoTraceLevelMessage(
907 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
908 "PDO %p PDO %p PDO %p PDO %p",
909 pRelations->Objects[i],
910 pRelations->Objects[i+1],
911 pRelations->Objects[i+2],
912 pRelations->Objects[i+3]
913 );
914 }
915 else if (i + 2 < pRelations->Count) {
916 DoTraceLevelMessage(
917 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
918 "PDO %p PDO %p PDO %p",
919 pRelations->Objects[i],
920 pRelations->Objects[i+1],
921 pRelations->Objects[i+2]
922 );
923 }
924 else if (i + 1 < pRelations->Count) {
925 DoTraceLevelMessage(
926 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
927 "PDO %p PDO %p",
928 pRelations->Objects[i],
929 pRelations->Objects[i+1]
930 );
931 }
932 else {
933 DoTraceLevelMessage(
934 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
935 "PDO %p",
936 pRelations->Objects[i]
937 );
938 }
939 }
940 }
941
942 return status;
943 }
944
945 _Must_inspect_result_
946 NTSTATUS
HandleQueryBusInformation(__inout FxIrp * Irp)947 FxPkgPnp::HandleQueryBusInformation(
948 __inout FxIrp* Irp
949 )
950 {
951 NTSTATUS status;
952
953 //
954 // Probably is a better check then this to see if the driver set the bus
955 // information
956 //
957 if (m_BusInformation.BusTypeGuid.Data1 != 0x0) {
958 PPNP_BUS_INFORMATION pBusInformation;
959 PFX_DRIVER_GLOBALS pFxDriverGlobals;
960
961 pFxDriverGlobals = GetDriverGlobals();
962 pBusInformation = (PPNP_BUS_INFORMATION) MxMemory::MxAllocatePoolWithTag(
963 PagedPool, sizeof(PNP_BUS_INFORMATION), pFxDriverGlobals->Tag);
964
965 if (pBusInformation != NULL) {
966 //
967 // Initialize the PNP_BUS_INFORMATION structure with the data
968 // from PDO properties.
969 //
970 RtlCopyMemory(pBusInformation,
971 &m_BusInformation,
972 sizeof(PNP_BUS_INFORMATION));
973
974 Irp->SetInformation((ULONG_PTR) pBusInformation);
975 status = STATUS_SUCCESS;
976 }
977 else {
978 Irp->SetInformation(NULL);
979 status = STATUS_INSUFFICIENT_RESOURCES;
980
981 DoTraceLevelMessage(
982 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
983 "WDFDEVICE %p could not allocate PNP_BUS_INFORMATION string, "
984 " %!STATUS!", m_Device->GetHandle(), status);
985 }
986 }
987 else {
988 status = Irp->GetStatus();
989 }
990
991 return status;
992 }
993
994 _Must_inspect_result_
995 NTSTATUS
HandleQueryDeviceRelations(__inout FxIrp * Irp,__inout FxRelatedDeviceList * List)996 FxPkgPnp::HandleQueryDeviceRelations(
997 __inout FxIrp* Irp,
998 __inout FxRelatedDeviceList* List
999 )
1000 /*++
1001
1002 Routine Description:
1003 Handles the query device relations request for all relation types *except*
1004 for bus relations (HandleQueryBusRelations handles that type exclusively).
1005
1006 This function will allocate a PDEVICE_RELATIONS structure if the passed in
1007 FxRelatedDeviceList contains any devices to add to the relations list.
1008
1009 Arguments:
1010 Irp - the request
1011
1012 List - list containing devices to report in the relations
1013
1014 Return Value:
1015 NTSTATUS
1016
1017 --*/
1018 {
1019 PDEVICE_RELATIONS pPriorRelations, pNewRelations;
1020 FxRelatedDevice* entry;
1021 DEVICE_RELATION_TYPE type;
1022 ULONG count;
1023 size_t size;
1024 NTSTATUS status;
1025 BOOLEAN retry;
1026 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1027
1028 if (List == NULL) {
1029 //
1030 // Indicate that we didn't modify the irp at all since we have no list
1031 //
1032 return STATUS_NOT_SUPPORTED;
1033 }
1034
1035 pFxDriverGlobals = GetDriverGlobals();
1036 type = Irp->GetParameterQDRType();
1037 status = STATUS_SUCCESS;
1038
1039 //
1040 // Notify driver that he should re-scan for device relations.
1041 //
1042 m_DeviceRelationsQuery.Invoke(m_Device->GetHandle(), type);
1043
1044 pPriorRelations = (PDEVICE_RELATIONS) Irp->GetInformation();
1045 retry = FALSE;
1046
1047 count = 0;
1048
1049 List->LockForEnum(pFxDriverGlobals);
1050
1051 //
1052 // Count how many entries there are in the list
1053 //
1054 for (entry = NULL; (entry = List->GetNextEntry(entry)) != NULL; count++) {
1055 DO_NOTHING();
1056 }
1057
1058 //
1059 // If we have
1060 // 1) no devices in the list AND
1061 // a) we have nothing to report OR
1062 // b) we have something to report and there are previous relations (which
1063 // if left unchanged will be used to report our missing devices)
1064 //
1065 // THEN we have nothing else to do, just return
1066 //
1067 if (count == 0 &&
1068 (List->m_NeedReportMissing == 0 || pPriorRelations != NULL)) {
1069 List->UnlockFromEnum(pFxDriverGlobals);
1070 return STATUS_NOT_SUPPORTED;
1071 }
1072
1073 if (pPriorRelations != NULL) {
1074 //
1075 // Looks like another driver in the stack has already added some
1076 // entries. Make sure we allocate space for these additional entries.
1077 //
1078 count += pPriorRelations->Count;
1079 }
1080
1081 //
1082 // Allocate space for the device relations structure (which includes
1083 // space for one PDEVICE_OBJECT, and then allocate enough additional
1084 // space for the extra PDEVICE_OBJECTS we need.
1085 //
1086 // (While no FxChildList objects are used in this function, this static
1087 // function from the class computes what we need.)
1088 //
1089 size = FxChildList::_ComputeRelationsSize(count);
1090
1091 pNewRelations = (PDEVICE_RELATIONS) MxMemory::MxAllocatePoolWithTag(
1092 PagedPool, size, pFxDriverGlobals->Tag);
1093
1094 if (pNewRelations == NULL) {
1095 //
1096 // Dereference any previously reported relations before exiting. They
1097 // are dereferenced here because the PNP manager will see error and not
1098 // do anything while the driver which added these objects expects the
1099 // pnp manager to do the dereference. Since this device is changing the
1100 // status, it must act like the pnp manager.
1101 //
1102 if (pPriorRelations != NULL) {
1103 ULONG i;
1104
1105 for (i = 0; i < pPriorRelations->Count; i++) {
1106 Mx::MxDereferenceObject(pPriorRelations->Objects[i]);
1107 }
1108 }
1109
1110 if (List->IncrementRetries() < 3) {
1111 retry = TRUE;
1112 }
1113
1114 status = STATUS_INSUFFICIENT_RESOURCES;
1115
1116 DoTraceLevelMessage(
1117 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1118 "WDFDEVICE %p could not allocate device relations for type %d string, "
1119 " %!STATUS!", m_Device->GetHandle(), type, status);
1120
1121 goto Done;
1122 }
1123
1124 RtlZeroMemory(pNewRelations, size);
1125
1126 //
1127 // If there was an existing device relations structure, copy
1128 // the entries to the new structure.
1129 //
1130 if (pPriorRelations != NULL && pPriorRelations->Count > 0) {
1131 RtlCopyMemory(
1132 pNewRelations,
1133 pPriorRelations,
1134 FxChildList::_ComputeRelationsSize(pPriorRelations->Count)
1135 );
1136 }
1137
1138 //
1139 // Walk the list and return the relations here
1140 //
1141 for (entry = NULL;
1142 (entry = List->GetNextEntry(entry)) != NULL;
1143 pNewRelations->Count++) {
1144 MdDeviceObject pdo;
1145
1146 pdo = entry->GetDevice();
1147
1148 if (entry->m_State == RelatedDeviceStateNeedsReportPresent) {
1149 entry->m_State = RelatedDeviceStateReportedPresent;
1150 }
1151
1152 //
1153 // Add it to the DEVICE_RELATIONS structure. Pnp dictates that each
1154 // PDO in the list be referenced.
1155 //
1156 pNewRelations->Objects[pNewRelations->Count] = reinterpret_cast<PDEVICE_OBJECT>(pdo);
1157 Mx::MxReferenceObject(pdo);
1158 }
1159
1160 Done:
1161 if (NT_SUCCESS(status)) {
1162 List->ZeroRetries();
1163 }
1164
1165 List->UnlockFromEnum(GetDriverGlobals());
1166
1167 if (pPriorRelations != NULL) {
1168 MxMemory::MxFreePool(pPriorRelations);
1169 }
1170
1171 if (retry) {
1172 MxDeviceObject physicalDeviceObject(
1173 m_Device->GetPhysicalDevice()
1174 );
1175
1176 physicalDeviceObject.InvalidateDeviceRelations(type);
1177 }
1178
1179 Irp->SetStatus(status);
1180 Irp->SetInformation((ULONG_PTR) pNewRelations);
1181
1182 return status;
1183 }
1184
1185 _Must_inspect_result_
1186 NTSTATUS
PostCreateDeviceInitialize(VOID)1187 FxPkgPnp::PostCreateDeviceInitialize(
1188 VOID
1189 )
1190
1191 /*++
1192
1193 Routine Description:
1194
1195 This function does any initialization to this object which must be done
1196 after the underlying device object has been attached to the device stack,
1197 i.e. you can send IRPs down this stack now.
1198
1199 Arguments:
1200
1201 none
1202
1203 Returns:
1204
1205 NTSTATUS
1206
1207 --*/
1208
1209 {
1210 NTSTATUS status;
1211
1212 status = m_PnpMachine.Init(this, &FxPkgPnp::_PnpProcessEventInner);
1213 if (!NT_SUCCESS(status)) {
1214 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1215 "PnP State Machine init failed, %!STATUS!",
1216 status);
1217 return status;
1218 }
1219
1220 status = m_PowerMachine.Init(this, &FxPkgPnp::_PowerProcessEventInner);
1221 if (!NT_SUCCESS(status)) {
1222 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1223 "Power State Machine init failed, %!STATUS!",
1224 status);
1225 return status;
1226 }
1227
1228 status = m_PowerPolicyMachine.Init(this, &FxPkgPnp::_PowerPolicyProcessEventInner);
1229 if (!NT_SUCCESS(status)) {
1230 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1231 "Power Policy State Machine init failed, %!STATUS!",
1232 status);
1233 return status;
1234 }
1235
1236 return status;
1237 }
1238
1239 VOID
FinishInitialize(__inout PWDFDEVICE_INIT DeviceInit)1240 FxPkgPnp::FinishInitialize(
1241 __inout PWDFDEVICE_INIT DeviceInit
1242 )
1243 /*++
1244
1245 Routine Description:
1246 Finish initializing the object. All initialization up until this point
1247 could fail. This function cannot fail, so all it can do is assign field
1248 values and take allocations from DeviceInit.
1249
1250 Arguments:
1251 DeviceInit - device initialization structure that the driver writer has
1252 initialized
1253
1254 Return Value:
1255 None
1256
1257 --*/
1258
1259 {
1260 //
1261 // Reassign the state callback arrays away from the init struct.
1262 // Set the init field to NULL so that it does not attempt to free the array
1263 // when it is destroyed.
1264 //
1265 m_PnpStateCallbacks = DeviceInit->PnpPower.PnpStateCallbacks;
1266 DeviceInit->PnpPower.PnpStateCallbacks = NULL;
1267
1268 m_PowerStateCallbacks = DeviceInit->PnpPower.PowerStateCallbacks;
1269 DeviceInit->PnpPower.PowerStateCallbacks = NULL;
1270
1271 m_PowerPolicyStateCallbacks = DeviceInit->PnpPower.PowerPolicyStateCallbacks;
1272 DeviceInit->PnpPower.PowerPolicyStateCallbacks = NULL;
1273
1274 //
1275 // Bias the count towards one so that we can optimize the synchronous
1276 // cleanup case when the device is being destroyed.
1277 //
1278 m_PendingChildCount = 1;
1279
1280 //
1281 // Now "Add" this device in the terms that the PnP state machine uses. This
1282 // will be in the context of an actual AddDevice function for FDOs, and
1283 // something very much like it for PDOs.
1284 //
1285 // Important that the posting of the event is after setting of the state
1286 // callback arrays so that we can guarantee that any state transition
1287 // callback will be made.
1288 //
1289 PnpProcessEvent(PnpEventAddDevice);
1290 }
1291
1292 VOID
ProcessDelayedDeletion(VOID)1293 FxPkgPnp::ProcessDelayedDeletion(
1294 VOID
1295 )
1296 {
1297 DoTraceLevelMessage(
1298 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1299 "WDFDEVICE %p, !devobj %p processing delayed deletion from pnp state "
1300 "machine", m_Device->GetHandle(), m_Device->GetDeviceObject());
1301
1302 CleanupStateMachines(FALSE);
1303 DeleteDevice();
1304 }
1305
1306 VOID
SetSpecialFileSupport(__in WDF_SPECIAL_FILE_TYPE FileType,__in BOOLEAN Supported)1307 FxPkgPnp::SetSpecialFileSupport(
1308 __in WDF_SPECIAL_FILE_TYPE FileType,
1309 __in BOOLEAN Supported
1310 )
1311
1312 /*++
1313
1314 Routine Description:
1315
1316 This function marks the device as capable of handling the paging path,
1317 hibernation or crashdumps. Any device that is necessary for one of these
1318 three things will get notification. It is then responsible for forwarding
1319 the notification to its parent. The Framework handles that. This
1320 function just allows a driver to tell the Framework how to respond.
1321
1322
1323 Arguments:
1324
1325 FileType - identifies which of the special paths the device is in
1326 Supported - Yes or No
1327
1328 Returns:
1329
1330 void
1331
1332 --*/
1333
1334 {
1335 switch (FileType) {
1336 case WdfSpecialFilePaging:
1337 case WdfSpecialFileHibernation:
1338 case WdfSpecialFileDump:
1339 case WdfSpecialFileBoot:
1340 SetUsageSupport(_SpecialTypeToUsage(FileType), Supported);
1341 break;
1342
1343 default:
1344 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1345 "Invalid special file type %x", FileType);
1346 }
1347 }
1348
1349 _Must_inspect_result_
1350 NTSTATUS
PnpPassThroughQI(__in CfxDevice * Device,__inout FxIrp * Irp)1351 PnpPassThroughQI(
1352 __in CfxDevice* Device,
1353 __inout FxIrp* Irp
1354 )
1355
1356 /*++
1357
1358 Routine Description:
1359
1360 This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting
1361 a direct-call table from some driver in a device stack. In some cases, the
1362 right response is to turn around and send a similar query to the device's
1363 parent. This function does that.
1364
1365
1366 Arguments:
1367
1368 Device - This WDFDEVICE.
1369 Irp - The IRP that was sent to us.
1370
1371 Returns:
1372
1373 NTSTATUS
1374
1375 --*/
1376
1377 {
1378 MdIrp pFwdIrp;
1379 NTSTATUS status;
1380 NTSTATUS prevStatus;
1381 MxDeviceObject pTopOfStack;
1382
1383 prevStatus = Irp->GetStatus();
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396 pTopOfStack.SetObject(Device->m_ParentDevice->GetAttachedDeviceReference());
1397
1398 pFwdIrp = FxIrp::AllocateIrp(pTopOfStack.GetStackSize());
1399
1400 if (pFwdIrp != NULL) {
1401 FxAutoIrp fxFwdIrp(pFwdIrp);
1402
1403 //
1404 // The worker routine copies stack parameters to forward-Irp, sends it
1405 // down the stack synchronously, then copies back the stack parameters
1406 // from forward-irp to original-irp
1407 //
1408 PnpPassThroughQIWorker(&pTopOfStack, Irp, &fxFwdIrp);
1409
1410 if (fxFwdIrp.GetStatus() != STATUS_NOT_SUPPORTED) {
1411 status = fxFwdIrp.GetStatus();
1412 }
1413 else {
1414 status = prevStatus;
1415 }
1416
1417 Irp->SetStatus(status);
1418 Irp->SetInformation(fxFwdIrp.GetInformation());
1419 }
1420 else {
1421 status = STATUS_INSUFFICIENT_RESOURCES;
1422
1423 DoTraceLevelMessage(
1424 Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1425 "WDFDEVICE %p could not allocate IRP to send QI to parent !devobj "
1426 "%p, %!STATUS!", Device->GetHandle(), pTopOfStack.GetObject(),
1427 status);
1428 }
1429
1430 pTopOfStack.DereferenceObject();
1431
1432 return status;
1433 }
1434
1435 _Must_inspect_result_
1436 NTSTATUS
HandleQueryInterfaceForPowerThread(__inout FxIrp * Irp,__out PBOOLEAN CompleteRequest)1437 FxPkgPnp::HandleQueryInterfaceForPowerThread(
1438 __inout FxIrp* Irp,
1439 __out PBOOLEAN CompleteRequest
1440 )
1441 {
1442 NTSTATUS status;
1443
1444 *CompleteRequest = TRUE;
1445
1446 //
1447 // Send the request down the stack first. If someone lower handles it
1448 // or failed trying to, just return their status
1449 //
1450 status = SendIrpSynchronously(Irp);
1451
1452 if (NT_SUCCESS(status) || status != STATUS_NOT_SUPPORTED) {
1453 //
1454 // Success or failure trying to handle it
1455 //
1456 return status;
1457 }
1458
1459 //
1460 // The semantic of this QI is that it sent down while processing start or
1461 // a device usage notification on the way *up* the stack. That means that
1462 // by the time the QI gets to the lower part of the stack, the power thread
1463 // will have already been allocated and exported.
1464 //
1465 ASSERT(HasPowerThread());
1466
1467 if (Irp->GetParameterQueryInterfaceVersion() == 1 &&
1468 Irp->GetParameterQueryInterfaceSize() >=
1469 m_PowerThreadInterface.Interface.Size) {
1470 //
1471 // Expose the interface to the requesting driver.
1472 //
1473 CopyQueryInterfaceToIrpStack(&m_PowerThreadInterface, Irp);
1474
1475 status = STATUS_SUCCESS;
1476
1477 //
1478 // Caller assumes a reference has been taken.
1479 //
1480 m_PowerThreadInterface.Interface.InterfaceReference(
1481 m_PowerThreadInterface.Interface.Context
1482 );
1483 }
1484 else {
1485 status = STATUS_INVALID_BUFFER_SIZE;
1486 }
1487
1488 return status;
1489 }
1490
1491 _Must_inspect_result_
1492 NTSTATUS
HandleQueryInterface(__inout FxIrp * Irp,__out PBOOLEAN CompleteRequest)1493 FxPkgPnp::HandleQueryInterface(
1494 __inout FxIrp* Irp,
1495 __out PBOOLEAN CompleteRequest
1496 )
1497
1498 /*++
1499
1500 Routine Description:
1501
1502 This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting
1503 a direct-call table from some driver in a device stack. This function
1504 looks into a list of interfaces that the driver has registered and, if
1505 the interface that is being sought is present, it answers the IRP.
1506
1507 Arguments:
1508
1509 Irp - The IRP that was sent to us.
1510 CompleteRequest - tells the caller whether the IRP should be completed
1511
1512 Returns:
1513
1514 NTSTATUS
1515
1516 --*/
1517
1518 {
1519 FxDeviceProcessQueryInterfaceRequest callback;
1520 const GUID* pInterfaceType;
1521 PSINGLE_LIST_ENTRY ple;
1522 FxQueryInterface *pQI;
1523 PVOID pFound;
1524 PINTERFACE pExposedInterface;
1525 PVOID pExposedInterfaceSpecificData;
1526 BOOLEAN sendToParent;
1527
1528 NTSTATUS status;
1529
1530 *CompleteRequest = FALSE;
1531
1532 pFound = NULL;
1533 pQI = NULL;
1534 pExposedInterface = NULL;
1535 pExposedInterfaceSpecificData = NULL;
1536 sendToParent = FALSE;
1537
1538 pInterfaceType = Irp->GetParameterQueryInterfaceType();
1539 //
1540 // The power thread is special cased because it has a different semantic
1541 // then the usual QI irp that we expose to the driver writer. In this case,
1542 // we want to fill in the interface if the lower stack does not support it.
1543 //
1544 if (FxIsEqualGuid(pInterfaceType, &GUID_POWER_THREAD_INTERFACE)) {
1545 return HandleQueryInterfaceForPowerThread(Irp, CompleteRequest);
1546 }
1547 else if (FxIsEqualGuid(pInterfaceType, &GUID_REENUMERATE_SELF_INTERFACE_STANDARD)) {
1548 if (m_Device->IsPdo()) {
1549 return ((FxPkgPdo*) this)->HandleQueryInterfaceForReenumerate(
1550 Irp, CompleteRequest);
1551 }
1552 }
1553
1554 status = Irp->GetStatus();
1555
1556 //
1557 // Walk the interface collection and return the appropriate interface.
1558 //
1559 m_QueryInterfaceLock.AcquireLock(GetDriverGlobals());
1560
1561 for (ple = m_QueryInterfaceHead.Next; ple != NULL; ple = ple->Next) {
1562 pQI = FxQueryInterface::_FromEntry(ple);
1563
1564 if (FxIsEqualGuid(Irp->GetParameterQueryInterfaceType(),
1565 &pQI->m_InterfaceType)) {
1566
1567 pExposedInterface = Irp->GetParameterQueryInterfaceInterface();
1568 pExposedInterfaceSpecificData =
1569 Irp->GetParameterQueryInterfaceInterfaceSpecificData();
1570
1571 if (pQI->m_Interface != NULL) {
1572 //
1573 // NOTE: If a driver has exposed the same interface GUID with
1574 // different sizes as a ways of versioning, then the driver
1575 // writer can specify the minimum size and version number
1576 // and then fill in the remaining fields in the callback
1577 // below.
1578 //
1579 if (pQI->m_Interface->Size <= Irp->GetParameterQueryInterfaceSize() &&
1580 pQI->m_Interface->Version <= Irp->GetParameterQueryInterfaceVersion()) {
1581
1582 if (pQI->m_ImportInterface == FALSE) {
1583 //
1584 // Expose the interface to the requesting driver.
1585 //
1586 RtlCopyMemory(pExposedInterface,
1587 pQI->m_Interface,
1588 pQI->m_Interface->Size);
1589 }
1590 else {
1591 //
1592 // The interface contains data which the driver wants
1593 // before copying over its information, so don't do a
1594 // copy and let the event callback do the copy
1595 //
1596 DO_NOTHING();
1597 }
1598 }
1599 else {
1600 status = STATUS_INVALID_BUFFER_SIZE;
1601 break;
1602 }
1603 }
1604
1605 callback.m_Method = pQI->m_ProcessRequest.m_Method;
1606 sendToParent = pQI->m_SendQueryToParentStack;
1607 pFound = pQI;
1608
1609 status = STATUS_SUCCESS;
1610 break;
1611 }
1612 }
1613
1614 m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals());
1615
1616 if (!NT_SUCCESS(status) || pFound == NULL) {
1617 goto Done;
1618 }
1619
1620 //
1621 // Let the driver see the interface before it is handed out.
1622 //
1623 status = callback.Invoke(m_Device->GetHandle(),
1624 (LPGUID) Irp->GetParameterQueryInterfaceType(),
1625 pExposedInterface,
1626 pExposedInterfaceSpecificData);
1627
1628 //
1629 // STATUS_NOT_SUPPORTED is a special cased error code which indicates that
1630 // the QI should travel down the rest of the stack.
1631 //
1632 if (!NT_SUCCESS(status) && status != STATUS_NOT_SUPPORTED) {
1633 goto Done;
1634 }
1635
1636 //
1637 // If it is meant for the parent, send it down the parent stack
1638 //
1639 if (sendToParent) {
1640 status = PnpPassThroughQI(m_Device, Irp);
1641 goto Done;
1642 }
1643
1644 //
1645 // Reference the interface before returning it to the requesting driver.
1646 // If this is an import interface, the event callback is free to not fill
1647 // in the InterfaceReference function pointer.
1648 //
1649 if (pExposedInterface->InterfaceReference != NULL) {
1650 pExposedInterface->InterfaceReference(pExposedInterface->Context);
1651 }
1652
1653 //
1654 // If we are not a PDO in the stack, then send the fully formatted QI request
1655 // down the stack to allow others to filter the interface.
1656 //
1657 if (m_Device->IsPdo() == FALSE) {
1658 ASSERT(NT_SUCCESS(status) || status == STATUS_NOT_SUPPORTED);
1659
1660 Irp->SetStatus(status);
1661 Irp->CopyCurrentIrpStackLocationToNext();
1662 status = Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
1663 }
1664
1665 Done:
1666 if (pFound != NULL) {
1667 *CompleteRequest = TRUE;
1668 }
1669
1670 return status;
1671 }
1672
1673 _Must_inspect_result_
1674 NTSTATUS
QueryForCapabilities(VOID)1675 FxPkgPnp::QueryForCapabilities(
1676 VOID
1677 )
1678 {
1679 STACK_DEVICE_CAPABILITIES caps;
1680 NTSTATUS status;
1681
1682 MxDeviceObject deviceObject;
1683
1684 deviceObject.SetObject(m_Device->GetDeviceObject());
1685
1686 status = GetStackCapabilities(GetDriverGlobals(),
1687 &deviceObject,
1688 &m_D3ColdInterface,
1689 &caps);
1690
1691 if (NT_SUCCESS(status)) {
1692 ULONG states, i;
1693
1694 ASSERT(caps.DeviceCaps.DeviceWake <= 0xFF && caps.DeviceCaps.SystemWake <= 0xFF);
1695
1696 m_SystemWake = (BYTE) caps.DeviceCaps.SystemWake;
1697
1698 //
1699 // Initialize the array of wakeable D-states to say that all system
1700 // states down to the one identified in the caps can generate wake.
1701 // This will be overridden below if the BIOS supplied more information.
1702 //
1703 // Compatibility Note: Non-ACPI bus drivers (root-enumerated drivers)
1704 // or other bus drivers that haven't set the power settings correctly
1705 // for their PDO may end up with a valid value for DeviceWake in the
1706 // device capabilities but a value of PowerSystemUnspecified for
1707 // SystemWake, in which case a call to WdfDeviceAssignS0IdleSettings or
1708 // WdfDeviceAssignSxWakeSettings DDIs will fail on 1.11+ resulting in
1709 // device compat issues. The failure is expected and right thing to do
1710 // but has compatibility implications - drivers that worked earlier now
1711 // fail on 1.11. Note that earlier versions of WDF did not have
1712 // m_DeviceWake as an array and stored just the capabilities->DeviceWake
1713 // value without regard to the SystemWake but the current implementation
1714 // introduces dependency on systemWake value). So for compat reasons,
1715 // for pre-1.11 compiled drivers we initilaize the array with DeviceWake
1716 // value ignoring SystemWake, removing any dependency of DeviceWake
1717 // on SystemWake value and thus preserving previous behavior for
1718 // pre-1.11 compiled drivers.
1719 //
1720 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) {
1721
1722 RtlFillMemory(m_DeviceWake, DeviceWakeStates, DeviceWakeDepthNotWakeable);
1723
1724 for (i = PowerSystemWorking; i <= m_SystemWake; i++) {
1725
1726 //
1727 // Note that this cast is hiding a conversion between two slightly
1728 // incompatible types. DeviceWake is in terms of DEVICE_POWER_STATE
1729 // which is defined this way:
1730 //
1731 // typedef enum _DEVICE_POWER_STATE {
1732 // PowerDeviceUnspecified = 0,
1733 // PowerDeviceD0,
1734 // PowerDeviceD1,
1735 // PowerDeviceD2,
1736 // PowerDeviceD3,
1737 // PowerDeviceMaximum
1738 // } DEVICE_POWER_STATE, *PDEVICE_POWER_STATE;
1739 //
1740 // m_DeviceWake is defined in terms of DEVICE_WAKE_DEPTH which is
1741 // defined this way:
1742 //
1743 // typedef enum _DEVICE_WAKE_DEPTH {
1744 // DeviceWakeDepthNotWakeable = 0,
1745 // DeviceWakeDepthD0,
1746 // DeviceWakeDepthD1,
1747 // DeviceWakeDepthD2,
1748 // DeviceWakeDepthD3hot,
1749 // DeviceWakeDepthD3cold,
1750 // DeviceWakeDepthMaximum
1751 // } DEVICE_WAKE_DEPTH, *PDEVICE_WAKE_DEPTH;
1752 //
1753 // The result is that the conversion below will map D3 onto D3hot,
1754 // which is a safe assumption to start with, one which may be
1755 // overridden later.
1756 //
1757 C_ASSERT(PowerDeviceD0 == static_cast<DEVICE_POWER_STATE>(DeviceWakeDepthD0));
1758 m_DeviceWake[i - PowerSystemWorking] = (BYTE) caps.DeviceCaps.DeviceWake;
1759 }
1760 }
1761 else {
1762 //
1763 // See comments above for information on mapping of device power
1764 // state to device wake depth.
1765 //
1766 RtlFillMemory(m_DeviceWake,
1767 DeviceWakeStates,
1768 (BYTE) caps.DeviceCaps.DeviceWake);
1769 }
1770
1771 //
1772 // Capture the S -> D state mapping table as a ULONG for use in the
1773 // power policy owner state machine when the machine moves into Sx and
1774 // the device is not armed for wake and has set an IdealDxStateForSx
1775 // value
1776 //
1777 states = 0x0;
1778
1779 for (i = 0; i < ARRAY_SIZE(caps.DeviceCaps.DeviceState); i++) {
1780 _SetPowerCapState(i, caps.DeviceCaps.DeviceState[i], &states);
1781 }
1782
1783 m_PowerPolicyMachine.m_Owner->m_SystemToDeviceStateMap = states;
1784
1785 //
1786 // Query for the D3cold support interface. If present, it will tell
1787 // us specifically which D-states will work for generating wake signals
1788 // from specific S-states.
1789 //
1790 // Earlier versions of WDF didn't make this query, so for compatibility,
1791 // we only make it now if the driver was built against WDF 1.11 or
1792 // later. In truth, this just shifts the failure from initialization
1793 // time to run time, because the information that we're presumably
1794 // getting from the BIOS with this interrogation is saying that the
1795 // code in earlier verisions of WDF would have blindly enabled a device
1796 // for wake which simply wasn't capable of generating its wake signal
1797 // from the chosen D-state. Thus the device would have been put into
1798 // a low power state and then failed to resume in response to its wake
1799 // signal.
1800 //
1801
1802 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) {
1803
1804 //
1805 // Cycle through all the system states that this device can wake
1806 // from. There's no need to look at deeper sleep states than
1807 // m_SystemWake because the driver will not arm for wake in
1808 // those states.
1809 //
1810 for (i = PowerSystemWorking; i <= m_SystemWake; i++) {
1811 if (caps.DeepestWakeableDstate[i] != DeviceWakeDepthMaximum) {
1812 m_DeviceWake[i - PowerSystemWorking] = (BYTE)caps.DeepestWakeableDstate[i];
1813 }
1814 }
1815 }
1816 }
1817
1818 return status;
1819 }
1820
1821 _Must_inspect_result_
1822 NTSTATUS
_PnpStartDevice(__inout FxPkgPnp * This,__inout FxIrp * Irp)1823 FxPkgPnp::_PnpStartDevice(
1824 __inout FxPkgPnp* This,
1825 __inout FxIrp *Irp
1826 )
1827 /*++
1828
1829 Routine Description:
1830 This method is called in response to a PnP StartDevice IRP coming down the
1831 stack.
1832
1833 Arguments:
1834 This - device instance
1835 Irp - a pointer to the FxIrp
1836
1837 Returns:
1838 STATUS_PENDING
1839
1840 --*/
1841 {
1842 This->SetPendingPnpIrp(Irp);
1843 This->PnpProcessEvent(PnpEventStartDevice);
1844
1845 return STATUS_PENDING;
1846 }
1847
1848 _Must_inspect_result_
1849 NTSTATUS
_PnpQueryStopDevice(__inout FxPkgPnp * This,__inout FxIrp * Irp)1850 FxPkgPnp::_PnpQueryStopDevice(
1851 __inout FxPkgPnp* This,
1852 __inout FxIrp *Irp
1853 )
1854
1855 /*++
1856
1857 Routine Description:
1858
1859 Pnp callback querying to see if the device can be stopped.
1860
1861 The Framework philosophy surrounding Query Stop (and Query Remove) is that
1862 it's impossible to really know if you can stop unless you've tried to stop.
1863 This may not always be true, but it's hard to find a general strategy that
1864 works that is less conservative. Furthermore, I couldn't find good examples
1865 of drivers that would really benefit from continuing to handle requests
1866 until the actual Stop IRP arrived, particularly when you consider that
1867 most QueryStops are followed immediately by Stops.
1868
1869 So this function sends an event to the PnP State machine that begins the
1870 stopping process. If it is successful, then ultimately the QueryStop IRP
1871 will be successfully completed.
1872
1873 Arguments:
1874
1875 This - a pointer to the PnP package
1876
1877 Irp - a pointer to the FxIrp
1878
1879 Return Value:
1880
1881 STATUS_PENDING
1882
1883 --*/
1884
1885 {
1886 //
1887 // Keep this IRP around, since we're going to deal with it later.
1888 //
1889 This->SetPendingPnpIrp(Irp);
1890
1891 //
1892 // Now run the state machine on this thread.
1893 //
1894 This->PnpProcessEvent(PnpEventQueryStop);
1895
1896 return STATUS_PENDING;
1897 }
1898
1899 _Must_inspect_result_
1900 NTSTATUS
_PnpCancelStopDevice(__inout FxPkgPnp * This,__inout FxIrp * Irp)1901 FxPkgPnp::_PnpCancelStopDevice(
1902 __inout FxPkgPnp* This,
1903 __inout FxIrp *Irp
1904 )
1905 /*++
1906
1907 Routine Description:
1908
1909 This routine is invoked in response to a query stop failing, somewhere in
1910 the stack. Note that we can receive a cancel stop without being in the
1911 query stop state if a driver above us in the stack failed the query stop.
1912
1913 Again, this function just exists to bridge the gap between the WDM IRPs
1914 and the PnP state machine. This function does little more than send an
1915 event to the machine.
1916
1917 Arguments:
1918
1919 This - the package
1920
1921 Irp - a pointer to the FxIrp
1922
1923 Returns:
1924
1925 STATUS_PENDING
1926
1927 --*/
1928 {
1929 //
1930 // Seed the irp with success
1931 //
1932 Irp->SetStatus(STATUS_SUCCESS);
1933
1934 //
1935 // Pend it and transition the state machine
1936 //
1937 This->SetPendingPnpIrp(Irp);
1938 This->PnpProcessEvent(PnpEventCancelStop);
1939
1940 return STATUS_PENDING;
1941 }
1942
1943 _Must_inspect_result_
1944 NTSTATUS
_PnpStopDevice(__inout FxPkgPnp * This,__inout FxIrp * Irp)1945 FxPkgPnp::_PnpStopDevice(
1946 __inout FxPkgPnp* This,
1947 __inout FxIrp *Irp
1948 )
1949 /*++
1950
1951 Routine Description:
1952
1953 This method is invoked in response to a Pnp StopDevice IRP.
1954
1955 Arguments:
1956
1957 Irp - a pointer to the FxIrp
1958
1959 Returns:
1960
1961 STATUS_PENDING
1962
1963 --*/
1964 {
1965 //
1966 // Seed the irp with success
1967 //
1968 Irp->SetStatus(STATUS_SUCCESS);
1969
1970 //
1971 // Pend and transition the state machine
1972 //
1973 This->SetPendingPnpIrp(Irp);
1974 This->PnpProcessEvent(PnpEventStop);
1975
1976 return STATUS_PENDING;
1977 }
1978
1979 _Must_inspect_result_
1980 NTSTATUS
_PnpQueryRemoveDevice(__inout FxPkgPnp * This,__inout FxIrp * Irp)1981 FxPkgPnp::_PnpQueryRemoveDevice(
1982 __inout FxPkgPnp* This,
1983 __inout FxIrp *Irp
1984 )
1985 /*++
1986
1987 Routine Description:
1988
1989 Again, the Framework handles QueryRemove by stopping everything going on
1990 related to the device and then asking the driver whether it can be
1991 removed. This function just kicks the state machine. Final completion
1992 of the IRP will come (much) later.
1993
1994 Arguments:
1995
1996 This - the package
1997
1998 Irp - a pointer to the FxIrp
1999
2000 Returns:
2001
2002 STATUS_PENDING
2003
2004 --*/
2005 {
2006 //
2007 // By default we handle this state.
2008 //
2009 Irp->SetStatus(STATUS_SUCCESS);
2010
2011 //
2012 // Keep this IRP around, since we're going to deal with it later.
2013 //
2014 This->SetPendingPnpIrp(Irp);
2015
2016 //
2017 // Now run the state machine on this thread.
2018 //
2019 This->PnpProcessEvent(PnpEventQueryRemove);
2020
2021 return STATUS_PENDING;
2022 }
2023
2024 _Must_inspect_result_
2025 NTSTATUS
_PnpCancelRemoveDevice(__inout FxPkgPnp * This,__inout FxIrp * Irp)2026 FxPkgPnp::_PnpCancelRemoveDevice(
2027 __inout FxPkgPnp* This,
2028 __inout FxIrp *Irp
2029 )
2030
2031 /*++
2032
2033 Routine Description:
2034
2035 Notification of a previous remove being canceled. Kick the state machine.
2036
2037 Arguments:
2038
2039 This - the package
2040
2041 Irp - FxIrp representing the notification
2042
2043 Return Value:
2044
2045 STATUS_PENDING
2046
2047 --*/
2048
2049 {
2050 //
2051 // Seed the irp with success
2052 //
2053 Irp->SetStatus(STATUS_SUCCESS);
2054
2055 //
2056 // Pend it and transition the state machine
2057 //
2058
2059 This->SetPendingPnpIrp(Irp);
2060 This->PnpProcessEvent(PnpEventCancelRemove);
2061
2062 return STATUS_PENDING;
2063 }
2064
2065 VOID
CleanupStateMachines(__in BOOLEAN CleanupPnp)2066 FxPkgPnp::CleanupStateMachines(
2067 __in BOOLEAN CleanupPnp
2068 )
2069 {
2070 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
2071 FxCREvent * event = m_CleanupEventUm.GetSelfPointer();
2072 #else
2073 FxCREvent eventOnStack;
2074 eventOnStack.Initialize();
2075 FxCREvent * event = eventOnStack.GetSelfPointer();
2076 #endif
2077
2078 //
2079 // Order of shutdown is important here.
2080 // o Pnp initiates events to power policy.
2081 // o Power policy initiates events to power and device-power-requirement
2082 // o Power does not initiate any events
2083 // o Device-power-requirement does not initiate any events
2084 //
2085 // By shutting them down in the order in which they send events, we can
2086 // guarantee that no new events will be posted into the subsidiary state
2087 // machines.
2088 //
2089
2090 //
2091 // This will shut off the pnp state machine and synchronize any outstanding
2092 // threads of execution.
2093 //
2094 if (CleanupPnp && m_PnpMachine.SetFinished(
2095 event
2096 ) == FALSE) {
2097 DoTraceLevelMessage(
2098 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
2099 "WDFDEVICE %p, !devobj %p waiting for pnp state machine to finish",
2100 m_Device->GetHandle(), m_Device->GetDeviceObject());
2101
2102 //
2103 // Process the event *before* completing the irp so that this event is in
2104 // the queue before the device remove event which will be processed
2105 // right after the start irp has been completed.
2106 //
2107 event->EnterCRAndWaitAndLeave();
2108 }
2109
2110 //
2111 // Even though event is a SynchronizationEvent, so we need to reset it for
2112 // the next wait because SetFinished will set it if even if the transition
2113 // to the finished state is immediate
2114 //
2115 event->Clear();
2116
2117 if (m_PowerPolicyMachine.SetFinished(event) == FALSE) {
2118 DoTraceLevelMessage(
2119 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
2120 "WDFDEVICE %p, !devobj %p waiting for pwr pol state machine to finish",
2121 m_Device->GetHandle(), m_Device->GetDeviceObject());
2122
2123 event->EnterCRAndWaitAndLeave();
2124 }
2125
2126 //
2127 // See previous comment about why we Clear()
2128 //
2129 event->Clear();
2130
2131 if (m_PowerMachine.SetFinished(event) == FALSE) {
2132 DoTraceLevelMessage(
2133 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
2134 "WDFDEVICE %p, !devobj %p waiting for pwr state machine to finish",
2135 m_Device->GetHandle(), m_Device->GetDeviceObject());
2136
2137 event->EnterCRAndWaitAndLeave();
2138 }
2139
2140 if (IsPowerPolicyOwner()) {
2141 //
2142 // See previous comment about why we Clear()
2143 //
2144 event->Clear();
2145
2146 if (NULL != m_PowerPolicyMachine.m_Owner->m_PoxInterface.
2147 m_DevicePowerRequirementMachine) {
2148
2149 if (FALSE == m_PowerPolicyMachine.m_Owner->m_PoxInterface.
2150 m_DevicePowerRequirementMachine->SetFinished(event)) {
2151
2152 DoTraceLevelMessage(
2153 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
2154 "WDFDEVICE %p, !devobj %p waiting for device power "
2155 "requirement state machine to finish",
2156 m_Device->GetHandle(),
2157 m_Device->GetDeviceObject());
2158
2159 event->EnterCRAndWaitAndLeave();
2160 }
2161 }
2162
2163 m_PowerPolicyMachine.m_Owner->CleanupPowerCallback();
2164 }
2165
2166 //
2167 // Release the power thread if we have one either through creation or query.
2168 // Since the power policy state machine is off, we should no longer need
2169 // a dedicated thread.
2170 //
2171 // *** NOTE ***
2172 // The power thread must be released *BEFORE* sending the irp down the stack
2173 // because this can happen
2174 // 1) this driver is not the power thread owner, but the last client
2175 // 2) we send the pnp irp first
2176 // 3) the power thread owner waits on this thread for all the clients to go
2177 // away, but this device still has a reference on it
2178 // 4) this device will not release the reference b/c the owner is waiting
2179 // in the same thread.
2180 //
2181 ReleasePowerThread();
2182
2183 //
2184 // Deref the reenumeration interface
2185 //
2186 ReleaseReenumerationInterface();
2187 }
2188
2189 VOID
CleanupDeviceFromFailedCreate(__in MxEvent * WaitEvent)2190 FxPkgPnp::CleanupDeviceFromFailedCreate(
2191 __in MxEvent * WaitEvent
2192 )
2193 /*++
2194
2195 Routine Description:
2196 The device failed creation in some stage. It is assumed that the device has
2197 enough state that it can survive a transition through the pnp state machine
2198 (which means that pointers like m_PkgIo are valid and != NULL). When this
2199 function returns, it will have deleted the owning FxDevice.
2200
2201 Arguments:
2202 WaitEvent - Event on which RemoveProcessed wait will be performed
2203
2204 We can't initialize this event on stack as the initialization
2205 can fail in user-mode. We can't have Initialize method
2206 preinitailize this event either as this function may get called
2207 before initialize (or in case of initialization failure).
2208
2209 Hence the caller preallocates the event and passes to this
2210 function.
2211
2212 Caller must initialize this event as SynchronizationEvent
2213 and it must be unsignalled.
2214 Return Value:
2215 None
2216
2217 --*/
2218 {
2219 Mx::MxAssert(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
2220
2221 //
2222 // Caller must initialize the event as Synchronization event and it should
2223 // be passed as non-signalled. But we Clear it just to be sure.
2224 //
2225 WaitEvent->Clear();
2226
2227 ADDREF(WaitEvent);
2228
2229 ASSERT(m_DeviceRemoveProcessed == NULL);
2230 m_DeviceRemoveProcessed = WaitEvent;
2231
2232 //
2233 // Simulate a remove event coming to the device. After this call returns
2234 // m_Device is still valid and must be deleted.
2235 //
2236 PnpProcessEvent(PnpEventRemove);
2237
2238 //
2239 // No need to wait in a critical region because we are in the context of a
2240 // pnp request which is in the system context.
2241 //
2242 WaitEvent->WaitFor(Executive, KernelMode, FALSE, NULL);
2243 m_DeviceRemoveProcessed = NULL;
2244
2245 RELEASE(WaitEvent);
2246 }
2247
2248 VOID
DeleteDevice(VOID)2249 FxPkgPnp::DeleteDevice(
2250 VOID
2251 )
2252 /*++
2253
2254 Routine Description:
2255 This routine will detach and delete the device object and free the memory
2256 for the device if there are no other references to it. Before calling this
2257 routine, the state machines should have been cleaned up and the power thread
2258 released.
2259
2260 --*/
2261 {
2262 //
2263 // This will detach and delete the device object
2264 //
2265 m_Device->Destroy();
2266
2267 //
2268 // If this is the last reference, this will free the memory for the device
2269 //
2270 m_Device->DeleteObject();
2271 }
2272
2273 _Must_inspect_result_
2274 NTSTATUS
_PnpRemoveDevice(__inout FxPkgPnp * This,__inout FxIrp * Irp)2275 FxPkgPnp::_PnpRemoveDevice(
2276 __inout FxPkgPnp* This,
2277 __inout FxIrp *Irp
2278 )
2279
2280 /*++
2281
2282 Routine Description:
2283
2284 Notification of a remove. Kick the state machine.
2285
2286 Arguments:
2287
2288 This - the package
2289
2290 Irp - FxIrp representing the notification
2291
2292 Return Value:
2293
2294 status
2295
2296 --*/
2297
2298 {
2299 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
2300 MxEvent * event = This->m_RemoveEventUm.GetSelfPointer();
2301 #else
2302 MxEvent eventOnStack;
2303 eventOnStack.Initialize(SynchronizationEvent, FALSE);
2304 MxEvent * event = eventOnStack.GetSelfPointer();
2305 #endif
2306
2307 NTSTATUS status;
2308
2309 status = Mx::MxAcquireRemoveLock(
2310 This->m_Device->GetRemoveLock(),
2311 Irp->GetIrp());
2312
2313 #if DBG
2314 ASSERT(NT_SUCCESS(status));
2315 #else
2316 UNREFERENCED_PARAMETER(status);
2317 #endif
2318
2319 //
2320 // Keep this object around after m_Device has RELEASE'ed its reference to
2321 // this package.
2322 //
2323 This->ADDREF(Irp);
2324
2325 //
2326 // Removes are always success
2327 //
2328 Irp->SetStatus(STATUS_SUCCESS);
2329
2330 ASSERT(This->m_DeviceRemoveProcessed == NULL);
2331 This->m_DeviceRemoveProcessed = event;
2332
2333 //
2334 // Post the event and wait for the FxDevice to destroy itself or determine
2335 // it has not been reported missing yet (for PDOs and bus filters).
2336 //
2337 This->PnpProcessEvent(PnpEventRemove);
2338
2339 DoTraceLevelMessage(
2340 This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
2341 "WDFDEVICE %p, !devobj %p waiting for remove event to finish processing",
2342 This->m_Device->GetHandle(), This->m_Device->GetDeviceObject());
2343
2344 //
2345 // No need to wait in a critical region because we are in the context of a
2346 // pnp request which is in the system context.
2347 //
2348 event->WaitFor(Executive, KernelMode, FALSE, NULL);
2349
2350 This->m_DeviceRemoveProcessed = NULL;
2351
2352 status = This->ProcessRemoveDeviceOverload(Irp);
2353
2354 //
2355 // Release the reference added at the top. This is most likely going to be
2356 // the last reference on the package for KMDF. For UMDF, host manages the
2357 // lifetime of FxDevice so this may not be the last release for UMDF.
2358 //
2359 This->RELEASE(Irp);
2360
2361 return status;
2362 }
2363
2364 _Must_inspect_result_
2365 NTSTATUS
PnpSurpriseRemoval(__inout FxIrp * Irp)2366 FxPkgPnp::PnpSurpriseRemoval(
2367 __inout FxIrp* Irp
2368 )
2369
2370 /*++
2371
2372 Routine Description:
2373
2374 Notification that the device has been surprise removed. Kick the state
2375 machine.
2376
2377 Arguments:
2378
2379 Irp - pointer to FxIrp representing this notification
2380
2381 Return Value:
2382
2383 STATUS_PENDING
2384
2385 --*/
2386
2387 {
2388 //
2389 // Package specific handling
2390 //
2391 Irp->SetStatus(STATUS_SUCCESS);
2392 SetPendingPnpIrp(Irp);
2393 PnpProcessEvent(PnpEventSurpriseRemove);
2394
2395 return STATUS_PENDING;
2396 }
2397
2398 _Must_inspect_result_
2399 NTSTATUS
_DispatchWaitWake(__inout FxPkgPnp * This,__inout FxIrp * Irp)2400 FxPkgPnp::_DispatchWaitWake(
2401 __inout FxPkgPnp* This,
2402 __inout FxIrp *Irp
2403 )
2404
2405 /*++
2406
2407 Routine Description:
2408
2409 This the first-level dispatch routine for IRP_MN_WAIT_WAKE. What one
2410 does with a WaitWake IRP depends very much on whether one is an FDO, a PDO
2411 or a filter. So dispatch immediately to a subclassable function.
2412
2413 Arguments:
2414
2415 This - the package
2416
2417 Irp - pointer to FxIrp representing this notification
2418
2419 Return Value:
2420
2421 status
2422
2423 --*/
2424
2425 {
2426 return This->DispatchWaitWake(Irp);
2427 }
2428
2429 _Must_inspect_result_
2430 NTSTATUS
DispatchWaitWake(__inout FxIrp * Irp)2431 FxPkgPnp::DispatchWaitWake(
2432 __inout FxIrp *Irp
2433 )
2434 /*++
2435
2436 Routine Description:
2437
2438 Handles wait wake requests in a generic fashion
2439
2440 Arguments:
2441
2442
2443 Return Value:
2444
2445 --*/
2446 {
2447 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
2448 NTSTATUS status;
2449 PIRP oldIrp;
2450 KIRQL irql;
2451
2452 if (IsPowerPolicyOwner()) {
2453 if (m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp == FALSE) {
2454 //
2455 // A power irp arrived, but we did not request it. log and bugcheck
2456 //
2457 DoTraceLevelMessage(
2458 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2459 "Received wait wake power irp %p on device %p, but the irp was "
2460 "not requested by the device (the power policy owner)",
2461 Irp->GetIrp(), m_Device->GetDeviceObject());
2462
2463 FxVerifierBugCheck(GetDriverGlobals(), // globals
2464 WDF_POWER_MULTIPLE_PPO, // specific type
2465 (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2
2466 (ULONG_PTR)Irp->GetIrp()); // parm 3
2467
2468 /* NOTREACHED */
2469 }
2470
2471 //
2472 // We are no longer requesting a power irp because we received the one
2473 // we requested.
2474 //
2475 m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp = FALSE;
2476 }
2477
2478 //
2479 // The Framework has the concept of a "Wait/Wake Owner." This is the layer
2480 // in the stack that is enabling and disabling wake at the bus level. This
2481 // is probably the PDO or a bus filter like ACPI.sys. This is distinct
2482 // from being the "Power Policy Owner," which would mean that this driver
2483 // is deciding what D-state is appropriate for the device, and also
2484 // sending Wait/Wake IRPs.
2485 //
2486
2487 if (m_SharedPower.m_WaitWakeOwner) {
2488 m_PowerMachine.m_WaitWakeLock.Acquire(&irql);
2489
2490 if (m_SharedPower.m_WaitWakeIrp != NULL) {
2491 //
2492 // We only allow one pended wait wake irp in the stack at a time.
2493 // Fail this secondary wait wake request.
2494 //
2495 status = STATUS_INVALID_DEVICE_STATE;
2496
2497 DoTraceLevelMessage(
2498 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2499 "Failing wait wake irp %p with %!STATUS! because wait wake irp "
2500 "%p already pended",
2501 Irp->GetIrp(), status, m_SharedPower.m_WaitWakeIrp);
2502 }
2503 else {
2504 MdCancelRoutine pRoutine;
2505
2506 //
2507 // No wait wake irp is currently in the stack, so attempt to set
2508 // a cancel routine and transition the power state machine into a
2509 // a state where it can arm the device at the bus level for this
2510 // child.
2511 //
2512 // The power state machine expects the wait wake irp to have a cancel
2513 // routine set in all states. For those states which require a
2514 // non cancelable irp, those states clear the cancel routine as
2515 // appropriate.
2516 //
2517 pRoutine = Irp->SetCancelRoutine(_PowerWaitWakeCancelRoutine);
2518 #if DBG
2519 ASSERT(pRoutine == NULL);
2520 #else
2521 UNREFERENCED_PARAMETER(pRoutine);
2522 #endif
2523 status = STATUS_PENDING;
2524
2525 if (Irp->IsCanceled()) {
2526 DoTraceLevelMessage(GetDriverGlobals(),
2527 TRACE_LEVEL_ERROR, TRACINGPNP,
2528 "wait wake irp %p already canceled", Irp->GetIrp());
2529
2530 //
2531 // This IRP has already been cancelled, we must clear the cancel
2532 // routine before completing the IRP.
2533 //
2534 pRoutine = Irp->SetCancelRoutine(NULL);
2535
2536 if (pRoutine != NULL) {
2537 //
2538 // Our cancel routine will not be called
2539 //
2540 #if DBG
2541 ASSERT(pRoutine == _PowerWaitWakeCancelRoutine);
2542 #else
2543 UNREFERENCED_PARAMETER(pRoutine);
2544 #endif
2545 Irp->SetStatus(STATUS_CANCELLED);
2546 status = STATUS_CANCELLED;
2547 }
2548 }
2549
2550 if (status == STATUS_PENDING) {
2551 //
2552 // Either we successfully set the cancel routine or the irp
2553 // was canceled and the cancel routine is about to run when
2554 // we drop the lock. If the routine is about to run, we still
2555 // need to setup m_SharedPower to values that it expects.
2556 //
2557 Irp->MarkIrpPending();
2558 m_SharedPower.m_WaitWakeIrp = Irp->GetIrp();
2559 }
2560 }
2561 m_PowerMachine.m_WaitWakeLock.Release(irql);
2562
2563 if (NT_SUCCESS(status)) {
2564 //
2565 // Post to the appropriate matchines
2566 //
2567 PowerProcessEvent(PowerWakeArrival);
2568
2569 if (IsPowerPolicyOwner()) {
2570 PowerPolicyProcessEvent(PwrPolWakeArrived);
2571 }
2572 }
2573 else {
2574 CompletePowerRequest(Irp, status);
2575 }
2576
2577 return status;
2578 }
2579 else if (IsPowerPolicyOwner()) {
2580 //
2581 // Try to set m_WaitWakeIrp to the new IRP value only if the current
2582 // value of m_WaitWakeIrp is NULL because there can only be one
2583 // active wait wake irp in the stack at a time. Since the power policy
2584 // state machine never sends more then one, this is really a guard
2585 // against some other device in the stack sending a wait wake irp to
2586 // this device in the wrong state.
2587 //
2588 oldIrp = (PIRP) InterlockedCompareExchangePointer(
2589 (PVOID*) &m_SharedPower.m_WaitWakeIrp,
2590 Irp->GetIrp(),
2591 NULL
2592 );
2593
2594 //
2595 // If oldIrp is NULL then there was no previous irp and we successfully
2596 // exchanged the new PIRP value into m_WaitWakeIrp
2597 //
2598 if (oldIrp == NULL) {
2599 m_PowerPolicyMachine.SetWaitWakeUnclaimed();
2600
2601 //
2602 // NOTE: There is a built in race condition here that WDF cannot
2603 // solve with the given WDM primitives. After arming the
2604 // device for wake, there is a window where the wait wake irp
2605 // has not yet been processed by the wait wake owner. Until
2606 // the wake request is processed, wake events could be generated
2607 // and lost. There is nothing we can do about this until we
2608 // have synchronous "goto Dx and arm" command available.
2609 //
2610 Irp->CopyCurrentIrpStackLocationToNext();
2611 Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(),
2612 _PowerPolicyWaitWakeCompletionRoutine,
2613 this);
2614
2615 //
2616 // Technically, there should be a PDO vs FDO overload here which
2617 // does the right thing w/regard to this request and if it is at the
2618 // bottom of the stack or not. But, by design, we check for
2619 // m_WaitWakeOwner first which has the direct side affect of making
2620 // it impossible for a PDO to get to this point.
2621 //
2622 ASSERT(m_Device->IsFdo());
2623
2624 status = Irp->PoCallDriver(m_Device->GetAttachedDevice());
2625
2626 //
2627 // Send the wake arrived after sending the request as commented above.
2628 // This window between sending the request and sending the event to
2629 // the state machine allows the wait owner to complete the request
2630 // immediately. When completed synchronously, it has an effect on
2631 // both wake scenarios:
2632 //
2633 // 1) wake from S0: the device never transitions to Dx and the idle
2634 // timer is resumed if no i/o is present
2635 //
2636 // 2) wake from sx: the device is disarmed for wake from Sx and
2637 // put into Dx with being armed for wake.
2638 //
2639 PowerPolicyProcessEvent(PwrPolWakeArrived);
2640 }
2641 else {
2642 status = STATUS_POWER_STATE_INVALID;
2643
2644 DoTraceLevelMessage(
2645 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
2646 "already have a ww irp %p, failing new ww irp %p with %!STATUS!",
2647 oldIrp, Irp->GetIrp(), status);
2648
2649 CompletePowerRequest(Irp, status);
2650 }
2651 }
2652 else {
2653 //
2654 // Not the power policy owner, not the wait wake irp owner, ignore the
2655 // irp
2656 //
2657 // This will release the remove lock.
2658 //
2659 status = FireAndForgetIrp(Irp);
2660 }
2661
2662 return status;
2663 }
2664
2665 _Must_inspect_result_
2666 NTSTATUS
RegisterCallbacks(__in PWDF_PNPPOWER_EVENT_CALLBACKS DispatchTable)2667 FxPkgPnp::RegisterCallbacks(
2668 __in PWDF_PNPPOWER_EVENT_CALLBACKS DispatchTable
2669 )
2670 {
2671 NTSTATUS status;
2672
2673 //
2674 // Update the callback table.
2675 //
2676 m_DeviceD0Entry.m_Method = DispatchTable->EvtDeviceD0Entry;
2677 m_DeviceD0EntryPostInterruptsEnabled.m_Method =
2678 DispatchTable->EvtDeviceD0EntryPostInterruptsEnabled;
2679 m_DeviceD0ExitPreInterruptsDisabled.m_Method =
2680 DispatchTable->EvtDeviceD0ExitPreInterruptsDisabled;
2681 m_DeviceD0Exit.m_Method = DispatchTable->EvtDeviceD0Exit;
2682
2683 m_DevicePrepareHardware.m_Method = DispatchTable->EvtDevicePrepareHardware;
2684 m_DeviceReleaseHardware.m_Method = DispatchTable->EvtDeviceReleaseHardware;
2685
2686 m_DeviceQueryStop.m_Method = DispatchTable->EvtDeviceQueryStop;
2687 m_DeviceQueryRemove.m_Method = DispatchTable->EvtDeviceQueryRemove;
2688
2689 m_DeviceSurpriseRemoval.m_Method = DispatchTable->EvtDeviceSurpriseRemoval;
2690
2691 m_DeviceUsageNotification.m_Method = DispatchTable->EvtDeviceUsageNotification;
2692 m_DeviceUsageNotificationEx.m_Method = DispatchTable->EvtDeviceUsageNotificationEx;
2693 m_DeviceRelationsQuery.m_Method = DispatchTable->EvtDeviceRelationsQuery;
2694
2695 if (DispatchTable->EvtDeviceSelfManagedIoCleanup != NULL ||
2696 DispatchTable->EvtDeviceSelfManagedIoFlush != NULL ||
2697 DispatchTable->EvtDeviceSelfManagedIoInit != NULL ||
2698 DispatchTable->EvtDeviceSelfManagedIoSuspend != NULL ||
2699 DispatchTable->EvtDeviceSelfManagedIoRestart != NULL) {
2700
2701 status = FxSelfManagedIoMachine::_CreateAndInit(&m_SelfManagedIoMachine,
2702 this);
2703
2704 if (!NT_SUCCESS(status)) {
2705 return status;
2706 }
2707
2708 m_SelfManagedIoMachine->InitializeMachine(DispatchTable);
2709 }
2710
2711 return STATUS_SUCCESS;
2712 }
2713
2714 VOID
RegisterPowerPolicyCallbacks(__in PWDF_POWER_POLICY_EVENT_CALLBACKS Callbacks)2715 FxPkgPnp::RegisterPowerPolicyCallbacks(
2716 __in PWDF_POWER_POLICY_EVENT_CALLBACKS Callbacks
2717 )
2718 {
2719 m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromS0.m_Method =
2720 Callbacks->EvtDeviceArmWakeFromS0;
2721 m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.m_Method =
2722 Callbacks->EvtDeviceArmWakeFromSx;
2723 m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.m_MethodWithReason =
2724 Callbacks->EvtDeviceArmWakeFromSxWithReason;
2725
2726 m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.m_Method =
2727 Callbacks->EvtDeviceDisarmWakeFromS0;
2728 m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromSx.m_Method =
2729 Callbacks->EvtDeviceDisarmWakeFromSx;
2730
2731 m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromS0Triggered.m_Method =
2732 Callbacks->EvtDeviceWakeFromS0Triggered;
2733 m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.m_Method =
2734 Callbacks->EvtDeviceWakeFromSxTriggered;
2735 }
2736
2737 NTSTATUS
RegisterPowerPolicyWmiInstance(__in const GUID * Guid,__in FxWmiInstanceInternalCallbacks * Callbacks,__out FxWmiInstanceInternal ** Instance)2738 FxPkgPnp::RegisterPowerPolicyWmiInstance(
2739 __in const GUID* Guid,
2740 __in FxWmiInstanceInternalCallbacks* Callbacks,
2741 __out FxWmiInstanceInternal** Instance
2742 )
2743 {
2744 // WDF_WMI_PROVIDER_CONFIG config;
2745 // NTSTATUS status;
2746
2747 // WDF_WMI_PROVIDER_CONFIG_INIT(&config, Guid);
2748
2749 // //
2750 // // We are assuming we are registering either for the wait wake or device
2751 // // timeout GUIDs which both operate on BOOLEANs. If we expand this API in
2752 // // the future, have the caller pass in a config structure for the provider
2753 // // GUID.
2754 // //
2755 // config.MinInstanceBufferSize = sizeof(BOOLEAN);
2756
2757 // status = m_Device->m_PkgWmi->AddPowerPolicyProviderAndInstance(
2758 // &config,
2759 // Callbacks,
2760 // Instance);
2761
2762 // if (status == STATUS_OBJECT_NAME_COLLISION) {
2763 // status = STATUS_SUCCESS;
2764 // }
2765
2766 // if (!NT_SUCCESS(status)) {
2767 // DoTraceLevelMessage(
2768 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2769 // "Failed to register WMI power GUID %!STATUS!", status);
2770 // }
2771 //
2772 // return status;
2773 ROSWDFNOTIMPLEMENTED;
2774 return STATUS_SUCCESS;
2775 }
2776
2777 NTSTATUS
PowerPolicySetS0IdleSettings(__in PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings)2778 FxPkgPnp::PowerPolicySetS0IdleSettings(
2779 __in PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings
2780 )
2781 /*++
2782
2783 Routine Description:
2784
2785 Updates the S0 Idle settings for the device and then posts an update event
2786 to the power policy state machine. The first this function is called, the
2787 ability to allow the user to control this setting is set.
2788
2789 Arguments:
2790
2791 Settings - The settings to apply.
2792
2793 Return Value:
2794
2795 NTSTATUS
2796
2797 --*/
2798 {
2799 DEVICE_POWER_STATE dxState;
2800 ULONG idleTimeout;
2801 NTSTATUS status;
2802 BOOLEAN enabled, s0Capable, overridable, firstTime;
2803 WDF_TRI_STATE powerUpOnSystemWake;
2804 const LONGLONG negliblySmallIdleTimeout = -1; // 100 nanoseconds
2805
2806 s0Capable = FALSE;
2807 dxState = PowerDeviceD3;
2808 overridable = FALSE;
2809 firstTime = TRUE;
2810
2811 if (Settings->Enabled == WdfTrue) {
2812 enabled = TRUE;
2813
2814 } else if (Settings->Enabled == WdfUseDefault) {
2815 enabled = TRUE;
2816
2817 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
2818 DECLARE_CONST_UNICODE_STRING(valueName, WDF_S0_IDLE_DEFAULT_VALUE_NAME);
2819
2820 //
2821 // Read registry. If registry value is not found, the value of "enabled"
2822 // remains unchanged
2823 //
2824 ReadRegistryS0Idle(&valueName, &enabled);
2825 }
2826 else {
2827 DoTraceLevelMessage(
2828 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
2829 "If registry value WdfDefaultIdleInWorkingState was present, "
2830 "it was not read because DDI WdfDeviceAssignS0IdleSettings "
2831 "was not called at PASSIVE_LEVEL");
2832 }
2833 }
2834 else {
2835 enabled = FALSE;
2836 }
2837
2838 if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Set) {
2839 firstTime = FALSE;
2840 }
2841
2842 if (m_CapsQueried == FALSE && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
2843 status = QueryForCapabilities();
2844 if (!NT_SUCCESS(status)) {
2845 return status;
2846 }
2847
2848 //
2849 // Do not set m_CapsQueried to TRUE yet because we will do that once we
2850 // know the entire stack has been built we will do the query again.
2851 //
2852 }
2853
2854 switch (Settings->IdleCaps) {
2855 case IdleUsbSelectiveSuspend:
2856 case IdleCanWakeFromS0:
2857 s0Capable = TRUE;
2858
2859 if (Settings->DxState == PowerDeviceMaximum) {
2860 dxState = PowerPolicyGetDeviceDeepestDeviceWakeState(PowerSystemWorking);
2861
2862 //
2863 // Some bus drivers
2864
2865 // incorrectly report DeviceWake=D0 to
2866 // indicate that it does not support wake instead of specifying
2867 // PowerDeviceUnspecified and KMDF ends up requesting
2868 // a D0 irp when going to Dx. The check prevents this bug.
2869 //
2870 if (dxState < PowerDeviceD1 ||
2871 dxState > PowerDeviceD3 ||
2872 (dxState > PowerDeviceD2 && Settings->IdleCaps == IdleUsbSelectiveSuspend)
2873 ) {
2874 status = STATUS_POWER_STATE_INVALID;
2875
2876 DoTraceLevelMessage(
2877 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2878 "DeviceWake power state reported in device capabilities "
2879 "%!DEVICE_POWER_STATE! indicates that device can not signal"
2880 " a wake event, %!STATUS!",
2881 dxState, status);
2882 return status;
2883 }
2884 }
2885 else {
2886 DEVICE_POWER_STATE dxDeepest;
2887
2888 dxState = Settings->DxState;
2889 dxDeepest = PowerPolicyGetDeviceDeepestDeviceWakeState(PowerSystemWorking);
2890
2891 if (dxState > dxDeepest) {
2892 status = STATUS_POWER_STATE_INVALID;
2893
2894 DoTraceLevelMessage(
2895 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2896 "DxState specified by driver %!DEVICE_POWER_STATE! cannot "
2897 "be lighter than lightest available device wake state"
2898 " %!DEVICE_POWER_STATE!, %!STATUS!", dxState,
2899 dxDeepest, status);
2900 return status;
2901 }
2902
2903 //
2904 // Can only perform wait wake from D2 on a USB device
2905 //
2906 if (dxState > PowerDeviceD2 &&
2907 Settings->IdleCaps == IdleUsbSelectiveSuspend) {
2908 status = STATUS_POWER_STATE_INVALID;
2909
2910 DoTraceLevelMessage(
2911 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2912 "DxState specified by driver %!DEVICE_POWER_STATE! cannot "
2913 "be lighter than PowerDeviceD2 for USB selective suspend "
2914 "%!STATUS!",
2915 dxState, status);
2916 return status;
2917 }
2918 }
2919
2920 if (Settings->IdleCaps == IdleUsbSelectiveSuspend) {
2921 status = m_PowerPolicyMachine.InitUsbSS();
2922
2923 if (!NT_SUCCESS(status)) {
2924 DoTraceLevelMessage(
2925 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2926 "Failed to initialize USB selective suspend %!STATUS!",
2927 status);
2928 return status;
2929 }
2930 }
2931
2932 break;
2933
2934 case IdleCannotWakeFromS0:
2935 s0Capable = FALSE;
2936
2937 if (Settings->DxState == PowerDeviceMaximum) {
2938 dxState = PowerDeviceD3;
2939 }
2940 else {
2941 dxState = Settings->DxState;
2942 }
2943
2944 break;
2945
2946 default:
2947 ASSERT(FALSE);
2948 break;
2949 }
2950
2951 if (Settings->IdleTimeout == IdleTimeoutDefaultValue) {
2952 idleTimeout = FxPowerPolicyDefaultTimeout;
2953 }
2954 else {
2955 idleTimeout = Settings->IdleTimeout;
2956 }
2957
2958 if (Settings->UserControlOfIdleSettings == IdleAllowUserControl) {
2959
2960 // status = UpdateWmiInstanceForS0Idle(AddInstance);
2961 // if (!NT_SUCCESS(status)) {
2962 // return status;
2963 // } __REACTOS__
2964
2965 if (Settings->Enabled == WdfUseDefault) {
2966 //
2967 // Read the registry entry for idle enabled if it's the first time.
2968 //
2969 if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
2970 DECLARE_CONST_UNICODE_STRING(valueName, WDF_S0_IDLE_ENABLED_VALUE_NAME);
2971
2972 //
2973 // Read registry. If registry value is not found, the value of
2974 // "enabled" remains unchanged
2975 //
2976 ReadRegistryS0Idle(&valueName, &enabled);
2977 }
2978 else {
2979 //
2980 // Use the saved value for idle enabled.
2981 //
2982 enabled = m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled;
2983 }
2984 }
2985
2986 overridable = TRUE;
2987 }
2988 else if (Settings->UserControlOfIdleSettings == IdleDoNotAllowUserControl) {
2989 //
2990 // No user control
2991 //
2992 overridable = FALSE;
2993
2994 // (void) UpdateWmiInstanceForS0Idle(RemoveInstance); __REACTOS__
2995 }
2996
2997 //
2998 // !!!! DO NOT INTRODUCE FAILURES BEYOND THIS POINT !!!!
2999 //
3000 // We should not introduce any failures that are not due to driver errors
3001 // beyond this point. This is because we are going to commit the driver's
3002 // S0-idle settings now and any failure in the midst of that could leave us
3003 // in a bad state. Therefore, all failable code where the failure is beyond
3004 // the driver's control should be placed above this point.
3005 //
3006 // For example, a driver may want wake-from-S0 support, but the device may
3007 // not support it. We already checked for that failure above, before we
3008 // started committing any of the driver's S0-idle settings.
3009 //
3010 // Any failures below this point should only be due to driver errors, i.e.
3011 // the driver incorrectly calling the AssignS0IdleSettings DDI.
3012 //
3013
3014 if (firstTime) {
3015 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Set = TRUE;
3016 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable = overridable;
3017 }
3018
3019 //
3020 // IdleTimeoutType is available only on > 1.9
3021 //
3022 #ifndef __REACTOS__
3023 if (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) {
3024 if (firstTime) {
3025 if ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) ||
3026 (SystemManagedIdleTimeoutWithHint ==
3027 Settings->IdleTimeoutType)) {
3028 //
3029 // This is the first time S0-idle policy is being specified and
3030 // the caller has asked for the idle timeout to be determined
3031 // by the power manager.
3032 //
3033 status = m_PowerPolicyMachine.m_Owner->m_IdleSettings.
3034 m_TimeoutMgmt.UseSystemManagedIdleTimeout(
3035 GetDriverGlobals()
3036 );
3037 if (!NT_SUCCESS(status)) {
3038 return status;
3039 }
3040 }
3041 } else {
3042 //
3043 // This is not the first time S0-idle policy is being specified.
3044 // Verify that the caller is not trying to change their mind about
3045 // whether the idle timeout is determined by the power manager.
3046 //
3047 BOOLEAN currentlyUsingSystemManagedIdleTimeout;
3048 BOOLEAN callerWantsSystemManagedIdleTimeout;
3049
3050 currentlyUsingSystemManagedIdleTimeout =
3051 m_PowerPolicyMachine.m_Owner->m_IdleSettings.m_TimeoutMgmt.
3052 UsingSystemManagedIdleTimeout();
3053 callerWantsSystemManagedIdleTimeout =
3054 ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) ||
3055 (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType));
3056
3057 //
3058 // UMDF currently does not implement
3059 // IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable. So
3060 // that method must be called only as part of the second check in
3061 // the "if" statement below. Since UMDF currently does not support
3062 // system managed idle timeout, the first check will always evaluate
3063 // to 'FALSE', so the second check never gets executed for UMDF.
3064 //
3065 if ((callerWantsSystemManagedIdleTimeout !=
3066 currentlyUsingSystemManagedIdleTimeout)
3067 &&
3068 (IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable())
3069 ) {
3070
3071 status = STATUS_INVALID_DEVICE_REQUEST;
3072 DoTraceLevelMessage(
3073 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3074 "A previous call to assign S0-idle policy specified that "
3075 "the idle timeout %s be determined by the power manager. "
3076 "This decision cannot be changed. %!STATUS!",
3077 currentlyUsingSystemManagedIdleTimeout ?
3078 "should" :
3079 "should not",
3080 status);
3081 FxVerifierDbgBreakPoint(GetDriverGlobals());
3082 return status;
3083 }
3084 }
3085 }
3086 #endif
3087
3088 if (Settings->IdleCaps == IdleCannotWakeFromS0) {
3089 //
3090 // PowerUpIdleDeviceOnSystemWake field added after v1.7.
3091 // By default KMDF uses an optimization where the device is not powered
3092 // up when resuming from Sx if it is idle. The field
3093 // PowerUpIdleDeviceOnSystemWake is used to turn off this optimization and allow
3094 // device to power up when resuming from Sx. Note that this optimization
3095 // is applicable only for IdleCannotWakeFromS0. In other cases the
3096 // device is always powered up in order to arm for wake.
3097 //
3098 powerUpOnSystemWake =
3099 (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7)) ?
3100 Settings->PowerUpIdleDeviceOnSystemWake :
3101 WdfUseDefault;
3102
3103 switch(powerUpOnSystemWake) {
3104 case WdfTrue:
3105 m_PowerPolicyMachine.m_Owner->m_IdleSettings.PowerUpIdleDeviceOnSystemWake = TRUE;
3106 DoTraceLevelMessage(
3107 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
3108 "Driver turned off S0Idle optimization. Device will be "
3109 "powered up on resume from Sx even when it is idle");
3110 break;
3111 case WdfFalse:
3112 m_PowerPolicyMachine.m_Owner->m_IdleSettings.PowerUpIdleDeviceOnSystemWake = FALSE;
3113 DoTraceLevelMessage(
3114 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
3115 "Driver turned on S0Idle optimization. Device will remain "
3116 "powered off if idle when resuming from Sx");
3117 break;
3118 case WdfUseDefault:
3119 DO_NOTHING();
3120 break;
3121 default:
3122 break;
3123 }
3124 }
3125
3126 if (FALSE ==
3127 m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapabilityKnown)
3128 {
3129 if (Settings->IdleCaps == IdleUsbSelectiveSuspend) {
3130 m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable = TRUE;
3131 m_PowerPolicyMachine.m_Owner->
3132 m_IdleSettings.UsbSSCapabilityKnown = TRUE;
3133
3134 } else if (Settings->IdleCaps == IdleCanWakeFromS0) {
3135
3136 m_PowerPolicyMachine.m_Owner->
3137 m_IdleSettings.UsbSSCapabilityKnown = TRUE;
3138 }
3139 }
3140
3141 //
3142 // Wake FromS0Capable is set every time because we want to allow the driver
3143 // to swap between idle wake capable and idle not wake capable. This should
3144 // be allowed so that a scenario similar to the following can be implemented:
3145 //
3146 // a) when the device has an outstanding open, the device should arm itself
3147 // for wake when idle
3148 //
3149 // b) when the device does not have an outstanding open, the device should
3150 // be off and not armed.
3151 //
3152 // The only way to be off is to assign S0 wake settings, so the
3153 // WakeFromS0Capable field must change on each DDI call. This is not a
3154 // problem for the power policy state machine because it evaluates
3155 // WakeFromS0Capable state before enabling of idle. If we are not
3156 // WakeFromS0Capable and USB SS capable (ie a have a torn/unsynchronized
3157 // state) in m_IdleSettings, we will recover from it when processing
3158 // PwrPolS0IdlePolicyChanged in the state machine (b/c this event causes
3159 // both fields to be reevaluated).
3160 //
3161 m_PowerPolicyMachine.m_Owner->m_IdleSettings.WakeFromS0Capable = s0Capable;
3162
3163 m_PowerPolicyMachine.m_Owner->m_IdleSettings.DxState = dxState;
3164
3165 if (m_PowerPolicyMachine.m_Owner->
3166 m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) {
3167 //
3168 // With system managed idle timeout, we don't want to apply an idle
3169 // timeout of our own on top of that. Effectively, our idle timeout is
3170 // 0.
3171 // But we apply a negligibly small timeout value as this allows us to
3172 // keep the same logic in the idle state machine, regardless of whether
3173 // we're using system-managed idle timeout or driver-managed idle
3174 // timeout.
3175 //
3176 if (firstTime) {
3177 m_PowerPolicyMachine.m_Owner->
3178 m_PowerIdleMachine.m_PowerTimeout.QuadPart =
3179 negliblySmallIdleTimeout;
3180 }
3181
3182 if (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType) {
3183 //
3184 // We save the idle timeout hint, but we don't provide the hint to
3185 // the power framework immediately. This is because currently we may
3186 // or may not be registered with the power framework. Note that
3187 // WdfDeviceAssignS0IdleSettings might get called even when we are
3188 // not registered with the power framework.
3189 //
3190 // Therefore, we provide the hint to the power framework only when
3191 // we get to the WdfDevStatePwrPolStartingDecideS0Wake state. This
3192 // state is a good choice for providing the hint because:
3193 // 1. We know we would be registered with the power framework when
3194 // we are in this state.
3195 // 2. Any change in S0-idle settings causes us to go through this
3196 // state.
3197 //
3198 m_PowerPolicyMachine.m_Owner->m_PoxInterface.m_NextIdleTimeoutHint =
3199 idleTimeout;
3200 }
3201
3202 } else {
3203 m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.m_PowerTimeout.QuadPart
3204 = WDF_REL_TIMEOUT_IN_MS(idleTimeout);
3205 }
3206
3207 //
3208 // If the driver is 1.11 or later, update the bus drivers with the client's
3209 // choice on the topic of D3hot or D3cold.
3210 //
3211 if ((Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) &&
3212 (Settings->ExcludeD3Cold != WdfUseDefault)) {
3213 MxDeviceObject deviceObject;
3214 BOOLEAN enableD3Cold;
3215
3216 deviceObject.SetObject(m_Device->GetDeviceObject());
3217
3218 switch (Settings->ExcludeD3Cold) {
3219 case WdfFalse:
3220 enableD3Cold = TRUE;
3221 break;
3222 default:
3223 DoTraceLevelMessage(
3224 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3225 "Invalid tri-state value for ExcludeD3Cold %d",
3226 Settings->ExcludeD3Cold);
3227 __fallthrough;
3228 case WdfTrue:
3229 enableD3Cold = FALSE;
3230 break;
3231 }
3232
3233 SetD3ColdSupport(GetDriverGlobals(),
3234 &deviceObject,
3235 &m_D3ColdInterface,
3236 enableD3Cold);
3237 }
3238
3239 PowerPolicySetS0IdleState(enabled);
3240
3241 return STATUS_SUCCESS;
3242 }
3243
3244 NTSTATUS
PowerPolicySetSxWakeSettings(__in PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings,__in BOOLEAN ArmForWakeIfChildrenAreArmedForWake,__in BOOLEAN IndicateChildWakeOnParentWake)3245 FxPkgPnp::PowerPolicySetSxWakeSettings(
3246 __in PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings,
3247 __in BOOLEAN ArmForWakeIfChildrenAreArmedForWake,
3248 __in BOOLEAN IndicateChildWakeOnParentWake
3249 )
3250 /*++
3251
3252 Routine Description:
3253
3254 Updates the Sx wake settings for the device. No event is posted to the
3255 state machine because this setting is statically checked when the machine
3256 is entering an Sx state (unlike S0 idle which can be checked at any time).
3257
3258 The first this function is called, the ability to allow the user to control
3259 this setting is set.
3260
3261 Arguments:
3262
3263 Settings - the new settings to apply
3264
3265 ArmForWakeIfChildrenAreArmedForWake - Inidicates whether the device
3266 should arm for wake when one or more children are armed for wake
3267
3268 IndicateChildWakeOnParentWake - Indicates whether the device should
3269 propagate the wake status to its children
3270
3271 Return Value:
3272
3273 NTSTATUS
3274
3275 --*/
3276 {
3277 DEVICE_POWER_STATE dxState;
3278 NTSTATUS status;
3279 BOOLEAN overridable, firstTime, enabled;
3280
3281 dxState = PowerDeviceD3;
3282 overridable = FALSE;
3283 firstTime = TRUE;
3284
3285 if (Settings->Enabled == WdfTrue) {
3286 enabled = TRUE;
3287
3288 }
3289 else if (Settings->Enabled == WdfUseDefault) {
3290 enabled = TRUE;
3291
3292 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
3293 DECLARE_CONST_UNICODE_STRING(valueName, WDF_SX_WAKE_DEFAULT_VALUE_NAME);
3294
3295 //
3296 // Read registry. If registry value is not found, the value of "enabled"
3297 // remains unchanged
3298 //
3299 ReadRegistrySxWake(&valueName, &enabled);
3300 }
3301 else {
3302 DoTraceLevelMessage(
3303 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
3304 "If registry value WdfDefaultWakeFromSleepState was present, "
3305 "it was not read because DDI WdfDeviceAssignSxWakeSettings "
3306 "was not called at PASSIVE_LEVEL");
3307 }
3308 }
3309 else {
3310 enabled = FALSE;
3311 }
3312
3313 if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Set) {
3314 firstTime = FALSE;
3315 }
3316
3317 if (m_CapsQueried == FALSE && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
3318 status = QueryForCapabilities();
3319 if (!NT_SUCCESS(status)) {
3320 return status;
3321 }
3322
3323 //
3324 // Do not set m_CapsQueried to TRUE yet because we will do that once we
3325 // know the entire stack has been built we will do the query again.
3326 //
3327 }
3328
3329 if (Settings->DxState == PowerDeviceMaximum) {
3330 dxState = PowerPolicyGetDeviceDeepestDeviceWakeState((SYSTEM_POWER_STATE)m_SystemWake);
3331
3332 //
3333 // Some bus drivers
3334
3335 // incorrectly report DeviceWake=D0 to
3336 // indicate that it does not support wake instead of specifying
3337 // PowerDeviceUnspecified and KMDF ends up requesting
3338 // a D0 irp when going to Dx. The check prevents this bug.
3339 //
3340 if (dxState < PowerDeviceD1 || dxState > PowerDeviceD3) {
3341 status = STATUS_POWER_STATE_INVALID;
3342
3343 DoTraceLevelMessage(
3344 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3345 "DeviceWake power state reported in device capabilities "
3346 "%!DEVICE_POWER_STATE! indicates that device can not signal a "
3347 "wake event, %!STATUS!",
3348 dxState, status);
3349 return status;
3350 }
3351 }
3352 else {
3353 DEVICE_POWER_STATE dxDeepest;
3354
3355 dxState = Settings->DxState;
3356 dxDeepest = PowerPolicyGetDeviceDeepestDeviceWakeState((SYSTEM_POWER_STATE)m_SystemWake);
3357
3358 if (dxState > dxDeepest) {
3359 status = STATUS_POWER_STATE_INVALID;
3360 DoTraceLevelMessage(
3361 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3362 "DxState specified by driver %!DEVICE_POWER_STATE! cannot be"
3363 " lighter than lightest available device wake state "
3364 "%!DEVICE_POWER_STATE!, %!STATUS!", dxState,
3365 dxDeepest, status);
3366 return status;
3367 }
3368 }
3369
3370 if (Settings->UserControlOfWakeSettings == WakeAllowUserControl) {
3371
3372 // status = UpdateWmiInstanceForSxWake(AddInstance); __REACTOS__
3373
3374 // if (!NT_SUCCESS(status)) {
3375 // return status;
3376 // }
3377
3378 if (Settings->Enabled == WdfUseDefault) {
3379 //
3380 // Read the registry entry for wake enabled if it's the first time.
3381 //
3382 if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
3383 DECLARE_CONST_UNICODE_STRING(valueName, WDF_SX_WAKE_ENABLED_VALUE_NAME);
3384
3385 //
3386 // Read registry. If registry value is not found, the value of
3387 // "enabled" remains unchanged
3388 //
3389 ReadRegistrySxWake(&valueName, &enabled);
3390 }
3391 else {
3392 //
3393 // Use the saved value for wake enabled.
3394 //
3395 enabled = m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled;
3396 }
3397 }
3398
3399 overridable = TRUE;
3400 }
3401 else if (Settings->UserControlOfWakeSettings == WakeDoNotAllowUserControl) {
3402 //
3403 // No user control, just set to enabled
3404 //
3405 overridable = FALSE;
3406
3407 // (void) UpdateWmiInstanceForSxWake(RemoveInstance); __REACTOS__
3408 }
3409
3410 if (firstTime) {
3411 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Set = TRUE;
3412 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable = overridable;
3413
3414 //
3415 // If ArmForWakeIfChildrenAreArmedForWake setting is set to FALSE,
3416 // then we use the legacy framework behavior which did not depend
3417 // on the child device being capable of arming for wake or not.
3418 //
3419 m_PowerPolicyMachine.m_Owner->m_WakeSettings.ArmForWakeIfChildrenAreArmedForWake =
3420 ArmForWakeIfChildrenAreArmedForWake;
3421
3422 //
3423 // If IndicateChildWakeOnParentWake setting is set to FALSE, then
3424 // we use the legacy framework behavior wherein the wake status
3425 // is not propagated from the parent device to the child device.
3426 //
3427 m_PowerPolicyMachine.m_Owner->m_WakeSettings.IndicateChildWakeOnParentWake =
3428 IndicateChildWakeOnParentWake;
3429 }
3430
3431 m_PowerPolicyMachine.m_Owner->m_WakeSettings.DxState = dxState;
3432
3433 PowerPolicySetSxWakeState(enabled);
3434
3435 return STATUS_SUCCESS;
3436 }
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454 NTSTATUS
_S0IdleQueryInstance(__in CfxDevice * Device,__in FxWmiInstanceInternal *,__in ULONG,__out PVOID OutBuffer,__out PULONG BufferUsed)3455 FxPkgPnp::_S0IdleQueryInstance(
3456 __in CfxDevice* Device,
3457 __in FxWmiInstanceInternal* /* Instance */,
3458 __in ULONG /* OutBufferSize */,
3459 __out PVOID OutBuffer,
3460 __out PULONG BufferUsed
3461 )
3462 {
3463 *((BOOLEAN*) OutBuffer) =
3464 (Device->m_PkgPnp)->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled;
3465 *BufferUsed = sizeof(BOOLEAN);
3466
3467 return STATUS_SUCCESS;
3468 }
3469
3470 NTSTATUS
_S0IdleSetInstance(__in CfxDevice * Device,__in FxWmiInstanceInternal *,__in ULONG,__in PVOID InBuffer)3471 FxPkgPnp::_S0IdleSetInstance(
3472 __in CfxDevice* Device,
3473 __in FxWmiInstanceInternal* /* Instance */,
3474 __in ULONG /* InBufferSize */,
3475 __in PVOID InBuffer
3476 )
3477 {
3478 BOOLEAN value;
3479
3480
3481 //
3482 // FxWmiIrpHandler makes sure the buffer is at least one byte big, so we
3483 // don't check the buffer size.
3484 //
3485
3486 value = *(PBOOLEAN) InBuffer;
3487
3488 (Device->m_PkgPnp)->PowerPolicySetS0IdleState(value);
3489
3490 return STATUS_SUCCESS;
3491 }
3492
3493 NTSTATUS
_S0IdleSetItem(__in CfxDevice * Device,__in FxWmiInstanceInternal *,__in ULONG DataItemId,__in ULONG InBufferSize,__in PVOID InBuffer)3494 FxPkgPnp::_S0IdleSetItem(
3495 __in CfxDevice* Device,
3496 __in FxWmiInstanceInternal* /* Instance */,
3497 __in ULONG DataItemId,
3498 __in ULONG InBufferSize,
3499 __in PVOID InBuffer
3500 )
3501 {
3502 BOOLEAN value;
3503
3504 if (DataItemId != 0) {
3505 return STATUS_INVALID_DEVICE_REQUEST;
3506 }
3507
3508 if (InBufferSize < sizeof(BOOLEAN)) {
3509 return STATUS_BUFFER_TOO_SMALL;
3510 }
3511
3512 value = *(BOOLEAN*) InBuffer;
3513 (Device->m_PkgPnp)->PowerPolicySetS0IdleState(value);
3514
3515 return STATUS_SUCCESS;
3516 }
3517
3518 NTSTATUS
_SxWakeQueryInstance(__in CfxDevice * Device,__in FxWmiInstanceInternal *,__in ULONG,__out PVOID OutBuffer,__out PULONG BufferUsed)3519 FxPkgPnp::_SxWakeQueryInstance(
3520 __in CfxDevice* Device,
3521 __in FxWmiInstanceInternal* /* Instance */,
3522 __in ULONG /* OutBufferSize */,
3523 __out PVOID OutBuffer,
3524 __out PULONG BufferUsed
3525 )
3526 {
3527 *((BOOLEAN*) OutBuffer) =
3528 (Device->m_PkgPnp)->m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled;
3529 *BufferUsed = sizeof(BOOLEAN);
3530
3531 return STATUS_SUCCESS;
3532 }
3533
3534 NTSTATUS
_SxWakeSetInstance(__in CfxDevice * Device,__in FxWmiInstanceInternal *,__in ULONG,__in PVOID InBuffer)3535 FxPkgPnp::_SxWakeSetInstance(
3536 __in CfxDevice* Device,
3537 __in FxWmiInstanceInternal* /* Instance */,
3538 __in ULONG /* InBufferSize */,
3539 __in PVOID InBuffer
3540 )
3541 {
3542 BOOLEAN value;
3543
3544 //
3545 // FxWmiIrpHandler makes sure that the buffer is at least one byte big, so
3546 // we don't check the buffer size
3547 //
3548 value = *(PBOOLEAN) InBuffer;
3549
3550 (Device->m_PkgPnp)->PowerPolicySetSxWakeState(value);
3551
3552 return STATUS_SUCCESS;
3553 }
3554
3555 NTSTATUS
_SxWakeSetItem(__in CfxDevice * Device,__in FxWmiInstanceInternal *,__in ULONG DataItemId,__in ULONG InBufferSize,__in PVOID InBuffer)3556 FxPkgPnp::_SxWakeSetItem(
3557 __in CfxDevice* Device,
3558 __in FxWmiInstanceInternal* /* Instance */,
3559 __in ULONG DataItemId,
3560 __in ULONG InBufferSize,
3561 __in PVOID InBuffer
3562 )
3563 {
3564 BOOLEAN value;
3565
3566 if (DataItemId != 0) {
3567 return STATUS_INVALID_DEVICE_REQUEST;
3568 }
3569
3570 if (InBufferSize < sizeof(BOOLEAN)) {
3571 return STATUS_BUFFER_TOO_SMALL;
3572 }
3573
3574 value = *(BOOLEAN*) InBuffer;
3575 (Device->m_PkgPnp)->PowerPolicySetSxWakeState(value);
3576
3577 return STATUS_SUCCESS;
3578 }
3579
3580 _Must_inspect_result_
3581 NTSTATUS
PowerPolicyHandleSystemQueryPower(__in SYSTEM_POWER_STATE QueryState)3582 FxPkgPnp::PowerPolicyHandleSystemQueryPower(
3583 __in SYSTEM_POWER_STATE QueryState
3584 )
3585 /*++
3586
3587 Framework Philosophy Discussion:
3588
3589 WDM sends IRP_MN_QUERY_POWER for system power states (where system power
3590 states are S0-working, S1-light-sleep, S2-deeper-sleep, S3-deepest-sleep,
3591 S4-hibernation, S5-soft-off.) The idea is that, if a driver can't support
3592 a particular state, it fails the query. The problem is that this idea is
3593 horribly broken.
3594
3595 The first problem is that WDM doesn't always send these IRPs. In some
3596 situations, (very low battery, system getting critically hot) WDM will
3597 attempt to preserve user data by sleeping or hibernating, rather than just
3598 crashing. This is good, but it makes a driver writer's life very difficult,
3599 since it means that you have to deal with being told to go to a particular
3600 state even if you think that your device won't be able to deal well with
3601 that state.
3602
3603 The second problem is that, by the time the system is going to sleep, the
3604 user probably isn't still looking at the screen. This is especially true
3605 for laptop computers, as the system is very likely sleeping because the
3606 user closed the clamshell lid. So any attempt to ask the user how to
3607 resolve a situation where a driver doesn't want to go to a low power state
3608 is futile. Furthermore, even when the screen is still available, users
3609 dislike it when they push the sleep button or the power button on their
3610 machines and the machines don't do what they were told to do.
3611
3612 The third problem is related to the second. While there may be completely
3613 legitimate reasons for the driver to want to delay or even to veto a
3614 transition into a sleep state, (an example of a valid scenario would be one
3615 in which the driver was involved in burning a CD, an operation which can't
3616 be interrupted,) there isn't any good way for a driver to interact with a
3617 user anyhow. (Which desktop is the right one to send messages to? What
3618 should the UI for problem resolution look like? How does a driver put up
3619 UI anyhow?)
3620
3621 All the driver really knows is that it will or won't be able to maintain
3622 device state, and it will or won't be able to get enough power to arm
3623 any wake events that it might want to deliver (like PME#.)
3624
3625 Consequently, the designers of the PnP/Power model in the Framework have
3626 decided that all QueryPower-Sx IRPs will be completed successfully
3627 except if the device cannot maintain enough power to trigger its wake
3628 signal *AND* if the system supports lighter sleep states than the
3629 one that is currently being queried. (If it does, then the kernel's power
3630 manager will turn right around and query for those, next.)
3631
3632 This story usually brings up a few objections:
3633
3634 1) My device is important! When it's operating, I don't want
3635 the machine to just fall asleep. I need to fail QueryPower-Sx to
3636 prevent that.
3637
3638 This objection is an unfortunate consequence of the existing DDK. There
3639 is a perfectly good API that allows a driver to say that the machine
3640 shouldn't just fall asleep. (See PoSetSystemState.) If a user presses
3641 a button telling the machine to go to sleep, then the driver has a
3642 responsibility to do that.
3643
3644 2) There are certain operations that just can't be interrupted!
3645
3646 While that's true, those operations started somewhere, probably in user-
3647 mode. Those same user-mode components would be much, much better suited
3648 toward negotiating with the user or with other components to figure out
3649 what to do when the uninterruptable must be interrupted. User-mode
3650 components get notification that the system is going to sleep and they
3651 can delay or veto the transition. Get over the idea that your driver
3652 needs to be involved, too.
3653
3654 Routine Description:
3655
3656 Determines if for the passed in System state, if we can wake the machine
3657 from it. If the query state is the machine's minimum system state, then
3658 we always succeed it because we want the machine to go to at least some
3659 sleeping state. We always succeed hibernate and system off requests as well.
3660
3661 Arguments:
3662
3663 QueryState - The proposed system state
3664
3665 Return Value:
3666
3667 NT_SUCCESS if the queried state should be allowed, !NT_SUCCESS otherwise
3668
3669 --*/
3670 {
3671 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
3672 NTSTATUS status;
3673
3674 if (QueryState >= PowerSystemHibernate ||
3675 PowerPolicyCanWakeFromSystemState(QueryState)) {
3676 //
3677 // If the query is for the machine's minimum S state or we going into
3678 // hibernate or off, always succeed it.
3679 //
3680 status = STATUS_SUCCESS;
3681 }
3682 else {
3683
3684 //
3685 // On Windows Vista and above, its OK to return a failure status code
3686 // if the system is going into an S state at which the device cannot
3687 // wake the system.
3688 //
3689 ASSERT(FxLibraryGlobals.OsVersionInfo.dwMajorVersion >= 6);
3690
3691 //
3692 // The S state the machine is going into is one where we can't
3693 // wake it up because our D state is too low for this S state.
3694 // Since this isn't the minimum S state the machine is capable
3695 // of, reject the current query.
3696 //
3697 DoTraceLevelMessage(
3698 FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP,
3699 "failing system query power because the device cannot wake the "
3700 "machine from S%d",
3701 QueryState - 1);
3702
3703 status = STATUS_POWER_STATE_INVALID;
3704 }
3705
3706 return status;
3707 }
3708
3709 VOID
PowerPolicySetS0IdleState(__in BOOLEAN State)3710 FxPkgPnp::PowerPolicySetS0IdleState(
3711 __in BOOLEAN State
3712 )
3713 {
3714 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled = State ? TRUE : FALSE;
3715 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty = TRUE;
3716 PowerPolicyProcessEvent(PwrPolS0IdlePolicyChanged);
3717 }
3718
3719 VOID
PowerPolicySetSxWakeState(__in BOOLEAN State)3720 FxPkgPnp::PowerPolicySetSxWakeState(
3721 __in BOOLEAN State
3722 )
3723 /*++
3724
3725 Routine Description:
3726 Sets the wake from Sx state
3727
3728 No need to post an event to the power policy state machine because we
3729 will not change any active due to a change in this setting. We only
3730 evaluate this state when going into Sx and once in this state we will not
3731 change our behavior until the next Sx, which will then evaluate this state.
3732
3733 Arguments:
3734 State - New state
3735
3736 Return Value:
3737 VOID
3738
3739 --*/
3740 {
3741 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled = State ? TRUE : FALSE;
3742 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty = TRUE;
3743
3744 //
3745 // Since we are not posting an event to the power policy state machine, try
3746 // to write out the value now, otherwise it will be written when we
3747 // transition
3748 //
3749 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
3750 NTSTATUS status;
3751 LONGLONG timeout;
3752
3753 timeout = 0;
3754
3755 //
3756 // If the lock is already acquired on this thread, this will fail, which
3757 // is OK.
3758 //
3759 status = m_PowerPolicyMachine.m_StateMachineLock.AcquireLock(
3760 GetDriverGlobals(),
3761 &timeout
3762 );
3763
3764 if (FxWaitLockInternal::IsLockAcquired(status)) {
3765 SaveState(TRUE);
3766
3767 m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock(
3768 GetDriverGlobals()
3769 );
3770 }
3771 }
3772 }
3773
3774 VOID
SetDeviceFailed(__in WDF_DEVICE_FAILED_ACTION FailedAction)3775 FxPkgPnp::SetDeviceFailed(
3776 __in WDF_DEVICE_FAILED_ACTION FailedAction
3777 )
3778 /*++
3779
3780 Routine Description:
3781 Marks the device as a victim of catastrophic failure, either in software
3782 or in hardware.
3783
3784 If AttemptToRestart is TRUE, then we should try to get the stack re-built
3785 after it has been torn down. This would typically be the case the failure
3786 was in the software, and possibly not be the case if the failure was in
3787 the hardware.
3788
3789 Arguments:
3790 FailedAction - action to take once the stack has been removed
3791
3792 Return Value:
3793 None
3794
3795 --*/
3796 {
3797 NTSTATUS status;
3798 MdDeviceObject pdo;
3799
3800 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
3801 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(2, 15) == FALSE &&
3802 FailedAction == WdfDeviceFailedAttemptRestart) {
3803
3804 FailedAction = WdfDeviceFailedNoRestart;
3805 DoTraceLevelMessage(
3806 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGDEVICE,
3807 "WdfDeviceFailedAttemptRestart is only available for UMDF 2.15 "
3808 "and later drivers. Reverting to WdfDeviceFailedNoRestart.");
3809 }
3810 #endif
3811
3812 m_FailedAction = (BYTE) FailedAction;
3813
3814 //
3815 // This will cause the PnP manager to tear down this stack, even if
3816 // the PDO can't be surprise-removed.
3817 //
3818 m_Failed = TRUE;
3819
3820 if (FailedAction == WdfDeviceFailedAttemptRestart) {
3821 //
3822 // Attempt to get the PDO surprise-removed.
3823 //
3824 status = AskParentToRemoveAndReenumerate();
3825
3826 if (NT_SUCCESS(status)) {
3827 return;
3828 }
3829 }
3830
3831 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
3832 //
3833 // In between creating a PDO WDFDEVICE and it starting, if this DDI is called,
3834 // we will not have a valid PDO. Make sure it is valid before we proceed.
3835 //
3836 pdo = m_Device->GetSafePhysicalDevice();
3837
3838 if (pdo != NULL) {
3839 //
3840 // Now tell the PnP manager to re-query us for our state.
3841 //
3842 MxDeviceObject physicalDeviceObject(pdo);
3843
3844 physicalDeviceObject.InvalidateDeviceState(
3845 m_Device->GetDeviceObject()
3846 );
3847 }
3848 #else // USER_MODE
3849 m_Device->GetMxDeviceObject()->InvalidateDeviceState(
3850 m_Device->GetDeviceObject());
3851 UNREFERENCED_PARAMETER(pdo);
3852 #endif
3853 }
3854
3855 _Must_inspect_result_
3856 NTSTATUS
_PnpDeviceUsageNotification(__inout FxPkgPnp * This,__inout FxIrp * Irp)3857 FxPkgPnp::_PnpDeviceUsageNotification(
3858 __inout FxPkgPnp* This,
3859 __inout FxIrp *Irp
3860 )
3861 {
3862 return This->PnpDeviceUsageNotification(Irp);
3863 }
3864
3865 _Must_inspect_result_
3866 NTSTATUS
PnpDeviceUsageNotification(__inout FxIrp * Irp)3867 FxPkgPnp::PnpDeviceUsageNotification(
3868 __inout FxIrp* Irp
3869 )
3870 {
3871 FxRelatedDeviceList* pList;
3872 FxRelatedDevice *pDependent;
3873 FxAutoIrp relatedIrp(NULL), parentIrp(NULL);
3874 MxDeviceObject topOfParentStack;
3875 DEVICE_USAGE_NOTIFICATION_TYPE type;
3876 NTSTATUS status;
3877 MxDeviceObject pAttached;
3878 MdIrp pNewIrp;
3879 CCHAR maxStack;
3880 BOOLEAN inPath, supported;
3881 ULONG oldFlags;
3882 MxAutoWorkItem workItem;
3883
3884 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
3885 "Entering DeviceUsageNotification handler");
3886
3887 status = STATUS_SUCCESS;
3888
3889 type = Irp->GetParameterUsageNotificationType();
3890 inPath = Irp->GetParameterUsageNotificationInPath();
3891 supported = FALSE;
3892
3893 DoTraceLevelMessage(
3894 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
3895 "type %x, in path %x, can support paging %x, dump file %x, "
3896 "hiber file %x, boot file %x",
3897 type, inPath,
3898 IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFilePaging)),
3899 IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileDump)),
3900 IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileHibernation)),
3901 IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileBoot)));
3902
3903
3904 if (type >= static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFilePaging)
3905 && type < static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileMax)) {
3906 if (inPath) {
3907 if (m_Device->IsFilter()) {
3908 //
3909 // Filters always support usage notifications
3910 //
3911 supported = TRUE;
3912 }
3913 else {
3914 supported = IsUsageSupported(type);
3915 }
3916 }
3917 else {
3918 //
3919 // We always handle notifications where we are out of the path
3920 //
3921 supported = TRUE;
3922 }
3923 }
3924
3925 if (supported == FALSE) {
3926 status = STATUS_NOT_IMPLEMENTED;
3927
3928 DoTraceLevelMessage(
3929 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
3930 "Usage type %x not supported, %!STATUS!", type, status);
3931
3932 return CompletePnpRequest(Irp, status);
3933 }
3934
3935 //
3936 // Usage notification IRP gets forwarded to parent stack or to
3937 // dependent stack. Since in such cases (with deep device tree) the stack
3938 // may run out quickly, ensure there is enough stack, otherwise use a
3939 // workitem.
3940 //
3941 if (Mx::MxHasEnoughRemainingThreadStack() == FALSE &&
3942 (m_Device->IsPdo() ||
3943 m_UsageDependentDeviceList != NULL)) {
3944
3945 status = workItem.Allocate(m_Device->GetDeviceObject());
3946 if (!NT_SUCCESS(status)) {
3947 DoTraceLevelMessage(
3948 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3949 "WDFDEVICE %p !devobj %p could not allocate workitem "
3950 "to send usage notification type %d, inpath %d, %!STATUS!",
3951 m_Device->GetHandle(),
3952 m_Device->GetDeviceObject(),
3953 type, inPath, status);
3954
3955 return CompletePnpRequest(Irp, status);
3956 }
3957 }
3958
3959 //
3960 // Usage notification is supported. Set the flags on the device object
3961 // before processing this any further and save the current flags on the
3962 // device object.
3963 //
3964 oldFlags = SetUsageNotificationFlags(type, inPath);
3965
3966 if (m_Device->IsPdo()) {
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979 topOfParentStack.SetObject(
3980 m_Device->m_ParentDevice->GetAttachedDeviceReference());
3981
3982 pNewIrp = FxIrp::AllocateIrp(topOfParentStack.GetStackSize());
3983 if (pNewIrp != NULL) {
3984 parentIrp.SetIrp(pNewIrp);
3985
3986 //
3987 // parentIrp now owns the irp
3988 //
3989 pNewIrp = NULL;
3990
3991 status = SendDeviceUsageNotification(&topOfParentStack,
3992 &parentIrp,
3993 &workItem,
3994 Irp,
3995 FALSE);
3996 }
3997 else {
3998 status = STATUS_INSUFFICIENT_RESOURCES;
3999
4000 DoTraceLevelMessage(
4001 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4002 "WDFDEVICE %p could not allocate PIRP for parent !devobj %p to "
4003 "send usage notification type %d, inpath %d, %!STATUS!",
4004 m_Device->GetHandle(), topOfParentStack.GetObject(),
4005 type, inPath, status);
4006 }
4007 topOfParentStack.DereferenceObject();
4008 topOfParentStack.SetObject(NULL);
4009
4010 if (!NT_SUCCESS(status)) {
4011 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
4012 "Exit %!STATUS!", status);
4013
4014 RevertUsageNotificationFlags(type, inPath, oldFlags);
4015 return CompletePnpRequest(Irp, status);
4016 }
4017 }
4018
4019 maxStack = 0;
4020 pDependent = NULL;
4021
4022 //
4023 // If the driver supports the given special file, lets notify dependent
4024 // stacks.
4025 //
4026
4027 //
4028 // LockForEnum will lock out new changes to the list until we unlock the list.
4029 // We remain at passive level once we are locked.
4030 //
4031 if (m_UsageDependentDeviceList != NULL) {
4032 //
4033 // We capture the m_UsageDependentDeviceList pointer value so that we
4034 // always use the same pointer value and that we have matched actions
4035 // (lock for enum / unlock from enum). What we are trying to avoid is
4036 // this:
4037 // 1) we do not lock for enum because m_UsageDependentDeviceList == NULL
4038 // 2) in the middle of this function, m_UsageDependentDeviceList is
4039 // assigned a pointer value
4040 // 3) we try to unlock from enum later (or iterate, thinking the enum
4041 // lock is held) by checking m_UsageDependentDeviceList for NULL, and
4042 // now that is != NULL, use it.
4043 //
4044 // By capturing the pointer now, we either have a list or not and we don't
4045 // hit situations 2 or 3. So, the rule is every subseqeunt time we need
4046 // to check if there is valid m_UsageDependentDeviceList pointer, we
4047 // use pList, but when we use the list, we can use m_UsageDependentDeviceList
4048 // directly.
4049 //
4050 pList = m_UsageDependentDeviceList;
4051
4052 m_UsageDependentDeviceList->LockForEnum(GetDriverGlobals());
4053
4054 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4055
4056 MxDeviceObject deviceObject(pDependent->GetDevice());
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070 pAttached.SetObject(deviceObject.GetAttachedDeviceReference());
4071
4072 if (pAttached.GetStackSize() > maxStack) {
4073 maxStack = pAttached.GetStackSize();
4074 }
4075
4076 pAttached.DereferenceObject();
4077 }
4078 }
4079 else {
4080 pList = NULL;
4081 }
4082
4083 if (maxStack > 0) {
4084 //
4085 // If we have a maxStack size, we have a list as well
4086 //
4087 ASSERT(m_UsageDependentDeviceList != NULL);
4088
4089 //
4090 // Allocate one irp for all the stacks so that we don't have an
4091 // allocation later. This way, once we have the irp, we can send the
4092 // usage notification to all stacks reliably, as well as the reverting
4093 // of the notification if we encounter failure.
4094 //
4095 pNewIrp = FxIrp::AllocateIrp(maxStack);
4096 if (pNewIrp == NULL) {
4097 status = STATUS_INSUFFICIENT_RESOURCES;
4098
4099 DoTraceLevelMessage(
4100 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4101 "WDFDEVICE %p could not allocate IRP to send usage notifications"
4102 " to related stacks, type %d, inpath %d, status %!STATUS!",
4103 m_Device->GetHandle(), type, inPath, status);
4104 }
4105 else {
4106 MxDeviceObject dependentDevice;
4107
4108 //
4109 // relatedIrp will free the irp when it goes out of scope
4110 //
4111 relatedIrp.SetIrp(pNewIrp);
4112
4113 //
4114 // Walk our collection of dependent device stacks, and notify
4115 // each stack of the device notification. If any fail, notify
4116 // the stacks who already were told of the reverted behavior.
4117 //
4118 pDependent = NULL;
4119 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4120 dependentDevice.SetObject(pDependent->GetDevice());
4121 status = SendDeviceUsageNotification(&dependentDevice,
4122 &relatedIrp,
4123 &workItem,
4124 Irp,
4125 FALSE);
4126
4127 if (!NT_SUCCESS(status)) {
4128 FxRelatedDevice* pDependent2;
4129
4130 pDependent2 = NULL;
4131
4132 //
4133 // A device failed the device usage notification request.
4134 // Notify the stacks that didn't fail, so they can unwind
4135 // the operation.
4136 //
4137 while ((pDependent2 = m_UsageDependentDeviceList->GetNextEntry(pDependent2)) != NULL &&
4138 pDependent2 != pDependent) {
4139 dependentDevice.SetObject(pDependent2->GetDevice());
4140
4141 //
4142 // We're already in a failure path. We can't do anything
4143 // about yet another failure. So we ignore the return
4144 // value.
4145 //
4146 (void) SendDeviceUsageNotification(&dependentDevice,
4147 &relatedIrp,
4148 &workItem,
4149 Irp,
4150 TRUE);
4151 }
4152
4153 //
4154 // Now break out of our outter loop.
4155 //
4156 break;
4157 }
4158 }
4159 }
4160 }
4161
4162 //
4163 // If we are successful to this point, then send the IRP down the
4164 // stack.
4165 //
4166 if (NT_SUCCESS(status)) {
4167 BOOLEAN referenceSucceeded, sendDown;
4168
4169 referenceSucceeded = FALSE;
4170 sendDown = TRUE;
4171
4172 //
4173 // Make sure the stack is in D0 before sending down the request. This
4174 // will at least guarantee that all devices below this one are in D0
4175 // when the make the transition from power pageable to non or vice versa.
4176 //
4177 if (IsPowerPolicyOwner()) {
4178 status = PowerReference(TRUE);
4179
4180 if (NT_SUCCESS(status)) {
4181 referenceSucceeded = TRUE;
4182 }
4183 else {
4184 Irp->SetStatus(status);
4185 sendDown = FALSE;
4186 }
4187 }
4188
4189 if (sendDown) {
4190 //
4191 // If we supported the usage, set the status to success, otherwise we
4192 // keep the status in the irp as it arrived to this device
4193 //
4194 if (supported) {
4195 Irp->SetStatus(status);
4196 }
4197 status = SendIrpSynchronously(Irp);
4198 }
4199
4200 //
4201 // Transitioning from a thread which was power pagable to non power
4202 // pagable. We now need a power thread for the stack, ask for it.
4203 // Note that there is no need for power thread in case of "boot"
4204 // notification since boot notification doesn't require clearing device's
4205 // DO_POWER_PAGABLE flag (power thread is required when handling power
4206 // irp at dispatch level which can happen if the DO_POWER_PAGABLE flag
4207 // is cleared).
4208 //
4209 // NOTE: Once we have a power thread, we never go back to using work
4210 // items even though the stack may revert to power pagable.
4211 // This is an acceptable tradeoff between resource usage and
4212 // WDF complexity.
4213 //
4214 //
4215 if (NT_SUCCESS(status) &&
4216 inPath &&
4217 (HasPowerThread() == FALSE) &&
4218 type != static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileBoot)
4219 ) {
4220 status = QueryForPowerThread();
4221
4222 if (!NT_SUCCESS(status)) {
4223 //
4224 // Keep status the same through out so we can set it back in
4225 // the irp when we are done.
4226 //
4227 if (m_Device->IsPdo()) {
4228 //
4229 // need to revert our parent's stack
4230 //
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243 topOfParentStack.SetObject(
4244 m_Device->m_ParentDevice->GetAttachedDeviceReference());
4245
4246 //
4247 // Ignore the status because we can't do anything on failure
4248 //
4249 (void) SendDeviceUsageNotification(&topOfParentStack,
4250 &parentIrp,
4251 &workItem,
4252 Irp,
4253 TRUE);
4254
4255 topOfParentStack.DereferenceObject();
4256 }
4257 else {
4258 //
4259 // Notify the stack below us
4260 //
4261 Irp->CopyCurrentIrpStackLocationToNext();
4262 Irp->SetParameterUsageNotificationInPath(FALSE);
4263
4264 //
4265 // Required for pnp irps
4266 //
4267 Irp->SetStatus(STATUS_NOT_SUPPORTED);
4268
4269 //
4270 // Ignore the status because we can't do anything on failure
4271 //
4272 (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
4273 }
4274
4275 Irp->SetStatus(status);
4276 }
4277 }
4278
4279 //
4280 // Now check whether the lower devices succeeded or failed. If they
4281 // failed, back out our changes and propogate the failure.
4282 //
4283 if (!NT_SUCCESS(status)) {
4284 //
4285 // Revert the flags set on the device object.
4286 //
4287 RevertUsageNotificationFlags(type, inPath, oldFlags);
4288
4289 //
4290 // Notify dependent stacks of the failure.
4291 //
4292 pDependent = NULL;
4293
4294 //
4295 // See pList initiatilazation as to why we compare pList for != NULL
4296 // and not m_UsageDependentDeviceList.
4297 //
4298 if (pList != NULL) {
4299 MxDeviceObject dependentDevice;
4300
4301 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4302 dependentDevice.SetObject(pDependent->GetDevice());
4303
4304 //
4305 // We're already in a failure path. We can't do anything
4306 // about yet another failure. So we ignore the return value.
4307 //
4308 (void) SendDeviceUsageNotification(&dependentDevice,
4309 &relatedIrp,
4310 &workItem,
4311 Irp,
4312 TRUE);
4313 }
4314 }
4315 }
4316
4317 //
4318 // By this point, we have propagated the notification to dependent devices
4319 // and lower stack, and if anyone failed during that time, we also
4320 // propagated failure to dependent stacks and lower stack.
4321 // If status is success at this point, invoke the driver's callback.
4322 //
4323 if (NT_SUCCESS(status)) {
4324 //
4325 // Invoke callback. Note that only one of the callbacks
4326 // DeviceUsageNotification or DeviceUsgeNotificationEx will get
4327 // invoked since only one of the callbacks at a time is supported.
4328 // We ensured that during registration of the callback.
4329 // Note that Ex callback will return success if driver did not
4330 // supply any callback.
4331 //
4332 m_DeviceUsageNotification.Invoke(m_Device->GetHandle(),
4333 _UsageToSpecialType(type),
4334 inPath);
4335
4336 status = m_DeviceUsageNotificationEx.Invoke(
4337 m_Device->GetHandle(),
4338 _UsageToSpecialType(type),
4339 inPath
4340 );
4341
4342 if (!NT_SUCCESS(status)) {
4343 //
4344 // Driver's callback returned failure. We need to propagate
4345 // failure to lower stack and dependent stacks.
4346 //
4347 //
4348 // Keep status the same through out so we can set it back in
4349 // the irp when we are done.
4350 //
4351 if (m_Device->IsPdo()) {
4352 //
4353 // need to revert our parent's stack
4354 //
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367 topOfParentStack.SetObject(
4368 m_Device->m_ParentDevice->GetAttachedDeviceReference());
4369
4370 //
4371 // Ignore the status because we can't do anything on failure
4372 //
4373 (void) SendDeviceUsageNotification(&topOfParentStack,
4374 &parentIrp,
4375 &workItem,
4376 Irp,
4377 TRUE);
4378
4379 topOfParentStack.DereferenceObject();
4380 }
4381 else {
4382 //
4383 // Notify the stack below us
4384 //
4385 Irp->CopyCurrentIrpStackLocationToNext();
4386 Irp->SetParameterUsageNotificationInPath(FALSE);
4387
4388 //
4389 // Required for pnp irps
4390 //
4391 Irp->SetStatus(STATUS_NOT_SUPPORTED);
4392
4393 //
4394 // Ignore the status because we can't do anything on failure
4395 //
4396 (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
4397 }
4398
4399 Irp->SetStatus(status);
4400
4401 //
4402 // Revert the flags set on the device object.
4403 //
4404 RevertUsageNotificationFlags(type, inPath, oldFlags);
4405
4406 //
4407 // Notify dependent stacks of the failure.
4408 //
4409 pDependent = NULL;
4410
4411 //
4412 // See pList initiatilazation as to why we compare pList for != NULL
4413 // and not m_UsageDependentDeviceList.
4414 //
4415 if (pList != NULL) {
4416 MxDeviceObject dependentDevice;
4417
4418 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4419 dependentDevice.SetObject(pDependent->GetDevice());
4420
4421 //
4422 // We're already in a failure path. We can't do anything
4423 // about yet another failure. So we ignore the return value.
4424 //
4425 (void) SendDeviceUsageNotification(&dependentDevice,
4426 &relatedIrp,
4427 &workItem,
4428 Irp,
4429 TRUE);
4430 }
4431 }
4432 }
4433
4434 if (NT_SUCCESS(status)) {
4435
4436 CommitUsageNotification(type, oldFlags);
4437
4438 //
4439 // If we are in the dump file path, we cannot idle out because we
4440 // can experience a crash dump at any time.
4441 //
4442 if (IsPowerPolicyOwner() && type == DeviceUsageTypeDumpFile) {
4443 //
4444 // Add a reference everytime we are notified of being in the
4445 // path, no need to match the first inPath notification and the
4446 // last !inPath notification.
4447 //
4448 if (inPath) {
4449 NTSTATUS refStatus;
4450
4451 ASSERT(GetUsageCount(type) > 0);
4452
4453 //
4454 // Since our previous synchronous power reference succeeded,
4455 // an addtional reference while we are powered up should
4456 // never fail.
4457 //
4458 refStatus = PowerReference(FALSE);
4459 #if DBG
4460 ASSERT(NT_SUCCESS(refStatus));
4461 #else
4462 UNREFERENCED_PARAMETER(refStatus);
4463 #endif
4464 }
4465 else {
4466 ASSERT(GetUsageCount(type) >= 0);
4467 PowerDereference();
4468 }
4469 }
4470 }
4471 }
4472
4473 //
4474 // We no longer need to be in D0 if we don't have to be.
4475 //
4476 if (referenceSucceeded) {
4477 ASSERT(IsPowerPolicyOwner());
4478 PowerDereference();
4479 }
4480 }
4481
4482 //
4483 // See pList initiatilazation as to why we compare pList for != NULL
4484 // and not m_UsageDependentDeviceList.
4485 //
4486 if (pList != NULL) {
4487 m_UsageDependentDeviceList->UnlockFromEnum(GetDriverGlobals());
4488 }
4489
4490 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
4491 "Exit %!STATUS!", status);
4492
4493 return CompletePnpRequest(Irp, status);
4494 }
4495
4496 ULONG
SetUsageNotificationFlags(__in DEVICE_USAGE_NOTIFICATION_TYPE Type,__in BOOLEAN InPath)4497 FxPkgPnp::SetUsageNotificationFlags(
4498 __in DEVICE_USAGE_NOTIFICATION_TYPE Type,
4499 __in BOOLEAN InPath
4500 )
4501 /*++
4502
4503 Routine Description:
4504
4505 This routine sets the usage notification flags on the device object (for
4506 non-boot usages) and updates the special file usage count .
4507
4508 Arguments:
4509
4510 Type - the special file type - paging, hibernate, dump or boot file.
4511
4512 InPath - indicates whether the system is creating or removing the special
4513 file on the device.
4514
4515 Return Value:
4516
4517 Returns the old flags on the device object.
4518
4519 --*/
4520 {
4521 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4522 ULONG oldFlags, newFlags;
4523
4524 oldFlags = m_Device->GetDeviceObjectFlags();
4525
4526 //
4527
4528 //
4529 DoTraceLevelMessage(
4530 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
4531 "Before: type %d, in path %d, special count %d, flags 0x%x, "
4532 "device %p (WDFDEVICE %p), is pageable capable %d",
4533 Type, InPath, GetUsageCount(Type), oldFlags,
4534 m_Device->GetDeviceObject(), m_Device->GetHandle(),
4535 m_Device->IsPowerPageableCapable());
4536
4537 //
4538 // Adjust our "special file count".
4539 //
4540 AdjustUsageCount(Type, InPath);
4541
4542 //
4543 // Boot notification doesn't require updating device flags.
4544 //
4545 if (Type == static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileBoot)) {
4546 return oldFlags;
4547 }
4548
4549 if (m_Device->IsFilter()) {
4550 //
4551 // Clear the previous flags and reset them to the attached
4552 // device's flags
4553 //
4554 newFlags = oldFlags & ~(DO_POWER_PAGABLE | DO_POWER_INRUSH);
4555 newFlags |= m_Device->GetAttachedDeviceObjectFlags() &
4556 (DO_POWER_PAGABLE | DO_POWER_INRUSH);
4557 m_Device->SetDeviceObjectFlags(newFlags);
4558 }
4559 else {
4560 if (InPath) {
4561 m_Device->SetDeviceObjectFlags(
4562 m_Device->GetDeviceObjectFlags() & ~DO_POWER_PAGABLE
4563 );
4564 }
4565 else {
4566 if (m_Device->IsPowerPageableCapable() && IsInSpecialUse() == FALSE) {
4567 m_Device->SetDeviceObjectFlags(
4568 m_Device->GetDeviceObjectFlags() | DO_POWER_PAGABLE
4569 );
4570 }
4571 }
4572 }
4573
4574 return oldFlags;
4575 }
4576
4577 VOID
RevertUsageNotificationFlags(__in DEVICE_USAGE_NOTIFICATION_TYPE Type,__in BOOLEAN InPath,__in ULONG OldFlags)4578 FxPkgPnp::RevertUsageNotificationFlags(
4579 __in DEVICE_USAGE_NOTIFICATION_TYPE Type,
4580 __in BOOLEAN InPath,
4581 __in ULONG OldFlags
4582 )
4583 /*++
4584
4585 Routine Description:
4586
4587 This routine reverts the usage notification flags to the old flags on
4588 the device object and updates the special file usage count.
4589
4590 Arguments:
4591
4592 Type - the special file type - paging, hibernate or dump file.
4593
4594 InPath - indicates whether the system is creating or removing the special
4595 file on the device.
4596
4597 OldFlags - the previous flags on the device object.
4598
4599 --*/
4600 {
4601 //
4602 // Re-adjust our "special file count".
4603 //
4604 InPath = !InPath;
4605 AdjustUsageCount(Type, InPath);
4606
4607 //
4608 // Restore the flags on the device object.
4609 //
4610 m_Device->SetDeviceObjectFlags(OldFlags);
4611 }
4612
4613 VOID
CommitUsageNotification(__in DEVICE_USAGE_NOTIFICATION_TYPE Type,__in ULONG OldFlags)4614 FxPkgPnp::CommitUsageNotification(
4615 __in DEVICE_USAGE_NOTIFICATION_TYPE Type,
4616 __in ULONG OldFlags
4617 )
4618 /*++
4619
4620 Routine Description:
4621
4622 This routine commits the usage notification flags on the device object
4623 and invokes the usage notification callbacks. If the current flags on
4624 the device object indicates that there was a transition from power-pagable
4625 to non power-pagable, or vice-versa, then an event is posted to the power
4626 state machine to notify it of the change. After this routine is called
4627 the PNP manager will no longer be able to disable the device.
4628
4629 Arguments:
4630
4631 Type - the special file type - paging, hibernation or crash dump file.
4632
4633 InPath - indicates whether the system is creating or removing the special
4634 file on the device.
4635
4636 OldFlags - the previous flags on the device object.
4637
4638 --*/
4639 {
4640 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4641 ULONG newFlags;
4642
4643 newFlags = m_Device->GetDeviceObjectFlags();
4644
4645 if ((OldFlags & DO_POWER_PAGABLE) == DO_POWER_PAGABLE &&
4646 (newFlags & DO_POWER_PAGABLE) == 0) {
4647 //
4648 // We transitioned from a power pageable to a non power pageable
4649 // device. Move the power state machine to the appropriate
4650 // state.
4651 //
4652 PowerProcessEvent(PowerMarkNonpageable);
4653 }
4654
4655 if ((OldFlags & DO_POWER_PAGABLE) == 0 &&
4656 (newFlags & DO_POWER_PAGABLE) == DO_POWER_PAGABLE) {
4657 //
4658 // We transitioned from a non power pageable to a power pageable
4659 // device. Move the power state machine to the appropriate
4660 // state.
4661 //
4662 PowerProcessEvent(PowerMarkPageable);
4663 }
4664
4665 //
4666 // Notify PNP that it should no longer be able
4667 // to disable this device.
4668 //
4669 MxDeviceObject physicalDeviceObject(
4670 m_Device->GetPhysicalDevice()
4671 );
4672 physicalDeviceObject.InvalidateDeviceState(
4673 m_Device->GetDeviceObject()
4674 );
4675
4676 DoTraceLevelMessage(
4677 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
4678 "After: special count %d, flags 0x%x, device %p (WDFDEVICE %p)",
4679 GetUsageCount(Type), newFlags,
4680 m_Device->GetDeviceObject(), m_Device->GetHandle());
4681 }
4682
4683 _Must_inspect_result_
4684 NTSTATUS
AddUsageDevice(__in MdDeviceObject DependentDevice)4685 FxPkgPnp::AddUsageDevice(
4686 __in MdDeviceObject DependentDevice
4687 )
4688 {
4689 FxRelatedDevice* pRelated;
4690 NTSTATUS status;
4691
4692 if (m_UsageDependentDeviceList == NULL) {
4693 KIRQL irql;
4694
4695 Lock(&irql);
4696 if (m_UsageDependentDeviceList == NULL) {
4697 m_UsageDependentDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList();
4698
4699 if (m_UsageDependentDeviceList != NULL) {
4700 status = STATUS_SUCCESS;
4701 }
4702 else {
4703 status = STATUS_INSUFFICIENT_RESOURCES;
4704
4705 DoTraceLevelMessage(
4706 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4707 "Could not allocate usage device list for WDFDEVICE %p, "
4708 "%!STATUS!", m_Device->GetHandle(), status);
4709 }
4710
4711 }
4712 else {
4713 //
4714 // another thread allocated the list already
4715 //
4716 status = STATUS_SUCCESS;
4717 }
4718 Unlock(irql);
4719
4720 if (!NT_SUCCESS(status)) {
4721 return status;
4722 }
4723 }
4724
4725 pRelated = new(GetDriverGlobals())
4726 FxRelatedDevice(DependentDevice, GetDriverGlobals());
4727
4728 if (pRelated == NULL) {
4729 return STATUS_INSUFFICIENT_RESOURCES;
4730 }
4731
4732 status = m_UsageDependentDeviceList->Add(GetDriverGlobals(), pRelated);
4733
4734 if (!NT_SUCCESS(status)) {
4735 pRelated->DeleteFromFailedCreate();
4736 }
4737
4738 return status;
4739 }
4740
4741 VOID
RemoveUsageDevice(__in MdDeviceObject DependentDevice)4742 FxPkgPnp::RemoveUsageDevice(
4743 __in MdDeviceObject DependentDevice
4744 )
4745 {
4746 if (m_UsageDependentDeviceList != NULL) {
4747 m_UsageDependentDeviceList->Remove(GetDriverGlobals(), DependentDevice);
4748 }
4749 }
4750
4751 _Must_inspect_result_
4752 NTSTATUS
AddRemovalDevice(__in MdDeviceObject DependentDevice)4753 FxPkgPnp::AddRemovalDevice(
4754 __in MdDeviceObject DependentDevice
4755 )
4756 {
4757 FxRelatedDevice* pRelated;
4758 NTSTATUS status;
4759
4760 if (m_RemovalDeviceList == NULL) {
4761 KIRQL irql;
4762
4763 Lock(&irql);
4764 if (m_RemovalDeviceList == NULL) {
4765 m_RemovalDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList();
4766
4767 if (m_RemovalDeviceList != NULL) {
4768 status = STATUS_SUCCESS;
4769 }
4770 else {
4771 status = STATUS_INSUFFICIENT_RESOURCES;
4772
4773 DoTraceLevelMessage(
4774 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4775 "Could not allocate removal device list for WDFDEVICE %p, "
4776 "%!STATUS!", m_Device->GetHandle(), status);
4777 }
4778 }
4779 else {
4780 //
4781 // another thread allocated the list already
4782 //
4783 status = STATUS_SUCCESS;
4784 }
4785 Unlock(irql);
4786
4787 if (!NT_SUCCESS(status)) {
4788 return status;
4789 }
4790 }
4791
4792 pRelated = new(GetDriverGlobals())
4793 FxRelatedDevice(DependentDevice, GetDriverGlobals());
4794 if (pRelated == NULL) {
4795 return STATUS_INSUFFICIENT_RESOURCES;
4796 }
4797
4798 status = m_RemovalDeviceList->Add(GetDriverGlobals(), pRelated);
4799
4800 if (NT_SUCCESS(status)) {
4801 //
4802 // RemovalRelations are queried automatically by PnP when the device is
4803 // going to be query removed. No need to tell pnp that the list changed
4804 // until it needs to query for it.
4805 //
4806 DO_NOTHING();
4807 }
4808 else {
4809 pRelated->DeleteFromFailedCreate();
4810 }
4811
4812 return status;
4813 }
4814
4815 VOID
RemoveRemovalDevice(__in MdDeviceObject DependentDevice)4816 FxPkgPnp::RemoveRemovalDevice(
4817 __in MdDeviceObject DependentDevice
4818 )
4819 {
4820 if (m_RemovalDeviceList != NULL) {
4821 m_RemovalDeviceList->Remove(GetDriverGlobals(), DependentDevice);
4822 }
4823
4824 //
4825 // RemovalRelations are queried automatically by PnP when the device is
4826 // going to be query removed. No need to tell pnp that the list changed
4827 // until it needs to query for it.
4828 //
4829 }
4830
4831 VOID
ClearRemovalDevicesList(VOID)4832 FxPkgPnp::ClearRemovalDevicesList(
4833 VOID
4834 )
4835 {
4836 FxRelatedDevice* pEntry;
4837
4838 if (m_RemovalDeviceList == NULL) {
4839 return;
4840 }
4841
4842 m_RemovalDeviceList->LockForEnum(GetDriverGlobals());
4843 while ((pEntry = m_RemovalDeviceList->GetNextEntry(NULL)) != NULL) {
4844 m_RemovalDeviceList->Remove(GetDriverGlobals(), pEntry->GetDevice());
4845 }
4846 m_RemovalDeviceList->UnlockFromEnum(GetDriverGlobals());
4847
4848 //
4849 // RemovalRelations are queried automatically by PnP when the device is
4850 // going to be query removed. No need to tell pnp that the list changed
4851 // until it needs to query for it.
4852 //
4853 }
4854
4855 VOID
SetInternalFailure(VOID)4856 FxPkgPnp::SetInternalFailure(
4857 VOID
4858 )
4859 /*++
4860
4861 Routine Description:
4862 Sets the failure field and then optionally invalidates the device state.
4863
4864 Arguments:
4865 InvalidateState - If TRUE, the state is invalidated
4866
4867 Return Value:
4868 None
4869
4870 --*/
4871 {
4872 m_InternalFailure = TRUE;
4873
4874 MxDeviceObject physicalDeviceObject(
4875 m_Device->GetPhysicalDevice()
4876 );
4877 physicalDeviceObject.InvalidateDeviceState(
4878 m_Device->GetDeviceObject()
4879 );
4880 }
4881
4882 VOID
SetPendingPnpIrp(__inout FxIrp * Irp,__in BOOLEAN MarkIrpPending)4883 FxPkgPnp::SetPendingPnpIrp(
4884 __inout FxIrp* Irp,
4885 __in BOOLEAN MarkIrpPending
4886 )
4887 {
4888 if (m_PendingPnPIrp != NULL ) {
4889 FxIrp pendingIrp(m_PendingPnPIrp);
4890
4891 //
4892 // A state changing pnp irp is already pended. If we don't bugcheck
4893 // the pended pnp irp will be overwritten with new pnp irp and the old
4894 // one may never get completed, which may have drastic implications (
4895 // unresponsive system, power manager not sending Sx Irp etc.)
4896 //
4897 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4898 "A new state changing pnp irp %!pnpmn! IRP %p arrived while another "
4899 "pnp irp %!pnpmn! IRP %p is still pending WDFDEVICE %p\n",
4900 Irp->GetMinorFunction(), Irp->GetIrp(),
4901 pendingIrp.GetMinorFunction(),pendingIrp.GetIrp(),
4902 m_Device->GetHandle());
4903
4904 FxVerifierBugCheck(GetDriverGlobals(), // globals
4905 WDF_PNP_FATAL_ERROR, // specific type
4906 (ULONG_PTR)m_Device->GetHandle(), //parm 2
4907 (ULONG_PTR)Irp->GetIrp()); // parm 3
4908
4909 /* NOTREACHED */
4910 return;
4911 }
4912 if (MarkIrpPending) {
4913 Irp->MarkIrpPending();
4914 }
4915 m_PendingPnPIrp = Irp->GetIrp();
4916 }
4917
4918 _Must_inspect_result_
4919 NTSTATUS
AllocateEnumInfo(VOID)4920 FxPkgPnp::AllocateEnumInfo(
4921 VOID
4922 )
4923 {
4924 KIRQL irql;
4925 NTSTATUS status;
4926
4927 if (m_EnumInfo != NULL) {
4928 return STATUS_SUCCESS;
4929 }
4930
4931 Lock(&irql);
4932 if (m_EnumInfo == NULL) {
4933 m_EnumInfo = new (GetDriverGlobals()) FxEnumerationInfo(GetDriverGlobals());
4934
4935 if (m_EnumInfo != NULL) {
4936 status = m_EnumInfo->Initialize();
4937
4938 if (!NT_SUCCESS(status)) {
4939 delete m_EnumInfo;
4940 m_EnumInfo = NULL;
4941
4942 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR,
4943 TRACINGPNP,
4944 "Could not initialize enum info for "
4945 "WDFDEVICE %p, %!STATUS!",
4946 m_Device->GetHandle(), status);
4947 }
4948
4949 }
4950 else {
4951 status = STATUS_INSUFFICIENT_RESOURCES;
4952
4953 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
4954 "Could not allocate enum info for WDFDEVICE %p, "
4955 "%!STATUS!", m_Device->GetHandle(), status);
4956 }
4957 }
4958 else {
4959 //
4960 // another thread allocated the list already
4961 //
4962 status = STATUS_SUCCESS;
4963 }
4964 Unlock(irql);
4965
4966 return status;
4967 }
4968
4969 VOID
AddChildList(__in FxChildList * List)4970 FxPkgPnp::AddChildList(
4971 __in FxChildList* List
4972 )
4973 {
4974 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
4975 "Adding FxChildList %p, WDFCHILDLIST %p", List,
4976 List->GetHandle());
4977
4978 m_EnumInfo->m_ChildListList.Add(GetDriverGlobals(),
4979 &List->m_TransactionLink);
4980 }
4981
4982 VOID
RemoveChildList(__in FxChildList * List)4983 FxPkgPnp::RemoveChildList(
4984 __in FxChildList* List
4985 )
4986 {
4987 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
4988 "Removing FxChildList %p, WDFCHILDLIST %p", List,
4989 List->GetHandle());
4990
4991 m_EnumInfo->m_ChildListList.Remove(GetDriverGlobals(), &List->m_TransactionLink);
4992
4993 //
4994
4995 //
4996 }
4997
4998 VOID
ChildListNotifyRemove(__inout PLONG PendingCount)4999 FxPkgPnp::ChildListNotifyRemove(
5000 __inout PLONG PendingCount
5001 )
5002 {
5003 FxTransactionedEntry* ple;
5004
5005 ple = NULL;
5006
5007 if (m_EnumInfo != NULL) {
5008 m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals());
5009 while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) {
5010 FxChildList::_FromEntry(ple)->NotifyDeviceRemove(PendingCount);
5011 }
5012 m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals());
5013 }
5014 }
5015
5016 VOID
AddQueryInterface(__in FxQueryInterface * QI,__in BOOLEAN Lock)5017 FxPkgPnp::AddQueryInterface(
5018 __in FxQueryInterface* QI,
5019 __in BOOLEAN Lock
5020 )
5021 /*++
5022
5023 Routine Description:
5024 Add a query interface structure to the list of interfaces supported
5025
5026 Arguments:
5027 QI - the interface to add
5028
5029 Lock - indication of the list lock should be acquired or not
5030
5031 Return Value:
5032 None
5033
5034 --*/
5035 {
5036 SINGLE_LIST_ENTRY **ppPrev, *pCur;
5037
5038 if (Lock) {
5039 m_QueryInterfaceLock.AcquireLock(GetDriverGlobals());
5040 }
5041
5042 ASSERT(QI->m_Entry.Next == NULL);
5043
5044 //
5045 // Iterate until we find the end of the list and then append the new
5046 // structure. ppPrev is the pointer to the Next pointer value. When we
5047 // get to the end, ppPrev will be equal to the Next field which points to NULL.
5048 //
5049 ppPrev = &m_QueryInterfaceHead.Next;
5050 pCur = m_QueryInterfaceHead.Next;
5051
5052 while (pCur != NULL) {
5053 ppPrev = &pCur->Next;
5054 pCur = pCur->Next;
5055 }
5056
5057 *ppPrev = &QI->m_Entry;
5058
5059 if (Lock) {
5060 m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals());
5061 }
5062 }
5063
5064 __drv_maxIRQL(DISPATCH_LEVEL)
__drv_minIRQL(DISPATCH_LEVEL)5065 __drv_minIRQL(DISPATCH_LEVEL)
5066 __drv_requiresIRQL(DISPATCH_LEVEL)
5067 __drv_sameIRQL
5068 VOID
5069 FxWatchdog::_WatchdogDpc(
5070 __in PKDPC Dpc,
5071 __in_opt PVOID Context,
5072 __in_opt PVOID SystemArgument1,
5073 __in_opt PVOID SystemArgument2
5074 )
5075 /*++
5076
5077 Routine Description:
5078
5079 This routine's job is to crash the machine, attempting to get some data
5080 into the crashdump file (or minidump) about why the machine stopped
5081 responding during an attempt to put the machine to sleep.
5082
5083 Arguments:
5084
5085 This - the instance of FxPkgPnp
5086
5087 Return Value:
5088
5089 this routine never returns
5090
5091 --*/
5092 {
5093 WDF_POWER_ROUTINE_TIMED_OUT_DATA data;
5094 FxWatchdog* pThis;
5095 CfxDevice* pDevice;
5096
5097 UNREFERENCED_PARAMETER(Dpc);
5098 UNREFERENCED_PARAMETER(SystemArgument1);
5099 UNREFERENCED_PARAMETER(SystemArgument2);
5100
5101 pThis = (FxWatchdog*) Context;
5102 pDevice = pThis->m_PkgPnp->GetDevice();
5103
5104 DoTraceLevelMessage(pDevice->GetDriverGlobals(),
5105 TRACE_LEVEL_ERROR, TRACINGPNP,
5106 "The driver failed to return from a callback routine "
5107 "in a reasonable period of time. This prevented the "
5108 "machine from going to sleep or from hibernating. The "
5109 "machine crashed because that was the best way to get "
5110 "data about the cause of the crash into a minidump file.");
5111
5112 data.PowerState = pDevice->GetDevicePowerState();
5113 data.PowerPolicyState = pDevice->GetDevicePowerPolicyState();
5114 data.DeviceObject = reinterpret_cast<PDEVICE_OBJECT>(pDevice->GetDeviceObject());
5115 data.Device = pDevice->GetHandle();
5116 data.TimedOutThread = reinterpret_cast<PKTHREAD>(pThis->m_CallingThread);
5117
5118 FxVerifierBugCheck(pDevice->GetDriverGlobals(),
5119 WDF_POWER_ROUTINE_TIMED_OUT,
5120 (ULONG_PTR) &data);
5121 }
5122
5123 _Must_inspect_result_
5124 NTSTATUS
CreatePowerThread(VOID)5125 FxPkgPnp::CreatePowerThread(
5126 VOID
5127 )
5128 /*++
5129
5130 Routine Description:
5131 Creates a power thread for the device node. This thread is share among all
5132 the devices in the stack through the POWER_THREAD_INTERFACE structure and
5133 PnP query interface.
5134
5135 Arguments:
5136 None
5137
5138 Return Value:
5139 NTSTATUS
5140
5141 --*/
5142 {
5143 FxSystemThread *pThread, *pOld;
5144 NTSTATUS status;
5145
5146 status = FxSystemThread::_CreateAndInit(
5147 &pThread,
5148 GetDriverGlobals(),
5149 m_Device->GetHandle(),
5150 m_Device->GetDeviceObject());
5151
5152 if (!NT_SUCCESS(status)) {
5153 return status;
5154 }
5155
5156 //
5157 // Simple locking logic in case N requests are conncurrent. (The requests
5158 // never should be concurrent, but in the case that there are 2 usage
5159 // notifications coming in from two different sources, it could
5160 // theoritically happen.)
5161 //
5162 pOld = (FxSystemThread*) InterlockedCompareExchangePointer(
5163 (PVOID*) &m_PowerThread, pThread, NULL);
5164
5165 if (pOld != NULL) {
5166 //
5167 // Someone also set the thread pointer value at the same time, free
5168 // our new one here.
5169 //
5170 pThread->ExitThread();
5171 pThread->DeleteObject();
5172 }
5173
5174 m_HasPowerThread = TRUE;
5175
5176 return STATUS_SUCCESS;
5177 }
5178
5179 VOID
ReleasePowerThread(VOID)5180 FxPkgPnp::ReleasePowerThread(
5181 VOID
5182 )
5183 /*++
5184
5185 Routine Description:
5186 If this device is the owner of the power thread, it kills the thread.
5187 Otherwise, if this device has acquired the thread from a lower device,
5188 release the reference now.
5189
5190 Arguments:
5191 None
5192
5193 Return Value:
5194 None
5195
5196 --*/
5197 {
5198 BOOLEAN hadThread;
5199
5200 hadThread = m_HasPowerThread;
5201
5202 //
5203 // Set to FALSE before cleaning up the reference or thread itself in case
5204 // there is some other context trying to enqueue. The only way that could
5205 // be happening is if the power policy owner is not WDF and sends power irps
5206 // after query remove or surprise remove.
5207 //
5208 m_HasPowerThread = FALSE;
5209
5210 //
5211 // Check for ownership
5212 //
5213 if (m_PowerThread != NULL) {
5214
5215 FxCREvent event;
5216
5217 //
5218 // Event on stack is used, which is fine since this code is invoked
5219 // only in KM. Verify this assumption.
5220 //
5221 // If this code is ever needed for UM, m_PowerThreadEvent should be
5222 // pre-initialized (simlar to the way m_RemoveEventUm is used)
5223 //
5224 WDF_VERIFY_KM_ONLY_CODE();
5225
5226 ASSERT(m_PowerThreadEvent == NULL);
5227 m_PowerThreadEvent = event.GetSelfPointer();
5228
5229 if (InterlockedDecrement(&m_PowerThreadInterfaceReferenceCount) > 0) {
5230 //
5231 // Wait for all references to go away before exitting the thread.
5232 // A reference will be taken for every device in the stack above this
5233 // one which queried for the interface.
5234 //
5235 event.EnterCRAndWaitAndLeave();
5236 }
5237
5238 m_PowerThreadEvent = NULL;
5239
5240 //
5241 // Wait for the thread to exit and then delete it. Since we have
5242 // turned off the power policy state machine, we can safely do this here.
5243 // Any upper level clients will have also turned off their power policy
5244 // state machines.
5245 //
5246 m_PowerThread->ExitThread();
5247 m_PowerThread->DeleteObject();
5248
5249 m_PowerThread = NULL;
5250 }
5251 else if (hadThread) {
5252 //
5253 // Release our reference
5254 //
5255 m_PowerThreadInterface.Interface.InterfaceDereference(
5256 m_PowerThreadInterface.Interface.Context
5257 );
5258 }
5259 }
5260
5261 VOID
_PowerThreadInterfaceReference(__inout PVOID Context)5262 FxPkgPnp::_PowerThreadInterfaceReference(
5263 __inout PVOID Context
5264 )
5265 /*++
5266
5267 Routine Description:
5268 Increments the ref count on the thread interface.
5269
5270 Arguments:
5271 Context - FxPkgPnp*
5272
5273 Return Value:
5274 None
5275
5276 --*/
5277 {
5278 LONG count;
5279
5280 count = InterlockedIncrement(
5281 &((FxPkgPnp*) Context)->m_PowerThreadInterfaceReferenceCount
5282 );
5283
5284 #if DBG
5285 ASSERT(count >= 2);
5286 #else
5287 UNREFERENCED_PARAMETER(count);
5288 #endif
5289 }
5290
5291 VOID
_PowerThreadInterfaceDereference(__inout PVOID Context)5292 FxPkgPnp::_PowerThreadInterfaceDereference(
5293 __inout PVOID Context
5294 )
5295 /*++
5296
5297 Routine Description:
5298 Interface deref for the thread interface. If this is the last reference
5299 released, an event is set so that the thread which waiting for the last ref
5300 to go away can unblock.
5301
5302 Arguments:
5303 Context - FxPkgPnp*
5304
5305 Return Value:
5306 None
5307
5308 --*/
5309
5310 {
5311 FxPkgPnp* pThis;
5312
5313 pThis = (FxPkgPnp*) Context;
5314
5315 if (InterlockedDecrement(&pThis->m_PowerThreadInterfaceReferenceCount) == 0) {
5316 pThis->m_PowerThreadEvent->Set();
5317 }
5318 }
5319
5320 _Must_inspect_result_
5321 NTSTATUS
PnpPowerReferenceSelf(VOID)5322 FxPkgPnp::PnpPowerReferenceSelf(
5323 VOID
5324 )
5325 /*++
5326
5327 Routine Description:
5328 Take a power reference during a query pnp transition.
5329
5330 Arguments:
5331 None
5332
5333 Return Value:
5334 None
5335
5336 --*/
5337 {
5338 if (IsPowerPolicyOwner()) {
5339 //
5340 // We want to synchronously wait to move into D0
5341 //
5342 return PowerReference(TRUE);
5343 }
5344 else {
5345 return STATUS_SUCCESS;
5346 }
5347 }
5348
5349 _Must_inspect_result_
5350 NTSTATUS
PnpPowerReferenceDuringQueryPnp(VOID)5351 FxPkgPnp::PnpPowerReferenceDuringQueryPnp(
5352 VOID
5353 )
5354 /*++
5355
5356 Routine Description:
5357 Take a power reference during a query pnp transition.
5358
5359 Arguments:
5360 None
5361
5362 Return Value:
5363 None
5364
5365 --*/
5366 {
5367 if (IsPowerPolicyOwner()) {
5368 //
5369 // We want to synchronously wait to move into D0
5370 //
5371 return m_PowerPolicyMachine.m_Owner->
5372 m_PowerIdleMachine.PowerReferenceWithFlags(
5373 FxPowerReferenceSendPnpPowerUpEvent
5374 );
5375 }
5376 else {
5377 return STATUS_SUCCESS;
5378 }
5379 }
5380
5381 VOID
PnpPowerDereferenceSelf(VOID)5382 FxPkgPnp::PnpPowerDereferenceSelf(
5383 VOID
5384 )
5385 /*++
5386
5387 Routine Description:
5388 Release the power reference taken during a query pnp transition
5389
5390 Arguments:
5391 None
5392
5393 Return Value:
5394 None
5395
5396 --*/
5397 {
5398 if (IsPowerPolicyOwner()) {
5399 PowerDereference();
5400 }
5401 }
5402
5403 NTSTATUS
CompletePowerRequest(__inout FxIrp * Irp,__in NTSTATUS Status)5404 FxPkgPnp::CompletePowerRequest(
5405 __inout FxIrp* Irp,
5406 __in NTSTATUS Status
5407 )
5408 {
5409 MdIrp irp;
5410
5411 //
5412 // Once we call CompleteRequest, 2 things happen
5413 // 1) this object may go away
5414 // 2) Irp->m_Irp will be cleared
5415 //
5416 // As such, we capture the underlying WDM objects so that we can use them
5417 // to release the remove lock and use the PIRP *value* as a tag to release
5418 // the remlock.
5419 //
5420 irp = Irp->GetIrp();
5421
5422 Irp->SetStatus(Status);
5423 Irp->StartNextPowerIrp();
5424 Irp->CompleteRequest(IO_NO_INCREMENT);
5425
5426 Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(),
5427 irp);
5428
5429 return Status;
5430 }
5431
5432 LONG
GetPnpStateInternal(VOID)5433 FxPkgPnp::GetPnpStateInternal(
5434 VOID
5435 )
5436 /*++
5437
5438 Routine Description:
5439 Returns the pnp device state encoded into a ULONG. This state is the state
5440 that is reported to PNp via IRP_MN_QUERY_PNP_DEVICE_STATE after it has been
5441 decoded into the bits pnp expects
5442
5443 Arguments:
5444 None
5445
5446 Return Value:
5447 the current state bits
5448
5449 --*/
5450 {
5451 LONG state;
5452 KIRQL irql;
5453
5454 //
5455 // State is shared with the caps bits. Use a lock to guard against
5456 // corruption of the value between these 2 values
5457 //
5458 Lock(&irql);
5459 state = m_PnpStateAndCaps.Value & FxPnpStateMask;
5460 Unlock(irql);
5461
5462 return state;
5463 }
5464
5465 LONG
GetPnpCapsInternal(VOID)5466 FxPkgPnp::GetPnpCapsInternal(
5467 VOID
5468 )
5469 /*++
5470
5471 Routine Description:
5472 Returns the pnp device capabilities encoded into a LONG. This state is used
5473 in reporting device capabilities via IRP_MN_QUERY_CAPABILITIES and filling
5474 in the PDEVICE_CAPABILITIES structure.
5475
5476 Arguments:
5477 None
5478
5479 Return Value:
5480 the current pnp cap bits
5481
5482 --*/
5483 {
5484 LONG caps;
5485 KIRQL irql;
5486
5487 Lock(&irql);
5488 caps = m_PnpStateAndCaps.Value & FxPnpCapMask;
5489 Unlock(irql);
5490
5491 return caps;
5492 }
5493
5494
5495 VOID
SetPnpCaps(__in PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities)5496 FxPkgPnp::SetPnpCaps(
5497 __in PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities
5498 )
5499 /*++
5500
5501 Routine Description:
5502 Encode the driver provided pnp capabilities into our internal capabilities
5503 bit field and store the result.
5504
5505 Arguments:
5506 PnpCapabilities - capabilities as reported by the driver writer
5507
5508 Return Value:
5509 None
5510
5511 --*/
5512 {
5513 LONG pnpCaps;
5514 KIRQL irql;
5515
5516 pnpCaps = 0;
5517 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, LockSupported);
5518 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, EjectSupported);
5519 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, Removable);
5520 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, DockDevice);
5521 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, UniqueID);
5522 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, SilentInstall);
5523 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, SurpriseRemovalOK);
5524 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, HardwareDisabled);
5525 pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, NoDisplayInUI);
5526
5527 //
5528 // Since the caller of IRP_MN_QUERY_CAPABILITIES sets these 2 values to -1,
5529 // we can reuse the -1 as the default/no override value since the associated
5530 // PDEVICE_CAPAPBILITIES structure will have been predisposed to these values
5531 //
5532 if (PnpCapabilities->Address != (ULONG) -1) {
5533 m_PnpCapsAddress = PnpCapabilities->Address;
5534 }
5535 if (PnpCapabilities->UINumber != (ULONG) -1) {
5536 m_PnpCapsUINumber = PnpCapabilities->UINumber;
5537 }
5538
5539 //
5540 // Use the FxPnpStateMask to keep the state mask while applying the new
5541 // pnp capabilities.
5542 //
5543 Lock(&irql);
5544 m_PnpStateAndCaps.Value = (m_PnpStateAndCaps.Value & FxPnpStateMask) | pnpCaps;
5545 Unlock(irql);
5546 }
5547
5548 VOID
GetPnpState(__out PWDF_DEVICE_STATE State)5549 FxPkgPnp::GetPnpState(
5550 __out PWDF_DEVICE_STATE State
5551 )
5552 /*++
5553
5554 Routine Description:
5555 Decodes our internal pnp state bitfield into the external WDF_DEVICE_STATE
5556 structure
5557
5558 Arguments:
5559 State - the structure to decode into
5560
5561 Return Value:
5562 None
5563
5564 --*/
5565 {
5566 LONG state;
5567
5568 state = GetPnpStateInternal();
5569
5570 SET_TRI_STATE_FROM_STATE_BITS(state, State, Disabled);
5571 SET_TRI_STATE_FROM_STATE_BITS(state, State, DontDisplayInUI);
5572 SET_TRI_STATE_FROM_STATE_BITS(state, State, Failed);
5573 SET_TRI_STATE_FROM_STATE_BITS(state, State, NotDisableable);
5574 SET_TRI_STATE_FROM_STATE_BITS(state, State, Removed);
5575 SET_TRI_STATE_FROM_STATE_BITS(state, State, ResourcesChanged);
5576 }
5577
5578 VOID
SetPnpState(__in PWDF_DEVICE_STATE State)5579 FxPkgPnp::SetPnpState(
5580 __in PWDF_DEVICE_STATE State
5581 )
5582 /*++
5583
5584 Routine Description:
5585 Encodes the driver writer provided state into our internal bit field.
5586
5587 Arguments:
5588 State - the states to encode
5589
5590 Return Value:
5591 None
5592
5593 --*/
5594 {
5595 LONG pnpState;
5596 KIRQL irql;
5597
5598 pnpState = 0x0;
5599 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Disabled);
5600 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, DontDisplayInUI);
5601 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Failed);
5602 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, NotDisableable);
5603 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Removed);
5604 pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, ResourcesChanged);
5605
5606 //
5607 // Mask off FxPnpCapMask to keep the capabilities part of the bitfield
5608 // the same while change the pnp state.
5609 //
5610 Lock(&irql);
5611 m_PnpStateAndCaps.Value = (m_PnpStateAndCaps.Value & FxPnpCapMask) | pnpState;
5612 Unlock(irql);
5613 }
5614
5615 VOID
_SetPowerCapState(__in ULONG Index,__in DEVICE_POWER_STATE State,__out PULONG Result)5616 FxPkgPnp::_SetPowerCapState(
5617 __in ULONG Index,
5618 __in DEVICE_POWER_STATE State,
5619 __out PULONG Result
5620 )
5621 /*++
5622
5623 Routine Description:
5624 Encodes the given device power state (State) into Result at the given Index.
5625 States are encoded in nibbles (4 bit chunks), starting at the bottom of the
5626 result and moving upward
5627
5628 Arguments:
5629 Index - zero based index into the number of nibbles to encode the value
5630
5631 State - State to encode
5632
5633 Result - pointer to where the encoding will take place
5634
5635 Return Value:
5636 None
5637
5638 --*/
5639 {
5640 //
5641 // We store off state in 4 bits, starting at the lowest byte
5642 //
5643 ASSERT(Index < 8);
5644
5645 //
5646 // Erase the old value
5647 //
5648 *Result &= ~(0xF << (Index * 4));
5649
5650 //
5651 // Write in the new one
5652 //
5653 *Result |= (0xF & State) << (Index * 4);
5654 }
5655
5656 DEVICE_POWER_STATE
_GetPowerCapState(__in ULONG Index,__in ULONG State)5657 FxPkgPnp::_GetPowerCapState(
5658 __in ULONG Index,
5659 __in ULONG State
5660 )
5661 /*++
5662
5663 Routine Description:
5664 Decodes our internal device state encoding and returns a normalized device
5665 power state for the given index.
5666
5667 Arguments:
5668 Index - nibble (4 bit chunk) index into the State
5669
5670 State - value which has the device states encoded into it
5671
5672 Return Value:
5673 device power state for the given Index
5674
5675 --*/
5676 {
5677 ASSERT(Index < 8);
5678 // isolate the value and normalize it
5679 return (DEVICE_POWER_STATE) ((State & (0xF << (Index * 4))) >> (Index * 4));
5680 }
5681
5682 VOID
SetPowerCaps(__in PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities)5683 FxPkgPnp::SetPowerCaps(
5684 __in PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities
5685 )
5686 /*++
5687
5688 Routine Description:
5689 Encodes the driver provided power capabilities into the object. The device
5690 power states are encoded into one ULONG while the other power caps are
5691 encoded into their own distinct fields.
5692
5693 Arguments:
5694 PowerCapabilities - the power caps reported by the driver writer
5695
5696 Return Value:
5697 None
5698
5699 --*/
5700 {
5701 ULONG states, i;
5702 USHORT powerCaps;
5703
5704 states = 0x0;
5705
5706 //
5707 // Build up the device power state encoding into a temp var so that if we are
5708 // retrieving the encoding in another thread, we don't get a partial view
5709 //
5710 for (i = 0; i < ARRAY_SIZE(PowerCapabilities->DeviceState); i++) {
5711 _SetPowerCapState(i, PowerCapabilities->DeviceState[i], &states);
5712 }
5713
5714 m_PowerCaps.States = states;
5715
5716 //
5717 // Same idea. Build up the caps locally first so that when we assign them
5718 // into the object, it is assigned as a whole.
5719 //
5720 powerCaps = 0x0;
5721 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, DeviceD1);
5722 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, DeviceD2);
5723 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD0);
5724 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD1);
5725 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD2);
5726 powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD3);
5727
5728 m_PowerCaps.Caps = powerCaps;
5729
5730 if (PowerCapabilities->DeviceWake != PowerDeviceMaximum) {
5731 m_PowerCaps.DeviceWake = (BYTE) PowerCapabilities->DeviceWake;
5732 }
5733 if (PowerCapabilities->SystemWake != PowerSystemMaximum) {
5734 m_PowerCaps.SystemWake = (BYTE) PowerCapabilities->SystemWake;
5735 }
5736
5737 m_PowerCaps.D1Latency = PowerCapabilities->D1Latency;
5738 m_PowerCaps.D2Latency = PowerCapabilities->D2Latency;
5739 m_PowerCaps.D3Latency = PowerCapabilities->D3Latency;
5740
5741 if (PowerCapabilities->IdealDxStateForSx != PowerDeviceMaximum) {
5742 //
5743 // Caller has already validated that IdealDxStateForSx is only set if
5744 // they device is the power policy owner.
5745 //
5746 m_PowerPolicyMachine.m_Owner->m_IdealDxStateForSx = (BYTE)
5747 PowerCapabilities->IdealDxStateForSx;
5748 }
5749 }
5750
5751 NTSTATUS
CompletePnpRequest(__inout FxIrp * Irp,__in NTSTATUS Status)5752 FxPkgPnp::CompletePnpRequest(
5753 __inout FxIrp* Irp,
5754 __in NTSTATUS Status
5755 )
5756 {
5757 MdIrp pIrp = Irp->GetIrp();
5758
5759 Irp->SetStatus(Status);
5760 Irp->CompleteRequest(IO_NO_INCREMENT);
5761
5762 Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(),
5763 pIrp);
5764
5765 return Status;
5766 }
5767
5768 BOOLEAN
PowerPolicyIsWakeEnabled(VOID)5769 FxPkgPnp::PowerPolicyIsWakeEnabled(
5770 VOID
5771 )
5772 {
5773 if (IsPowerPolicyOwner() && PowerPolicyGetCurrentWakeReason() != 0x0) {
5774 return TRUE;
5775 }
5776 else {
5777 return FALSE;
5778 }
5779 }
5780
5781 ULONG
PowerPolicyGetCurrentWakeReason(VOID)5782 FxPkgPnp::PowerPolicyGetCurrentWakeReason(
5783 VOID
5784 )
5785 /*++
5786
5787 Routine Description:
5788 This routine determines the reasons for whether wake should be enabled or
5789 not. Wake could be enabled because it is explicitly enabled for the device
5790 in the wake policy settings or, because the device opted to depend on its
5791 children being armed for wake.
5792
5793 Arguments:
5794 None
5795
5796 Return Value:
5797 Returns a combination of FxPowerPolicySxWakeChildrenArmedFlag, to indicate
5798 that wake can be enabled because of more than one children being armed for
5799 wake, and FxPowerPolicySxWakeDeviceEnabledFlag, to indicate that wake can
5800 be enabled because the device was explicitly enabled in the wake policy
5801 settings.
5802
5803 Returns Zero to indicate that wake is currently disabled for the device.
5804
5805 --*/
5806 {
5807 ULONG wakeReason;
5808
5809 wakeReason = 0x0;
5810
5811 if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.ArmForWakeIfChildrenAreArmedForWake &&
5812 m_PowerPolicyMachine.m_Owner->m_ChildrenArmedCount > 0) {
5813 //
5814 // Wake settings depends on children and one or more children are
5815 // armed for wake.
5816 //
5817 wakeReason |= FxPowerPolicySxWakeChildrenArmedFlag;
5818 }
5819
5820 if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled) {
5821 //
5822 // Wake settings is explicitly enabled.
5823 //
5824 wakeReason |= FxPowerPolicySxWakeDeviceEnabledFlag;
5825 }
5826
5827 return wakeReason;
5828 }
5829
5830 VOID
SaveState(__in BOOLEAN UseCanSaveState)5831 FxPkgPnp::SaveState(
5832 __in BOOLEAN UseCanSaveState
5833 )
5834 /*++
5835
5836 Routine Description:
5837 Saves any permanent state of the device out to the registry
5838
5839 Arguments:
5840 None
5841
5842 Return Value:
5843 None
5844
5845 --*/
5846
5847 {
5848 UNICODE_STRING name;
5849 FxAutoRegKey hKey;
5850 NTSTATUS status;
5851 ULONG value;
5852
5853 //
5854 // We only have settings to save if we are the power policy owner
5855 //
5856 if (IsPowerPolicyOwner() == FALSE) {
5857 return;
5858 }
5859
5860 if (UseCanSaveState &&
5861 m_PowerPolicyMachine.m_Owner->m_CanSaveState == FALSE) {
5862 DoTraceLevelMessage(
5863 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
5864 "Not saving wake settings for WDFDEVICE %p due to system power "
5865 "transition", m_Device->GetHandle());
5866 return;
5867 }
5868
5869 //
5870 // Check to see if there is anything to write out
5871 //
5872 if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty == FALSE &&
5873 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty == FALSE) {
5874 return;
5875 }
5876
5877 //
5878 // No need to write out if user control is not enabled
5879 //
5880 if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable == FALSE &&
5881 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable == FALSE) {
5882 return;
5883 }
5884
5885 //
5886 // If the device is in paging path we should not be touching registry during
5887 // power up because it may incur page fault which won't be satisfied if the
5888 // device is still not powered up, blocking power Irp. User control state
5889 // change will not get written if any at this time but will be flushed out
5890 // to registry during device disable/remove in the remove path.
5891 //
5892 if (IsUsageSupported(DeviceUsageTypePaging) && IsDevicePowerUpIrpPending()) {
5893 return;
5894 }
5895
5896 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
5897
5898 status = m_Device->OpenSettingsKey(&hKey.m_Key, STANDARD_RIGHTS_WRITE);
5899 if (!NT_SUCCESS(status)) {
5900 return;
5901 }
5902 #else
5903 status = STATUS_SUCCESS;
5904 #endif
5905
5906 if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable &&
5907 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty) {
5908 RtlInitUnicodeString(&name, WDF_S0_IDLE_ENABLED_VALUE_NAME);
5909 value = m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled;
5910
5911 WriteStateToRegistry(hKey.m_Key, &name, value);
5912
5913 m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty = FALSE;
5914 }
5915
5916 if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable &&
5917 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty) {
5918 RtlInitUnicodeString(&name, WDF_SX_WAKE_ENABLED_VALUE_NAME);
5919 value = m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled;
5920
5921 WriteStateToRegistry(hKey.m_Key, &name, value);
5922
5923 m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty = FALSE;
5924 }
5925 }
5926
5927 VOID
AddInterruptObject(__in FxInterrupt * Interrupt)5928 FxPkgPnp::AddInterruptObject(
5929 __in FxInterrupt* Interrupt
5930 )
5931 /*++
5932
5933 Routine Description:
5934
5935 This routine adds a WDFINTERRUPT object onto the list of interrupts
5936 which are attached to this device. This list is used in response to
5937 several IRPs.
5938
5939 Note:
5940
5941 It shouldn't be necessary to lock this list, since the driver will add or
5942 remove interrupt objects only in callbacks that are effectively serialized
5943 by the PnP manager.
5944
5945 Further note:
5946
5947 This list must remain sorted by order of interrupt object creation. E.g.
5948 the first interrupt object created must be first in this list.
5949
5950 Arguments:
5951
5952 Interrupt - a Framework interrupt object
5953
5954 Return Value:
5955
5956 VOID
5957
5958 --*/
5959 {
5960 m_InterruptObjectCount++;
5961 InsertTailList(&m_InterruptListHead, &Interrupt->m_PnpList);
5962 }
5963
5964 VOID
RemoveInterruptObject(__in FxInterrupt * Interrupt)5965 FxPkgPnp::RemoveInterruptObject(
5966 __in FxInterrupt* Interrupt
5967 )
5968 /*++
5969
5970 Routine Description:
5971 This routine removes a WDFINTERRUPT object onto the list of interrupts
5972 which are attached to this device. This list is used in response to
5973 several IRPs.
5974
5975 Arguments:
5976
5977 Interrupt - a Framework interrupt object
5978
5979 Return Value:
5980
5981 VOID
5982
5983 --*/
5984 {
5985 m_InterruptObjectCount--;
5986 RemoveEntryList(&Interrupt->m_PnpList);
5987 }
5988
5989 VOID
NotifyResourceobjectsToReleaseResources(VOID)5990 FxPkgPnp::NotifyResourceobjectsToReleaseResources(
5991 VOID
5992 )
5993 /*++
5994
5995 Routine Description:
5996
5997 This routine traverses all resource objects and tells them that their
5998 resources are no longer valid.
5999
6000 Arguments:
6001
6002 none
6003
6004 Return Value:
6005
6006 VOID
6007
6008 --*/
6009 {
6010 FxInterrupt* interruptInstance;
6011 PLIST_ENTRY intListEntry;
6012
6013 //
6014 // Revoke each of the interrupts.
6015 //
6016
6017 intListEntry = m_InterruptListHead.Flink;
6018
6019 while (intListEntry != &m_InterruptListHead) {
6020
6021 //
6022 // Disconnect interrupts and then tell them that they no longer
6023 // own their resources.
6024 //
6025
6026 interruptInstance = CONTAINING_RECORD(intListEntry, FxInterrupt, m_PnpList);
6027 interruptInstance->RevokeResources();
6028 intListEntry = intListEntry->Flink;
6029 }
6030
6031 //
6032 // Now revoke each of the DMA enablers (only system-mode enablers
6033 // will be affected by this)
6034 //
6035
6036 if (m_DmaEnablerList != NULL) {
6037 FxTransactionedEntry* listEntry;
6038
6039 m_DmaEnablerList->LockForEnum(GetDriverGlobals());
6040
6041 for (listEntry = m_DmaEnablerList->GetNextEntry(NULL);
6042 listEntry != NULL;
6043 listEntry = m_DmaEnablerList->GetNextEntry(listEntry)) {
6044 RevokeDmaEnablerResources(
6045 (FxDmaEnabler *) listEntry->GetTransactionedObject()
6046 );
6047 }
6048
6049 m_DmaEnablerList->UnlockFromEnum(GetDriverGlobals());
6050 }
6051 }
6052
6053 _Must_inspect_result_
6054 NTSTATUS
NotifyResourceObjectsD0(__in ULONG NotifyFlags)6055 FxPkgPnp::NotifyResourceObjectsD0(
6056 __in ULONG NotifyFlags
6057 )
6058 /*++
6059
6060 Routine Description:
6061
6062 This routine traverses all resource objects and tells them that the device
6063 is entering D0. If an error is encountered, the walking of the list is
6064 halted.
6065
6066 Arguments:
6067
6068 none
6069
6070 Return Value:
6071
6072 VOID
6073
6074 --*/
6075 {
6076 FxInterrupt* pInterrupt;
6077 PLIST_ENTRY ple;
6078 NTSTATUS status;
6079
6080 for (ple = m_InterruptListHead.Flink;
6081 ple != &m_InterruptListHead;
6082 ple = ple->Flink) {
6083
6084 //
6085 // Connect the interrupts
6086 //
6087 pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList);
6088
6089 status = pInterrupt->Connect(NotifyFlags);
6090
6091 if (!NT_SUCCESS(status)) {
6092 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
6093 "WDFINTERRUPT %p failed to connect, %!STATUS!",
6094 pInterrupt->GetHandle(), status);
6095
6096 return status;
6097 }
6098 }
6099
6100 return STATUS_SUCCESS;
6101 }
6102
6103 NTSTATUS
NotifyResourceObjectsDx(__in ULONG NotifyFlags)6104 FxPkgPnp::NotifyResourceObjectsDx(
6105 __in ULONG NotifyFlags
6106 )
6107 /*++
6108
6109 Routine Description:
6110 This routine traverses all resource objects and tells them that the device
6111 is leaving D0. If there is an error, the remaining resources in the list
6112 are still notified of exitting D0.
6113
6114 Arguments:
6115 NotifyFlags - combination of values from the enum NotifyResourcesFlags
6116
6117 Return Value:
6118 None
6119
6120 --*/
6121 {
6122 FxInterrupt* pInterrupt;
6123 PLIST_ENTRY ple;
6124 NTSTATUS status, finalStatus;
6125
6126 finalStatus = STATUS_SUCCESS;
6127
6128 //
6129 // Disconect in the reverse order in which we connected the interrupts
6130 //
6131 for (ple = m_InterruptListHead.Blink;
6132 ple != &m_InterruptListHead;
6133 ple = ple->Blink) {
6134
6135 //
6136 // Disconnect interrupts and then tell them that they no longer
6137 // own their resources.
6138 //
6139 pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList);
6140
6141 status = pInterrupt->Disconnect(NotifyFlags);
6142
6143 if (!NT_SUCCESS(status)) {
6144 //
6145 // When we encounter an error we still disconnect the remaining
6146 // interrupts b/c we would just do it later during device tear down
6147 // (might as well do it now).
6148 //
6149 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
6150 "WDFINTERRUPT %p failed to disconnect, %!STATUS!",
6151 pInterrupt->GetHandle(), status);
6152 //
6153 // Overwriting a previous finalStatus is OK, we'll just report the
6154 // last one
6155 //
6156 finalStatus = status;
6157 }
6158 }
6159
6160 return finalStatus;
6161 }
6162
6163 VOID
SendEventToAllWakeInterrupts(__in FxWakeInterruptEvents WakeInterruptEvent)6164 FxPkgPnp::SendEventToAllWakeInterrupts(
6165 __in FxWakeInterruptEvents WakeInterruptEvent
6166 )
6167 /*++
6168
6169 Routine Description:
6170 This routine traverses all interrupt objects and queues the
6171 given event into those interrupts that are marked as wake
6172 capable and have a state machine
6173
6174 Arguments:
6175 WakeInterruptEvent - Event to be queued in the wake interrupt
6176 state machines
6177
6178 Return Value:
6179 None
6180
6181 --*/
6182 {
6183 FxInterrupt* pInterrupt;
6184 PLIST_ENTRY ple;
6185
6186 if (m_WakeInterruptCount == 0) {
6187 return;
6188 }
6189
6190 //
6191 // Initialize the pending count to the wake interrupt count
6192 // If the event needs an acknowledgement, this variable will
6193 // be decremented as the interrupt machines ack.
6194 //
6195 m_WakeInterruptPendingAckCount = m_WakeInterruptCount;
6196
6197 for (ple = m_InterruptListHead.Flink;
6198 ple != &m_InterruptListHead;
6199 ple = ple->Flink) {
6200
6201 pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList);
6202
6203 if (pInterrupt->IsWakeCapable()) {
6204 pInterrupt->ProcessWakeInterruptEvent(WakeInterruptEvent);
6205 }
6206
6207 }
6208 }
6209
6210 VOID
AckPendingWakeInterruptOperation(__in BOOLEAN ProcessPowerEventOnDifferentThread)6211 FxPkgPnp::AckPendingWakeInterruptOperation(
6212 __in BOOLEAN ProcessPowerEventOnDifferentThread
6213 )
6214 /*++
6215
6216 Routine Description:
6217 This routine is invoked by the interrupt wake machine to acknowledge
6218 back an event that was queued into it. When the last interrupt machine
6219 acknowledges, an event is queued back into the Pnp/power state machine
6220
6221 Arguments:
6222
6223 ProcessPowerEventOnDifferentThread - Once all wake interrupts for the device
6224 have acknowledged the operation, if this is TRUE, the power state
6225 machine will process the PowerWakeInterruptCompleteTransition event on a
6226 seperate thread.
6227
6228 Return Value:
6229 None
6230
6231 --*/
6232 {
6233 if (InterlockedDecrement((LONG *)&m_WakeInterruptPendingAckCount) == 0) {
6234 PowerProcessEvent(
6235 PowerWakeInterruptCompleteTransition,
6236 ProcessPowerEventOnDifferentThread
6237 );
6238 }
6239 }
6240
6241
6242 NTSTATUS
AssignPowerFrameworkSettings(__in PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings)6243 FxPkgPnp::AssignPowerFrameworkSettings(
6244 __in PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings
6245 )
6246 {
6247 // NTSTATUS status;
6248 // PPO_FX_COMPONENT_IDLE_STATE idleStates = NULL;
6249 // ULONG idleStatesSize = 0;
6250 // PPO_FX_COMPONENT component = NULL;
6251 // ULONG componentSize = 0;
6252 // PPOX_SETTINGS poxSettings = NULL;
6253 // ULONG poxSettingsSize = 0;
6254 // BYTE * buffer = NULL;
6255
6256 // if (FALSE==(IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable())) {
6257 // //
6258 // // If system-managed idle timeout is not available on this OS, then
6259 // // there is nothing to do.
6260 // //
6261 // DoTraceLevelMessage(
6262 // GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
6263 // "WDFDEVICE %p !devobj %p Power framework is not supported on the "
6264 // "current OS. Therefore, the power framework settings will not take "
6265 // "effect.",
6266 // m_Device->GetHandle(),
6267 // m_Device->GetDeviceObject()
6268 // );
6269 // return STATUS_SUCCESS;
6270 // }
6271
6272 // if (NULL != PowerFrameworkSettings->Component) {
6273 // //
6274 // // Caller should ensure that IdleStateCount is not zero
6275 // //
6276 // ASSERT(0 != PowerFrameworkSettings->Component->IdleStateCount);
6277
6278 // //
6279 // // Compute buffer size needed for storing F-states
6280 // //
6281 // status = RtlULongMult(
6282 // PowerFrameworkSettings->Component->IdleStateCount,
6283 // sizeof(*(PowerFrameworkSettings->Component->IdleStates)),
6284 // &idleStatesSize
6285 // );
6286 // if (FALSE == NT_SUCCESS(status)) {
6287 // DoTraceLevelMessage(
6288 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
6289 // "WDFDEVICE %p !devobj %p Unable to compute length of buffer "
6290 // "required to store F-states. RtlULongMult failed with "
6291 // "%!STATUS!",
6292 // m_Device->GetHandle(),
6293 // m_Device->GetDeviceObject(),
6294 // status
6295 // );
6296 // goto exit;
6297 // }
6298
6299 // //
6300 // // Compute buffer size needed for storing component information
6301 // // (including F-states)
6302 // //
6303 // status = RtlULongAdd(idleStatesSize,
6304 // sizeof(*component),
6305 // &componentSize);
6306 // if (FALSE == NT_SUCCESS(status)) {
6307 // DoTraceLevelMessage(
6308 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
6309 // "WDFDEVICE %p !devobj %p Unable to compute length of buffer "
6310 // "required to store driver's component information. RtlULongAdd "
6311 // "failed with %!STATUS!",
6312 // m_Device->GetHandle(),
6313 // m_Device->GetDeviceObject(),
6314 // status
6315 // );
6316 // goto exit;
6317 // }
6318 // }
6319
6320 // //
6321 // // Compute total buffer size needed for power framework settings
6322 // //
6323 // status = RtlULongAdd(componentSize,
6324 // sizeof(*poxSettings),
6325 // &poxSettingsSize);
6326 // if (FALSE == NT_SUCCESS(status)) {
6327 // DoTraceLevelMessage(
6328 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
6329 // "WDFDEVICE %p !devobj %p Unable to compute length of buffer "
6330 // "required to store driver's power framework settings. RtlULongAdd "
6331 // "failed with %!STATUS!",
6332 // m_Device->GetHandle(),
6333 // m_Device->GetDeviceObject(),
6334 // status
6335 // );
6336 // goto exit;
6337 // }
6338
6339 // //
6340 // // Allocate memory to copy the settings
6341 // //
6342 // buffer = (BYTE *) MxMemory::MxAllocatePoolWithTag(NonPagedPool,
6343 // poxSettingsSize,
6344 // GetDriverGlobals()->Tag);
6345 // if (NULL == buffer) {
6346 // status = STATUS_INSUFFICIENT_RESOURCES;
6347 // DoTraceLevelMessage(
6348 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
6349 // "WDFDEVICE %p !devobj %p Unable to allocate buffer required to "
6350 // "store F-states. %!STATUS!",
6351 // m_Device->GetHandle(),
6352 // m_Device->GetDeviceObject(),
6353 // status
6354 // );
6355 // goto exit;
6356 // }
6357
6358 // //
6359 // // Set our pointers to point to appropriate locations in the buffer.
6360 // //
6361 // // NOTES:
6362 // // - The array of F-states comes first because it has ULONGLONG members
6363 // // because of which it has the biggest alignment requirement.
6364 // // - The logic below works even if the client driver did not specify any
6365 // // component information. In that case idleStatesSize and componentSize
6366 // // are both 0 and 'poxSettings' points to the beginning of the allocated
6367 // // buffer
6368 // //
6369 // idleStates = (PPO_FX_COMPONENT_IDLE_STATE) buffer;
6370 // component = (PPO_FX_COMPONENT) (buffer + idleStatesSize);
6371 // poxSettings = (PPOX_SETTINGS) (buffer + componentSize);
6372
6373 // //
6374 // // Copy the relevant parts of the settings buffer
6375 // //
6376 // poxSettings->EvtDeviceWdmPostPoFxRegisterDevice =
6377 // PowerFrameworkSettings->EvtDeviceWdmPostPoFxRegisterDevice;
6378 // poxSettings->EvtDeviceWdmPrePoFxUnregisterDevice =
6379 // PowerFrameworkSettings->EvtDeviceWdmPrePoFxUnregisterDevice;
6380 // poxSettings->Component = PowerFrameworkSettings->Component;
6381 // poxSettings->ComponentActiveConditionCallback =
6382 // PowerFrameworkSettings->ComponentActiveConditionCallback;
6383 // poxSettings->ComponentIdleConditionCallback =
6384 // PowerFrameworkSettings->ComponentIdleConditionCallback;
6385 // poxSettings->ComponentIdleStateCallback =
6386 // PowerFrameworkSettings->ComponentIdleStateCallback;
6387 // poxSettings->PowerControlCallback =
6388 // PowerFrameworkSettings->PowerControlCallback;
6389 // poxSettings->PoFxDeviceContext = PowerFrameworkSettings->PoFxDeviceContext;
6390
6391 // if (NULL != PowerFrameworkSettings->Component) {
6392 // //
6393 // // Copy the component information
6394 // //
6395 // poxSettings->Component = component;
6396 // RtlCopyMemory(poxSettings->Component,
6397 // PowerFrameworkSettings->Component,
6398 // sizeof(*component));
6399
6400 // //
6401 // // Caller should ensure that IdleStates is not NULL
6402 // //
6403 // ASSERT(NULL != PowerFrameworkSettings->Component->IdleStates);
6404
6405 // //
6406 // // Copy the F-states
6407 // //
6408 // poxSettings->Component->IdleStates = idleStates;
6409 // RtlCopyMemory(poxSettings->Component->IdleStates,
6410 // PowerFrameworkSettings->Component->IdleStates,
6411 // idleStatesSize);
6412 // }
6413
6414 // //
6415 // // Commit these settings
6416 // //
6417 // status = m_PowerPolicyMachine.m_Owner->
6418 // m_IdleSettings.m_TimeoutMgmt.CommitPowerFrameworkSettings(
6419 // GetDriverGlobals(),
6420 // poxSettings
6421 // );
6422 // if (FALSE == NT_SUCCESS(status)) {
6423 // goto exit;
6424 // }
6425
6426 // status = STATUS_SUCCESS;
6427
6428 // exit:
6429 // if (FALSE == NT_SUCCESS(status)) {
6430 // if (NULL != buffer) {
6431 // MxMemory::MxFreePool(buffer);
6432 // }
6433 // }
6434 // return status;
6435 ROSWDFNOTIMPLEMENTED;
6436 return STATUS_SUCCESS;
6437 }
6438
6439 DEVICE_POWER_STATE
PowerPolicyGetDeviceDeepestDeviceWakeState(__in SYSTEM_POWER_STATE SystemState)6440 FxPkgPnp::PowerPolicyGetDeviceDeepestDeviceWakeState(
6441 __in SYSTEM_POWER_STATE SystemState
6442 )
6443 {
6444 DEVICE_POWER_STATE dxState;
6445
6446 //
6447 // Earlier versions of WDF (pre-1.11) did not take into account SystemState
6448 // in figuring out the deepest wake state. So for compatibility we restrict
6449 // this to drivers compiled for 1.11 or newer. See comments in the
6450 // FxPkgPnp::QueryForCapabilities function for more information on
6451 // compatibility risk.
6452 //
6453 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) {
6454 if ((SystemState < PowerSystemWorking) ||
6455 (SystemState > PowerSystemHibernate)) {
6456 dxState = PowerDeviceD0;
6457 } else {
6458 dxState = MapWakeDepthToDstate(
6459 (DEVICE_WAKE_DEPTH)m_DeviceWake[SystemState - PowerSystemWorking]
6460 );
6461 }
6462 }
6463 else {
6464 //
6465 // For pre-1.11 drivers, all of m_DeviceWake array is populated with
6466 // the same DeviceWake value obtained from device capabilities so we
6467 // just use the first one (index 0).
6468 //
6469 dxState = MapWakeDepthToDstate((DEVICE_WAKE_DEPTH)m_DeviceWake[0]);
6470 }
6471
6472 //
6473 // Per WDM docs DeviceWake and SystemWake must be non-zero to support
6474 // wake. We warn about the violation. Ideally, a verifier check would have
6475 // been better but we want to avoid that because some drivers may
6476 // intentionally call this DDI and do not treat the DDI failure as fatal (
6477 // because they are aware that DDI may succeed in some cases), and a verifier
6478 // breakpoint would force them to avoid the verifier failure by not enabling
6479 // verifier.
6480 //
6481 if (dxState == PowerDeviceUnspecified ||
6482 m_SystemWake == PowerSystemUnspecified) {
6483 DoTraceLevelMessage(
6484 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
6485 "SystemWake %!SYSTEM_POWER_STATE! and DeviceWake "
6486 "%!DEVICE_POWER_STATE! power state reported in device "
6487 "capabilities do not support wake. Both the SystemWake and "
6488 "DeviceWake members should be nonzero to support wake-up on "
6489 "this system.", m_SystemWake, dxState);
6490 }
6491
6492 return dxState;
6493 }
6494
6495