xref: /reactos/drivers/network/ndis/ndis/control.c (revision 4f8379a0)
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
NdisInitializeReadWriteLock(IN PNDIS_RW_LOCK Lock)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
NdisAcquireReadWriteLock(IN PNDIS_RW_LOCK Lock,IN BOOLEAN fWrite,IN PLOCK_STATE LockState)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
NdisReleaseReadWriteLock(IN PNDIS_RW_LOCK Lock,IN PLOCK_STATE LockState)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
NdisAcquireSpinLock(IN PNDIS_SPIN_LOCK SpinLock)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
NdisAllocateSpinLock(IN PNDIS_SPIN_LOCK SpinLock)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
NdisDprAcquireSpinLock(IN PNDIS_SPIN_LOCK SpinLock)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
NdisDprReleaseSpinLock(IN PNDIS_SPIN_LOCK SpinLock)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
NdisFreeSpinLock(IN PNDIS_SPIN_LOCK SpinLock)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
NdisInitializeEvent(IN PNDIS_EVENT Event)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
NdisReleaseSpinLock(IN PNDIS_SPIN_LOCK SpinLock)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
NdisResetEvent(IN PNDIS_EVENT Event)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   KeClearEvent(&Event->Event);
265 }
266 
267 
268 /*
269  * @implemented
270  */
271 VOID
272 EXPORT
NdisSetEvent(IN PNDIS_EVENT Event)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
NdisWaitEvent(IN PNDIS_EVENT Event,IN UINT MsToWait)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 */
313