1 /*++ 2 3 Copyright (c) Microsoft. All rights reserved. 4 5 Module Name: 6 7 PnpStateMachineUm.cpp 8 9 Abstract: 10 11 This module implements the PnP state machine for the driver framework. 12 This code was split out from FxPkgPnp.cpp. 13 14 Author: 15 16 17 18 19 20 Environment: 21 22 User mode only 23 24 Revision History: 25 26 --*/ 27 28 #include "../pnppriv.hpp" 29 30 extern "C" { 31 #if defined(EVENT_TRACING) 32 #include "PnpStateMachineUM.tmh" 33 #endif 34 } 35 36 BOOLEAN 37 FxPkgPnp::PnpCheckAndIncrementRestartCount( 38 VOID 39 ) 40 /*++ 41 42 Routine Description: 43 This is a mode-dependent wrapper for PnpIncrementRestartCountLogic, 44 which determines if this device should ask the bus driver to 45 reenumerate the device. Please refer to PnpIncrementRestartCountLogic's 46 comment block for more information. 47 48 Arguments: 49 None 50 51 Return Value: 52 TRUE if a restart should be requested. 53 54 --*/ 55 { 56 HRESULT hr; 57 FxAutoRegKey restart; 58 FxDevice* device; 59 IWudfDeviceStack* deviceStack; 60 UMINT::WDF_PROPERTY_STORE_ROOT propertyStore; 61 UMINT::WDF_PROPERTY_STORE_DISPOSITION disposition; 62 63 device = GetDevice(); 64 deviceStack = device->GetDeviceStack(); 65 66 propertyStore.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); 67 propertyStore.RootClass = UMINT::WdfPropertyStoreRootClassHardwareKey; 68 propertyStore.Qualifier.HardwareKey.ServiceName = L"WudfDiagnostics"; 69 70 hr = deviceStack->CreateRegistryEntry(&propertyStore, 71 UMINT::WdfPropertyStoreCreateVolatile, 72 KEY_QUERY_VALUE | KEY_SET_VALUE, 73 L"Restart", 74 (HKEY*)&restart.m_Key, 75 &disposition); 76 if (FAILED(hr)) { 77 return FALSE; 78 } 79 80 return PnpIncrementRestartCountLogic(restart.m_Key, 81 disposition == UMINT::CreatedNewStore); 82 } 83 84 BOOLEAN 85 FxPkgPnp::ShouldProcessPnpEventOnDifferentThread( 86 __in KIRQL CurrentIrql, 87 __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread 88 ) 89 /*++ 90 Routine Description: 91 92 This function returns whether the PnP state machine should process the 93 current event on the same thread or on a different one. 94 95 This function has been added to work around a bug in the state machines. 96 The idle state machine always calls PnpProcessEvent with the idle state 97 machine lock held. Some events sent by the idle state machine can cause the 98 Pnp state machine to invoke FxPowerIdleMachine::IoDecrement(). 99 FxPowerIdleMachine::IoDecrement() will try to acquire the idle state 100 machine lock, which is already being held, so it will result in a recursive 101 acquire of the idle state machine lock. 102 103 The above bug only affects UMDF, but not KMDF. In KMDF, the idle state 104 machine lock is a spinlock. When PnpProcessEvent is called, it is called 105 with the spinlock held and hence at dispatch level. Note that if called at 106 a non-passive IRQL, PnpProcessEvent will always queue a work item to 107 process the event at passive IRQL later. Queuing a work item forces 108 processing to happen on a different thread and hence we don't attempt to 109 recursively acquire the spinlock. On the other hand, with UMDF we are 110 always at passive IRQL and hence we process the event on the same thread 111 and run into the recursive acquire problem. 112 113 114 115 116 117 118 119 120 Arguments: 121 122 CurrentIrql - The current IRQL 123 124 CallerSpecifiedProcessingOnDifferentThread - Whether or not caller of 125 PnpProcessEvent specified that the event be processed on a different 126 thread. 127 128 Returns: 129 TRUE if the PnP state machine should process the event on a different 130 thread. 131 132 FALSE if the PnP state machine should process the event on the same thread 133 134 --*/ 135 { 136 // 137 // For UMDF, we ignore the IRQL and just do what the caller of 138 // PnpProcessEvent wants. 139 // 140 UNREFERENCED_PARAMETER(CurrentIrql); 141 142 return CallerSpecifiedProcessingOnDifferentThread; 143 } 144 145 _Must_inspect_result_ 146 NTSTATUS 147 FxPkgPnp::CreatePowerThreadIfNeeded( 148 VOID 149 ) 150 /*++ 151 Routine description: 152 If needed, creates a thread for processing power IRPs 153 154 Arguments: 155 None 156 157 Return value: 158 An NTSTATUS code indicating success or failure of this function 159 --*/ 160 { 161 // 162 // For UMDF, we never need a power thread, so just return success. 163 // 164 return STATUS_SUCCESS; 165 } 166 167 NTSTATUS 168 FxPkgPnp::PnpPrepareHardwareInternal( 169 VOID 170 ) 171 { 172 // 173 // Update maximum interrupt thread count now that we know how many 174 // total interrupts we have. 175 // 176 return GetDevice()->UpdateInterruptThreadpoolLimits(); 177 } 178 179