2 * This file contains driver-related part of NDIS5.X adapter driver.
4 * Copyright (c) 2008-2017 Red Hat, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
29 #include "ParaNdis5.h"
31 //#define NO_XP_POWER_MANAGEMENT
33 #ifdef WPP_EVENT_TRACING
34 #include "ParaNdis5-Driver.tmh"
37 static NDIS_HANDLE DriverHandle
;
40 /******************************************************
41 Unload handler, only responsibility is cleanup WPP
42 *******************************************************/
43 static VOID NTAPI
ParaVirtualNICUnload(IN PDRIVER_OBJECT pDriverObject
)
46 ParaNdis_DebugCleanup(pDriverObject
);
49 /*************************************************************
50 Required NDIS function
51 Responsible to put the adapter to known (initial) hardware state
53 Do not call any NDIS functions
54 *************************************************************/
55 static VOID NTAPI
ParaNdis5_Shutdown(IN NDIS_HANDLE MiniportAdapterContext
)
57 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)MiniportAdapterContext
;
58 ParaNdis_OnShutdown(pContext
);
61 /******************************************************
62 Required NDIS procedure
63 Allocates and initializes adapter context
64 Finally sets send and receive to Enabled state and reports connect
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
)
75 NDIS_STATUS status
= NDIS_STATUS_UNSUPPORTED_MEDIA
;
76 PARANDIS_ADAPTER
*pContext
= NULL
;
78 for(i
= 0; i
< MediumArraySize
; ++i
)
80 if(MediumArray
[i
] == NdisMedium802_3
)
82 *SelectedMediumIndex
= i
;
83 status
= NDIS_STATUS_SUCCESS
;
88 if (status
== NDIS_STATUS_SUCCESS
)
91 (PARANDIS_ADAPTER
*)ParaNdis_AllocateMemory(NULL
, sizeof(PARANDIS_ADAPTER
));
94 status
= NDIS_STATUS_RESOURCES
;
98 if (status
== NDIS_STATUS_SUCCESS
)
100 PVOID pResourceList
= &status
;
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
);
109 pResourceList
= ParaNdis_AllocateMemory(MiniportAdapterHandle
, uSize
);
111 pResourceList
= NULL
;
113 status
= uSize
> 0 ? NDIS_STATUS_RESOURCES
: NDIS_STATUS_FAILURE
;
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
;
124 NdisMSetAttributesEx(
125 MiniportAdapterHandle
,
130 NdisMQueryAdapterResources(&status
, WrapperConfigurationContext
, pResourceList
, &uSize
);
131 status
= ParaNdis_InitializeContext(pContext
, (PNDIS_RESOURCE_LIST
)pResourceList
);
132 NdisFreeMemory(pResourceList
, 0, 0);
136 if (status
== NDIS_STATUS_SUCCESS
)
138 status
= ParaNdis_FinishInitialization(pContext
);
139 if (status
== NDIS_STATUS_SUCCESS
)
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
)
147 ParaNdis_ReportLinkStatus(pContext
, FALSE
);
151 NdisSetTimer(&pContext
->ConnectTimer
, pContext
->ulMilliesToConnect
);
156 ParaNdis_CleanupContext(pContext
);
160 if (status
!= NDIS_STATUS_SUCCESS
&& pContext
)
162 NdisFreeMemory(pContext
, 0, 0);
165 DEBUG_EXIT_STATUS(0, status
);
170 /*************************************************************
171 Callback of delayed receive pause procedure upon reset request
172 *************************************************************/
173 static void OnReceiveStoppedOnReset(VOID
*p
)
175 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)p
;
177 NdisSetEvent(&pContext
->ResetEvent
);
180 /*************************************************************
181 Callback of delayed send pause procedure upon reset request
182 *************************************************************/
183 static void OnSendStoppedOnReset(VOID
*p
)
185 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)p
;
187 NdisSetEvent(&pContext
->ResetEvent
);
190 VOID
ParaNdis_Suspend(PARANDIS_ADAPTER
*pContext
)
193 NdisResetEvent(&pContext
->ResetEvent
);
194 if (NDIS_STATUS_PENDING
!= ParaNdis5_StopSend(pContext
, TRUE
, OnSendStoppedOnReset
))
196 NdisSetEvent(&pContext
->ResetEvent
);
198 NdisWaitEvent(&pContext
->ResetEvent
, 0);
199 NdisResetEvent(&pContext
->ResetEvent
);
200 if (NDIS_STATUS_PENDING
!= ParaNdis5_StopReceive(pContext
, TRUE
, OnReceiveStoppedOnReset
))
202 NdisSetEvent(&pContext
->ResetEvent
);
204 NdisWaitEvent(&pContext
->ResetEvent
, 0);
205 NdisResetEvent(&pContext
->ResetEvent
);
206 DEBUG_EXIT_STATUS(0, 0);
209 VOID
ParaNdis_Resume(PARANDIS_ADAPTER
*pContext
)
211 ParaNdis5_StopSend(pContext
, FALSE
, NULL
);
212 ParaNdis5_StopReceive(pContext
, FALSE
, NULL
);
213 DEBUG_EXIT_STATUS(0, 0);
216 static void NTAPI
OnResetWorkItem(NDIS_WORK_ITEM
* pWorkItem
, PVOID Context
)
218 tGeneralWorkItem
*pwi
= (tGeneralWorkItem
*)pWorkItem
;
219 PARANDIS_ADAPTER
*pContext
= pwi
->pContext
;
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
);
229 NdisFreeMemory(pwi
, 0, 0);
230 ParaNdis_DebugHistory(pContext
, hopSysReset
, NULL
, 0, NDIS_STATUS_SUCCESS
, 0);
231 NdisMResetComplete(pContext
->MiniportHandle
, NDIS_STATUS_SUCCESS
, TRUE
);
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
)
245 tGeneralWorkItem
*pwi
;
246 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)MiniportAdapterContext
;
248 ParaNdis_DebugHistory(pContext
, hopSysReset
, NULL
, 1, 0, 0);
249 status
= NDIS_STATUS_FAILURE
;
250 pwi
= ParaNdis_AllocateMemory(pContext
, sizeof(tGeneralWorkItem
));
253 pwi
->pContext
= pContext
;
254 NdisInitializeWorkItem(&pwi
->wi
, OnResetWorkItem
, pwi
);
255 if (NdisScheduleWorkItem(&pwi
->wi
) == NDIS_STATUS_SUCCESS
)
257 status
= NDIS_STATUS_PENDING
;
261 NdisFreeMemory(pwi
, 0, 0);
264 if (status
!= NDIS_STATUS_PENDING
)
266 ParaNdis_DebugHistory(pContext
, hopSysReset
, NULL
, 0, status
, 0);
271 /*************************************************************
272 Callback of delayed receive pause procedure
273 *************************************************************/
274 static VOID
OnReceiveStopped(VOID
*p
)
276 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)p
;
278 NdisSetEvent(&pContext
->HaltEvent
);
281 /*************************************************************
282 Callback of delayed send pause procedure
283 *************************************************************/
284 static VOID
OnSendStopped(VOID
*p
)
286 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)p
;
288 NdisSetEvent(&pContext
->HaltEvent
);
291 static void WaitHaltEvent(PARANDIS_ADAPTER
*pContext
, const char *Reason
)
294 if (!NdisWaitEvent(&pContext
->HaltEvent
, 1))
296 while (!NdisWaitEvent(&pContext
->HaltEvent
, ms
))
298 DPrintf(0, ("[%s]", __FUNCTION__
));
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
)
310 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
312 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)MiniportAdapterContext
;
315 ParaNdis_DebugHistory(pContext
, hopHalt
, NULL
, 1, 0, 0);
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
);
335 /*************************************************************
336 Called periodically (usually each 2 seconds)
337 *************************************************************/
338 static BOOLEAN NTAPI
ParaNdis5_CheckForHang(IN NDIS_HANDLE MiniportAdapterContext
)
340 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)MiniportAdapterContext
;
342 return ParaNdis_CheckForHang(pContext
);
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
)
353 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)MiniportAdapterContext
;
355 *QueueMiniportHandleInterrupt
= FALSE
;
356 b
= ParaNdis_OnLegacyInterrupt(pContext
, QueueMiniportHandleInterrupt
);
357 *InterruptRecognized
= b
;
358 DEBUG_EXIT_STATUS(7, (ULONG
)b
);
361 /*************************************************************
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
)
372 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)MiniportAdapterContext
;
373 ParaNdis_OnPnPEvent(pContext
, PnPEvent
, InformationBuffer
, InformationBufferLength
);
376 /*************************************************************
381 SUCCESS or error code
382 *************************************************************/
383 NDIS_STATUS NTAPI
DriverEntry(PVOID DriverObject
,PVOID RegistryPath
)
386 NDIS_MINIPORT_CHARACTERISTICS chars
;
387 ParaNdis_DebugInitialize(DriverObject
, RegistryPath
);
389 status
= NDIS_STATUS_FAILURE
;
392 _LogOutString(0, __DATE__
" " __TIME__
);
394 NdisMInitializeWrapper(&DriverHandle
,
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
;
410 //Interrupt and DPC handling
411 chars
.HandleInterruptHandler
= ParaNdis5_HandleDPC
;
412 chars
.ISRHandler
= ParaNdis5_MiniportISR
;
414 //Packet transfer - send path and notification on the send packet
415 chars
.SendPacketsHandler
= ParaNdis5_SendPackets
;
416 chars
.ReturnPacketHandler
= ParaNdis5_ReturnPacket
;
419 chars
.SetInformationHandler
= ParaNdis5_SetOID
;
420 chars
.QueryInformationHandler
= ParaNdis5_QueryOID
;
423 chars
.ResetHandler
= ParaNdis5_Reset
;
424 chars
.CheckForHangHandler
= ParaNdis5_CheckForHang
; //optional
426 chars
.CancelSendPacketsHandler
= ParaNdis5_CancelSendPackets
;
427 chars
.PnPEventNotifyHandler
= ParaNdis5_PnPEventNotify
;
428 chars
.AdapterShutdownHandler
= ParaNdis5_Shutdown
;
430 status
= NdisMRegisterMiniport(
436 if (status
== NDIS_STATUS_SUCCESS
)
438 NdisMRegisterUnloadHandler(DriverHandle
, ParaVirtualNICUnload
);
440 else if (DriverHandle
)
442 DPrintf(0, ("NdisMRegisterMiniport failed"));
443 NdisTerminateWrapper(DriverHandle
, NULL
);
447 DPrintf(0, ("NdisMInitializeWrapper failed"));
450 DEBUG_EXIT_STATUS(status
? 0 : 4, status
);