1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxTimerApi.cpp
8 
9 Abstract:
10 
11     This implements the WDFTIMER API's
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19     Both kernel and user mode
20 
21 Revision History:
22 
23 
24 --*/
25 
26 #include "coreprivshared.hpp"
27 
28 #include "fxtimer.hpp"
29 
30 extern "C" {
31 // #include "FxTimerApi.tmh"
32 }
33 
34 //
35 // extern "C" the entire file
36 //
37 extern "C" {
38 
39 _Must_inspect_result_
40 __drv_maxIRQL(DISPATCH_LEVEL)
41 NTSTATUS
42 STDCALL
43 WDFEXPORT(WdfTimerCreate)(
44     __in
45     PWDF_DRIVER_GLOBALS DriverGlobals,
46     __in
47     PWDF_TIMER_CONFIG Config,
48     __in
49     PWDF_OBJECT_ATTRIBUTES Attributes,
50     __out
51     WDFTIMER * Timer
52     )
53 
54 /*++
55 
56 Routine Description:
57 
58     Create a TIMER object that will call the supplied function
59     when it fires. It returns a handle to the WDFTIMER object.
60 
61 Arguments:
62 
63     Config     - WDF_TIMER_CONFIG structure.
64 
65     Attributes - WDF_OBJECT_ATTRIBUTES to set the parent object, to request
66                  a context memory allocation and a DestroyCallback.
67 
68     Timer - Pointer to location to return the resulting WDFTIMER handle.
69 
70 Returns:
71 
72     STATUS_SUCCESS - A WDFTIMER handle has been created.
73 
74 Notes:
75 
76     The WDFTIMER object is deleted either when the DEVICE or QUEUE it is
77     associated with is deleted, or WdfObjectDelete is called.
78 
79 --*/
80 
81 {
82     DDI_ENTRY();
83 
84     PFX_DRIVER_GLOBALS pFxDriverGlobals;
85     FxObject* pParent;
86     NTSTATUS status;
87 
88     pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
89 
90     status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
91                                                        Attributes,
92                                                        FX_VALIDATE_OPTION_PARENT_REQUIRED);
93     if (!NT_SUCCESS(status)) {
94         return status;
95     }
96 
97     FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
98                                    Attributes->ParentObject,
99                                    FX_TYPE_OBJECT,
100                                    (PVOID*)&pParent,
101                                    &pFxDriverGlobals);
102 
103     FxPointerNotNull(pFxDriverGlobals, Config);
104     FxPointerNotNull(pFxDriverGlobals, Timer);
105 
106     if (Config->Size != sizeof(WDF_TIMER_CONFIG) &&
107         Config->Size != sizeof(WDF_TIMER_CONFIG_V1_7) &&
108         Config->Size != sizeof(WDF_TIMER_CONFIG_V1_11)) {
109         status = STATUS_INFO_LENGTH_MISMATCH;
110 
111         DoTraceLevelMessage(
112             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
113             "PWDF_TIMER_CONFIG Size %d, expected %d, %!STATUS!",
114             Config->Size, sizeof(WDF_TIMER_CONFIG), status);
115 
116         return status;
117     }
118 
119     if (Config->Period > MAXLONG) {
120         status = STATUS_INVALID_PARAMETER;
121 
122         DoTraceLevelMessage(
123             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
124             "Period value %u for a periodic timer cannot be greater than "
125             "MAXLONG, %!STATUS!", Config->Period, status);
126 
127         return status;
128     }
129 
130     //
131     // For version 1.13 and higher, the tolerable delay could
132     // go upto MAXULONG
133     //
134     if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_7) &&
135         (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13) == FALSE)) {
136         if (Config->TolerableDelay > MAXLONG) {
137 
138             status = STATUS_INVALID_PARAMETER;
139 
140             DoTraceLevelMessage(
141                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
142                 "TolerableDelay value %u cannot be greater than MAXLONG, "
143                 "%!STATUS!", Config->TolerableDelay, status);
144 
145             return status;
146         }
147     }
148 
149     if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_11)) {
150 
151 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
152         if (Config->UseHighResolutionTimer) {
153 
154             status = STATUS_NOT_IMPLEMENTED;
155             DoTraceLevelMessage(
156                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
157                 "UseHighResolutionTimer option is not supported for UMDF "
158                 "%!STATUS!", status);
159             return status;
160         }
161 #endif
162 
163         if ((Config->TolerableDelay > 0) &&
164             (Config->UseHighResolutionTimer)) {
165 
166             status = STATUS_INVALID_PARAMETER;
167 
168             DoTraceLevelMessage(
169                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
170                 "UseHighResolutionTimer option sepcified with non zero tolerable delay %u "
171                 "%!STATUS!", Config->TolerableDelay, status);
172 
173             return status;
174         }
175     }
176 
177     status = FxValidateObjectAttributes(pFxDriverGlobals,
178                                 Attributes,
179                                 FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED);
180     if (!NT_SUCCESS(status)) {
181         return status;
182     }
183 
184     if (Config->Period  > 0 &&
185         Attributes->ExecutionLevel == WdfExecutionLevelPassive) {
186         status = STATUS_NOT_SUPPORTED;
187 
188         DoTraceLevelMessage(
189             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
190             "Passive level periodic timer is not supported. "
191             "Use one shot timer and queue the next timer from the callback "
192             "or use a dedicated thread, %!STATUS!",
193             status);
194 
195         return status;
196     }
197 
198     return FxTimer::_Create(pFxDriverGlobals, Config, Attributes, pParent, Timer);
199 }
200 
201 __drv_maxIRQL(DISPATCH_LEVEL)
202 BOOLEAN
203 STDCALL
204 WDFEXPORT(WdfTimerStart)(
205     __in
206     PWDF_DRIVER_GLOBALS DriverGlobals,
207     __in
208     WDFTIMER Timer,
209     __in
210     LONGLONG DueTime
211     )
212 
213 /*++
214 
215 Routine Description:
216 
217     Enqueue the TIMER to run at the specified time.
218 
219 Arguments:
220 
221     WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate.
222 
223     DueTime - Time to execute
224 
225 Returns:
226 
227     TRUE if the timer object was in the system's timer queue
228 
229 --*/
230 
231 {
232     DDI_ENTRY();
233 
234     FxTimer* pFxTimer;
235     LARGE_INTEGER li;
236 
237     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
238                          Timer,
239                          FX_TYPE_TIMER,
240                          (PVOID*)&pFxTimer);
241 
242     li.QuadPart = DueTime;
243 
244     return pFxTimer->Start(li);
245 }
246 
247 __drv_when(Wait == __true, __drv_maxIRQL(PASSIVE_LEVEL))
248 __drv_when(Wait == __false, __drv_maxIRQL(DISPATCH_LEVEL))
249 BOOLEAN
250 STDCALL
251 WDFEXPORT(WdfTimerStop)(
252     __in
253     PWDF_DRIVER_GLOBALS DriverGlobals,
254     __in
255     WDFTIMER Timer,
256     __in
257     BOOLEAN  Wait
258     )
259 
260 /*++
261 
262 Routine Description:
263 
264     Stop the TIMER
265 
266 Arguments:
267 
268     WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate.
269 
270 Returns:
271 
272     TRUE if the timer object was in the system's timer queue
273 
274 --*/
275 
276 {
277     DDI_ENTRY();
278 
279     PFX_DRIVER_GLOBALS pFxDriverGlobals;
280     FxTimer* pFxTimer;
281     NTSTATUS status;
282 
283     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
284                                    Timer,
285                                    FX_TYPE_TIMER,
286                                    (PVOID*)&pFxTimer,
287                                    &pFxDriverGlobals);
288 
289     if (Wait) {
290         status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
291         if (!NT_SUCCESS(status)) {
292             return FALSE;
293         }
294     }
295 
296     return pFxTimer->Stop(Wait);
297 }
298 
299 __drv_maxIRQL(DISPATCH_LEVEL)
300 WDFOBJECT
301 STDCALL
302 WDFEXPORT(WdfTimerGetParentObject)(
303     __in
304     PWDF_DRIVER_GLOBALS DriverGlobals,
305     __in
306     WDFTIMER Timer
307     )
308 
309 /*++
310 
311 Routine Description:
312 
313     Return the Parent Object handle supplied to WdfTimerCreate
314 
315 Arguments:
316 
317     WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate.
318 
319 Returns:
320 
321     Handle to the framework object that is the specified timer object's
322     parent object
323 
324 --*/
325 
326 {
327     DDI_ENTRY();
328 
329     FxTimer* pFxTimer;
330 
331     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
332                          Timer,
333                          FX_TYPE_TIMER,
334                          (PVOID*)&pFxTimer);
335 
336     return pFxTimer->GetObject();
337 }
338 
339 } // extern "C"
340