mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1966 lines
50 KiB
1966 lines
50 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
mp_main.c
|
|
|
|
Abstract:
|
|
This module contains NDIS miniport handlers
|
|
|
|
Revision History:
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
DChen 11-01-99 created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#if DBG
|
|
#define _FILENUMBER "NIAM"
|
|
#endif
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, DriverEntry)
|
|
#endif
|
|
|
|
//
|
|
// Global data for LBFO
|
|
//
|
|
#if LBFO
|
|
LIST_ENTRY g_AdapterList;
|
|
NDIS_SPIN_LOCK g_Lock;
|
|
#endif
|
|
|
|
NDIS_STATUS DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to the driver object
|
|
RegistryPath - pointer to the driver registry path
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS - the value returned by NdisMRegisterMiniport
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
NDIS_HANDLE NdisWrapperHandle;
|
|
NDIS_MINIPORT_CHARACTERISTICS MPChar;
|
|
|
|
DBGPRINT(MP_TRACE, ("====> DriverEntry\n"));
|
|
|
|
//
|
|
// Notify the NDIS wrapper about this driver, get a NDIS wrapper handle back
|
|
//
|
|
NdisMInitializeWrapper(
|
|
&NdisWrapperHandle,
|
|
DriverObject,
|
|
RegistryPath,
|
|
NULL);
|
|
|
|
if (NdisWrapperHandle == NULL)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
DBGPRINT_S(Status, ("<==== DriverEntry failed to InitWrapper, Status=%x\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
#if LBFO
|
|
//
|
|
// Init the global data
|
|
//
|
|
InitializeListHead(&g_AdapterList);
|
|
NdisAllocateSpinLock(&g_Lock);
|
|
|
|
//
|
|
// For regular miniports, there is NO need to have an Unload handler
|
|
// For a LBFO miniport, register an Unload handler for global data cleanup
|
|
// The unload handler has a more global scope, whereas the scope of the
|
|
// MiniportHalt function is restricted to a particular miniport instance.
|
|
//
|
|
NdisMRegisterUnloadHandler(NdisWrapperHandle, MPUnload);
|
|
#endif
|
|
|
|
//
|
|
// Fill in the Miniport characteristics structure with the version numbers
|
|
// and the entry points for driver-supplied MiniportXxx
|
|
//
|
|
NdisZeroMemory(&MPChar, sizeof(MPChar));
|
|
|
|
MPChar.MajorNdisVersion = MP_NDIS_MAJOR_VERSION;
|
|
MPChar.MinorNdisVersion = MP_NDIS_MINOR_VERSION;
|
|
|
|
MPChar.CheckForHangHandler = MPCheckForHang;
|
|
MPChar.DisableInterruptHandler = NULL;
|
|
MPChar.EnableInterruptHandler = NULL;
|
|
MPChar.HaltHandler = MPHalt;
|
|
MPChar.InitializeHandler = MPInitialize;
|
|
MPChar.QueryInformationHandler = MPQueryInformation;
|
|
//MPChar.ReconfigureHandler = NULL;
|
|
MPChar.ResetHandler = MPReset;
|
|
MPChar.ReturnPacketHandler = MPReturnPacket;
|
|
|
|
MPChar.SendPacketsHandler = MpSendPacketsHandler;
|
|
|
|
MPChar.SetInformationHandler = MPSetInformation;
|
|
MPChar.AllocateCompleteHandler = MPAllocateComplete;
|
|
MPChar.HandleInterruptHandler = MPHandleInterrupt;
|
|
MPChar.ISRHandler = MPIsr;
|
|
|
|
#ifdef NDIS51_MINIPORT
|
|
MPChar.CancelSendPacketsHandler = MPCancelSendPackets;
|
|
MPChar.PnPEventNotifyHandler = MPPnPEventNotify;
|
|
MPChar.AdapterShutdownHandler = MPShutdown;
|
|
#endif
|
|
|
|
DBGPRINT(MP_LOUD, ("Calling NdisMRegisterMiniport...\n"));
|
|
|
|
Status = NdisMRegisterMiniport(
|
|
NdisWrapperHandle,
|
|
&MPChar,
|
|
sizeof(NDIS_MINIPORT_CHARACTERISTICS));
|
|
|
|
DBGPRINT_S(Status, ("<==== DriverEntry, Status=%x\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS MPInitialize(
|
|
OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE WrapperConfigurationContext
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
MiniportInitialize handler
|
|
|
|
Arguments:
|
|
|
|
OpenErrorStatus Not used
|
|
SelectedMediumIndex Place-holder for what media we are using
|
|
MediumArray Array of ndis media passed down to us to pick from
|
|
MediumArraySize Size of the array
|
|
MiniportAdapterHandle The handle NDIS uses to refer to us
|
|
WrapperConfigurationContext For use by NdisOpenConfiguration
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS unless something goes wrong
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PMP_ADAPTER Adapter = NULL;
|
|
NDIS_HANDLE ConfigurationHandle;
|
|
PVOID NetworkAddress;
|
|
UINT index;
|
|
UINT uiPnpCommandValue;
|
|
|
|
#if DBG
|
|
LARGE_INTEGER TS, TD, TE;
|
|
#endif
|
|
|
|
DBGPRINT(MP_TRACE, ("====> MPInitialize\n"));
|
|
|
|
#if DBG
|
|
NdisGetCurrentSystemTime(&TS);
|
|
#endif
|
|
|
|
do
|
|
{
|
|
//
|
|
// Find the media type we support
|
|
//
|
|
for (index = 0; index < MediumArraySize; ++index)
|
|
{
|
|
if (MediumArray[index] == NIC_MEDIA_TYPE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index == MediumArraySize)
|
|
{
|
|
DBGPRINT(MP_ERROR, ("Expected media (%x) is not in MediumArray.\n", NIC_MEDIA_TYPE));
|
|
Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
|
|
break;
|
|
}
|
|
|
|
*SelectedMediumIndex = index;
|
|
|
|
//
|
|
// Allocate MP_ADAPTER structure
|
|
//
|
|
Status = MpAllocAdapterBlock(&Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Adapter->AdapterHandle = MiniportAdapterHandle;
|
|
|
|
//
|
|
// Read the registry parameters
|
|
//
|
|
Status = NICReadRegParameters(
|
|
Adapter,
|
|
WrapperConfigurationContext);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Inform NDIS of the attributes of our adapter.
|
|
// This has to be done before calling NdisMRegisterXxx or NdisXxxx function
|
|
// that depends on the information supplied to NdisMSetAttributesEx
|
|
// e.g. NdisMAllocateMapRegisters
|
|
//
|
|
NdisMSetAttributesEx(
|
|
MiniportAdapterHandle,
|
|
(NDIS_HANDLE) Adapter,
|
|
0,
|
|
NDIS_ATTRIBUTE_DESERIALIZE | NDIS_ATTRIBUTE_BUS_MASTER | NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND ,
|
|
NIC_INTERFACE_TYPE);
|
|
|
|
//
|
|
// Find the physical adapter
|
|
//
|
|
Status = MpFindAdapter(Adapter, WrapperConfigurationContext);
|
|
if (Status != NDIS_STATUS_SUCCESS) break;
|
|
|
|
//
|
|
// Map bus-relative IO range to system IO space
|
|
//
|
|
Status = NdisMRegisterIoPortRange(
|
|
(PVOID *)&Adapter->PortOffset,
|
|
Adapter->AdapterHandle,
|
|
Adapter->IoBaseAddress,
|
|
Adapter->IoRange);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(MP_ERROR, ("NdisMRegisterioPortRange failed\n"));
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->AdapterHandle,
|
|
NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
|
|
0);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Read additional info from NIC such as MAC address
|
|
//
|
|
Status = NICReadAdapterInfo(Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS) break;
|
|
|
|
//
|
|
// Allocate all other memory blocks including shared memory
|
|
//
|
|
Status = NICAllocAdapterMemory(Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS) break;
|
|
|
|
//
|
|
// Init send data structures
|
|
//
|
|
NICInitSend(Adapter);
|
|
|
|
//
|
|
// Init receive data structures
|
|
//
|
|
Status = NICInitRecv(Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS) break;
|
|
|
|
// Map bus-relative registers to virtual system-space
|
|
Status = NdisMMapIoSpace(
|
|
(PVOID *) &(Adapter->CSRAddress),
|
|
Adapter->AdapterHandle,
|
|
Adapter->MemPhysAddress,
|
|
NIC_MAP_IOSPACE_LENGTH);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(MP_ERROR, ("NdisMMapIoSpace failed\n"));
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->AdapterHandle,
|
|
NDIS_ERROR_CODE_RESOURCE_CONFLICT,
|
|
1,
|
|
ERRLOG_MAP_IO_SPACE);
|
|
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(MP_INFO, ("CSRAddress="PTR_FORMAT"\n", Adapter->CSRAddress));
|
|
|
|
//
|
|
// Disable interrupts here which is as soon as possible
|
|
//
|
|
NICDisableInterrupt(Adapter);
|
|
|
|
//
|
|
// Register the interrupt
|
|
//
|
|
Status = NdisMRegisterInterrupt(
|
|
&Adapter->Interrupt,
|
|
Adapter->AdapterHandle,
|
|
Adapter->InterruptLevel,
|
|
Adapter->InterruptLevel,
|
|
TRUE, // RequestISR
|
|
TRUE, // SharedInterrupt
|
|
NIC_INTERRUPT_MODE);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(MP_ERROR, ("NdisMRegisterInterrupt failed\n"));
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->AdapterHandle,
|
|
NDIS_ERROR_CODE_INTERRUPT_CONNECT,
|
|
0);
|
|
|
|
break;
|
|
}
|
|
|
|
MP_SET_FLAG(Adapter, fMP_ADAPTER_INTERRUPT_IN_USE);
|
|
|
|
//
|
|
// Test our adapter hardware
|
|
//
|
|
Status = NICSelfTest(Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS) break;
|
|
|
|
//
|
|
// Init the hardware and set up everything
|
|
//
|
|
Status = NICInitializeAdapter(Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS) break;
|
|
|
|
#ifdef NDIS50_MINIPORT
|
|
//
|
|
// Register a shutdown handler for NDIS50 or earlier miniports
|
|
// For NDIS51 miniports, set AdapterShutdownHandler as shown above
|
|
//
|
|
NdisMRegisterAdapterShutdownHandler(
|
|
Adapter->AdapterHandle,
|
|
(PVOID) Adapter,
|
|
(ADAPTER_SHUTDOWN_HANDLER) MPShutdown);
|
|
#endif
|
|
|
|
//
|
|
// Enable the interrupt
|
|
//
|
|
NICEnableInterrupt(Adapter);
|
|
|
|
//
|
|
// Minimize init-time
|
|
//
|
|
NdisMInitializeTimer(
|
|
&Adapter->LinkDetectionTimer,
|
|
Adapter->AdapterHandle,
|
|
MpLinkDetectionDpc,
|
|
Adapter);
|
|
|
|
//
|
|
// Set the link detection flag
|
|
//
|
|
MP_SET_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION);
|
|
|
|
//
|
|
// Increment the reference count so halt handler will wait
|
|
//
|
|
MP_INC_REF(Adapter);
|
|
NdisMSetTimer(&Adapter->LinkDetectionTimer, NIC_LINK_DETECTION_DELAY);
|
|
|
|
#if LBFO
|
|
//
|
|
// Add this adapter to the global miniport list
|
|
//
|
|
MpAddAdapterToList(Adapter);
|
|
#endif
|
|
|
|
} while (FALSE);
|
|
|
|
if (Adapter && Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Undo everything if it failed
|
|
//
|
|
MP_DEC_REF(Adapter);
|
|
MpFreeAdapter(Adapter);
|
|
}
|
|
|
|
#if DBG
|
|
NdisGetCurrentSystemTime(&TE);
|
|
TD.QuadPart = TE.QuadPart - TS.QuadPart;
|
|
TD.QuadPart /= 10000; // Convert to ms
|
|
DBGPRINT(MP_WARN, ("Init time = %d ms\n", TD.LowPart));
|
|
#endif
|
|
|
|
DBGPRINT_S(Status, ("<==== MPInitialize, Status=%x\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
BOOLEAN MPCheckForHang(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportCheckForHang handler
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
TRUE This NIC needs a reset
|
|
FALSE Everything is fine
|
|
|
|
Note:
|
|
CheckForHang handler is called in the context of a timer DPC.
|
|
take advantage of this fact when acquiring/releasing spinlocks
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext;
|
|
NDIS_MEDIA_STATE CurrMediaState;
|
|
NDIS_STATUS Status;
|
|
PMP_TCB pMpTcb;
|
|
|
|
//
|
|
// Just skip this part if the adapter is doing link detection
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// any nonrecoverable hardware error?
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_NON_RECOVER_ERROR))
|
|
{
|
|
DBGPRINT(MP_WARN, ("Non recoverable error - remove\n"));
|
|
return (TRUE);
|
|
}
|
|
|
|
//
|
|
// hardware failure?
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_HARDWARE_ERROR))
|
|
{
|
|
DBGPRINT(MP_WARN, ("hardware error - reset\n"));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Is send stuck?
|
|
//
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->SendLock);
|
|
|
|
if (Adapter->nBusySend > 0)
|
|
{
|
|
pMpTcb = Adapter->CurrSendHead;
|
|
pMpTcb->Count++;
|
|
if (pMpTcb->Count > NIC_SEND_HANG_THRESHOLD)
|
|
{
|
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
|
DBGPRINT(MP_WARN, ("Send stuck - reset\n"));
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
|
NdisDprAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
//
|
|
// Update the RFD shrink count
|
|
//
|
|
if (Adapter->CurrNumRfd > Adapter->NumRfd)
|
|
{
|
|
Adapter->RfdShrinkCount++;
|
|
}
|
|
|
|
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
NdisDprAcquireSpinLock(&Adapter->Lock);
|
|
CurrMediaState = NICGetMediaState(Adapter);
|
|
|
|
if (CurrMediaState != Adapter->MediaState)
|
|
{
|
|
DBGPRINT(MP_WARN, ("Media state changed to %s\n",
|
|
((CurrMediaState == NdisMediaStateConnected)?
|
|
"Connected": "Disconnected")));
|
|
|
|
Adapter->MediaState = CurrMediaState;
|
|
Status = (CurrMediaState == NdisMediaStateConnected) ?
|
|
NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT;
|
|
if (Status == NDIS_STATUS_MEDIA_CONNECT)
|
|
{
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_NO_CABLE);
|
|
}
|
|
else
|
|
{
|
|
MP_SET_FLAG(Adapter, fMP_ADAPTER_NO_CABLE);
|
|
}
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
|
|
// Indicate the media event
|
|
NdisMIndicateStatus(Adapter->AdapterHandle, Status, (PVOID)0, 0);
|
|
|
|
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
|
|
}
|
|
else
|
|
{
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
VOID MPHalt(
|
|
IN NDIS_HANDLE MiniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportHalt handler
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bCancelled;
|
|
LONG Count;
|
|
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext;
|
|
|
|
MP_SET_FLAG(Adapter, fMP_ADAPTER_HALT_IN_PROGRESS);
|
|
|
|
DBGPRINT(MP_TRACE, ("====> MPHalt\n"));
|
|
|
|
//
|
|
// Call Shutdown handler to disable interrupt and turn the hardware off
|
|
// by issuing a full reset
|
|
//
|
|
MPShutdown(MiniportAdapterContext);
|
|
|
|
//
|
|
// Deregister interrupt as early as possible
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_INTERRUPT_IN_USE))
|
|
{
|
|
NdisMDeregisterInterrupt(&Adapter->Interrupt);
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_INTERRUPT_IN_USE);
|
|
}
|
|
|
|
#if LBFO
|
|
MpRemoveAdapterFromList(Adapter);
|
|
|
|
//
|
|
// For a regualr miniport, no send packets and OID requests should be outstanding
|
|
// when Halt handler is called. But for a LBFO miniport in secondary mode,
|
|
// some packets from primary miniport may be still around
|
|
//
|
|
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
|
|
//
|
|
// Free the packets on SendWaitList
|
|
//
|
|
MpFreeQueuedSendPackets(Adapter);
|
|
|
|
//
|
|
// Free the packets being actively sent & stopped
|
|
//
|
|
MpFreeBusySendPackets(Adapter);
|
|
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Decrement the ref count which was incremented in MPInitialize
|
|
//
|
|
Count = MP_DEC_REF(Adapter);
|
|
|
|
//
|
|
// Possible non-zero ref counts mean one or more of the following conditions:
|
|
// 1) Pending async shared memory allocation;
|
|
// 2) DPC's are not finished (e.g. link detection)
|
|
//
|
|
if (Count)
|
|
{
|
|
DBGPRINT(MP_WARN, ("RefCount=%d --- waiting!\n", MP_GET_REF(Adapter)));
|
|
|
|
while (TRUE)
|
|
{
|
|
if (NdisWaitEvent(&Adapter->ExitEvent, 2000))
|
|
{
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(MP_WARN, ("RefCount=%d --- rewaiting!\n", MP_GET_REF(Adapter)));
|
|
}
|
|
}
|
|
|
|
NdisAcquireSpinLock(&Adapter->RcvLock);
|
|
//
|
|
// wait for all the received packets to return
|
|
//
|
|
MP_DEC_RCV_REF(Adapter);
|
|
Count = MP_GET_RCV_REF(Adapter);
|
|
|
|
NdisReleaseSpinLock(&Adapter->RcvLock);
|
|
|
|
if (Count)
|
|
{
|
|
DBGPRINT(MP_WARN, ("RcvRefCount=%d --- waiting!\n", Count));
|
|
|
|
while (TRUE)
|
|
{
|
|
if (NdisWaitEvent(&Adapter->AllPacketsReturnedEvent, 2000))
|
|
{
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(MP_WARN, ("RcvRefCount=%d --- rewaiting!\n", MP_GET_RCV_REF(Adapter)));
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef NDIS50_MINIPORT
|
|
//
|
|
// Deregister shutdown handler as it's being halted
|
|
//
|
|
NdisMDeregisterAdapterShutdownHandler(Adapter->AdapterHandle);
|
|
#endif
|
|
|
|
//
|
|
// Reset the PHY chip. We do this so that after a warm boot, the PHY will
|
|
// be in a known state, with auto-negotiation enabled.
|
|
//
|
|
ResetPhy(Adapter);
|
|
|
|
//
|
|
// Free the entire adapter object, including the shared memory structures.
|
|
//
|
|
MpFreeAdapter(Adapter);
|
|
|
|
DBGPRINT(MP_TRACE, ("<==== MPHalt\n"));
|
|
}
|
|
|
|
NDIS_STATUS MPReset(
|
|
OUT PBOOLEAN AddressingReset,
|
|
IN NDIS_HANDLE MiniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportReset handler
|
|
|
|
Arguments:
|
|
|
|
AddressingReset To let NDIS know whether we need help from it with our reset
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_PENDING
|
|
NDIS_STATUS_RESET_IN_PROGRESS
|
|
NDIS_STATUS_HARD_ERRORS
|
|
|
|
Note:
|
|
ResetHandler is called at DPC. take advantage of this fact when acquiring or releasing
|
|
spinlocks
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET Packet;
|
|
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext;
|
|
BOOLEAN bDone = TRUE;
|
|
|
|
DBGPRINT(MP_TRACE, ("====> MPReset\n"));
|
|
|
|
*AddressingReset = TRUE;
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->Lock);
|
|
NdisDprAcquireSpinLock(&Adapter->SendLock);
|
|
NdisDprAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
do
|
|
{
|
|
ASSERT(!MP_TEST_FLAG(Adapter, fMP_ADAPTER_HALT_IN_PROGRESS));
|
|
|
|
//
|
|
// Is this adapter already doing a reset?
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_RESET_IN_PROGRESS))
|
|
{
|
|
Status = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
MP_EXIT;
|
|
}
|
|
|
|
MP_SET_FLAG(Adapter, fMP_ADAPTER_RESET_IN_PROGRESS);
|
|
|
|
//
|
|
// Is this adapter doing link detection?
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION))
|
|
{
|
|
DBGPRINT(MP_WARN, ("Reset is pended...\n"));
|
|
|
|
Adapter->bResetPending = TRUE;
|
|
Status = NDIS_STATUS_PENDING;
|
|
MP_EXIT;
|
|
}
|
|
//
|
|
// Is this adapter going to be removed
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_NON_RECOVER_ERROR))
|
|
{
|
|
Status = NDIS_STATUS_HARD_ERRORS;
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_REMOVE_IN_PROGRESS))
|
|
{
|
|
MP_EXIT;
|
|
}
|
|
|
|
// This is an unrecoverable hardware failure.
|
|
// We need to tell NDIS to remove this miniport
|
|
MP_SET_FLAG(Adapter, fMP_ADAPTER_REMOVE_IN_PROGRESS);
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_RESET_IN_PROGRESS);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->AdapterHandle,
|
|
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
|
1,
|
|
ERRLOG_REMOVE_MINIPORT);
|
|
|
|
NdisMRemoveMiniport(Adapter->AdapterHandle);
|
|
|
|
DBGPRINT_S(Status, ("<==== MPReset, Status=%x\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Disable the interrupt and issue a reset to the NIC
|
|
//
|
|
NICDisableInterrupt(Adapter);
|
|
NICIssueSelectiveReset(Adapter);
|
|
|
|
|
|
//
|
|
// release all the locks and then acquire back the send lock
|
|
// we are going to clean up the send queues
|
|
// which may involve calling Ndis APIs
|
|
// release all the locks before grabbing the send lock to
|
|
// avoid deadlocks
|
|
//
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->SendLock);
|
|
|
|
|
|
//
|
|
// This is a deserialized miniport, we need to free all the send packets
|
|
// Free the packets on SendWaitList
|
|
//
|
|
MpFreeQueuedSendPackets(Adapter);
|
|
|
|
//
|
|
// Free the packets being actively sent & stopped
|
|
//
|
|
MpFreeBusySendPackets(Adapter);
|
|
|
|
#if DBG
|
|
if (MP_GET_REF(Adapter) > 1)
|
|
{
|
|
DBGPRINT(MP_WARN, ("RefCount=%d\n", MP_GET_REF(Adapter)));
|
|
}
|
|
#endif
|
|
|
|
NdisZeroMemory(Adapter->MpTcbMem, Adapter->MpTcbMemSize);
|
|
|
|
//
|
|
// Re-initialize the send structures
|
|
//
|
|
NICInitSend(Adapter);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
//
|
|
// get all the locks again in the right order
|
|
//
|
|
NdisDprAcquireSpinLock(&Adapter->Lock);
|
|
NdisDprAcquireSpinLock(&Adapter->SendLock);
|
|
NdisDprAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
//
|
|
// Reset the RFD list and re-start RU
|
|
//
|
|
NICResetRecv(Adapter);
|
|
Status = NICStartRecv(Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
// Are we having failures in a few consecutive resets?
|
|
if (Adapter->HwErrCount < NIC_HARDWARE_ERROR_THRESHOLD)
|
|
{
|
|
// It's not over the threshold yet, let it to continue
|
|
Adapter->HwErrCount++;
|
|
}
|
|
else
|
|
{
|
|
// This is an unrecoverable hardware failure.
|
|
// We need to tell NDIS to remove this miniport
|
|
MP_SET_FLAG(Adapter, fMP_ADAPTER_REMOVE_IN_PROGRESS);
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_RESET_IN_PROGRESS);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->AdapterHandle,
|
|
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
|
1,
|
|
ERRLOG_REMOVE_MINIPORT);
|
|
|
|
NdisMRemoveMiniport(Adapter->AdapterHandle);
|
|
|
|
DBGPRINT_S(Status, ("<==== MPReset, Status=%x\n", Status));
|
|
return(Status);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
Adapter->HwErrCount = 0;
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_HARDWARE_ERROR);
|
|
|
|
NICEnableInterrupt(Adapter);
|
|
|
|
} while (FALSE);
|
|
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_RESET_IN_PROGRESS);
|
|
|
|
exit:
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
|
|
|
|
|
|
DBGPRINT_S(Status, ("<==== MPReset, Status=%x\n", Status));
|
|
return(Status);
|
|
}
|
|
|
|
VOID MPReturnPacket(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportReturnPacket handler
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
Packet Pointer to a packet being returned to the miniport
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Note:
|
|
ReturnPacketHandler is called at DPC. take advantage of this fact when acquiring or releasing
|
|
spinlocks
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
PMP_RFD pMpRfd = MP_GET_PACKET_RFD(Packet);
|
|
ULONG Count;
|
|
|
|
DBGPRINT(MP_TRACE, ("====> MPReturnPacket\n"));
|
|
|
|
ASSERT(pMpRfd);
|
|
|
|
ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_PEND));
|
|
MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_PEND);
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
RemoveEntryList((PLIST_ENTRY)pMpRfd);
|
|
|
|
|
|
// Decrement the Power Mgmt Ref.
|
|
Adapter->PoMgmt.OutstandingRecv --;
|
|
|
|
if (Adapter->RfdShrinkCount < NIC_RFD_SHRINK_THRESHOLD)
|
|
{
|
|
NICReturnRFD(Adapter, pMpRfd);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(Adapter->CurrNumRfd > Adapter->NumRfd);
|
|
|
|
Adapter->RfdShrinkCount = 0;
|
|
NICFreeRfd(Adapter, pMpRfd);
|
|
Adapter->CurrNumRfd--;
|
|
|
|
DBGPRINT(MP_TRACE, ("Shrink... CurrNumRfd = %d\n", Adapter->CurrNumRfd));
|
|
}
|
|
|
|
|
|
//
|
|
// note that we get the ref count here, but check
|
|
// to see if it is zero and signal the event -after-
|
|
// releasign the SpinLock. otherwise, we may let the Halthandler
|
|
// continue while we are holding a lock.
|
|
//
|
|
MP_DEC_RCV_REF(Adapter);
|
|
Count = MP_GET_RCV_REF(Adapter);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
|
|
if (Count == 0)
|
|
NdisSetEvent(&Adapter->AllPacketsReturnedEvent);
|
|
|
|
DBGPRINT(MP_TRACE, ("<==== MPReturnPacket\n"));
|
|
}
|
|
|
|
|
|
VOID MPSendPackets(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportSendPackets handler
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
PacketArray Set of packets to send
|
|
NumberOfPackets Self-explanatory
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter;
|
|
NDIS_STATUS Status;
|
|
UINT PacketCount;
|
|
|
|
|
|
#if LBFO
|
|
PMP_ADAPTER ThisAdapter;
|
|
#endif
|
|
|
|
DBGPRINT(MP_TRACE, ("====> MPSendPackets\n"));
|
|
|
|
Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
|
|
#if LBFO
|
|
NdisAcquireSpinLock(&Adapter->LockLBFO);
|
|
|
|
// Any secondary adapters?
|
|
if (Adapter->NumSecondary)
|
|
{
|
|
// In this sample driver, we do very simple load balancing ...
|
|
// Walk through the secondary miniport list, send the packets on a secondary
|
|
// miniport if it's ready
|
|
// If none of the secondary miniports is ready, we'll use the primary miniport
|
|
ThisAdapter = Adapter->NextSecondary;
|
|
while (ThisAdapter)
|
|
{
|
|
if (MP_IS_NOT_READY(ThisAdapter))
|
|
{
|
|
ThisAdapter = ThisAdapter->NextSecondary;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Found a good secondary miniport to send packets on
|
|
// Need to put a ref on this adapter so it won't go away
|
|
//
|
|
MP_LBFO_INC_REF(ThisAdapter);
|
|
NdisReleaseSpinLock(&Adapter->LockLBFO);
|
|
|
|
NdisAcquireSpinLock(&ThisAdapter->SendLock);
|
|
|
|
//
|
|
// Send these packets
|
|
//
|
|
for (PacketCount=0;PacketCount < NumberOfPackets; PacketCount++)
|
|
{
|
|
MpSendPacket(ThisAdapter, PacketArray[PacketCount], FALSE);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&ThisAdapter->SendLock);
|
|
|
|
//
|
|
// Done with this adapter for now, deref it
|
|
//
|
|
MP_LBFO_DEC_REF(ThisAdapter);
|
|
|
|
//
|
|
// Sent all the packets on a secondary miniport, return
|
|
//
|
|
return;
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->LockLBFO);
|
|
|
|
#endif
|
|
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
|
|
// Is this adapter ready for sending?
|
|
if (MP_IS_NOT_READY(Adapter))
|
|
{
|
|
//
|
|
// there is link
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION))
|
|
{
|
|
for (PacketCount = 0; PacketCount < NumberOfPackets; PacketCount++)
|
|
{
|
|
|
|
InsertTailQueue(&Adapter->SendWaitQueue,
|
|
MP_GET_PACKET_MR(PacketArray[PacketCount]));
|
|
Adapter->nWaitSend++;
|
|
DBGPRINT(MP_WARN, ("MpSendPackets: link detection - queue packet "PTR_FORMAT"\n",
|
|
PacketArray[PacketCount]));
|
|
}
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Adapter is not ready and there is not link
|
|
//
|
|
Status = MP_GET_STATUS_FROM_FLAGS(Adapter);
|
|
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
for (PacketCount = 0; PacketCount < NumberOfPackets; PacketCount++)
|
|
{
|
|
NdisMSendComplete(
|
|
MP_GET_ADAPTER_HANDLE(Adapter),
|
|
PacketArray[PacketCount],
|
|
Status);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Adapter is ready, send these packets
|
|
//
|
|
for (PacketCount = 0; PacketCount < NumberOfPackets; PacketCount++)
|
|
{
|
|
//
|
|
// queue is not empty or tcb is not available
|
|
//
|
|
if (!IsQueueEmpty(&Adapter->SendWaitQueue) ||
|
|
!MP_TCB_RESOURCES_AVAIABLE(Adapter))
|
|
{
|
|
InsertTailQueue(&Adapter->SendWaitQueue, MP_GET_PACKET_MR(PacketArray[PacketCount]));
|
|
Adapter->nWaitSend++;
|
|
}
|
|
else
|
|
{
|
|
MpSendPacket(Adapter, PacketArray[PacketCount], FALSE);
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
DBGPRINT(MP_TRACE, ("<==== MPSendPackets\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
VOID MPShutdown(
|
|
IN NDIS_HANDLE MiniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportShutdown handler
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
|
|
DBGPRINT(MP_TRACE, ("====> MPShutdown\n"));
|
|
|
|
//
|
|
// Disable interrupt and issue a full reset
|
|
//
|
|
NICDisableInterrupt(Adapter);
|
|
NICIssueFullReset(Adapter);
|
|
|
|
DBGPRINT(MP_TRACE, ("<==== MPShutdown\n"));
|
|
}
|
|
|
|
VOID MPAllocateComplete(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PVOID VirtualAddress,
|
|
IN PNDIS_PHYSICAL_ADDRESS PhysicalAddress,
|
|
IN ULONG Length,
|
|
IN PVOID Context)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportAllocateComplete handler
|
|
This handler is needed because we make calls to NdisMAllocateSharedMemoryAsync
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
VirtualAddress Pointer to the allocated memory block
|
|
PhysicalAddress Physical address of the memory block
|
|
Length Length of the memory block
|
|
Context Context in NdisMAllocateSharedMemoryAsync
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONG ErrorValue;
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
PMP_RFD pMpRfd = (PMP_RFD)Context;
|
|
|
|
DBGPRINT(MP_TRACE, ("==== MPAllocateComplete\n"));
|
|
|
|
ASSERT(pMpRfd);
|
|
ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_ALLOC_PEND));
|
|
MP_CLEAR_FLAG(pMpRfd, fMP_RFD_ALLOC_PEND);
|
|
|
|
NdisAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
//
|
|
// Is allocation successful?
|
|
//
|
|
if (VirtualAddress)
|
|
{
|
|
pMpRfd->HwRfd = (PHW_RFD) VirtualAddress;
|
|
pMpRfd->HwRfdPa = *PhysicalAddress;
|
|
|
|
ErrorValue = NICAllocRfd(Adapter, pMpRfd);
|
|
if (ErrorValue == 0)
|
|
{
|
|
// Add this RFD to the RecvList
|
|
Adapter->CurrNumRfd++;
|
|
NICReturnRFD(Adapter, pMpRfd);
|
|
|
|
ASSERT(Adapter->CurrNumRfd <= Adapter->MaxNumRfd);
|
|
DBGPRINT(MP_TRACE, ("CurrNumRfd=%d\n", Adapter->CurrNumRfd));
|
|
}
|
|
else
|
|
{
|
|
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pMpRfd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pMpRfd);
|
|
}
|
|
|
|
Adapter->bAllocNewRfd = FALSE;
|
|
MP_DEC_REF(Adapter);
|
|
|
|
if (MP_GET_REF(Adapter) == 0)
|
|
{
|
|
NdisSetEvent(&Adapter->ExitEvent);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->RcvLock);
|
|
}
|
|
|
|
VOID MPIsr(
|
|
OUT PBOOLEAN InterruptRecognized,
|
|
OUT PBOOLEAN QueueMiniportHandleInterrupt,
|
|
IN NDIS_HANDLE MiniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportIsr handler
|
|
|
|
Arguments:
|
|
|
|
InterruptRecognized TRUE on return if the interrupt comes from this NIC
|
|
QueueMiniportHandleInterrupt TRUE on return if MiniportHandleInterrupt should be called
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
|
|
DBGPRINT(MP_LOUD, ("====> MPIsr\n"));
|
|
|
|
do
|
|
{
|
|
//
|
|
// If the adapter is in low power state, then it should not
|
|
// recognize any interrupt
|
|
//
|
|
if (Adapter->CurrentPowerState > NdisDeviceStateD0)
|
|
{
|
|
*InterruptRecognized = FALSE;
|
|
*QueueMiniportHandleInterrupt = FALSE;
|
|
break;
|
|
}
|
|
//
|
|
// We process the interrupt if it's not disabled and it's active
|
|
//
|
|
if (!NIC_INTERRUPT_DISABLED(Adapter) && NIC_INTERRUPT_ACTIVE(Adapter))
|
|
{
|
|
*InterruptRecognized = TRUE;
|
|
*QueueMiniportHandleInterrupt = TRUE;
|
|
|
|
//
|
|
// Disable the interrupt (will be re-enabled in MPHandleInterrupt
|
|
//
|
|
NICDisableInterrupt(Adapter);
|
|
}
|
|
else
|
|
{
|
|
*InterruptRecognized = FALSE;
|
|
*QueueMiniportHandleInterrupt = FALSE;
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
DBGPRINT(MP_LOUD, ("<==== MPIsr\n"));
|
|
}
|
|
|
|
|
|
VOID MPHandleInterrupt(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportHandleInterrupt handler
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
USHORT IntStatus;
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Acknowledge the interrupt(s) and get the interrupt status
|
|
//
|
|
NIC_ACK_INTERRUPT(Adapter, IntStatus);
|
|
|
|
// Handle receive interrupt
|
|
//
|
|
// if we have a Recv interrupt and have reported a media disconnect status
|
|
// time to indicate the new status
|
|
//
|
|
|
|
if (NdisMediaStateDisconnected == Adapter->MediaState)
|
|
{
|
|
DBGPRINT(MP_WARN, ("Media state changed to Connected\n"));
|
|
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_NO_CABLE);
|
|
|
|
Adapter->MediaState = NdisMediaStateConnected;
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
//
|
|
// Indicate the media event
|
|
//
|
|
NdisMIndicateStatus(Adapter->AdapterHandle, NDIS_STATUS_MEDIA_CONNECT, (PVOID)0, 0);
|
|
|
|
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
}
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
MpHandleRecvInterrupt(Adapter);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
|
|
//
|
|
// Handle send interrupt
|
|
//
|
|
NdisDprAcquireSpinLock(&Adapter->SendLock);
|
|
|
|
MpHandleSendInterrupt(Adapter);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
//
|
|
// Start the receive unit if it had stopped
|
|
//
|
|
NdisDprAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
NICStartRecv(Adapter);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
|
|
|
|
//
|
|
// Re-enable the interrupt (disabled in MPIsr)
|
|
//
|
|
NdisMSynchronizeWithInterrupt(
|
|
&Adapter->Interrupt,
|
|
NICEnableInterrupt,
|
|
Adapter);
|
|
}
|
|
|
|
#ifdef NDIS51_MINIPORT
|
|
VOID MPCancelSendPackets(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PVOID CancelId)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportCancelSendpackets handler - NDIS51 and later
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
CancelId All the packets with this Id should be cancelled
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PQUEUE_ENTRY pEntry, pPrevEntry, pNextEntry;
|
|
PNDIS_PACKET Packet;
|
|
PVOID PacketId;
|
|
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
|
|
DBGPRINT(MP_TRACE, ("====> MPCancelSendPackets\n"));
|
|
|
|
pPrevEntry = NULL;
|
|
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
|
|
//
|
|
// Walk through the send wait queue and complete the sends with matching Id
|
|
//
|
|
pEntry = Adapter->SendWaitQueue.Head;
|
|
|
|
while (pEntry)
|
|
{
|
|
Packet = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
|
|
|
|
PacketId = NdisGetPacketCancelId(Packet);
|
|
if (PacketId == CancelId)
|
|
{
|
|
Adapter->nWaitSend--;
|
|
|
|
//
|
|
// This packet has the right CancelId
|
|
//
|
|
pNextEntry = pEntry->Next;
|
|
|
|
if (pPrevEntry == NULL)
|
|
{
|
|
Adapter->SendWaitQueue.Head = pNextEntry;
|
|
if (pNextEntry == NULL)
|
|
{
|
|
Adapter->SendWaitQueue.Tail = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPrevEntry->Next = pNextEntry;
|
|
if (pNextEntry == NULL)
|
|
{
|
|
Adapter->SendWaitQueue.Tail = pPrevEntry;
|
|
}
|
|
}
|
|
|
|
pEntry = pEntry->Next;
|
|
|
|
// Put this packet on SendCancelQueue
|
|
InsertTailQueue(&Adapter->SendCancelQueue, MP_GET_PACKET_MR(Packet));
|
|
Adapter->nCancelSend++;
|
|
}
|
|
else
|
|
{
|
|
// This packet doesn't have the right CancelId
|
|
pPrevEntry = pEntry;
|
|
pEntry = pEntry->Next;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the packets from SendCancelQueue and complete them if any
|
|
//
|
|
while (!IsQueueEmpty(&Adapter->SendCancelQueue))
|
|
{
|
|
pEntry = RemoveHeadQueue(&Adapter->SendCancelQueue);
|
|
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
ASSERT(pEntry);
|
|
Packet = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
|
|
|
|
NdisMSendComplete(
|
|
MP_GET_ADAPTER_HANDLE(Adapter),
|
|
Packet,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
DBGPRINT(MP_TRACE, ("<==== MPCancelSendPackets\n"));
|
|
|
|
}
|
|
|
|
VOID MPPnPEventNotify(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN NDIS_DEVICE_PNP_EVENT PnPEvent,
|
|
IN PVOID InformationBuffer,
|
|
IN ULONG InformationBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MiniportPnPEventNotify handler - NDIS51 and later
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
PnPEvent Self-explanatory
|
|
InformationBuffer Self-explanatory
|
|
InformationBufferLength Self-explanatory
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
|
|
DBGPRINT(MP_TRACE, ("====> MPPnPEventNotify\n"));
|
|
|
|
switch (PnPEvent)
|
|
{
|
|
case NdisDevicePnPEventQueryRemoved:
|
|
DBGPRINT(MP_WARN, ("MPPnPEventNotify: NdisDevicePnPEventQueryRemoved\n"));
|
|
break;
|
|
|
|
case NdisDevicePnPEventRemoved:
|
|
DBGPRINT(MP_WARN, ("MPPnPEventNotify: NdisDevicePnPEventRemoved\n"));
|
|
break;
|
|
|
|
case NdisDevicePnPEventSurpriseRemoved:
|
|
DBGPRINT(MP_WARN, ("MPPnPEventNotify: NdisDevicePnPEventSurpriseRemoved\n"));
|
|
break;
|
|
|
|
case NdisDevicePnPEventQueryStopped:
|
|
DBGPRINT(MP_WARN, ("MPPnPEventNotify: NdisDevicePnPEventQueryStopped\n"));
|
|
break;
|
|
|
|
case NdisDevicePnPEventStopped:
|
|
DBGPRINT(MP_WARN, ("MPPnPEventNotify: NdisDevicePnPEventStopped\n"));
|
|
break;
|
|
|
|
case NdisDevicePnPEventPowerProfileChanged:
|
|
DBGPRINT(MP_WARN, ("MPPnPEventNotify: NdisDevicePnPEventPowerProfileChanged\n"));
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT(MP_ERROR, ("MPPnPEventNotify: unknown PnP event %x \n", PnPEvent));
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(MP_TRACE, ("<==== MPPnPEventNotify\n"));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if LBFO
|
|
VOID MPUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The Unload handler
|
|
This handler is registered through NdisMRegisterUnloadHandler
|
|
|
|
Arguments:
|
|
|
|
DriverObject Not used
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ASSERT(IsListEmpty(&g_AdapterList));
|
|
|
|
NdisFreeSpinLock(&g_Lock);
|
|
}
|
|
|
|
VOID MpAddAdapterToList(
|
|
IN PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function adds a new adapter to the global adapter list
|
|
1. Not part of bundle (primary) if BundleId string is empty
|
|
2. Primary if no adapter with the same BundleId
|
|
3. Secondary if there is already one adapter with the same BundleId
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PMP_ADAPTER ThisAdapter;
|
|
PMP_ADAPTER PrimaryAdapter = NULL;
|
|
|
|
DBGPRINT(MP_WARN, ("Add adapter "PTR_FORMAT" ...", Adapter));
|
|
|
|
//
|
|
// Set the primary adapter to itself by default
|
|
//
|
|
Adapter->PrimaryAdapter = Adapter;
|
|
|
|
//
|
|
// Is this adapter part of a bundle? Just insert it in the list if not
|
|
//
|
|
if (Adapter->BundleId.Length == 0)
|
|
{
|
|
DBGPRINT_RAW(MP_WARN, ("not in a bundle\n"));
|
|
NdisInterlockedInsertTailList(&g_AdapterList, &Adapter->List, &g_Lock);
|
|
return;
|
|
}
|
|
|
|
NdisAllocateSpinLock(&Adapter->LockLBFO);
|
|
|
|
do
|
|
{
|
|
NdisAcquireSpinLock(&g_Lock);
|
|
|
|
//
|
|
// Search for the primary adapter if it exists.
|
|
// Skip searching if the list is empty
|
|
//
|
|
if (IsListEmpty(&g_AdapterList))
|
|
{
|
|
DBGPRINT_RAW(MP_WARN, ("Primary\n"));
|
|
break;
|
|
}
|
|
|
|
ThisAdapter = (PMP_ADAPTER)GetListHeadEntry(&g_AdapterList);
|
|
|
|
while ((PLIST_ENTRY)ThisAdapter != &g_AdapterList)
|
|
{
|
|
if (!MP_TEST_FLAG(ThisAdapter, fMP_ADAPTER_SECONDARY) &&
|
|
ThisAdapter->BundleId.Length == Adapter->BundleId.Length)
|
|
{
|
|
if (NdisEqualMemory(ThisAdapter->BundleId.Buffer,
|
|
Adapter->BundleId.Buffer, Adapter->BundleId.Length))
|
|
{
|
|
PrimaryAdapter = ThisAdapter;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ThisAdapter = (PMP_ADAPTER)GetListFLink((PLIST_ENTRY)ThisAdapter);
|
|
}
|
|
|
|
//
|
|
// Does a primary adapter exist? If not, this adapter will be primary.
|
|
//
|
|
if (PrimaryAdapter == NULL)
|
|
{
|
|
DBGPRINT_RAW(MP_WARN, ("Primary\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Found the primary adapter, so set this adapter as secondary
|
|
// Put a ref on the primary adapter so it won't go away while
|
|
// we are calling NdisMSetMiniportSecondary.
|
|
//
|
|
MP_LBFO_INC_REF(PrimaryAdapter);
|
|
|
|
NdisReleaseSpinLock(&g_Lock);
|
|
|
|
//
|
|
// We found the primary adapter with the same BundleIdentifier string
|
|
// Set this adapter as scondary
|
|
//
|
|
Status = NdisMSetMiniportSecondary(
|
|
Adapter->AdapterHandle,
|
|
PrimaryAdapter->AdapterHandle);
|
|
|
|
ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
|
|
NdisAcquireSpinLock(&g_Lock);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
MP_SET_FLAG(Adapter, fMP_ADAPTER_SECONDARY);
|
|
Adapter->PrimaryAdapter = PrimaryAdapter;
|
|
|
|
DBGPRINT_RAW(MP_WARN, ("Secondary, use primary adapter "PTR_FORMAT"\n",
|
|
PrimaryAdapter));
|
|
|
|
//
|
|
// Add this to the end of primary's secondary miniport list
|
|
//
|
|
NdisAcquireSpinLock(&PrimaryAdapter->LockLBFO);
|
|
|
|
PrimaryAdapter->NumSecondary++;
|
|
ThisAdapter = PrimaryAdapter;
|
|
while (ThisAdapter->NextSecondary)
|
|
{
|
|
ThisAdapter = ThisAdapter->NextSecondary;
|
|
}
|
|
ThisAdapter->NextSecondary = Adapter;
|
|
|
|
NdisReleaseSpinLock(&PrimaryAdapter->LockLBFO);
|
|
}
|
|
|
|
MP_LBFO_DEC_REF(PrimaryAdapter);
|
|
|
|
} while (FALSE);
|
|
|
|
InsertTailList(&g_AdapterList, &Adapter->List);
|
|
|
|
NdisReleaseSpinLock(&g_Lock);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID MpRemoveAdapterFromList(
|
|
IN PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function removes the adapter from the global adapter list
|
|
1. Not part of bundle (primary) if BundleId string is empty
|
|
2. Secondary - Remove it from primary's secondary adapter list
|
|
3. Primary - If a secondary adapter exists, promote the secondary
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER PrimaryAdapter;
|
|
PMP_ADAPTER ThisAdapter;
|
|
|
|
DBGPRINT(MP_WARN, ("Remove adapter "PTR_FORMAT" ...", Adapter));
|
|
|
|
ASSERT(!IsListEmpty(&g_AdapterList));
|
|
|
|
//
|
|
// Is this adapter part of a bundle? Just remove it if not
|
|
//
|
|
if (Adapter->BundleId.Length == 0)
|
|
{
|
|
DBGPRINT_RAW(MP_WARN, ("not in a bundle\n"));
|
|
|
|
NdisAcquireSpinLock(&g_Lock);
|
|
RemoveEntryList(&Adapter->List);
|
|
NdisReleaseSpinLock(&g_Lock);
|
|
return;
|
|
}
|
|
|
|
NdisAcquireSpinLock(&g_Lock);
|
|
|
|
//
|
|
// Check to see if it's secondary adapter, need to remove it from primary
|
|
// adapter's secondary list so the primary adapter won't pass more packets
|
|
// to this adapter
|
|
//
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_SECONDARY))
|
|
{
|
|
//
|
|
// This is a secondary adapter
|
|
//
|
|
PrimaryAdapter = Adapter->PrimaryAdapter;
|
|
|
|
DBGPRINT_RAW(MP_WARN, ("Secondary, primary adapter = "PTR_FORMAT"\n",
|
|
PrimaryAdapter));
|
|
|
|
NdisAcquireSpinLock(&PrimaryAdapter->LockLBFO);
|
|
|
|
//
|
|
// Remove it from the primary's secondary miniport list
|
|
//
|
|
ThisAdapter = PrimaryAdapter;
|
|
while (ThisAdapter)
|
|
{
|
|
if (ThisAdapter->NextSecondary == Adapter)
|
|
{
|
|
ThisAdapter->NextSecondary = Adapter->NextSecondary;
|
|
PrimaryAdapter->NumSecondary--;
|
|
break;
|
|
}
|
|
|
|
ThisAdapter = ThisAdapter->NextSecondary;
|
|
}
|
|
|
|
NdisReleaseSpinLock(&PrimaryAdapter->LockLBFO);
|
|
|
|
//
|
|
// Remove this adapter from the list
|
|
//
|
|
RemoveEntryList(&Adapter->List);
|
|
}
|
|
|
|
//
|
|
// Need to wait for the ref count to be zero ...
|
|
// For a primary adapter, non-zero ref count means one or more adapters are
|
|
// trying to become this adapter's secondary adapters
|
|
// For a secondary adapter, non-zero ref count means the primary is actively
|
|
// sending some packets on this adapter
|
|
//
|
|
while (TRUE)
|
|
{
|
|
if (MP_LBFO_GET_REF(Adapter) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NdisReleaseSpinLock(&g_Lock);
|
|
NdisMSleep(100);
|
|
NdisAcquireSpinLock(&g_Lock);
|
|
}
|
|
|
|
if (!MP_TEST_FLAG(Adapter, fMP_ADAPTER_SECONDARY))
|
|
{
|
|
//
|
|
// Remove this adapter from the list
|
|
//
|
|
RemoveEntryList(&Adapter->List);
|
|
|
|
DBGPRINT_RAW(MP_WARN, ("Primary\n"));
|
|
if (Adapter->NumSecondary > 0)
|
|
{
|
|
//
|
|
// Promote a secondary adapter
|
|
//
|
|
MpPromoteSecondary(Adapter);
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&g_Lock);
|
|
|
|
NdisFreeSpinLock(&Adapter->LockLBFO);
|
|
}
|
|
|
|
VOID MpPromoteSecondary(
|
|
IN PMP_ADAPTER Adapter)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function promotes a secondary miniport and sets up this new primary's
|
|
secondary adapter list
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PMP_ADAPTER ThisAdapter, FirstSecondary;
|
|
PMP_ADAPTER PromoteAdapter = NULL;
|
|
|
|
//
|
|
// Promote a secondary adapter
|
|
//
|
|
ThisAdapter = Adapter->NextSecondary;
|
|
while (ThisAdapter)
|
|
{
|
|
DBGPRINT(MP_WARN, ("Promote adapter "PTR_FORMAT"\n", ThisAdapter));
|
|
|
|
Status = NdisMPromoteMiniport(ThisAdapter->AdapterHandle);
|
|
ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
PromoteAdapter = ThisAdapter;
|
|
MP_CLEAR_FLAG(PromoteAdapter, fMP_ADAPTER_SECONDARY);
|
|
break;
|
|
}
|
|
|
|
ThisAdapter = ThisAdapter->NextSecondary;
|
|
}
|
|
|
|
if (PromoteAdapter)
|
|
{
|
|
//
|
|
// Remove the new primary from old primary's secondary miniport list
|
|
//
|
|
NdisAcquireSpinLock(&Adapter->LockLBFO);
|
|
ThisAdapter = Adapter;
|
|
while (ThisAdapter)
|
|
{
|
|
if (ThisAdapter->NextSecondary == PromoteAdapter)
|
|
{
|
|
ThisAdapter->NextSecondary = PromoteAdapter->NextSecondary;
|
|
Adapter->NumSecondary--;
|
|
break;
|
|
}
|
|
|
|
ThisAdapter = ThisAdapter->NextSecondary;
|
|
}
|
|
NdisReleaseSpinLock(&Adapter->LockLBFO);
|
|
|
|
//
|
|
// Set all adapters in the bundle to use the new primary
|
|
//
|
|
PromoteAdapter->PrimaryAdapter = PromoteAdapter;
|
|
while (ThisAdapter)
|
|
{
|
|
ThisAdapter->PrimaryAdapter = PromoteAdapter;
|
|
ThisAdapter = ThisAdapter->NextSecondary;
|
|
}
|
|
|
|
//
|
|
// Set the new primary's secondary miniport list
|
|
//
|
|
NdisAcquireSpinLock(&PromoteAdapter->LockLBFO);
|
|
PromoteAdapter->NextSecondary = Adapter->NextSecondary;
|
|
PromoteAdapter->NumSecondary = Adapter->NumSecondary;
|
|
NdisReleaseSpinLock(&PromoteAdapter->LockLBFO);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This shouldn't happen!
|
|
// Set each secondary's primary to point to itself
|
|
//
|
|
DBGPRINT(MP_ERROR, ("Failed to promote any seconday adapter\n"));
|
|
ASSERT(FALSE);
|
|
|
|
ThisAdapter = Adapter->NextSecondary;
|
|
while (ThisAdapter)
|
|
{
|
|
ThisAdapter->PrimaryAdapter = ThisAdapter;
|
|
ThisAdapter = ThisAdapter->NextSecondary;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|