mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 03:54:02 +00:00
4c37757e81
CORE-15841
452 lines
16 KiB
C
452 lines
16 KiB
C
/*
|
|
* This file contains driver-related part of NDIS5.X adapter driver.
|
|
*
|
|
* Copyright (c) 2008-2017 Red Hat, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met :
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and / or other materials provided with the distribution.
|
|
* 3. Neither the names of the copyright holders nor the names of their contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
#include "ParaNdis5.h"
|
|
|
|
//#define NO_XP_POWER_MANAGEMENT
|
|
|
|
#ifdef WPP_EVENT_TRACING
|
|
#include "ParaNdis5-Driver.tmh"
|
|
#endif
|
|
|
|
static NDIS_HANDLE DriverHandle;
|
|
static ULONG gID = 0;
|
|
|
|
/******************************************************
|
|
Unload handler, only responsibility is cleanup WPP
|
|
*******************************************************/
|
|
static VOID NTAPI ParaVirtualNICUnload(IN PDRIVER_OBJECT pDriverObject)
|
|
{
|
|
DEBUG_ENTRY(0);
|
|
ParaNdis_DebugCleanup(pDriverObject);
|
|
}
|
|
|
|
/*************************************************************
|
|
Required NDIS function
|
|
Responsible to put the adapter to known (initial) hardware state
|
|
|
|
Do not call any NDIS functions
|
|
*************************************************************/
|
|
static VOID NTAPI ParaNdis5_Shutdown(IN NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
|
|
ParaNdis_OnShutdown(pContext);
|
|
}
|
|
|
|
/******************************************************
|
|
Required NDIS procedure
|
|
Allocates and initializes adapter context
|
|
Finally sets send and receive to Enabled state and reports connect
|
|
Returns:
|
|
NDIS_STATUS SUCCESS or some error code
|
|
*******************************************************/
|
|
static NDIS_STATUS NTAPI ParaNdis5_Initialize(OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE WrapperConfigurationContext)
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_UNSUPPORTED_MEDIA;
|
|
PARANDIS_ADAPTER *pContext = NULL;
|
|
UINT i;
|
|
for(i = 0; i < MediumArraySize; ++i)
|
|
{
|
|
if(MediumArray[i] == NdisMedium802_3)
|
|
{
|
|
*SelectedMediumIndex = i;
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pContext =
|
|
(PARANDIS_ADAPTER *)ParaNdis_AllocateMemory(NULL, sizeof(PARANDIS_ADAPTER));
|
|
if (!pContext)
|
|
{
|
|
status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
}
|
|
|
|
if (status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
PVOID pResourceList = &status;
|
|
UINT uSize = 0;
|
|
NdisZeroMemory(pContext, sizeof(PARANDIS_ADAPTER));
|
|
pContext->ulUniqueID = NdisInterlockedIncrement(&gID);
|
|
pContext->DriverHandle = DriverHandle;
|
|
pContext->MiniportHandle = MiniportAdapterHandle;
|
|
pContext->WrapperConfigurationHandle = WrapperConfigurationContext;
|
|
NdisMQueryAdapterResources(&status, WrapperConfigurationContext, pResourceList, &uSize);
|
|
if (uSize > 0)
|
|
pResourceList = ParaNdis_AllocateMemory(MiniportAdapterHandle, uSize);
|
|
else
|
|
pResourceList = NULL;
|
|
if (!pResourceList)
|
|
status = uSize > 0 ? NDIS_STATUS_RESOURCES : NDIS_STATUS_FAILURE;
|
|
else
|
|
{
|
|
ULONG attributes;
|
|
attributes = NDIS_ATTRIBUTE_DESERIALIZE | NDIS_ATTRIBUTE_BUS_MASTER;
|
|
// in XP SP2, if this flag is NOT set, the NDIS halts miniport
|
|
// upon transition to S1..S4.
|
|
// it seems that XP SP3 ignores it and always sends SET_POWER to D3
|
|
#ifndef NO_XP_POWER_MANAGEMENT
|
|
attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
|
|
#endif
|
|
NdisMSetAttributesEx(
|
|
MiniportAdapterHandle,
|
|
pContext,
|
|
0,
|
|
attributes,
|
|
NdisInterfacePci);
|
|
NdisMQueryAdapterResources(&status, WrapperConfigurationContext, pResourceList, &uSize);
|
|
status = ParaNdis_InitializeContext(pContext, (PNDIS_RESOURCE_LIST)pResourceList);
|
|
NdisFreeMemory(pResourceList, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
status = ParaNdis_FinishInitialization(pContext);
|
|
if (status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ParaNdis_DebugRegisterMiniport(pContext, TRUE);
|
|
ParaNdis_IndicateConnect(pContext, FALSE, TRUE);
|
|
ParaNdis5_StopSend(pContext, FALSE, NULL);
|
|
ParaNdis5_StopReceive(pContext, FALSE, NULL);
|
|
if (!pContext->ulMilliesToConnect)
|
|
{
|
|
ParaNdis_ReportLinkStatus(pContext, FALSE);
|
|
}
|
|
else
|
|
{
|
|
NdisSetTimer(&pContext->ConnectTimer, pContext->ulMilliesToConnect);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ParaNdis_CleanupContext(pContext);
|
|
}
|
|
}
|
|
|
|
if (status != NDIS_STATUS_SUCCESS && pContext)
|
|
{
|
|
NdisFreeMemory(pContext, 0, 0);
|
|
}
|
|
|
|
DEBUG_EXIT_STATUS(0, status);
|
|
return status;
|
|
}
|
|
|
|
|
|
/*************************************************************
|
|
Callback of delayed receive pause procedure upon reset request
|
|
*************************************************************/
|
|
static void OnReceiveStoppedOnReset(VOID *p)
|
|
{
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p;
|
|
DEBUG_ENTRY(0);
|
|
NdisSetEvent(&pContext->ResetEvent);
|
|
}
|
|
|
|
/*************************************************************
|
|
Callback of delayed send pause procedure upon reset request
|
|
*************************************************************/
|
|
static void OnSendStoppedOnReset(VOID *p)
|
|
{
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p;
|
|
DEBUG_ENTRY(0);
|
|
NdisSetEvent(&pContext->ResetEvent);
|
|
}
|
|
|
|
VOID ParaNdis_Suspend(PARANDIS_ADAPTER *pContext)
|
|
{
|
|
DEBUG_ENTRY(0);
|
|
NdisResetEvent(&pContext->ResetEvent);
|
|
if (NDIS_STATUS_PENDING != ParaNdis5_StopSend(pContext, TRUE, OnSendStoppedOnReset))
|
|
{
|
|
NdisSetEvent(&pContext->ResetEvent);
|
|
}
|
|
NdisWaitEvent(&pContext->ResetEvent, 0);
|
|
NdisResetEvent(&pContext->ResetEvent);
|
|
if (NDIS_STATUS_PENDING != ParaNdis5_StopReceive(pContext, TRUE, OnReceiveStoppedOnReset))
|
|
{
|
|
NdisSetEvent(&pContext->ResetEvent);
|
|
}
|
|
NdisWaitEvent(&pContext->ResetEvent, 0);
|
|
NdisResetEvent(&pContext->ResetEvent);
|
|
DEBUG_EXIT_STATUS(0, 0);
|
|
}
|
|
|
|
VOID ParaNdis_Resume(PARANDIS_ADAPTER *pContext)
|
|
{
|
|
ParaNdis5_StopSend(pContext, FALSE, NULL);
|
|
ParaNdis5_StopReceive(pContext, FALSE, NULL);
|
|
DEBUG_EXIT_STATUS(0, 0);
|
|
}
|
|
|
|
static void NTAPI OnResetWorkItem(NDIS_WORK_ITEM * pWorkItem, PVOID Context)
|
|
{
|
|
tGeneralWorkItem *pwi = (tGeneralWorkItem *)pWorkItem;
|
|
PARANDIS_ADAPTER *pContext = pwi->pContext;
|
|
DEBUG_ENTRY(0);
|
|
|
|
pContext->bResetInProgress = TRUE;
|
|
ParaNdis_IndicateConnect(pContext, FALSE, FALSE);
|
|
ParaNdis_Suspend(pContext);
|
|
ParaNdis_Resume(pContext);
|
|
pContext->bResetInProgress = FALSE;
|
|
ParaNdis_ReportLinkStatus(pContext, FALSE);
|
|
|
|
NdisFreeMemory(pwi, 0, 0);
|
|
ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 0, NDIS_STATUS_SUCCESS, 0);
|
|
NdisMResetComplete(pContext->MiniportHandle, NDIS_STATUS_SUCCESS, TRUE);
|
|
}
|
|
|
|
|
|
/*************************************************************
|
|
Required NDIS procedure
|
|
Called when some procedure (like OID handler) returns PENDING and
|
|
does not complete or when CheckForHang return TRUE
|
|
*************************************************************/
|
|
static NDIS_STATUS NTAPI ParaNdis5_Reset(
|
|
OUT PBOOLEAN AddressingReset,
|
|
IN NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
NDIS_STATUS status;
|
|
tGeneralWorkItem *pwi;
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
|
|
DEBUG_ENTRY(0);
|
|
ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 1, 0, 0);
|
|
status = NDIS_STATUS_FAILURE;
|
|
pwi = ParaNdis_AllocateMemory(pContext, sizeof(tGeneralWorkItem));
|
|
if (pwi)
|
|
{
|
|
pwi->pContext = pContext;
|
|
NdisInitializeWorkItem(&pwi->wi, OnResetWorkItem, pwi);
|
|
if (NdisScheduleWorkItem(&pwi->wi) == NDIS_STATUS_SUCCESS)
|
|
{
|
|
status = NDIS_STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
NdisFreeMemory(pwi, 0, 0);
|
|
}
|
|
}
|
|
if (status != NDIS_STATUS_PENDING)
|
|
{
|
|
ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 0, status, 0);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*************************************************************
|
|
Callback of delayed receive pause procedure
|
|
*************************************************************/
|
|
static VOID OnReceiveStopped(VOID *p)
|
|
{
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p;
|
|
DEBUG_ENTRY(0);
|
|
NdisSetEvent(&pContext->HaltEvent);
|
|
}
|
|
|
|
/*************************************************************
|
|
Callback of delayed send pause procedure
|
|
*************************************************************/
|
|
static VOID OnSendStopped(VOID *p)
|
|
{
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p;
|
|
DEBUG_ENTRY(0);
|
|
NdisSetEvent(&pContext->HaltEvent);
|
|
}
|
|
|
|
static void WaitHaltEvent(PARANDIS_ADAPTER *pContext, const char *Reason)
|
|
{
|
|
UINT ms = 5000;
|
|
if (!NdisWaitEvent(&pContext->HaltEvent, 1))
|
|
{
|
|
while (!NdisWaitEvent(&pContext->HaltEvent, ms))
|
|
{
|
|
DPrintf(0, ("[%s]", __FUNCTION__));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*************************************************************
|
|
Required NDIS procedure
|
|
Stops TX and RX path and finished the function of adapter
|
|
*************************************************************/
|
|
static VOID NTAPI ParaNdis5_Halt(
|
|
IN NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
BOOLEAN bUnused;
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
|
|
DEBUG_ENTRY(0);
|
|
|
|
ParaNdis_DebugHistory(pContext, hopHalt, NULL, 1, 0, 0);
|
|
|
|
NdisCancelTimer(&pContext->ConnectTimer, &bUnused);
|
|
NdisResetEvent(&pContext->HaltEvent);
|
|
if (NDIS_STATUS_PENDING != ParaNdis5_StopSend(pContext, TRUE, OnSendStopped))
|
|
NdisSetEvent(&pContext->HaltEvent);
|
|
WaitHaltEvent(pContext, "Send");
|
|
NdisResetEvent(&pContext->HaltEvent);
|
|
if (NDIS_STATUS_PENDING != ParaNdis5_StopReceive(pContext, TRUE, OnReceiveStopped))
|
|
NdisSetEvent(&pContext->HaltEvent);
|
|
WaitHaltEvent(pContext, "Receive");
|
|
ParaNdis_CleanupContext(pContext);
|
|
NdisCancelTimer(&pContext->DPCPostProcessTimer, &bUnused);
|
|
ParaNdis_DebugHistory(pContext, hopHalt, NULL, 0, 0, 0);
|
|
ParaNdis_DebugRegisterMiniport(pContext, FALSE);
|
|
NdisFreeMemory(pContext, 0, 0);
|
|
DEBUG_EXIT_STATUS(0, status);
|
|
}
|
|
|
|
|
|
/*************************************************************
|
|
Called periodically (usually each 2 seconds)
|
|
*************************************************************/
|
|
static BOOLEAN NTAPI ParaNdis5_CheckForHang(IN NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
|
|
DEBUG_ENTRY(8);
|
|
return ParaNdis_CheckForHang(pContext);
|
|
}
|
|
|
|
/*************************************************************
|
|
Required NDIS procedure
|
|
Responsible for hardware interrupt handling
|
|
*************************************************************/
|
|
static VOID NTAPI ParaNdis5_MiniportISR(OUT PBOOLEAN InterruptRecognized,
|
|
OUT PBOOLEAN QueueMiniportHandleInterrupt,
|
|
IN NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
|
|
BOOLEAN b;
|
|
*QueueMiniportHandleInterrupt = FALSE;
|
|
b = ParaNdis_OnLegacyInterrupt(pContext, QueueMiniportHandleInterrupt);
|
|
*InterruptRecognized = b;
|
|
DEBUG_EXIT_STATUS(7, (ULONG)b);
|
|
}
|
|
|
|
/*************************************************************
|
|
Parameters:
|
|
|
|
Return value:
|
|
|
|
*************************************************************/
|
|
VOID NTAPI ParaNdis5_PnPEventNotify(IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN NDIS_DEVICE_PNP_EVENT PnPEvent,
|
|
IN PVOID InformationBuffer,
|
|
IN ULONG InformationBufferLength)
|
|
{
|
|
PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
|
|
ParaNdis_OnPnPEvent(pContext, PnPEvent, InformationBuffer, InformationBufferLength);
|
|
}
|
|
|
|
/*************************************************************
|
|
Driver's entry point
|
|
Parameters:
|
|
as usual
|
|
Return value:
|
|
SUCCESS or error code
|
|
*************************************************************/
|
|
NDIS_STATUS NTAPI DriverEntry(PVOID DriverObject,PVOID RegistryPath)
|
|
{
|
|
NDIS_STATUS status;
|
|
NDIS_MINIPORT_CHARACTERISTICS chars;
|
|
ParaNdis_DebugInitialize(DriverObject, RegistryPath);
|
|
|
|
status = NDIS_STATUS_FAILURE;
|
|
|
|
DEBUG_ENTRY(0);
|
|
_LogOutString(0, __DATE__ " " __TIME__);
|
|
|
|
NdisMInitializeWrapper(&DriverHandle,
|
|
DriverObject,
|
|
RegistryPath,
|
|
NULL
|
|
);
|
|
|
|
if (DriverHandle)
|
|
{
|
|
NdisZeroMemory(&chars, sizeof(chars));
|
|
//NDIS version of the miniport
|
|
chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
|
|
chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
|
|
//Init and destruction
|
|
chars.InitializeHandler = ParaNdis5_Initialize;
|
|
chars.HaltHandler = ParaNdis5_Halt;
|
|
|
|
//Interrupt and DPC handling
|
|
chars.HandleInterruptHandler = ParaNdis5_HandleDPC;
|
|
chars.ISRHandler = ParaNdis5_MiniportISR;
|
|
|
|
//Packet transfer - send path and notification on the send packet
|
|
chars.SendPacketsHandler = ParaNdis5_SendPackets;
|
|
chars.ReturnPacketHandler = ParaNdis5_ReturnPacket;
|
|
|
|
//OID set\get
|
|
chars.SetInformationHandler = ParaNdis5_SetOID;
|
|
chars.QueryInformationHandler = ParaNdis5_QueryOID;
|
|
|
|
//Reset
|
|
chars.ResetHandler = ParaNdis5_Reset;
|
|
chars.CheckForHangHandler = ParaNdis5_CheckForHang; //optional
|
|
|
|
chars.CancelSendPacketsHandler = ParaNdis5_CancelSendPackets;
|
|
chars.PnPEventNotifyHandler = ParaNdis5_PnPEventNotify;
|
|
chars.AdapterShutdownHandler = ParaNdis5_Shutdown;
|
|
|
|
status = NdisMRegisterMiniport(
|
|
DriverHandle,
|
|
&chars,
|
|
sizeof(chars));
|
|
}
|
|
|
|
if (status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
NdisMRegisterUnloadHandler(DriverHandle, ParaVirtualNICUnload);
|
|
}
|
|
else if (DriverHandle)
|
|
{
|
|
DPrintf(0, ("NdisMRegisterMiniport failed"));
|
|
NdisTerminateWrapper(DriverHandle, NULL);
|
|
}
|
|
else
|
|
{
|
|
DPrintf(0, ("NdisMInitializeWrapper failed"));
|
|
}
|
|
|
|
DEBUG_EXIT_STATUS(status ? 0 : 4, status);
|
|
return status;
|
|
}
|