1 //
2 //    Copyright (C) Microsoft.  All rights reserved.
3 //
4 #include "pnppriv.hpp"
5 
6 #include <initguid.h>
7 #include <wdmguid.h>
8 
9 extern "C" {
10 #if defined(EVENT_TRACING)
11 #include "PoxInterfaceKm.tmh"
12 #endif
13 }
14 
15 VOID
16 FxPoxInterface::StateCallback(
17     __in PVOID Context,
18     __in ULONG Component,
19     __in ULONG State
20     )
21 {
22     PPOX_SETTINGS poxSettings = NULL;
23     FxPoxInterface * pThis = NULL;
24 
25     pThis = (FxPoxInterface*) Context;
26 
27     DoTraceLevelMessage(
28         pThis->m_PkgPnp->GetDriverGlobals(),
29         TRACE_LEVEL_VERBOSE,
30         TRACINGPNP,
31         "WDFDEVICE 0x%p !devobj 0x%p PO_FX_COMPONENT_IDLE_STATE_CALLBACK "
32         "invoked.",
33         pThis->m_PkgPnp->GetDevice()->GetHandle(),
34         pThis->m_PkgPnp->GetDevice()->GetDeviceObject()
35         );
36 
37     //
38     // If the client driver has specified power framework settings, retrieve
39     // them.
40     //
41     poxSettings = pThis->GetPowerFrameworkSettings();
42 
43     //
44     // If the client driver has specified an F-state change callback, invoke it.
45     //
46     if ((NULL != poxSettings) &&
47         (NULL != poxSettings->ComponentIdleStateCallback)) {
48 
49         DoTraceLevelMessage(
50             pThis->m_PkgPnp->GetDriverGlobals(),
51             TRACE_LEVEL_VERBOSE,
52             TRACINGPNP,
53             "WDFDEVICE 0x%p !devobj 0x%p Invoking client driver's "
54             "PO_FX_COMPONENT_IDLE_STATE_CALLBACK.",
55             pThis->m_PkgPnp->GetDevice()->GetHandle(),
56             pThis->m_PkgPnp->GetDevice()->GetDeviceObject()
57             );
58 
59         poxSettings->ComponentIdleStateCallback(
60                        poxSettings->PoFxDeviceContext,
61                        Component,
62                        State);
63     } else {
64         PoFxCompleteIdleState(pThis->m_PoHandle, Component);
65     }
66 }
67 
68 VOID
69 FxPoxInterface::ComponentActiveCallback(
70     __in PVOID Context,
71     __in ULONG Component
72     )
73 {
74     PPOX_SETTINGS poxSettings = NULL;
75     FxPoxInterface * pThis = NULL;
76 
77     pThis = (FxPoxInterface*) Context;
78 
79     DoTraceLevelMessage(
80         pThis->m_PkgPnp->GetDriverGlobals(),
81         TRACE_LEVEL_VERBOSE,
82         TRACINGPNP,
83         "WDFDEVICE 0x%p !devobj 0x%p PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK "
84         "invoked.",
85         pThis->m_PkgPnp->GetDevice()->GetHandle(),
86         pThis->m_PkgPnp->GetDevice()->GetDeviceObject()
87         );
88 
89     //
90     // If the client driver has specified power framework settings, retrieve
91     // them.
92     //
93     poxSettings = pThis->GetPowerFrameworkSettings();
94 
95     //
96     // If the client driver has specified a component-active callback, invoke it
97     //
98     if ((NULL != poxSettings) &&
99         (NULL != poxSettings->ComponentActiveConditionCallback)) {
100 
101         DoTraceLevelMessage(
102             pThis->m_PkgPnp->GetDriverGlobals(),
103             TRACE_LEVEL_VERBOSE,
104             TRACINGPNP,
105             "WDFDEVICE 0x%p !devobj 0x%p Invoking client driver's "
106             "PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK.",
107             pThis->m_PkgPnp->GetDevice()->GetHandle(),
108             pThis->m_PkgPnp->GetDevice()->GetDeviceObject()
109             );
110 
111         poxSettings->ComponentActiveConditionCallback(
112                            poxSettings->PoFxDeviceContext,
113                            Component
114                            );
115     } else {
116         //
117         // Nothing to do.
118         //
119         DO_NOTHING();
120     }
121 
122     return;
123 }
124 
125 VOID
126 FxPoxInterface::ComponentIdleCallback(
127     __in PVOID Context,
128     __in ULONG Component
129     )
130 {
131     PPOX_SETTINGS poxSettings = NULL;
132     FxPoxInterface * pThis = NULL;
133 
134     pThis = (FxPoxInterface*) Context;
135 
136     DoTraceLevelMessage(
137         pThis->m_PkgPnp->GetDriverGlobals(),
138         TRACE_LEVEL_VERBOSE,
139         TRACINGPNP,
140         "WDFDEVICE 0x%p !devobj 0x%p PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK "
141         "invoked.",
142         pThis->m_PkgPnp->GetDevice()->GetHandle(),
143         pThis->m_PkgPnp->GetDevice()->GetDeviceObject()
144         );
145 
146     //
147     // If the client driver has specified power framework settings, retrieve
148     // them.
149     //
150     poxSettings = pThis->GetPowerFrameworkSettings();
151 
152     //
153     // If the client driver has specified a component-idle callback, invoke it
154     //
155     if ((NULL != poxSettings) &&
156         (NULL != poxSettings->ComponentIdleConditionCallback)) {
157 
158         DoTraceLevelMessage(
159             pThis->m_PkgPnp->GetDriverGlobals(),
160             TRACE_LEVEL_VERBOSE,
161             TRACINGPNP,
162             "WDFDEVICE 0x%p !devobj 0x%p Invoking client driver's "
163             "PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK.",
164             pThis->m_PkgPnp->GetDevice()->GetHandle(),
165             pThis->m_PkgPnp->GetDevice()->GetDeviceObject()
166             );
167 
168         poxSettings->ComponentIdleConditionCallback(
169                            poxSettings->PoFxDeviceContext,
170                            Component
171                            );
172     } else {
173         //
174         // We're being notified that we're idle, but there is no action that we
175         // need to take here. We power down the device only when we get the
176         // device-power-not-required event.
177         //
178         PoFxCompleteIdleCondition(pThis->m_PoHandle, Component);
179     }
180     return;
181 }
182 
183 VOID
184 FxPoxInterface::PowerRequiredCallback(
185     __in PVOID Context
186     )
187 {
188     FxPoxInterface * pThis = NULL;
189 
190     pThis = (FxPoxInterface*) Context;
191     pThis->PowerRequiredCallbackWorker(TRUE /* InvokedFromPoxCallback */);
192     return;
193 }
194 
195 VOID
196 FxPoxInterface::PowerNotRequiredCallback(
197     __in PVOID Context
198     )
199 {
200     FxPoxInterface * pThis = NULL;
201 
202     pThis = (FxPoxInterface*) Context;
203     pThis->PowerNotRequiredCallbackWorker(TRUE /* InvokedFromPoxCallback */);
204     PoFxCompleteDevicePowerNotRequired(pThis->m_PoHandle);
205     return;
206 }
207 
208 _Function_class_(PO_FX_POWER_CONTROL_CALLBACK)
209 _IRQL_requires_max_(DISPATCH_LEVEL)
210 NTSTATUS
211 FxPoxInterface::PowerControlCallback(
212     _In_ PVOID Context,
213     _In_ LPCGUID PowerControlCode,
214     _In_reads_bytes_opt_(InBufferSize) PVOID InBuffer,
215     _In_ SIZE_T InBufferSize,
216     _Out_writes_bytes_opt_(OutBufferSize) PVOID OutBuffer,
217     _In_ SIZE_T OutBufferSize,
218     _Out_opt_ PSIZE_T BytesReturned
219     )
220 {
221     NTSTATUS status;
222     PPOX_SETTINGS poxSettings = NULL;
223     FxPoxInterface * pThis = NULL;
224 
225     pThis = (FxPoxInterface*) Context;
226 
227     DoTraceLevelMessage(
228         pThis->m_PkgPnp->GetDriverGlobals(),
229         TRACE_LEVEL_VERBOSE,
230         TRACINGPNP,
231         "WDFDEVICE 0x%p !devobj 0x%p PO_FX_POWER_CONTROL_CALLBACK invoked.",
232         pThis->m_PkgPnp->GetDevice()->GetHandle(),
233         pThis->m_PkgPnp->GetDevice()->GetDeviceObject()
234         );
235 
236     //
237     // If the client driver has specified power framework settings, retrieve
238     // them.
239     //
240     poxSettings = pThis->GetPowerFrameworkSettings();
241 
242     //
243     // The client driver must have specified a power control callback
244     //
245     ASSERT((NULL != poxSettings) &&
246            (NULL != poxSettings->PowerControlCallback));
247 
248     //
249     // Invoke the client driver's power control callback
250     //
251     status = poxSettings->PowerControlCallback(poxSettings->PoFxDeviceContext,
252                                                PowerControlCode,
253                                                InBuffer,
254                                                InBufferSize,
255                                                OutBuffer,
256                                                OutBufferSize,
257                                                BytesReturned);
258 
259     DoTraceLevelMessage(
260         pThis->m_PkgPnp->GetDriverGlobals(),
261         TRACE_LEVEL_VERBOSE,
262         TRACINGPNP,
263         "WDFDEVICE 0x%p !devobj 0x%p Client driver's "
264         "PO_FX_POWER_CONTROL_CALLBACK returned %!STATUS!.",
265         pThis->m_PkgPnp->GetDevice()->GetHandle(),
266         pThis->m_PkgPnp->GetDevice()->GetDeviceObject(),
267         status
268         );
269 
270     return status;
271 }
272 
273 NTSTATUS
274 FxPoxInterface::PoxRegisterDevice(
275     VOID
276     )
277 {
278 
279     NTSTATUS status;
280     PO_FX_DEVICE poxDevice;
281     PO_FX_COMPONENT_IDLE_STATE idleState;
282     PPOX_SETTINGS poxSettings = NULL;
283 
284     RtlZeroMemory(&poxDevice, sizeof(poxDevice));
285     RtlZeroMemory(&idleState, sizeof(idleState));
286 
287     poxDevice.Version = PO_FX_VERSION_V1;
288 
289     //
290     // Specify callbacks and context
291     //
292     poxDevice.ComponentIdleStateCallback =
293                     FxPoxInterface::StateCallback;
294     poxDevice.ComponentActiveConditionCallback =
295                     FxPoxInterface::ComponentActiveCallback;
296     poxDevice.ComponentIdleConditionCallback =
297                     FxPoxInterface::ComponentIdleCallback;
298     poxDevice.DevicePowerRequiredCallback =
299                     FxPoxInterface::PowerRequiredCallback;
300     poxDevice.DevicePowerNotRequiredCallback =
301                     FxPoxInterface::PowerNotRequiredCallback;
302     poxDevice.DeviceContext = this;
303 
304     //
305     // We register as a single component device
306     //
307     poxDevice.ComponentCount = 1;
308 
309     //
310     // If the client driver has specified power framework settings, retrieve
311     // them.
312     //
313     poxSettings = GetPowerFrameworkSettings();
314 
315     //
316     // We specify a power control callback only if the client driver supplies us
317     // a power control callback
318     //
319     poxDevice.PowerControlCallback =
320         ((NULL == poxSettings) || (NULL == poxSettings->PowerControlCallback)) ?
321             NULL :
322             FxPoxInterface::PowerControlCallback;
323 
324     //
325     // If the client driver has specified any settings for component 0, use
326     // them. Otherwise use the default settings.
327     //
328     if ((NULL == poxSettings) || (NULL == poxSettings->Component)) {
329         //
330         // Default settings
331         //
332 
333         //
334         // We only support F0
335         //
336         poxDevice.Components[0].IdleStateCount = 1;
337 
338         //
339         // Transition latency should be 0 for F0
340         //
341         idleState.TransitionLatency = 0;
342 
343         //
344         // Residency requirement should be 0 for F0
345         //
346         idleState.ResidencyRequirement = 0;
347 
348         //
349         // The value doesn't matter because we do not support multiple F-states.
350         //
351         idleState.NominalPower = PO_FX_UNKNOWN_POWER;
352 
353         //
354         // Specify the state information for F0
355         //
356         poxDevice.Components[0].IdleStates = &idleState;
357     }
358     else {
359         //
360         // Client driver's settings
361         //
362         RtlCopyMemory(&(poxDevice.Components[0]),
363                       poxSettings->Component,
364                       sizeof(poxDevice.Components[0]));
365     }
366 
367     //
368     // Register with the power framework
369     //
370     status = PoFxRegisterDevice(
371                 m_PkgPnp->GetDevice()->GetPhysicalDevice(),
372                 &poxDevice,
373                 &(m_PoHandle)
374                 );
375     if (FALSE == NT_SUCCESS(status)) {
376         DoTraceLevelMessage(
377             m_PkgPnp->GetDriverGlobals(),
378             TRACE_LEVEL_ERROR, TRACINGPNP,
379             "WDFDEVICE 0x%p !devobj 0x%p FxPox::PoxRegisterDevice failed. "
380             "%!STATUS!.",
381             m_PkgPnp->GetDevice()->GetHandle(),
382             m_PkgPnp->GetDevice()->GetDeviceObject(),
383             status);
384         goto exit;
385     }
386 
387     status = STATUS_SUCCESS;
388 
389 exit:
390     return status;
391 
392 }
393 
394 VOID
395 FxPoxInterface::PoxStartDevicePowerManagement(
396     VOID
397     )
398 {
399     PoFxStartDevicePowerManagement(m_PoHandle);
400 }
401 
402 
403 VOID
404 FxPoxInterface::PoxUnregisterDevice(
405     VOID
406     )
407 {
408     PoFxUnregisterDevice(m_PoHandle);
409 }
410 
411 
412 VOID
413 FxPoxInterface::PoxActivateComponent(
414     VOID
415     )
416 {
417     //
418     // We only support single component and don't
419     // need to set any flags
420     //
421     PoFxActivateComponent(m_PoHandle,
422                           0, //component
423                           0  //flags
424                           );
425 }
426 
427 
428 VOID
429 FxPoxInterface::PoxIdleComponent(
430     VOID
431     )
432 {
433     //
434     // We only support single component and don't
435     // need to set any flags
436     //
437     PoFxIdleComponent(m_PoHandle,
438                       0, //component
439                       0  //flags
440                       );
441 }
442 
443 
444 VOID
445 FxPoxInterface::PoxReportDevicePoweredOn(
446     VOID
447     )
448 {
449     PoFxReportDevicePoweredOn(m_PoHandle);
450 }
451 
452 
453 VOID
454 FxPoxInterface::PoxSetDeviceIdleTimeout(
455     __in ULONGLONG IdleTimeout
456     )
457 {
458     PoFxSetDeviceIdleTimeout(m_PoHandle, IdleTimeout);
459 }
460 
461