1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 supportKM.cpp 8 9 Abstract: 10 11 This module implements the pnp support routines. 12 13 Author: 14 15 16 Environment: 17 18 kernel mode only 19 20 Revision History: 21 22 --*/ 23 24 #include "../pnppriv.hpp" 25 #include <wdmguid.h> 26 27 #if defined(EVENT_TRACING) 28 #include "supportKM.tmh" 29 #endif 30 31 VOID 32 CopyQueryInterfaceToIrpStack( 33 __in PPOWER_THREAD_INTERFACE PowerThreadInterface, 34 __in FxIrp* Irp 35 ) 36 { 37 PIO_STACK_LOCATION stack; 38 39 stack = Irp->GetCurrentIrpStackLocation(); 40 41 RtlCopyMemory(stack->Parameters.QueryInterface.Interface, 42 PowerThreadInterface, 43 PowerThreadInterface->Interface.Size); 44 } 45 46 _Must_inspect_result_ 47 NTSTATUS 48 GetStackCapabilities( 49 __in PFX_DRIVER_GLOBALS DriverGlobals, 50 __in MxDeviceObject* DeviceInStack, 51 __in_opt PD3COLD_SUPPORT_INTERFACE D3ColdInterface, 52 __out PSTACK_DEVICE_CAPABILITIES Capabilities 53 ) 54 { 55 ULONG i; 56 FxAutoIrp irp; 57 NTSTATUS status; 58 59 ASSERT(Capabilities != NULL); 60 61 status = STATUS_INSUFFICIENT_RESOURCES; 62 63 // 64 // Normally this would be assigned to a local variable on the stack. Since 65 // query caps iteratively moves down the device's tree until it hits the 66 // root. As such, stack usage is consumed quickly. While this is only one 67 // pointer value we are saving, it does eventually add up on very deep stacks. 68 // 69 DeviceInStack->SetObject(DeviceInStack->GetAttachedDeviceReference()); 70 if (DeviceInStack->GetObject() == NULL) { 71 goto Done; 72 } 73 74 irp.SetIrp(FxIrp::AllocateIrp(DeviceInStack->GetStackSize())); 75 if (irp.GetIrp() == NULL) { 76 goto Done; 77 } 78 79 // 80 // Initialize device capabilities. 81 // 82 RtlZeroMemory(Capabilities, sizeof(STACK_DEVICE_CAPABILITIES)); 83 Capabilities->DeviceCaps.Size = sizeof(DEVICE_CAPABILITIES); 84 Capabilities->DeviceCaps.Version = 1; 85 Capabilities->DeviceCaps.Address = (ULONG) -1; 86 Capabilities->DeviceCaps.UINumber = (ULONG) -1; 87 88 // 89 // Initialize the Irp. 90 // 91 irp.SetStatus(STATUS_NOT_SUPPORTED); 92 93 irp.ClearNextStack(); 94 irp.SetMajorFunction(IRP_MJ_PNP); 95 irp.SetMinorFunction(IRP_MN_QUERY_CAPABILITIES); 96 irp.SetParameterDeviceCapabilities(&Capabilities->DeviceCaps); 97 98 status = irp.SendIrpSynchronously(DeviceInStack->GetObject()); 99 100 if (!NT_SUCCESS(status)) { 101 DoTraceLevelMessage( 102 DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 103 "Failed to get DEVICE_CAPABILITIES from !devobj %p, %!STATUS!", 104 DeviceInStack->GetObject(), status); 105 goto Done; 106 } 107 108 // 109 // Invoke the D3cold support interface. If present, it will tell 110 // us specifically which D-states will work for generating wake signals 111 // from specific S-states. 112 // 113 // Earlier versions of WDF didn't make this query, so for compatibility, 114 // we only make it now if the driver was built against WDF 1.11 or 115 // later. In truth, this just shifts the failure from initialization 116 // time to run time, because the information that we're presumably 117 // getting from the BIOS with this interrogation is saying that the 118 // code in earlier verisions of WDF would have blindly enabled a device 119 // for wake which simply wasn't capable of generating its wake signal 120 // from the chosen D-state. Thus the device would have been put into 121 // a low power state and then failed to resume in response to its wake 122 // signal. 123 // 124 125 for (i = 0; i <= PowerSystemHibernate; i++) { 126 Capabilities->DeepestWakeableDstate[i] = DeviceWakeDepthMaximum; 127 } 128 129 if (ARGUMENT_PRESENT(D3ColdInterface) && 130 (D3ColdInterface->GetIdleWakeInfo != NULL) && 131 DriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { 132 133 DEVICE_WAKE_DEPTH deepestWakeableDstate; 134 135 for (i = PowerSystemWorking; i <= PowerSystemHibernate; i++) { 136 137 // 138 // Failure from D3ColdInterface->GetIdleWakeInfo just means that 139 // the bus drivers didn't have any information beyond what can 140 // gleaned from the older Query-Capabilities code path. 141 // 142 // In specific ACPI terms, ACPI will respond to this function with 143 // success whenever there is an _SxW object (where x is the sleep 144 // state, a value from 0 to 4.) 145 // 146 // PCI will respond to this interface if ACPI doesn't override its 147 // answer and if a parent bus is capable of leaving D0 in S0, and 148 // if the PCI device has 149 status = D3ColdInterface->GetIdleWakeInfo( 150 D3ColdInterface->Context, 151 (SYSTEM_POWER_STATE)i, 152 &deepestWakeableDstate 153 ); 154 155 if (NT_SUCCESS(status)) { 156 Capabilities->DeepestWakeableDstate[i] = deepestWakeableDstate; 157 } 158 } 159 } 160 161 status = STATUS_SUCCESS; 162 163 Done: 164 if (DeviceInStack->GetObject() != NULL) { 165 DeviceInStack->DereferenceObject(); 166 } 167 168 return status; 169 } 170 171 VOID 172 SetD3ColdSupport( 173 __in PFX_DRIVER_GLOBALS DriverGlobals, 174 __in MxDeviceObject* DeviceInStack, 175 __in PD3COLD_SUPPORT_INTERFACE D3ColdInterface, 176 __in BOOLEAN UseD3Cold 177 ) 178 { 179 UNREFERENCED_PARAMETER(DriverGlobals); 180 UNREFERENCED_PARAMETER(DeviceInStack); 181 182 if (D3ColdInterface->SetD3ColdSupport != NULL) { 183 D3ColdInterface->SetD3ColdSupport(D3ColdInterface->Context, UseD3Cold); 184 } 185 } 186 187 _Must_inspect_result_ 188 PVOID 189 GetIoMgrObjectForWorkItemAllocation( 190 VOID 191 ) 192 /*++ 193 Routine description: 194 Returns an IO manager object that can be passed in to IoAllocateWorkItem 195 196 Arguments: 197 None 198 199 Return value: 200 Pointer to the object that can be passed in to IoAllocateWorkItem 201 --*/ 202 { 203 // return (PVOID) FxLibraryGlobals.DriverObject; 204 // __REACTOS__ : we don't have a WDF driver object here, use a child one 205 206 PFX_DRIVER_GLOBALS fxDriverGlobals = GetFxDriverGlobals(WdfDriverGlobals); 207 return fxDriverGlobals->Driver->GetDriverObject(); 208 } 209 210 BOOLEAN 211 IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable( 212 VOID 213 ) 214 { 215 return (NULL != FxLibraryGlobals.PoxRegisterDevice); 216 } 217 218 _Must_inspect_result_ 219 NTSTATUS 220 SendDeviceUsageNotification( 221 __in MxDeviceObject* RelatedDevice, 222 __inout FxIrp* RelatedIrp, 223 __in MxWorkItem* Workitem, 224 __in FxIrp* OriginalIrp, 225 __in BOOLEAN Revert 226 ) 227 { 228 NTSTATUS status; 229 230 // 231 // use workitem if available 232 // 233 if (Workitem->GetWorkItem() != NULL) { 234 FxUsageWorkitemParameters param; 235 236 param.RelatedDevice = RelatedDevice; 237 param.RelatedIrp = RelatedIrp; 238 param.OriginalIrp = OriginalIrp; 239 param.Revert = Revert; 240 241 // 242 // Kick off to another thread 243 // 244 Workitem->Enqueue(_DeviceUsageNotificationWorkItem, ¶m); 245 246 // 247 // wait for the workitem to finish 248 // 249 param.Event.EnterCRAndWaitAndLeave(); 250 251 status = param.Status; 252 } 253 else { 254 status = SendDeviceUsageNotificationWorker(RelatedDevice, 255 RelatedIrp, 256 OriginalIrp, 257 Revert); 258 } 259 260 return status; 261 } 262 263 NTSTATUS 264 SendDeviceUsageNotificationWorker( 265 __in MxDeviceObject* RelatedDevice, 266 __inout FxIrp* RelatedIrp, 267 __in FxIrp* OriginalIrp, 268 __in BOOLEAN Revert 269 ) 270 { 271 MxDeviceObject relatedTopOfStack; 272 NTSTATUS status; 273 274 relatedTopOfStack.SetObject(RelatedDevice->GetAttachedDeviceReference()); 275 ASSERT(relatedTopOfStack.GetObject() != NULL); 276 277 // 278 // Initialize the new IRP with the stack data from the current IRP and 279 // and send it to the parent stack. 280 // 281 RelatedIrp->InitNextStackUsingStack(OriginalIrp); 282 283 if (Revert) { 284 RelatedIrp->SetParameterUsageNotificationInPath( 285 !RelatedIrp->GetNextStackParameterUsageNotificationInPath()); 286 } 287 288 RelatedIrp->SetStatus(STATUS_NOT_SUPPORTED); 289 290 status = RelatedIrp->SendIrpSynchronously(relatedTopOfStack.GetObject()); 291 292 relatedTopOfStack.DereferenceObject(); 293 294 return status; 295 } 296 297 VOID 298 STDCALL 299 _DeviceUsageNotificationWorkItem( 300 __in MdDeviceObject DeviceObject, 301 __in PVOID Context 302 ) 303 { 304 FxUsageWorkitemParameters* param; 305 NTSTATUS status; 306 307 UNREFERENCED_PARAMETER(DeviceObject); 308 309 param = (FxUsageWorkitemParameters*) Context; 310 311 status = SendDeviceUsageNotificationWorker(param->RelatedDevice, 312 param->RelatedIrp, 313 param->OriginalIrp, 314 param->Revert); 315 316 // 317 // capture status in notification object 318 // 319 param->Status = status; 320 321 // 322 // set event to allow the origial notifcation thread to proceed 323 // 324 param->Event.Set(); 325 } 326 327