[NETKVM] Import NetKVM network adapter driver by Red Hat
[reactos.git] / drivers / network / dd / netkvm / wxp / ParaNdis5-Driver.c
1 /*
2 * This file contains driver-related part of NDIS5.X adapter driver.
3 *
4 * Copyright (c) 2008-2017 Red Hat, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met :
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and / or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of their contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29 #include "ParaNdis5.h"
30
31 //#define NO_XP_POWER_MANAGEMENT
32
33 #ifdef WPP_EVENT_TRACING
34 #include "ParaNdis5-Driver.tmh"
35 #endif
36
37 static NDIS_HANDLE DriverHandle;
38 static ULONG gID = 0;
39
40 /******************************************************
41 Unload handler, only responsibility is cleanup WPP
42 *******************************************************/
43 static VOID NTAPI ParaVirtualNICUnload(IN PDRIVER_OBJECT pDriverObject)
44 {
45 DEBUG_ENTRY(0);
46 ParaNdis_DebugCleanup(pDriverObject);
47 }
48
49 /*************************************************************
50 Required NDIS function
51 Responsible to put the adapter to known (initial) hardware state
52
53 Do not call any NDIS functions
54 *************************************************************/
55 static VOID NTAPI ParaNdis5_Shutdown(IN NDIS_HANDLE MiniportAdapterContext)
56 {
57 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
58 ParaNdis_OnShutdown(pContext);
59 }
60
61 /******************************************************
62 Required NDIS procedure
63 Allocates and initializes adapter context
64 Finally sets send and receive to Enabled state and reports connect
65 Returns:
66 NDIS_STATUS SUCCESS or some error code
67 *******************************************************/
68 static NDIS_STATUS NTAPI ParaNdis5_Initialize(OUT PNDIS_STATUS OpenErrorStatus,
69 OUT PUINT SelectedMediumIndex,
70 IN PNDIS_MEDIUM MediumArray,
71 IN UINT MediumArraySize,
72 IN NDIS_HANDLE MiniportAdapterHandle,
73 IN NDIS_HANDLE WrapperConfigurationContext)
74 {
75 NDIS_STATUS status = NDIS_STATUS_UNSUPPORTED_MEDIA;
76 PARANDIS_ADAPTER *pContext = NULL;
77 UINT i;
78 for(i = 0; i < MediumArraySize; ++i)
79 {
80 if(MediumArray[i] == NdisMedium802_3)
81 {
82 *SelectedMediumIndex = i;
83 status = NDIS_STATUS_SUCCESS;
84 break;
85 }
86 }
87
88 if (status == NDIS_STATUS_SUCCESS)
89 {
90 pContext =
91 (PARANDIS_ADAPTER *)ParaNdis_AllocateMemory(NULL, sizeof(PARANDIS_ADAPTER));
92 if (!pContext)
93 {
94 status = NDIS_STATUS_RESOURCES;
95 }
96 }
97
98 if (status == NDIS_STATUS_SUCCESS)
99 {
100 PVOID pResourceList = &status;
101 UINT uSize = 0;
102 NdisZeroMemory(pContext, sizeof(PARANDIS_ADAPTER));
103 pContext->ulUniqueID = NdisInterlockedIncrement(&gID);
104 pContext->DriverHandle = DriverHandle;
105 pContext->MiniportHandle = MiniportAdapterHandle;
106 pContext->WrapperConfigurationHandle = WrapperConfigurationContext;
107 NdisMQueryAdapterResources(&status, WrapperConfigurationContext, pResourceList, &uSize);
108 if (uSize > 0)
109 pResourceList = ParaNdis_AllocateMemory(MiniportAdapterHandle, uSize);
110 else
111 pResourceList = NULL;
112 if (!pResourceList)
113 status = uSize > 0 ? NDIS_STATUS_RESOURCES : NDIS_STATUS_FAILURE;
114 else
115 {
116 ULONG attributes;
117 attributes = NDIS_ATTRIBUTE_DESERIALIZE | NDIS_ATTRIBUTE_BUS_MASTER;
118 // in XP SP2, if this flag is NOT set, the NDIS halts miniport
119 // upon transition to S1..S4.
120 // it seems that XP SP3 ignores it and always sends SET_POWER to D3
121 #ifndef NO_XP_POWER_MANAGEMENT
122 attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
123 #endif
124 NdisMSetAttributesEx(
125 MiniportAdapterHandle,
126 pContext,
127 0,
128 attributes,
129 NdisInterfacePci);
130 NdisMQueryAdapterResources(&status, WrapperConfigurationContext, pResourceList, &uSize);
131 status = ParaNdis_InitializeContext(pContext, (PNDIS_RESOURCE_LIST)pResourceList);
132 NdisFreeMemory(pResourceList, 0, 0);
133 }
134 }
135
136 if (status == NDIS_STATUS_SUCCESS)
137 {
138 status = ParaNdis_FinishInitialization(pContext);
139 if (status == NDIS_STATUS_SUCCESS)
140 {
141 ParaNdis_DebugRegisterMiniport(pContext, TRUE);
142 ParaNdis_IndicateConnect(pContext, FALSE, TRUE);
143 ParaNdis5_StopSend(pContext, FALSE, NULL);
144 ParaNdis5_StopReceive(pContext, FALSE, NULL);
145 if (!pContext->ulMilliesToConnect)
146 {
147 ParaNdis_ReportLinkStatus(pContext, FALSE);
148 }
149 else
150 {
151 NdisSetTimer(&pContext->ConnectTimer, pContext->ulMilliesToConnect);
152 }
153 }
154 else
155 {
156 ParaNdis_CleanupContext(pContext);
157 }
158 }
159
160 if (status != NDIS_STATUS_SUCCESS && pContext)
161 {
162 NdisFreeMemory(pContext, 0, 0);
163 }
164
165 DEBUG_EXIT_STATUS(0, status);
166 return status;
167 }
168
169
170 /*************************************************************
171 Callback of delayed receive pause procedure upon reset request
172 *************************************************************/
173 static void OnReceiveStoppedOnReset(VOID *p)
174 {
175 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p;
176 DEBUG_ENTRY(0);
177 NdisSetEvent(&pContext->ResetEvent);
178 }
179
180 /*************************************************************
181 Callback of delayed send pause procedure upon reset request
182 *************************************************************/
183 static void OnSendStoppedOnReset(VOID *p)
184 {
185 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p;
186 DEBUG_ENTRY(0);
187 NdisSetEvent(&pContext->ResetEvent);
188 }
189
190 VOID ParaNdis_Suspend(PARANDIS_ADAPTER *pContext)
191 {
192 DEBUG_ENTRY(0);
193 NdisResetEvent(&pContext->ResetEvent);
194 if (NDIS_STATUS_PENDING != ParaNdis5_StopSend(pContext, TRUE, OnSendStoppedOnReset))
195 {
196 NdisSetEvent(&pContext->ResetEvent);
197 }
198 NdisWaitEvent(&pContext->ResetEvent, 0);
199 NdisResetEvent(&pContext->ResetEvent);
200 if (NDIS_STATUS_PENDING != ParaNdis5_StopReceive(pContext, TRUE, OnReceiveStoppedOnReset))
201 {
202 NdisSetEvent(&pContext->ResetEvent);
203 }
204 NdisWaitEvent(&pContext->ResetEvent, 0);
205 NdisResetEvent(&pContext->ResetEvent);
206 DEBUG_EXIT_STATUS(0, 0);
207 }
208
209 VOID ParaNdis_Resume(PARANDIS_ADAPTER *pContext)
210 {
211 ParaNdis5_StopSend(pContext, FALSE, NULL);
212 ParaNdis5_StopReceive(pContext, FALSE, NULL);
213 DEBUG_EXIT_STATUS(0, 0);
214 }
215
216 static void NTAPI OnResetWorkItem(NDIS_WORK_ITEM * pWorkItem, PVOID Context)
217 {
218 tGeneralWorkItem *pwi = (tGeneralWorkItem *)pWorkItem;
219 PARANDIS_ADAPTER *pContext = pwi->pContext;
220 DEBUG_ENTRY(0);
221
222 pContext->bResetInProgress = TRUE;
223 ParaNdis_IndicateConnect(pContext, FALSE, FALSE);
224 ParaNdis_Suspend(pContext);
225 ParaNdis_Resume(pContext);
226 pContext->bResetInProgress = FALSE;
227 ParaNdis_ReportLinkStatus(pContext, FALSE);
228
229 NdisFreeMemory(pwi, 0, 0);
230 ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 0, NDIS_STATUS_SUCCESS, 0);
231 NdisMResetComplete(pContext->MiniportHandle, NDIS_STATUS_SUCCESS, TRUE);
232 }
233
234
235 /*************************************************************
236 Required NDIS procedure
237 Called when some procedure (like OID handler) returns PENDING and
238 does not complete or when CheckForHang return TRUE
239 *************************************************************/
240 static NDIS_STATUS NTAPI ParaNdis5_Reset(
241 OUT PBOOLEAN AddressingReset,
242 IN NDIS_HANDLE MiniportAdapterContext)
243 {
244 NDIS_STATUS status;
245 tGeneralWorkItem *pwi;
246 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
247 DEBUG_ENTRY(0);
248 ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 1, 0, 0);
249 status = NDIS_STATUS_FAILURE;
250 pwi = ParaNdis_AllocateMemory(pContext, sizeof(tGeneralWorkItem));
251 if (pwi)
252 {
253 pwi->pContext = pContext;
254 NdisInitializeWorkItem(&pwi->wi, OnResetWorkItem, pwi);
255 if (NdisScheduleWorkItem(&pwi->wi) == NDIS_STATUS_SUCCESS)
256 {
257 status = NDIS_STATUS_PENDING;
258 }
259 else
260 {
261 NdisFreeMemory(pwi, 0, 0);
262 }
263 }
264 if (status != NDIS_STATUS_PENDING)
265 {
266 ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 0, status, 0);
267 }
268 return status;
269 }
270
271 /*************************************************************
272 Callback of delayed receive pause procedure
273 *************************************************************/
274 static VOID OnReceiveStopped(VOID *p)
275 {
276 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p;
277 DEBUG_ENTRY(0);
278 NdisSetEvent(&pContext->HaltEvent);
279 }
280
281 /*************************************************************
282 Callback of delayed send pause procedure
283 *************************************************************/
284 static VOID OnSendStopped(VOID *p)
285 {
286 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p;
287 DEBUG_ENTRY(0);
288 NdisSetEvent(&pContext->HaltEvent);
289 }
290
291 static void WaitHaltEvent(PARANDIS_ADAPTER *pContext, const char *Reason)
292 {
293 UINT ms = 5000;
294 if (!NdisWaitEvent(&pContext->HaltEvent, 1))
295 {
296 while (!NdisWaitEvent(&pContext->HaltEvent, ms))
297 {
298 DPrintf(0, ("[%s]", __FUNCTION__));
299 }
300 }
301 }
302
303 /*************************************************************
304 Required NDIS procedure
305 Stops TX and RX path and finished the function of adapter
306 *************************************************************/
307 static VOID NTAPI ParaNdis5_Halt(
308 IN NDIS_HANDLE MiniportAdapterContext)
309 {
310 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
311 BOOLEAN bUnused;
312 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
313 DEBUG_ENTRY(0);
314
315 ParaNdis_DebugHistory(pContext, hopHalt, NULL, 1, 0, 0);
316
317 NdisCancelTimer(&pContext->ConnectTimer, &bUnused);
318 NdisResetEvent(&pContext->HaltEvent);
319 if (NDIS_STATUS_PENDING != ParaNdis5_StopSend(pContext, TRUE, OnSendStopped))
320 NdisSetEvent(&pContext->HaltEvent);
321 WaitHaltEvent(pContext, "Send");
322 NdisResetEvent(&pContext->HaltEvent);
323 if (NDIS_STATUS_PENDING != ParaNdis5_StopReceive(pContext, TRUE, OnReceiveStopped))
324 NdisSetEvent(&pContext->HaltEvent);
325 WaitHaltEvent(pContext, "Receive");
326 ParaNdis_CleanupContext(pContext);
327 NdisCancelTimer(&pContext->DPCPostProcessTimer, &bUnused);
328 ParaNdis_DebugHistory(pContext, hopHalt, NULL, 0, 0, 0);
329 ParaNdis_DebugRegisterMiniport(pContext, FALSE);
330 NdisFreeMemory(pContext, 0, 0);
331 DEBUG_EXIT_STATUS(0, status);
332 }
333
334
335 /*************************************************************
336 Called periodically (usually each 2 seconds)
337 *************************************************************/
338 static BOOLEAN NTAPI ParaNdis5_CheckForHang(IN NDIS_HANDLE MiniportAdapterContext)
339 {
340 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
341 DEBUG_ENTRY(8);
342 return ParaNdis_CheckForHang(pContext);
343 }
344
345 /*************************************************************
346 Required NDIS procedure
347 Responsible for hardware interrupt handling
348 *************************************************************/
349 static VOID NTAPI ParaNdis5_MiniportISR(OUT PBOOLEAN InterruptRecognized,
350 OUT PBOOLEAN QueueMiniportHandleInterrupt,
351 IN NDIS_HANDLE MiniportAdapterContext)
352 {
353 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
354 BOOLEAN b;
355 *QueueMiniportHandleInterrupt = FALSE;
356 b = ParaNdis_OnLegacyInterrupt(pContext, QueueMiniportHandleInterrupt);
357 *InterruptRecognized = b;
358 DEBUG_EXIT_STATUS(7, (ULONG)b);
359 }
360
361 /*************************************************************
362 Parameters:
363
364 Return value:
365
366 *************************************************************/
367 VOID NTAPI ParaNdis5_PnPEventNotify(IN NDIS_HANDLE MiniportAdapterContext,
368 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
369 IN PVOID InformationBuffer,
370 IN ULONG InformationBufferLength)
371 {
372 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
373 ParaNdis_OnPnPEvent(pContext, PnPEvent, InformationBuffer, InformationBufferLength);
374 }
375
376 /*************************************************************
377 Driver's entry point
378 Parameters:
379 as usual
380 Return value:
381 SUCCESS or error code
382 *************************************************************/
383 NDIS_STATUS NTAPI DriverEntry(PVOID DriverObject,PVOID RegistryPath)
384 {
385 NDIS_STATUS status;
386 NDIS_MINIPORT_CHARACTERISTICS chars;
387 ParaNdis_DebugInitialize(DriverObject, RegistryPath);
388
389 status = NDIS_STATUS_FAILURE;
390
391 DEBUG_ENTRY(0);
392 _LogOutString(0, __DATE__ " " __TIME__);
393
394 NdisMInitializeWrapper(&DriverHandle,
395 DriverObject,
396 RegistryPath,
397 NULL
398 );
399
400 if (DriverHandle)
401 {
402 NdisZeroMemory(&chars, sizeof(chars));
403 //NDIS version of the miniport
404 chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
405 chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
406 //Init and destruction
407 chars.InitializeHandler = ParaNdis5_Initialize;
408 chars.HaltHandler = ParaNdis5_Halt;
409
410 //Interrupt and DPC handling
411 chars.HandleInterruptHandler = ParaNdis5_HandleDPC;
412 chars.ISRHandler = ParaNdis5_MiniportISR;
413
414 //Packet transfer - send path and notification on the send packet
415 chars.SendPacketsHandler = ParaNdis5_SendPackets;
416 chars.ReturnPacketHandler = ParaNdis5_ReturnPacket;
417
418 //OID set\get
419 chars.SetInformationHandler = ParaNdis5_SetOID;
420 chars.QueryInformationHandler = ParaNdis5_QueryOID;
421
422 //Reset
423 chars.ResetHandler = ParaNdis5_Reset;
424 chars.CheckForHangHandler = ParaNdis5_CheckForHang; //optional
425
426 chars.CancelSendPacketsHandler = ParaNdis5_CancelSendPackets;
427 chars.PnPEventNotifyHandler = ParaNdis5_PnPEventNotify;
428 chars.AdapterShutdownHandler = ParaNdis5_Shutdown;
429
430 status = NdisMRegisterMiniport(
431 DriverHandle,
432 &chars,
433 sizeof(chars));
434 }
435
436 if (status == NDIS_STATUS_SUCCESS)
437 {
438 NdisMRegisterUnloadHandler(DriverHandle, ParaVirtualNICUnload);
439 }
440 else if (DriverHandle)
441 {
442 DPrintf(0, ("NdisMRegisterMiniport failed"));
443 NdisTerminateWrapper(DriverHandle, NULL);
444 }
445 else
446 {
447 DPrintf(0, ("NdisMInitializeWrapper failed"));
448 }
449
450 DEBUG_EXIT_STATUS(status ? 0 : 4, status);
451 return status;
452 }