Sync with trunk r64222.
[reactos.git] / drivers / network / ndis / ndis / time.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
4 * FILE: ndis/time.c
5 * PURPOSE: Time related routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * Vizzini 08-Oct-2003 Formatting, commenting, and ASSERTs
11 *
12 * NOTES:
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
17 * and badly.
18 */
19
20 #include "ndissys.h"
21
22 /*
23 * @implemented
24 */
25 VOID
26 EXPORT
27 NdisCancelTimer(
28 IN PNDIS_TIMER Timer,
29 OUT PBOOLEAN TimerCancelled)
30 /*
31 * FUNCTION: Cancels a scheduled NDIS timer
32 * ARGUMENTS:
33 * Timer: pointer to an NDIS_TIMER object to cancel
34 * TimerCancelled: boolean that returns cancellation status
35 * NOTES:
36 * - call at IRQL <= DISPATCH_LEVEL
37 */
38 {
39 ASSERT_IRQL(DISPATCH_LEVEL);
40 ASSERT(Timer);
41
42 *TimerCancelled = KeCancelTimer (&Timer->Timer);
43 }
44
45 /*
46 * @implemented
47 */
48 #undef NdisGetCurrentSystemTime
49 VOID
50 EXPORT
51 NdisGetCurrentSystemTime (
52 IN OUT PLARGE_INTEGER pSystemTime)
53 /*
54 * FUNCTION: Retrieve the current system time
55 * ARGUMENTS:
56 * pSystemTime: pointer to the returned system time
57 * NOTES:
58 * - call at any IRQL
59 */
60 {
61 ASSERT(pSystemTime);
62
63 KeQuerySystemTime (pSystemTime);
64 }
65
66 /*
67 * @implemented
68 */
69 VOID
70 EXPORT
71 NdisInitializeTimer(
72 IN OUT PNDIS_TIMER Timer,
73 IN PNDIS_TIMER_FUNCTION TimerFunction,
74 IN PVOID FunctionContext)
75 /*
76 * FUNCTION: Set up an NDIS_TIMER for later use
77 * ARGUMENTS:
78 * Timer: pointer to caller-allocated storage to receive an NDIS_TIMER
79 * TimerFunction: function pointer to routine to run when timer expires
80 * FunctionContext: context (param 2) to be passed to the timer function when it runs
81 * NOTES:
82 * - TimerFunction will be called at DISPATCH_LEVEL
83 * - call at IRQL = PASSIVE_LEVEL
84 */
85 {
86 PAGED_CODE();
87 ASSERT(Timer);
88
89 KeInitializeTimer (&Timer->Timer);
90
91 KeInitializeDpc (&Timer->Dpc, (PKDEFERRED_ROUTINE)TimerFunction, FunctionContext);
92 }
93
94 BOOLEAN DequeueMiniportTimer(PNDIS_MINIPORT_TIMER Timer)
95 {
96 PNDIS_MINIPORT_TIMER CurrentTimer;
97
98 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
99
100 if (!Timer->Miniport->TimerQueue)
101 return FALSE;
102
103 if (Timer->Miniport->TimerQueue == Timer)
104 {
105 Timer->Miniport->TimerQueue = Timer->NextDeferredTimer;
106 Timer->NextDeferredTimer = NULL;
107 return TRUE;
108 }
109 else
110 {
111 CurrentTimer = Timer->Miniport->TimerQueue;
112 while (CurrentTimer->NextDeferredTimer)
113 {
114 if (CurrentTimer->NextDeferredTimer == Timer)
115 {
116 CurrentTimer->NextDeferredTimer = Timer->NextDeferredTimer;
117 Timer->NextDeferredTimer = NULL;
118 return TRUE;
119 }
120 CurrentTimer = CurrentTimer->NextDeferredTimer;
121 }
122 return FALSE;
123 }
124 }
125
126 /*
127 * @implemented
128 */
129 VOID
130 EXPORT
131 NdisMCancelTimer(
132 IN PNDIS_MINIPORT_TIMER Timer,
133 OUT PBOOLEAN TimerCancelled)
134 /*
135 * FUNCTION: cancel a scheduled NDIS_MINIPORT_TIMER
136 * ARGUMENTS:
137 * Timer: timer object to cancel
138 * TimerCancelled: status of cancel operation
139 * NOTES:
140 * - call at IRQL <= DISPATCH_LEVEL
141 */
142 {
143 //KIRQL OldIrql;
144
145 ASSERT_IRQL(DISPATCH_LEVEL);
146 ASSERT(TimerCancelled);
147 ASSERT(Timer);
148
149 *TimerCancelled = KeCancelTimer (&Timer->Timer);
150
151 #if 0
152 if (*TimerCancelled)
153 {
154 KeAcquireSpinLock(&Timer->Miniport->Lock, &OldIrql);
155 /* If it's somebody already dequeued it, something is wrong (maybe a double-cancel?) */
156 if (!DequeueMiniportTimer(Timer)) ASSERT(FALSE);
157 KeReleaseSpinLock(&Timer->Miniport->Lock, OldIrql);
158 }
159 #endif
160 }
161
162 VOID NTAPI
163 MiniTimerDpcFunction(PKDPC Dpc,
164 PVOID DeferredContext,
165 PVOID SystemArgument1,
166 PVOID SystemArgument2)
167 {
168 PNDIS_MINIPORT_TIMER Timer = DeferredContext;
169
170 #if 0
171 /* Only dequeue if the timer has a period of 0 */
172 if (!Timer->Timer.Period)
173 {
174 KeAcquireSpinLockAtDpcLevel(&Timer->Miniport->Lock);
175 /* If someone already dequeued it, something is wrong (borked timer implementation?) */
176 if (!DequeueMiniportTimer(Timer)) ASSERT(FALSE);
177 KeReleaseSpinLockFromDpcLevel(&Timer->Miniport->Lock);
178 }
179 #endif
180
181 Timer->MiniportTimerFunction(Dpc,
182 Timer->MiniportTimerContext,
183 SystemArgument1,
184 SystemArgument2);
185 }
186
187 /*
188 * @implemented
189 */
190 VOID
191 EXPORT
192 NdisMInitializeTimer(
193 IN OUT PNDIS_MINIPORT_TIMER Timer,
194 IN NDIS_HANDLE MiniportAdapterHandle,
195 IN PNDIS_TIMER_FUNCTION TimerFunction,
196 IN PVOID FunctionContext)
197 /*
198 * FUNCTION: Initialize an NDIS_MINIPORT_TIMER
199 * ARGUMENTS:
200 * Timer: Timer object to initialize
201 * MiniportAdapterHandle: Handle to the miniport, passed in to MiniportInitialize
202 * TimerFunction: function to be executed when the timer expires
203 * FunctionContext: argument passed to TimerFunction when it is called
204 * NOTES:
205 * - TimerFunction is called at IRQL = DISPATCH_LEVEL
206 * - call at IRQL = PASSIVE_LEVEL
207 */
208 {
209 PAGED_CODE();
210 ASSERT(Timer);
211
212 KeInitializeTimer (&Timer->Timer);
213 KeInitializeDpc (&Timer->Dpc, MiniTimerDpcFunction, Timer);
214
215 Timer->MiniportTimerFunction = TimerFunction;
216 Timer->MiniportTimerContext = FunctionContext;
217 Timer->Miniport = &((PLOGICAL_ADAPTER)MiniportAdapterHandle)->NdisMiniportBlock;
218 Timer->NextDeferredTimer = NULL;
219 }
220
221 /*
222 * @implemented
223 */
224 VOID
225 EXPORT
226 NdisMSetPeriodicTimer(
227 IN PNDIS_MINIPORT_TIMER Timer,
228 IN UINT MillisecondsPeriod)
229 /*
230 * FUNCTION: Set a timer to go off periodically
231 * ARGUMENTS:
232 * Timer: pointer to the timer object to set
233 * MillisecondsPeriod: period of the timer
234 * NOTES:
235 * - Minimum predictible interval is ~10ms
236 * - Must be called at IRQL <= DISPATCH_LEVEL
237 */
238 {
239 LARGE_INTEGER Timeout;
240 //KIRQL OldIrql;
241
242 ASSERT_IRQL(DISPATCH_LEVEL);
243 ASSERT(Timer);
244
245 /* relative delays are negative, absolute are positive; resolution is 100ns */
246 Timeout.QuadPart = Int32x32To64(MillisecondsPeriod, -10000);
247
248 #if 0
249 /* Lock the miniport block */
250 KeAcquireSpinLock(&Timer->Miniport->Lock, &OldIrql);
251
252 /* Attempt to dequeue the timer */
253 DequeueMiniportTimer(Timer);
254
255 /* Add the timer at the head of the timer queue */
256 Timer->NextDeferredTimer = Timer->Miniport->TimerQueue;
257 Timer->Miniport->TimerQueue = Timer;
258
259 /* Unlock the miniport block */
260 KeReleaseSpinLock(&Timer->Miniport->Lock, OldIrql);
261 #endif
262
263 KeSetTimerEx(&Timer->Timer, Timeout, MillisecondsPeriod, &Timer->Dpc);
264 }
265
266 /*
267 * @implemented
268 */
269 #undef NdisMSetTimer
270 VOID
271 EXPORT
272 NdisMSetTimer(
273 IN PNDIS_MINIPORT_TIMER Timer,
274 IN UINT MillisecondsToDelay)
275 /*
276 * FUNCTION: Set a NDIS_MINIPORT_TIMER so that it goes off
277 * ARGUMENTS:
278 * Timer: timer object to set
279 * MillisecondsToDelay: time to wait for the timer to expire
280 * NOTES:
281 * - Minimum predictible interval is ~10ms
282 * - Must be called at IRQL <= DISPATCH_LEVEL
283 */
284 {
285 LARGE_INTEGER Timeout;
286 //KIRQL OldIrql;
287
288 ASSERT_IRQL(DISPATCH_LEVEL);
289 ASSERT(Timer);
290
291 /* relative delays are negative, absolute are positive; resolution is 100ns */
292 Timeout.QuadPart = Int32x32To64(MillisecondsToDelay, -10000);
293
294 #if 0
295 /* Lock the miniport block */
296 KeAcquireSpinLock(&Timer->Miniport->Lock, &OldIrql);
297
298 /* Attempt to dequeue the timer */
299 DequeueMiniportTimer(Timer);
300
301 /* Add the timer at the head of the timer queue */
302 Timer->NextDeferredTimer = Timer->Miniport->TimerQueue;
303 Timer->Miniport->TimerQueue = Timer;
304
305 /* Unlock the miniport block */
306 KeReleaseSpinLock(&Timer->Miniport->Lock, OldIrql);
307 #endif
308
309 KeSetTimer(&Timer->Timer, Timeout, &Timer->Dpc);
310 }
311
312 /*
313 * @implemented
314 */
315 VOID
316 EXPORT
317 NdisSetTimer(
318 IN PNDIS_TIMER Timer,
319 IN UINT MillisecondsToDelay)
320 /*
321 * FUNCTION: Set an NDIS_TIMER so that it goes off
322 * ARGUMENTS:
323 * Timer: timer object to set
324 * MillisecondsToDelay: time to wait for the timer to expire
325 * NOTES:
326 * - Minimum predictible interval is ~10ms
327 * - Must be called at IRQL <= DISPATCH_LEVEL
328 */
329 {
330 LARGE_INTEGER Timeout;
331
332 ASSERT_IRQL(DISPATCH_LEVEL);
333 ASSERT(Timer);
334
335 NDIS_DbgPrint(MAX_TRACE, ("Called. Timer is: 0x%x, Timeout is: %ld\n", Timer, MillisecondsToDelay));
336
337 /* relative delays are negative, absolute are positive; resolution is 100ns */
338 Timeout.QuadPart = Int32x32To64(MillisecondsToDelay, -10000);
339
340 KeSetTimer (&Timer->Timer, Timeout, &Timer->Dpc);
341 }
342
343 /*
344 * @implemented
345 */
346 VOID
347 EXPORT
348 NdisSetTimerEx(
349 IN PNDIS_TIMER Timer,
350 IN UINT MillisecondsToDelay,
351 IN PVOID FunctionContext)
352 {
353 NDIS_DbgPrint(MAX_TRACE, ("Called. Timer is: 0x%x, Timeout is: %ld, FunctionContext is: 0x%x\n",
354 Timer, MillisecondsToDelay, FunctionContext));
355
356 Timer->Dpc.DeferredContext = FunctionContext;
357
358 NdisSetTimer(Timer, MillisecondsToDelay);
359 }
360
361 /* EOF */