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
);
159 KeAcquireSpinLock(&Timer
->Miniport
->Lock
, &OldIrql
);
160 /* If it's somebody already dequeued it, something is wrong (maybe a double-cancel?) */
161 if (!DequeueMiniportTimer(Timer
)) ASSERT(FALSE
);
162 KeReleaseSpinLock(&Timer
->Miniport
->Lock
, OldIrql
);
168 MiniTimerDpcFunction(PKDPC Dpc
,
169 PVOID DeferredContext
,
170 PVOID SystemArgument1
,
171 PVOID SystemArgument2
)
173 PNDIS_MINIPORT_TIMER Timer
= DeferredContext
;
176 /* Only dequeue if the timer has a period of 0 */
177 if (!Timer
->Timer
.Period
)
179 KeAcquireSpinLockAtDpcLevel(&Timer
->Miniport
->Lock
);
180 /* If someone already dequeued it, something is wrong (borked timer implementation?) */
181 if (!DequeueMiniportTimer(Timer
)) ASSERT(FALSE
);
182 KeReleaseSpinLockFromDpcLevel(&Timer
->Miniport
->Lock
);
186 Timer
->MiniportTimerFunction(Dpc
,
187 Timer
->MiniportTimerContext
,
198 NdisMInitializeTimer(
199 IN OUT PNDIS_MINIPORT_TIMER Timer
,
200 IN NDIS_HANDLE MiniportAdapterHandle
,
201 IN PNDIS_TIMER_FUNCTION TimerFunction
,
202 IN PVOID FunctionContext
)
204 * FUNCTION: Initialize an NDIS_MINIPORT_TIMER
206 * Timer: Timer object to initialize
207 * MiniportAdapterHandle: Handle to the miniport, passed in to MiniportInitialize
208 * TimerFunction: function to be executed when the timer expires
209 * FunctionContext: argument passed to TimerFunction when it is called
211 * - TimerFunction is called at IRQL = DISPATCH_LEVEL
212 * - call at IRQL = PASSIVE_LEVEL
218 KeInitializeTimer (&Timer
->Timer
);
219 KeInitializeDpc (&Timer
->Dpc
, MiniTimerDpcFunction
, Timer
);
221 Timer
->MiniportTimerFunction
= TimerFunction
;
222 Timer
->MiniportTimerContext
= FunctionContext
;
223 Timer
->Miniport
= &((PLOGICAL_ADAPTER
)MiniportAdapterHandle
)->NdisMiniportBlock
;
224 Timer
->NextDeferredTimer
= NULL
;
233 NdisMSetPeriodicTimer(
234 IN PNDIS_MINIPORT_TIMER Timer
,
235 IN UINT MillisecondsPeriod
)
237 * FUNCTION: Set a timer to go off periodically
239 * Timer: pointer to the timer object to set
240 * MillisecondsPeriod: period of the timer
242 * - Minimum predictible interval is ~10ms
243 * - Must be called at IRQL <= DISPATCH_LEVEL
246 LARGE_INTEGER Timeout
;
249 ASSERT_IRQL(DISPATCH_LEVEL
);
252 /* relative delays are negative, absolute are positive; resolution is 100ns */
253 Timeout
.QuadPart
= Int32x32To64(MillisecondsPeriod
, -10000);
256 /* Lock the miniport block */
257 KeAcquireSpinLock(&Timer
->Miniport
->Lock
, &OldIrql
);
259 /* Attempt to dequeue the timer */
260 DequeueMiniportTimer(Timer
);
262 /* Add the timer at the head of the timer queue */
263 Timer
->NextDeferredTimer
= Timer
->Miniport
->TimerQueue
;
264 Timer
->Miniport
->TimerQueue
= Timer
;
266 /* Unlock the miniport block */
267 KeReleaseSpinLock(&Timer
->Miniport
->Lock
, OldIrql
);
270 KeSetTimerEx(&Timer
->Timer
, Timeout
, MillisecondsPeriod
, &Timer
->Dpc
);
281 IN PNDIS_MINIPORT_TIMER Timer
,
282 IN UINT MillisecondsToDelay
)
284 * FUNCTION: Set a NDIS_MINIPORT_TIMER so that it goes off
286 * Timer: timer object to set
287 * MillisecondsToDelay: time to wait for the timer to expire
289 * - Minimum predictible interval is ~10ms
290 * - Must be called at IRQL <= DISPATCH_LEVEL
293 LARGE_INTEGER Timeout
;
296 ASSERT_IRQL(DISPATCH_LEVEL
);
299 /* relative delays are negative, absolute are positive; resolution is 100ns */
300 Timeout
.QuadPart
= Int32x32To64(MillisecondsToDelay
, -10000);
303 /* Lock the miniport block */
304 KeAcquireSpinLock(&Timer
->Miniport
->Lock
, &OldIrql
);
306 /* Attempt to dequeue the timer */
307 DequeueMiniportTimer(Timer
);
309 /* Add the timer at the head of the timer queue */
310 Timer
->NextDeferredTimer
= Timer
->Miniport
->TimerQueue
;
311 Timer
->Miniport
->TimerQueue
= Timer
;
313 /* Unlock the miniport block */
314 KeReleaseSpinLock(&Timer
->Miniport
->Lock
, OldIrql
);
317 KeSetTimer(&Timer
->Timer
, Timeout
, &Timer
->Dpc
);
327 IN PNDIS_TIMER Timer
,
328 IN UINT MillisecondsToDelay
)
330 * FUNCTION: Set an NDIS_TIMER so that it goes off
332 * Timer: timer object to set
333 * MillisecondsToDelay: time to wait for the timer to expire
335 * - Minimum predictible interval is ~10ms
336 * - Must be called at IRQL <= DISPATCH_LEVEL
339 LARGE_INTEGER Timeout
;
341 ASSERT_IRQL(DISPATCH_LEVEL
);
344 NDIS_DbgPrint(MAX_TRACE
, ("Called. Timer is: 0x%x, Timeout is: %ld\n", Timer
, MillisecondsToDelay
));
346 /* relative delays are negative, absolute are positive; resolution is 100ns */
347 Timeout
.QuadPart
= Int32x32To64(MillisecondsToDelay
, -10000);
349 KeSetTimer (&Timer
->Timer
, Timeout
, &Timer
->Dpc
);
358 IN PNDIS_TIMER Timer
,
359 IN UINT MillisecondsToDelay
,
360 IN PVOID FunctionContext
)
362 NDIS_DbgPrint(MAX_TRACE
, ("Called. Timer is: 0x%x, Timeout is: %ld, FunctionContext is: 0x%x\n",
363 Timer
, MillisecondsToDelay
, FunctionContext
));
365 Timer
->Dpc
.DeferredContext
= FunctionContext
;
367 NdisSetTimer(Timer
, MillisecondsToDelay
);