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
CopyQueryInterfaceToIrpStack(__in PPOWER_THREAD_INTERFACE PowerThreadInterface,__in FxIrp * Irp)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
GetStackCapabilities(__in PFX_DRIVER_GLOBALS DriverGlobals,__in MxDeviceObject * DeviceInStack,__in_opt PD3COLD_SUPPORT_INTERFACE D3ColdInterface,__out PSTACK_DEVICE_CAPABILITIES Capabilities)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
SetD3ColdSupport(__in PFX_DRIVER_GLOBALS DriverGlobals,__in MxDeviceObject * DeviceInStack,__in PD3COLD_SUPPORT_INTERFACE D3ColdInterface,__in BOOLEAN UseD3Cold)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
GetIoMgrObjectForWorkItemAllocation(VOID)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
_SystemManagedIdleTimeoutAvailable(VOID)211 IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable(
212 VOID
213 )
214 {
215 return (NULL != FxLibraryGlobals.PoxRegisterDevice);
216 }
217
218 _Must_inspect_result_
219 NTSTATUS
SendDeviceUsageNotification(__in MxDeviceObject * RelatedDevice,__inout FxIrp * RelatedIrp,__in MxWorkItem * Workitem,__in FxIrp * OriginalIrp,__in BOOLEAN Revert)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
SendDeviceUsageNotificationWorker(__in MxDeviceObject * RelatedDevice,__inout FxIrp * RelatedIrp,__in FxIrp * OriginalIrp,__in BOOLEAN Revert)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
_DeviceUsageNotificationWorkItem(__in MdDeviceObject DeviceObject,__in PVOID Context)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