2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
5 * PURPOSE: Time related routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
9 * CSH 01/08-2000 Created
10 * Vizzini 08-Oct-2003 Formatting, commenting, and ASSERTs
13 * - Although the standard kernel-mode M.O. is to trust the caller
14 * to not provide bad arguments, we have added lots of argument
15 * validation to assist in the effort to get third-party binaries
16 * working. It is easiest to track bugs when things break quickly
30 OUT PBOOLEAN TimerCancelled
)
32 * FUNCTION: Cancels a scheduled NDIS timer
34 * Timer: pointer to an NDIS_TIMER object to cancel
35 * TimerCancelled: boolean that returns cancellation status
37 * - call at IRQL <= DISPATCH_LEVEL
40 ASSERT_IRQL(DISPATCH_LEVEL
);
43 *TimerCancelled
= KeCancelTimer (&Timer
->Timer
);
50 #undef NdisGetCurrentSystemTime
53 NdisGetCurrentSystemTime (
54 IN OUT PLARGE_INTEGER pSystemTime
)
56 * FUNCTION: Retrieve the current system time
58 * pSystemTime: pointer to the returned system time
60 * - call at IRQL <= DISPATCH_LEVEL
63 ASSERT_IRQL(DISPATCH_LEVEL
);
66 KeQuerySystemTime (pSystemTime
);
76 IN OUT PNDIS_TIMER Timer
,
77 IN PNDIS_TIMER_FUNCTION TimerFunction
,
78 IN PVOID FunctionContext
)
80 * FUNCTION: Set up an NDIS_TIMER for later use
82 * Timer: pointer to caller-allocated storage to receive an NDIS_TIMER
83 * TimerFunction: function pointer to routine to run when timer expires
84 * FunctionContext: context (param 2) to be passed to the timer function when it runs
86 * - TimerFunction will be called at DISPATCH_LEVEL
87 * - call at IRQL = PASSIVE_LEVEL
93 KeInitializeTimer (&Timer
->Timer
);
95 KeInitializeDpc (&Timer
->Dpc
, (PKDEFERRED_ROUTINE
)TimerFunction
, FunctionContext
);
98 BOOLEAN
DequeueMiniportTimer(PNDIS_MINIPORT_TIMER Timer
)
100 PNDIS_MINIPORT_TIMER CurrentTimer
;
102 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
104 if (!Timer
->Miniport
->TimerQueue
)
107 if (Timer
->Miniport
->TimerQueue
== Timer
)
109 Timer
->Miniport
->TimerQueue
= Timer
->NextDeferredTimer
;
110 Timer
->NextDeferredTimer
= NULL
;
115 CurrentTimer
= Timer
->Miniport
->TimerQueue
;
116 while (CurrentTimer
->NextDeferredTimer
)
118 if (CurrentTimer
->NextDeferredTimer
== Timer
)
120 CurrentTimer
->NextDeferredTimer
= Timer
->NextDeferredTimer
;
121 Timer
->NextDeferredTimer
= NULL
;
124 CurrentTimer
= CurrentTimer
->NextDeferredTimer
;
137 IN PNDIS_MINIPORT_TIMER Timer
,
138 OUT PBOOLEAN TimerCancelled
)
140 * FUNCTION: cancel a scheduled NDIS_MINIPORT_TIMER
142 * Timer: timer object to cancel
143 * TimerCancelled: status of cancel operation
145 * - call at IRQL <= DISPATCH_LEVEL
150 ASSERT_IRQL(DISPATCH_LEVEL
);
151 ASSERT(TimerCancelled
);
154 *TimerCancelled
= KeCancelTimer (&Timer
->Timer
);
158 KeAcquireSpinLock(&Timer
->Miniport
->Lock
, &OldIrql
);
159 /* If it's somebody already dequeued it, something is wrong (maybe a double-cancel?) */
160 if (!DequeueMiniportTimer(Timer
)) ASSERT(FALSE
);
161 KeReleaseSpinLock(&Timer
->Miniport
->Lock
, OldIrql
);
166 MiniTimerDpcFunction(PKDPC Dpc
,
167 PVOID DeferredContext
,
168 PVOID SystemArgument1
,
169 PVOID SystemArgument2
)
171 PNDIS_MINIPORT_TIMER Timer
= DeferredContext
;
173 /* Only dequeue if the timer has a period of 0 */
174 if (!Timer
->Timer
.Period
)
176 KeAcquireSpinLockAtDpcLevel(&Timer
->Miniport
->Lock
);
177 /* If someone already dequeued it, something is wrong (borked timer implementation?) */
178 if (!DequeueMiniportTimer(Timer
)) ASSERT(FALSE
);
179 KeReleaseSpinLockFromDpcLevel(&Timer
->Miniport
->Lock
);
182 Timer
->MiniportTimerFunction(Dpc
,
183 Timer
->MiniportTimerContext
,
194 NdisMInitializeTimer(
195 IN OUT PNDIS_MINIPORT_TIMER Timer
,
196 IN NDIS_HANDLE MiniportAdapterHandle
,
197 IN PNDIS_TIMER_FUNCTION TimerFunction
,
198 IN PVOID FunctionContext
)
200 * FUNCTION: Initialize an NDIS_MINIPORT_TIMER
202 * Timer: Timer object to initialize
203 * MiniportAdapterHandle: Handle to the miniport, passed in to MiniportInitialize
204 * TimerFunction: function to be executed when the timer expires
205 * FunctionContext: argument passed to TimerFunction when it is called
207 * - TimerFunction is called at IRQL = DISPATCH_LEVEL
208 * - call at IRQL = PASSIVE_LEVEL
214 KeInitializeTimer (&Timer
->Timer
);
215 KeInitializeDpc (&Timer
->Dpc
, MiniTimerDpcFunction
, Timer
);
217 Timer
->MiniportTimerFunction
= TimerFunction
;
218 Timer
->MiniportTimerContext
= FunctionContext
;
219 Timer
->Miniport
= &((PLOGICAL_ADAPTER
)MiniportAdapterHandle
)->NdisMiniportBlock
;
220 Timer
->NextDeferredTimer
= NULL
;
229 NdisMSetPeriodicTimer(
230 IN PNDIS_MINIPORT_TIMER Timer
,
231 IN UINT MillisecondsPeriod
)
233 * FUNCTION: Set a timer to go off periodically
235 * Timer: pointer to the timer object to set
236 * MillisecondsPeriod: period of the timer
238 * - Minimum predictible interval is ~10ms
239 * - Must be called at IRQL <= DISPATCH_LEVEL
242 LARGE_INTEGER Timeout
;
245 ASSERT_IRQL(DISPATCH_LEVEL
);
248 /* relative delays are negative, absolute are positive; resolution is 100ns */
249 Timeout
.QuadPart
= Int32x32To64(MillisecondsPeriod
, -10000);
251 KeAcquireSpinLock(&Timer
->Miniport
->Lock
, &OldIrql
);
252 /* If KeSetTimer(Ex) returns FALSE then the timer is not in the system's queue (and not in ours either) */
253 if (!KeSetTimerEx(&Timer
->Timer
, Timeout
, MillisecondsPeriod
, &Timer
->Dpc
))
255 /* Add the timer at the head of the timer queue */
256 Timer
->NextDeferredTimer
= Timer
->Miniport
->TimerQueue
;
257 Timer
->Miniport
->TimerQueue
= Timer
;
259 KeReleaseSpinLock(&Timer
->Miniport
->Lock
, OldIrql
);
270 IN PNDIS_MINIPORT_TIMER Timer
,
271 IN UINT MillisecondsToDelay
)
273 * FUNCTION: Set a NDIS_MINIPORT_TIMER so that it goes off
275 * Timer: timer object to set
276 * MillisecondsToDelay: time to wait for the timer to expire
278 * - Minimum predictible interval is ~10ms
279 * - Must be called at IRQL <= DISPATCH_LEVEL
282 LARGE_INTEGER Timeout
;
285 ASSERT_IRQL(DISPATCH_LEVEL
);
288 /* relative delays are negative, absolute are positive; resolution is 100ns */
289 Timeout
.QuadPart
= Int32x32To64(MillisecondsToDelay
, -10000);
291 KeAcquireSpinLock(&Timer
->Miniport
->Lock
, &OldIrql
);
292 /* If KeSetTimer(Ex) returns FALSE then the timer is not in the system's queue (and not in ours either) */
293 if (!KeSetTimer(&Timer
->Timer
, Timeout
, &Timer
->Dpc
))
295 /* Add the timer at the head of the timer queue */
296 Timer
->NextDeferredTimer
= Timer
->Miniport
->TimerQueue
;
297 Timer
->Miniport
->TimerQueue
= Timer
;
299 KeReleaseSpinLock(&Timer
->Miniport
->Lock
, OldIrql
);
309 IN PNDIS_TIMER Timer
,
310 IN UINT MillisecondsToDelay
)
312 * FUNCTION: Set an NDIS_TIMER so that it goes off
314 * Timer: timer object to set
315 * MillisecondsToDelay: time to wait for the timer to expire
317 * - Minimum predictible interval is ~10ms
318 * - Must be called at IRQL <= DISPATCH_LEVEL
321 LARGE_INTEGER Timeout
;
323 ASSERT_IRQL(DISPATCH_LEVEL
);
326 NDIS_DbgPrint(MAX_TRACE
, ("Called. Timer is: 0x%x, Timeout is: %ld\n", Timer
, MillisecondsToDelay
));
328 /* relative delays are negative, absolute are positive; resolution is 100ns */
329 Timeout
.QuadPart
= Int32x32To64(MillisecondsToDelay
, -10000);
331 KeSetTimer (&Timer
->Timer
, Timeout
, &Timer
->Dpc
);
340 IN PNDIS_TIMER Timer
,
341 IN UINT MillisecondsToDelay
,
342 IN PVOID FunctionContext
)
344 NDIS_DbgPrint(MAX_TRACE
, ("Called. Timer is: 0x%x, Timeout is: %ld, FunctionContext is: 0x%x\n",
345 Timer
, MillisecondsToDelay
, FunctionContext
));
347 Timer
->Dpc
.DeferredContext
= FunctionContext
;
349 NdisSetTimer(Timer
, MillisecondsToDelay
);