Sync to trunk revision 63922.
[reactos.git] / drivers / network / ndis / ndis / control.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
4 * FILE: ndis/control.c
5 * PURPOSE: Program control routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * 3 Oct 2003 Vizzini - Formatting and minor bugfixes
11 */
12
13 #include "ndissys.h"
14
15 /*
16 * @implemented
17 */
18 VOID
19 EXPORT
20 NdisInitializeReadWriteLock(
21 IN PNDIS_RW_LOCK Lock)
22 /*
23 * FUNCTION: Initialize a NDIS_RW_LOCK
24 * ARGUMENTS:
25 * Lock: pointer to the lock to initialize
26 * NOTES:
27 * NDIS 5.0
28 */
29 {
30 RtlZeroMemory(Lock, sizeof(NDIS_RW_LOCK));
31
32 KeInitializeSpinLock(&Lock->SpinLock);
33 }
34
35 /*
36 * @implemented
37 */
38 VOID
39 EXPORT
40 NdisAcquireReadWriteLock(
41 IN PNDIS_RW_LOCK Lock,
42 IN BOOLEAN fWrite,
43 IN PLOCK_STATE LockState)
44 /*
45 * FUNCTION:
46 * ARGUMENTS:
47 * NOTES:
48 * NDIS 5.0
49 */
50 {
51 ULONG RefCount;
52 UCHAR ProcessorNumber;
53 volatile UCHAR BusyLoop;
54
55 ASSERT_IRQL(DISPATCH_LEVEL);
56
57 if (fWrite) {
58 if (Lock->Context == PsGetCurrentThread()) {
59 LockState->LockState = 2;
60 } else {
61 KeAcquireSpinLock(&Lock->SpinLock, &LockState->OldIrql);
62 /* Check if any other processor helds a shared lock. */
63 for (ProcessorNumber = KeNumberProcessors; ProcessorNumber--; ) {
64 if (ProcessorNumber != KeGetCurrentProcessorNumber()) {
65 /* Wait till the shared lock is released. */
66 while (Lock->RefCount[ProcessorNumber].RefCount != 0) {
67 for (BusyLoop = 32; BusyLoop--; )
68 ;
69 }
70 }
71 }
72 Lock->Context = PsGetCurrentThread();
73 LockState->LockState = 4;
74 }
75 } else {
76 KeRaiseIrql(DISPATCH_LEVEL, &LockState->OldIrql);
77 RefCount = InterlockedIncrement((PLONG)&Lock->RefCount[KeGetCurrentProcessorNumber()].RefCount);
78 /* Racing with a exclusive write lock case. */
79 if (Lock->SpinLock != 0) {
80 if (RefCount == 1) {
81 if (Lock->Context != PsGetCurrentThread()) {
82 /* Wait for the exclusive lock to be released. */
83 Lock->RefCount[KeGetCurrentProcessorNumber()].RefCount--;
84 KeAcquireSpinLockAtDpcLevel(&Lock->SpinLock);
85 Lock->RefCount[KeGetCurrentProcessorNumber()].RefCount++;
86 KeReleaseSpinLockFromDpcLevel(&Lock->SpinLock);
87 }
88 }
89 }
90 Lock->Context = PsGetCurrentThread();
91 LockState->LockState = 3;
92 }
93 }
94
95 /*
96 * @implemented
97 */
98 VOID
99 EXPORT
100 NdisReleaseReadWriteLock(
101 IN PNDIS_RW_LOCK Lock,
102 IN PLOCK_STATE LockState)
103 /*
104 * FUNCTION:
105 * ARGUMENTS:
106 * NOTES:
107 * NDIS 5.0
108 */
109 {
110 switch (LockState->LockState) {
111 case 2: /* Exclusive write lock, recursive */
112 return;
113
114 case 3: /* Shared read lock */
115 Lock->RefCount[KeGetCurrentProcessorNumber()].RefCount--;
116 LockState->LockState = -1;
117 if (LockState->OldIrql < DISPATCH_LEVEL)
118 KeLowerIrql(LockState->OldIrql);
119 return;
120
121 case 4: /* Exclusive write lock */
122 Lock->Context = NULL;
123 LockState->LockState = -1;
124 KeReleaseSpinLock(&Lock->SpinLock, LockState->OldIrql);
125 return;
126 }
127 }
128
129 /*
130 * @implemented
131 */
132 #undef NdisAcquireSpinLock
133 VOID
134 EXPORT
135 NdisAcquireSpinLock(
136 IN PNDIS_SPIN_LOCK SpinLock)
137 /*
138 * FUNCTION: Acquires a spin lock for exclusive access to a resource
139 * ARGUMENTS:
140 * SpinLock = Pointer to the initialized NDIS spin lock to be acquired
141 */
142 {
143 KeAcquireSpinLock(&SpinLock->SpinLock, &SpinLock->OldIrql);
144 }
145
146 /*
147 * @implemented
148 */
149 #undef NdisAllocateSpinLock
150 VOID
151 EXPORT
152 NdisAllocateSpinLock(
153 IN PNDIS_SPIN_LOCK SpinLock)
154 /*
155 * FUNCTION: Initializes for an NDIS spin lock
156 * ARGUMENTS:
157 * SpinLock = Pointer to an NDIS spin lock structure
158 */
159 {
160 KeInitializeSpinLock(&SpinLock->SpinLock);
161 }
162
163 /*
164 * @implemented
165 */
166 #undef NdisDprAcquireSpinLock
167 VOID
168 EXPORT
169 NdisDprAcquireSpinLock(
170 IN PNDIS_SPIN_LOCK SpinLock)
171 /*
172 * FUNCTION: Acquires a spin lock from IRQL DISPATCH_LEVEL
173 * ARGUMENTS:
174 * SpinLock = Pointer to the initialized NDIS spin lock to be acquired
175 */
176 {
177 KeAcquireSpinLockAtDpcLevel(&SpinLock->SpinLock);
178 SpinLock->OldIrql = DISPATCH_LEVEL;
179 }
180
181 /*
182 * @implemented
183 */
184 #undef NdisDprReleaseSpinLock
185 VOID
186 EXPORT
187 NdisDprReleaseSpinLock(
188 IN PNDIS_SPIN_LOCK SpinLock)
189 /*
190 * FUNCTION: Releases an acquired spin lock from IRQL DISPATCH_LEVEL
191 * ARGUMENTS:
192 * SpinLock = Pointer to the acquired NDIS spin lock to be released
193 */
194 {
195 KeReleaseSpinLockFromDpcLevel(&SpinLock->SpinLock);
196 }
197
198 /*
199 * @implemented
200 */
201 #undef NdisFreeSpinLock
202 VOID
203 EXPORT
204 NdisFreeSpinLock(
205 IN PNDIS_SPIN_LOCK SpinLock)
206 /*
207 * FUNCTION: Releases a spin lock initialized with NdisAllocateSpinLock
208 * ARGUMENTS:
209 * SpinLock = Pointer to an initialized NDIS spin lock
210 */
211 {
212 /* Nothing to do here! */
213 }
214
215
216 /*
217 * @implemented
218 */
219 VOID
220 EXPORT
221 NdisInitializeEvent(
222 IN PNDIS_EVENT Event)
223 /*
224 * FUNCTION: Initializes an event to be used for synchronization
225 * ARGUMENTS:
226 * Event = Pointer to an NDIS event structure to be initialized
227 */
228 {
229 KeInitializeEvent(&Event->Event, NotificationEvent, FALSE);
230 }
231
232
233 /*
234 * @implemented
235 */
236 #undef NdisReleaseSpinLock
237 VOID
238 EXPORT
239 NdisReleaseSpinLock(
240 IN PNDIS_SPIN_LOCK SpinLock)
241 /*
242 * FUNCTION: Releases a spin lock previously acquired with NdisAcquireSpinLock
243 * ARGUMENTS:
244 * SpinLock = Pointer to the acquired NDIS spin lock to be released
245 */
246 {
247 KeReleaseSpinLock(&SpinLock->SpinLock, SpinLock->OldIrql);
248 }
249
250
251 /*
252 * @implemented
253 */
254 VOID
255 EXPORT
256 NdisResetEvent(
257 IN PNDIS_EVENT Event)
258 /*
259 * FUNCTION: Clears the signaled state of an event
260 * ARGUMENTS:
261 * Event = Pointer to the initialized event object to be reset
262 */
263 {
264 KeResetEvent(&Event->Event);
265 }
266
267
268 /*
269 * @implemented
270 */
271 VOID
272 EXPORT
273 NdisSetEvent(
274 IN PNDIS_EVENT Event)
275 /*
276 * FUNCTION: Sets an event to a signaled state if not already signaled
277 * ARGUMENTS:
278 * Event = Pointer to the initialized event object to be set
279 */
280 {
281 KeSetEvent(&Event->Event, IO_NO_INCREMENT, FALSE);
282 }
283
284
285 /*
286 * @implemented
287 */
288 BOOLEAN
289 EXPORT
290 NdisWaitEvent(
291 IN PNDIS_EVENT Event,
292 IN UINT MsToWait)
293 /*
294 * FUNCTION: Waits for an event to become signaled
295 * ARGUMENTS:
296 * Event = Pointer to the initialized event object to wait for
297 * MsToWait = Maximum milliseconds to wait for the event to become signaled
298 * RETURNS:
299 * TRUE if the event is in the signaled state
300 */
301 {
302 LARGE_INTEGER Timeout;
303 NTSTATUS Status;
304
305 Timeout.QuadPart = Int32x32To64(MsToWait, -10000);
306
307 Status = KeWaitForSingleObject(&Event->Event, Executive, KernelMode, TRUE, &Timeout);
308
309 return (Status == STATUS_SUCCESS);
310 }
311
312 /* EOF */