2020-09-30 17:12:29 +02:00

4600 lines
99 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
wd.c
Abstract:
This is the main file for the Western Digital
Ethernet controller. This driver conforms to the NDIS 3.1 interface.
Author:
Sean Selitrennikoff (SeanSe) 15-Jan-1992
Environment:
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
Revision History:
--*/
#include <ndis.h>
#include <efilter.h>
#include <wdhrd.h>
#include <wdlmireg.h>
#include <wdlmi.h>
#include <wdsft.h>
#include "keywords.h"
#if DBG
#define STATIC
#else
#define STATIC static
#endif
static UCHAR WdBroadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#if DBG
#define LOGSIZE 512
extern UCHAR WdDebugLog[LOGSIZE] = {0};
extern UINT WdDebugLogPlace = 0;
extern
VOID
LOG (UCHAR A) {
WdDebugLog[WdDebugLogPlace++] = A;
WdDebugLog[(WdDebugLogPlace + 4) % LOGSIZE] = '\0';
if (WdDebugLogPlace >= LOGSIZE) WdDebugLogPlace = 0;
}
ULONG WdDebugFlag= WD_DEBUG_LOG; // WD_DEBUG_LOG | WD_DEBUG_LOUD | WD_DEBUG_VERY_LOUD;
#define IF_LOG(A) A
#else
#define IF_LOG(A)
#endif
//
// This constant is used for places where NdisAllocateMemory
// needs to be called and the HighestAcceptableAddress does
// not matter.
//
NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
//
// The global MAC block.
//
extern MAC_BLOCK WdMacBlock={0};
//
// If you add to this, make sure to add the
// a case in WdFillInGlobalData() and in
// WdQueryGlobalStatistics() if global
// information only or
// WdQueryProtocolStatistics() if it is
// protocol queriable information.
//
UINT WdGlobalSupportedOids[] = {
OID_GEN_SUPPORTED_LIST,
OID_GEN_HARDWARE_STATUS,
OID_GEN_MEDIA_SUPPORTED,
OID_GEN_MEDIA_IN_USE,
OID_GEN_MAXIMUM_LOOKAHEAD,
OID_GEN_MAXIMUM_FRAME_SIZE,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_MAC_OPTIONS,
OID_GEN_PROTOCOL_OPTIONS,
OID_GEN_LINK_SPEED,
OID_GEN_TRANSMIT_BUFFER_SPACE,
OID_GEN_RECEIVE_BUFFER_SPACE,
OID_GEN_TRANSMIT_BLOCK_SIZE,
OID_GEN_RECEIVE_BLOCK_SIZE,
OID_GEN_VENDOR_ID,
OID_GEN_VENDOR_DESCRIPTION,
OID_GEN_DRIVER_VERSION,
OID_GEN_CURRENT_PACKET_FILTER,
OID_GEN_CURRENT_LOOKAHEAD,
OID_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
OID_802_3_MAXIMUM_LIST_SIZE,
OID_802_3_RCV_ERROR_ALIGNMENT,
OID_802_3_XMIT_ONE_COLLISION,
OID_802_3_XMIT_MORE_COLLISIONS
};
//
// If you add to this, make sure to add the
// a case in WdQueryGlobalStatistics() and in
// WdQueryProtocolInformation()
//
UINT WdProtocolSupportedOids[] = {
OID_GEN_SUPPORTED_LIST,
OID_GEN_HARDWARE_STATUS,
OID_GEN_MEDIA_SUPPORTED,
OID_GEN_MEDIA_IN_USE,
OID_GEN_MAXIMUM_LOOKAHEAD,
OID_GEN_MAXIMUM_FRAME_SIZE,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_MAC_OPTIONS,
OID_GEN_PROTOCOL_OPTIONS,
OID_GEN_LINK_SPEED,
OID_GEN_TRANSMIT_BUFFER_SPACE,
OID_GEN_RECEIVE_BUFFER_SPACE,
OID_GEN_TRANSMIT_BLOCK_SIZE,
OID_GEN_RECEIVE_BLOCK_SIZE,
OID_GEN_VENDOR_ID,
OID_GEN_VENDOR_DESCRIPTION,
OID_GEN_DRIVER_VERSION,
OID_GEN_CURRENT_PACKET_FILTER,
OID_GEN_CURRENT_LOOKAHEAD,
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
OID_802_3_MAXIMUM_LIST_SIZE
};
UINT
WdCopyOver(
OUT PUCHAR Buf, // destination
IN PNDIS_PACKET Packet, // source packet
IN UINT Offset, // offset in packet
IN UINT Length // number of bytes to copy
);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
#pragma NDIS_INIT_FUNCTION(DriverEntry)
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the transfer address of the driver. It initializes
WdMacBlock and calls NdisInitializeWrapper() and
NdisRegisterMac().
Arguments:
Return Value:
Indicates the success or failure of the initialization.
--*/
{
PMAC_BLOCK NewMacP = &WdMacBlock;
NDIS_STATUS Status;
NDIS_HANDLE NdisWrapperHandle;
#ifdef NDIS_NT
NDIS_STRING MacName = NDIS_STRING_CONST("Smc8000n");
#endif
#ifdef NDIS_WIN
NDIS_STRING MacName = NDIS_STRING_CONST("SMC8000W");
#endif
#if NDIS_WIN
UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + 8 * sizeof (USHORT)];
#endif
#if NDIS_WIN
((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=0;
((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=9;
*((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 0)=CNFG_ID_8003E;
*((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 1)=CNFG_ID_8003S;
*((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 2)=CNFG_ID_8003W;
*((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 3)=CNFG_ID_BISTRO03E;
*((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 4)=CNFG_ID_8013E;
*((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 5)=CNFG_ID_8013W;
*((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 6)=CNFG_ID_BISTRO13E;
*((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 7)=CNFG_ID_BISTRO13W;
(PVOID) DriverObject = (PVOID) pIds;
#endif
//
// Ensure that the MAC_RESERVED structure will fit in the
// MacReserved section of a packet.
//
ASSERT(sizeof(MAC_RESERVED) <= sizeof(((PNDIS_PACKET)NULL)->MacReserved));
//
// Pass the wrapper a pointer to the device object.
//
NdisInitializeWrapper(&NdisWrapperHandle,
DriverObject,
RegistryPath,
NULL
);
//
// Set up the driver object.
//
NewMacP->DriverObject = DriverObject;
NdisAllocateSpinLock(&NewMacP->SpinLock);
NewMacP->NdisWrapperHandle = NdisWrapperHandle;
NewMacP->Unloading = FALSE;
NewMacP->NumAdapters = 0;
NewMacP->AdapterQueue = (PWD_ADAPTER)NULL;
//
// Prepare to call NdisRegisterMac.
//
NewMacP->MacCharacteristics.MajorNdisVersion = WD_NDIS_MAJOR_VERSION;
NewMacP->MacCharacteristics.MinorNdisVersion = WD_NDIS_MINOR_VERSION;
NewMacP->MacCharacteristics.Reserved = 0;
NewMacP->MacCharacteristics.OpenAdapterHandler = WdOpenAdapter;
NewMacP->MacCharacteristics.CloseAdapterHandler = WdCloseAdapter;
NewMacP->MacCharacteristics.SendHandler = WdSend;
NewMacP->MacCharacteristics.TransferDataHandler = WdTransferData;
NewMacP->MacCharacteristics.ResetHandler = WdReset;
NewMacP->MacCharacteristics.RequestHandler = WdRequest;
NewMacP->MacCharacteristics.QueryGlobalStatisticsHandler =
WdQueryGlobalStatistics;
NewMacP->MacCharacteristics.UnloadMacHandler = WdUnload;
NewMacP->MacCharacteristics.AddAdapterHandler = WdAddAdapter;
NewMacP->MacCharacteristics.RemoveAdapterHandler = WdRemoveAdapter;
NewMacP->MacCharacteristics.Name = MacName;
NdisRegisterMac(&Status,
&NewMacP->NdisMacHandle,
NdisWrapperHandle,
(NDIS_HANDLE)&WdMacBlock,
&NewMacP->MacCharacteristics,
sizeof(NewMacP->MacCharacteristics));
if (Status != NDIS_STATUS_SUCCESS) {
//
// NdisRegisterMac failed.
//
NdisFreeSpinLock(&NewMacP->SpinLock);
NdisTerminateWrapper(NdisWrapperHandle, NULL);
IF_LOUD( DbgPrint( "NdisRegisterMac failed with code 0x%x\n", Status );)
return Status;
}
IF_LOUD( DbgPrint( "NdisRegisterMac succeeded\n" );)
IF_LOUD( DbgPrint("Adapter Initialization Complete\n");)
return Status;
}
#pragma NDIS_INIT_FUNCTION(WdAddAdapter)
NDIS_STATUS
WdAddAdapter(
IN NDIS_HANDLE MacMacContext,
IN NDIS_HANDLE ConfigurationHandle,
IN PNDIS_STRING AdapterName
)
/*++
Routine Description:
This is the Wd MacAddAdapter routine. The system calls this routine
to add support for a particular WD adapter. This routine extracts
configuration information from the configuration data base and registers
the adapter with NDIS.
Arguments:
see NDIS 3.0 spec...
Return Value:
NDIS_STATUS_SUCCESS - Adapter was successfully added.
NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered.
--*/
{
LM_STATUS LmStatus;
NDIS_HANDLE ConfigHandle;
PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
NDIS_STRING IOAddressStr = IOBASE;
NDIS_STRING MaxMulticastListStr = MAXMULTICASTLIST;
NDIS_STRING NetworkAddressStr = NETADDRESS;
NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
NDIS_STRING MediaTypeStr = NDIS_STRING_CONST("MediaType");
NDIS_STRING MaxPacketSizeStr = NDIS_STRING_CONST("MaximumPacketSize");
NDIS_STRING InterruptStr = INTERRUPT;
NDIS_STRING MemoryBaseAddrStr = MEMMAPPEDBASEADDRESS;
ULONG ConfigErrorValue = 0;
BOOLEAN ConfigError = FALSE;
USHORT WdIoBaseAddr = DEFAULT_IOBASEADDR;
UCHAR WdBusType = 0; // AT bus, 1 == MCA;
UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS] = {0x00};
PVOID NetAddress;
ULONG Length;
UINT MaxMulticastList = DEFAULT_MULTICASTLISTMAX;
PMAC_BLOCK NewMacP = &WdMacBlock;
NDIS_STATUS Status;
PWD_ADAPTER Adapter;
NDIS_ADAPTER_INFORMATION AdapterInformation; // needed to register adapter
UNREFERENCED_PARAMETER(MacMacContext);
NdisOpenConfiguration(
&Status,
&ConfigHandle,
ConfigurationHandle
);
if (Status != NDIS_STATUS_SUCCESS) {
return NDIS_STATUS_FAILURE;
}
//
// Read MaxMulticastList
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&MaxMulticastListStr,
NdisParameterInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
}
//
// Read Bus Type
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&BusTypeStr,
NdisParameterHexInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
if (ReturnedValue->ParameterData.IntegerData == NdisInterfaceMca) {
WdBusType = 1;
} else {
WdBusType = 0;
}
}
//
// Read Io Base Address (if Appropriate)
//
if (WdBusType != 1) {
//
// Read I/O Address
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&IOAddressStr,
NdisParameterHexInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
WdIoBaseAddr = (USHORT)(ReturnedValue->ParameterData.IntegerData);
}
}
//
// Read net address
//
NdisReadNetworkAddress(
&Status,
&NetAddress,
&Length,
ConfigHandle
);
if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
ETH_COPY_NETWORK_ADDRESS(
CurrentAddress,
NetAddress
);
}
RegisterAdapter:
//
// Allocate memory for the adapter block now.
//
Status = NdisAllocateMemory( (PVOID *)&Adapter, sizeof(WD_ADAPTER), 0, HighestAcceptableMax);
if (Status != NDIS_STATUS_SUCCESS) {
ConfigError = TRUE;
ConfigErrorValue = NDIS_ERROR_CODE_OUT_OF_RESOURCES;
goto RegisterAdapter;
}
NdisZeroMemory(Adapter,sizeof(WD_ADAPTER));
if (!ConfigError && (WdBusType == 1)) {
if (LM_Get_Mca_Io_Base_Address(
&(Adapter->LMAdapter),
ConfigurationHandle,
&WdIoBaseAddr
)) {
WdIoBaseAddr = 0;
ConfigError = TRUE;
ConfigErrorValue = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
}
}
//
// The adapter is initialized, register it with NDIS.
// This must occur before interrupts are enabled since the
// InitializeInterrupt routine requires the NdisAdapterHandle
//
//
// Set up the AdapterInformation structure; zero it
// first in case it is extended later.
//
NdisZeroMemory (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
AdapterInformation.AdapterType = (WdBusType == 1)?
NdisInterfaceMca:
NdisInterfaceIsa;
AdapterInformation.NumberOfPortDescriptors = 1;
AdapterInformation.PortDescriptors[0].InitialPort = (ULONG)WdIoBaseAddr;
AdapterInformation.PortDescriptors[0].NumberOfPorts = 0x20;
Status = NdisRegisterAdapter(&Adapter->LMAdapter.NdisAdapterHandle,
WdMacBlock.NdisMacHandle,
(NDIS_HANDLE)Adapter,
ConfigurationHandle,
AdapterName,
&AdapterInformation
);
if (Status != NDIS_STATUS_SUCCESS) {
//
// NdisRegisterAdapter failed.
//
NdisCloseConfiguration(ConfigHandle);
NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
return NDIS_STATUS_FAILURE;
}
if (ConfigError) {
//
// Log Error and exit.
//
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
ConfigErrorValue,
1
);
NdisCloseConfiguration(ConfigHandle);
NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
return(NDIS_STATUS_FAILURE);
}
Adapter->LMAdapter.io_base = WdIoBaseAddr;
Adapter->LMAdapter.bus_type = WdBusType;
LmStatus = LM_Get_Config(&(Adapter->LMAdapter));
if (LmStatus == ADAPTER_NOT_FOUND) {
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
0
);
NdisCloseConfiguration(ConfigHandle);
NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
return(NDIS_STATUS_FAILURE);
}
if (LmStatus == ADAPTER_NO_CONFIG) {
//
// Read any information from the registry which might help
//
//
// Read Interrupt
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&InterruptStr,
NdisParameterInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
Adapter->LMAdapter.irq_value = (USHORT)(ReturnedValue->ParameterData.IntegerData);
}
//
// Read MemoryBaseAddress
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&MemoryBaseAddrStr,
NdisParameterHexInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
#if NDIS_NT
Adapter->LMAdapter.ram_base = (ULONG)(ReturnedValue->ParameterData.IntegerData);
#else
Adapter->LMAdapter.ram_base = (ULONG)((ReturnedValue->ParameterData.IntegerData) << 4);
#endif
}
}
NdisCloseConfiguration(ConfigHandle);
if (WdRegisterAdapter(Adapter,
DEFAULT_NUMBUFFERS,
MaxMulticastList,
CurrentAddress
)
!= NDIS_STATUS_SUCCESS) {
//
// WdRegisterAdapter failed.
//
NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
return NDIS_STATUS_FAILURE;
}
IF_LOUD( DbgPrint( "WdRegisterAdapter succeeded\n" );)
return NDIS_STATUS_SUCCESS;
}
#pragma NDIS_INIT_FUNCTION(WdRegisterAdapter)
NDIS_STATUS
WdRegisterAdapter(
IN PWD_ADAPTER Adapter,
IN UINT NumBuffers,
IN UINT MulticastListMax,
IN UCHAR NodeAddress[ETH_LENGTH_OF_ADDRESS]
)
/*++
Routine Description:
Called when a new adapter should be registered. It allocates space for
the adapter and open blocks, initializes the adapters block, and
calls NdisRegisterAdapter().
Arguments:
Adapter - A pointer to the adapter structure.
NumBuffers - Number of transmit buffers.
MulticastListMax - Number of multicast list addresses allowed.
NodeAddress - Ethernet address for this adapter. if all 0x00 then the
permanent address on the card is used.
Return Value:
Indicates the success or failure of the registration.
--*/
{
UINT i;
CHAR KernelInterrupt;
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
NDIS_STATUS status; //general purpose return from NDIS calls
Adapter->MulticastListMax = MulticastListMax;
//
// check that NumBuffers <= MAX_XMIT_BUFS
//
if (NumBuffers > MAX_XMIT_BUFS) {
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
status = NDIS_STATUS_RESOURCES;
goto fail1;
}
Adapter->OpenQueue = (PWD_OPEN)NULL;
//
// Allocate the Spin lock.
//
NdisAllocateSpinLock(&Adapter->Lock);
//
// Initialize Transmit information
//
Adapter->DeferredDpc = (PVOID) WdInterruptDpc;
//
// Initialize References.
//
NdisInitializeTimer(&(Adapter->DeferredTimer),
Adapter->DeferredDpc,
Adapter);
//
// Link us on to the chain of adapters for this MAC.
//
Adapter->MacBlock = &WdMacBlock;
NdisAcquireSpinLock(&WdMacBlock.SpinLock);
Adapter->NextAdapter = WdMacBlock.AdapterQueue;
WdMacBlock.AdapterQueue = Adapter;
NdisReleaseSpinLock(&WdMacBlock.SpinLock);
//
// Set up the interrupt handlers.
//
KernelInterrupt = (CCHAR)(Adapter->LMAdapter.irq_value);
NdisInitializeInterrupt(&status, // status of call
&(Adapter->LMAdapter.NdisInterrupt), // interrupt info str
Adapter->LMAdapter.NdisAdapterHandle,
(PNDIS_INTERRUPT_SERVICE) WdInterruptHandler,
Adapter, // context for ISR, DPC
(PNDIS_DEFERRED_PROCESSING) WdInterruptDpc,
KernelInterrupt, // int #
KernelInterrupt, // IRQL
FALSE, // NOT shared
(Adapter->LMAdapter.bus_type == 0) ?
NdisInterruptLatched : // ATBus
NdisInterruptLevelSensitive // MCA
);
if (status != NDIS_STATUS_SUCCESS) {
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_INTERRUPT_CONNECT,
0
);
goto fail3;
}
IF_LOUD( DbgPrint("Interrupt Connected\n");)
//
// Map the memory mapped portion of the card.
//
//
NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)(Adapter->LMAdapter.ram_base));
NdisMapIoSpace(&status,
&Adapter->LMAdapter.ram_access,
Adapter->LMAdapter.NdisAdapterHandle,
PhysicalAddress,
Adapter->LMAdapter.ram_size * 1024);
if (status != NDIS_STATUS_SUCCESS) {
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_RESOURCE_CONFLICT,
0
);
goto failmap;
}
//
// Now Initialize the card.
//
//
// Set Relevant variables first...
//
// base_io and ram_size are set from LM_Get_Config.
//
//
//
// ram_access, node_address, max_packet_size, buffer_page_size,
// num_of_tx_buffs and receive_mask need to be set.
//
for (i = 0; i < 6 ; i ++) {
Adapter->LMAdapter.node_address[i] = NodeAddress[i];
}
Adapter->LMAdapter.max_packet_size = WD_MAX_PACKET_SIZE;
Adapter->LMAdapter.buffer_page_size= WD_BUFFER_PAGE_SIZE;
Adapter->LMAdapter.num_of_tx_buffs = (USHORT)NumBuffers;
Adapter->LMAdapter.ptr_rx_CRC_errors = &(Adapter->CrcErrors);
Adapter->LMAdapter.ptr_rx_too_big = &(Adapter->TooBig);
Adapter->LMAdapter.ptr_rx_lost_pkts = &(Adapter->MissedPackets);
Adapter->LMAdapter.ptr_rx_align_errors = &(Adapter->FrameAlignmentErrors);
Adapter->LMAdapter.ptr_rx_overruns = &(Adapter->Overruns);
Adapter->LMAdapter.ptr_tx_deferred = &(Adapter->FramesXmitDeferred);
Adapter->LMAdapter.ptr_tx_max_collisions = &(Adapter->FramesXmitBad);
Adapter->LMAdapter.ptr_tx_one_collision = &(Adapter->FramesXmitOneCollision);
Adapter->LMAdapter.ptr_tx_mult_collisions = &(Adapter->FramesXmitManyCollisions);
Adapter->LMAdapter.ptr_tx_ow_collision = &(Adapter->FramesXmitOverWrite);
Adapter->LMAdapter.ptr_tx_CD_heartbeat = &(Adapter->FramesXmitHeartbeat);
Adapter->LMAdapter.ptr_tx_underruns = &(Adapter->FramesXmitUnderruns);
Adapter->LMAdapter.FilterDB = NULL;
if (LM_Initialize_Adapter(&(Adapter->LMAdapter)) != SUCCESS){
//
// The Card could not be written to.
//
Adapter->HardwareFailure = TRUE;
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
0
);
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
goto fail6;
}
//
// Initialize Filter Database
//
if (!EthCreateFilter(MulticastListMax,
WdChangeMulticastAddresses,
WdChangeFilterClasses,
WdCloseAction,
Adapter->LMAdapter.node_address,
&Adapter->Lock,
&Adapter->LMAdapter.FilterDB
)) {
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
status = NDIS_STATUS_FAILURE;
goto fail6;
}
//
// Initialize the wake up timer to catch interrupts that
// don't complete. It fires continuously
// every 5 seconds, and we check if there are any
// uncompleted operations from the previous two-second
// period.
//
Adapter->WakeUpDpc = (PVOID)WdWakeUpDpc;
NdisInitializeTimer(&Adapter->WakeUpTimer,
(PVOID)(Adapter->WakeUpDpc),
Adapter );
NdisSetTimer(
&Adapter->WakeUpTimer,
5000
);
//
// Initialization completed successfully.
//
IF_LOUD( { DbgPrint(" WdLan: [OK]\n");})
return NDIS_STATUS_SUCCESS;
//
// Code to unwind what has already been set up when a part of
// initialization fails, which is jumped into at various
// points based on where the failure occured. Jumping to
// a higher-numbered failure point will execute the code
// for that block and all lower-numbered ones.
//
fail6:
NdisUnmapIoSpace(
Adapter->LMAdapter.NdisAdapterHandle,
Adapter->LMAdapter.ram_access,
Adapter->LMAdapter.ram_size * 1024);
failmap:
NdisRemoveInterrupt(&(Adapter->LMAdapter.NdisInterrupt));
NdisAcquireSpinLock(&WdMacBlock.SpinLock);
//
// Take us out of the AdapterQueue.
//
if (WdMacBlock.AdapterQueue == Adapter) {
WdMacBlock.AdapterQueue = Adapter->NextAdapter;
} else {
PWD_ADAPTER TmpAdapter = WdMacBlock.AdapterQueue;
while (TmpAdapter->NextAdapter != Adapter) {
TmpAdapter = TmpAdapter->NextAdapter;
}
TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter;
}
NdisReleaseSpinLock(&WdMacBlock.SpinLock);
fail3:
NdisFreeSpinLock(&Adapter->Lock);
fail1:
return status;
}
#pragma NDIS_PAGABLE_FUNCTION(WdOpenAdapter)
NDIS_STATUS
WdOpenAdapter(
OUT PNDIS_STATUS OpenErrorStatus,
OUT NDIS_HANDLE * MacBindingHandle,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE NdisBindingContext,
IN NDIS_HANDLE MacAdapterContext,
IN UINT OpenOptions,
IN PSTRING AddressingInformation OPTIONAL
)
/*++
Routine Description:
NDIS function. It initializes the open block and links it in
the appropriate lists.
Arguments:
See NDIS 3.0 spec.
--*/
{
PWD_ADAPTER Adapter = ((PWD_ADAPTER)MacAdapterContext);
PWD_OPEN NewOpen;
NDIS_STATUS Status;
//
// Don't use extended error or OpenOptions for Wd
//
UNREFERENCED_PARAMETER(OpenOptions);
*OpenErrorStatus=NDIS_STATUS_SUCCESS;
IF_LOUD( DbgPrint("In Open Adapter\n");)
//
// Scan the media list for our media type (802.3)
//
*SelectedMediumIndex = (UINT)(-1);
while (MediumArraySize > 0) {
if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
*SelectedMediumIndex = MediumArraySize;
break;
}
}
if (*SelectedMediumIndex == -1) {
return NDIS_STATUS_UNSUPPORTED_MEDIA;
}
//
// Link this open to the appropriate lists.
//
if (Adapter->HardwareFailure) {
return(NDIS_STATUS_FAILURE);
}
//
// Allocate memory for the open.
//
Status = NdisAllocateMemory((PVOID *)&NewOpen, sizeof(WD_OPEN), 0, HighestAcceptableMax);
if (Status != NDIS_STATUS_SUCCESS) {
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
return(NDIS_STATUS_RESOURCES);
}
NdisAcquireSpinLock(&Adapter->Lock);
Adapter->References++;
//
// Link this open to the appropriate lists.
//
if (Adapter->OpenQueue == NULL) {
//
// The first open on this adapter.
//
if (LM_Open_Adapter(&(Adapter->LMAdapter)) != SUCCESS) {
IF_LOUD( DbgPrint("OpenFailed!\n");)
NdisReleaseSpinLock(&Adapter->Lock);
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
0
);
return(NDIS_STATUS_FAILURE);
}
IF_LOUD( DbgPrint("OpenSuccess!\n");)
}
NewOpen->NextOpen = Adapter->OpenQueue;
Adapter->OpenQueue = NewOpen;
if (!EthNoteFilterOpenAdapter(
Adapter->LMAdapter.FilterDB,
NewOpen,
NdisBindingContext,
&NewOpen->NdisFilterHandle
)) {
Adapter->References--;
Adapter->OpenQueue = NewOpen->NextOpen;
NdisReleaseSpinLock(&Adapter->Lock);
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
return NDIS_STATUS_FAILURE;
}
//
// Set up the open block.
//
NewOpen->Adapter = Adapter;
NewOpen->MacBlock = Adapter->MacBlock;
NewOpen->NdisBindingContext = NdisBindingContext;
NewOpen->AddressingInformation = AddressingInformation;
NewOpen->Closing = FALSE;
NewOpen->LookAhead = WD_MAX_LOOKAHEAD;
NewOpen->ProtOptionFlags = 0;
Adapter->MaxLookAhead = WD_MAX_LOOKAHEAD;
NewOpen->ReferenceCount = 1;
*MacBindingHandle = (NDIS_HANDLE)NewOpen;
WD_DO_DEFERRED(Adapter);
IF_LOUD( DbgPrint("Out Open Adapter\n");)
return NDIS_STATUS_SUCCESS;
}
VOID
WdAdjustMaxLookAhead(
IN PWD_ADAPTER Adapter
)
/*++
Routine Description:
This routine finds the open with the maximum lookahead value and
stores that in the adapter block.
NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
Arguments:
Adapter - A pointer to the adapter block.
Returns:
None.
--*/
{
ULONG CurrentMax = 0;
PWD_OPEN CurrentOpen;
CurrentOpen = Adapter->OpenQueue;
while (CurrentOpen != NULL) {
if (CurrentOpen->LookAhead > CurrentMax) {
CurrentMax = CurrentOpen->LookAhead;
}
CurrentOpen = CurrentOpen->NextOpen;
}
if (CurrentMax == 0) {
CurrentMax = WD_MAX_LOOKAHEAD;
}
Adapter->MaxLookAhead = CurrentMax;
}
NDIS_STATUS
WdCloseAdapter(
IN NDIS_HANDLE MacBindingHandle
)
/*++
Routine Description:
NDIS function. Unlinks the open block and frees it.
Arguments:
See NDIS 3.0 spec.
--*/
{
PWD_OPEN Open = ((PWD_OPEN)MacBindingHandle);
PWD_ADAPTER Adapter = Open->Adapter;
PWD_OPEN TmpOpen;
NDIS_STATUS StatusToReturn;
NdisAcquireSpinLock(&Adapter->Lock);
if (Open->Closing) {
//
// The open is already being closed.
//
NdisReleaseSpinLock(&Adapter->Lock);
return NDIS_STATUS_CLOSING;
}
Adapter->References++;
Open->ReferenceCount++;
//
// Remove this open from the list for this adapter.
//
if (Open == Adapter->OpenQueue) {
Adapter->OpenQueue = Open->NextOpen;
} else {
TmpOpen = Adapter->OpenQueue;
while (TmpOpen->NextOpen != Open) {
TmpOpen = TmpOpen->NextOpen;
}
TmpOpen->NextOpen = Open->NextOpen;
}
//
// Remove from Filter package to block all receives.
//
StatusToReturn = EthDeleteFilterOpenAdapter(
Adapter->LMAdapter.FilterDB,
Open->NdisFilterHandle,
NULL
);
//
// If the status is successful that merely implies that
// we were able to delete the reference to the open binding
// from the filtering code. If we have a successful status
// at this point we still need to check whether the reference
// count to determine whether we can close.
//
//
// The delete filter routine can return a "special" status
// that indicates that there is a current NdisIndicateReceive
// on this binding. See below.
//
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
//
// Check whether the reference count is two. If
// it is then we can get rid of the memory for
// this open.
//
// A count of two indicates one for this routine
// and one for the filter which we *know* we can
// get rid of.
//
if (Open->ReferenceCount != 2) {
//
// We are not the only reference to the open. Remove
// it from the open list and delete the memory.
//
Open->Closing = TRUE;
//
// Account for this routines reference to the open
// as well as reference because of the original open.
//
Open->ReferenceCount -= 2;
//
// Change the status to indicate that we will
// be closing this later.
//
StatusToReturn = NDIS_STATUS_PENDING;
} else {
Open->ReferenceCount -= 2;
}
} else if (StatusToReturn == NDIS_STATUS_PENDING) {
Open->Closing = TRUE;
//
// Account for this routines reference to the open
// as well as reference because of the original open.
//
Open->ReferenceCount -= 2;
} else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
//
// When we have this status it indicates that the filtering
// code was currently doing an NdisIndicateReceive. It
// would not be wise to delete the memory for the open at
// this point. The filtering code will call our close action
// routine upon return from NdisIndicateReceive and that
// action routine will decrement the reference count for
// the open.
//
Open->Closing = TRUE;
//
// This status is private to the filtering routine. Just
// tell the caller the the close is pending.
//
StatusToReturn = NDIS_STATUS_PENDING;
//
// Account for this routines reference to the open.
//
Open->ReferenceCount--;
} else {
//
// Account for this routines reference to the open.
//
Open->ReferenceCount--;
}
//
// See if this is the last reference to this open.
//
if (Open->ReferenceCount == 0) {
//
// Check if the MaxLookAhead needs adjustment.
//
if (Open->LookAhead == Adapter->MaxLookAhead) {
WdAdjustMaxLookAhead(Adapter);
}
if (Adapter->OpenQueue == NULL) {
//
// We can disable the card.
//
if (NdisSynchronizeWithInterrupt(
&(Adapter->LMAdapter.NdisInterrupt),
(PVOID)WdSyncCloseAdapter,
(PVOID)(&(Adapter->LMAdapter))
) == FALSE) {
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
0
);
IF_LOUD( DbgPrint("CloseAdapter FAILED!\n");)
} else {
IF_LOUD( DbgPrint("CloseAdapter Success!\n");)
}
}
} else {
//
// Will get removed when count drops to zero.
//
StatusToReturn = NDIS_STATUS_PENDING;
}
WD_DO_DEFERRED(Adapter);
return(StatusToReturn);
}
NDIS_STATUS
WdRequest(
IN NDIS_HANDLE MacBindingHandle,
IN PNDIS_REQUEST NdisRequest
)
/*++
Routine Description:
This routine allows a protocol to query and set information
about the MAC.
Arguments:
MacBindingHandle - The context value returned by the MAC when the
adapter was opened. In reality, it is a pointer to PWD_OPEN.
NdisRequest - A structure which contains the request type (Set or
Query), an array of operations to perform, and an array for holding
the results of the operations.
Return Value:
The function value is the status of the operation.
--*/
{
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
PWD_OPEN Open = (PWD_OPEN)(MacBindingHandle);
PWD_ADAPTER Adapter = (Open->Adapter);
IF_LOUD( DbgPrint("In Request\n");)
NdisAcquireSpinLock(&Adapter->Lock);
//
// Ensure that the open does not close while in this function.
//
Open->ReferenceCount++;
Adapter->References++;
//
// Process request
//
if (Open->Closing) {
NdisReleaseSpinLock(&Adapter->Lock);
StatusToReturn = NDIS_STATUS_CLOSING;
} else if (NdisRequest->RequestType == NdisRequestQueryInformation) {
NdisReleaseSpinLock(&Adapter->Lock);
StatusToReturn = WdQueryInformation(Adapter, Open, NdisRequest);
} else if (NdisRequest->RequestType == NdisRequestSetInformation) {
if (Adapter->HardwareFailure) {
NdisReleaseSpinLock(&Adapter->Lock);
StatusToReturn = NDIS_STATUS_FAILURE;
} else {
NdisReleaseSpinLock(&Adapter->Lock);
StatusToReturn = WdSetInformation(Adapter,Open,NdisRequest);
}
} else {
NdisReleaseSpinLock(&Adapter->Lock);
StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED;
}
NdisAcquireSpinLock(&Adapter->Lock);
WdRemoveReference(Open);
WD_DO_DEFERRED(Adapter);
IF_LOUD( DbgPrint("Out Request\n");)
return(StatusToReturn);
}
NDIS_STATUS
WdQueryProtocolInformation(
IN PWD_ADAPTER Adapter,
IN PWD_OPEN Open,
IN NDIS_OID Oid,
IN BOOLEAN GlobalMode,
IN PVOID InfoBuffer,
IN UINT BytesLeft,
OUT PUINT BytesNeeded,
OUT PUINT BytesWritten
)
/*++
Routine Description:
The WdQueryProtocolInformation process a Query request for
NDIS_OIDs that are specific to a binding about the MAC. Note that
some of the OIDs that are specific to bindings are also queryable
on a global basis. Rather than recreate this code to handle the
global queries, I use a flag to indicate if this is a query for the
global data or the binding specific data.
Arguments:
Adapter - a pointer to the adapter.
Open - a pointer to the open instance.
Oid - the NDIS_OID to process.
GlobalMode - Some of the binding specific information is also used
when querying global statistics. This is a flag to specify whether
to return the global value, or the binding specific value.
PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer
into which store the result of the query.
BytesLeft - the number of bytes left in the InformationBuffer.
BytesNeeded - If there is not enough room in the information buffer
then this will contain the number of bytes needed to complete the
request.
BytesWritten - a pointer to the number of bytes written into the
InformationBuffer.
Return Value:
The function value is the status of the operation.
--*/
{
NDIS_MEDIUM Medium = NdisMedium802_3;
ULONG GenericULong;
USHORT GenericUShort;
UCHAR GenericArray[6];
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
//
// Common variables for pointing to result of query
//
PVOID MoveSource = (PVOID)(&GenericULong);
ULONG MoveBytes = sizeof(ULONG);
NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
//
// General Algorithm:
//
// Switch(Request)
// Get requested information
// Store results in a common variable.
// Copy result in common variable to result buffer.
//
//
// Make sure that ulong is 4 bytes. Else GenericULong must change
// to something of size 4.
//
ASSERT(sizeof(ULONG) == 4);
IF_LOUD( DbgPrint("In QueryProtocol\n");)
//
// Make sure no changes occur while processing.
//
NdisAcquireSpinLock(&Adapter->Lock);
//
// Switch on request type
//
switch (Oid) {
case OID_GEN_MAC_OPTIONS:
GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
NDIS_MAC_OPTION_NO_LOOPBACK
);
break;
case OID_GEN_SUPPORTED_LIST:
if (!GlobalMode) {
MoveSource = (PVOID)(WdProtocolSupportedOids);
MoveBytes = sizeof(WdProtocolSupportedOids);
} else {
MoveSource = (PVOID)(WdGlobalSupportedOids);
MoveBytes = sizeof(WdGlobalSupportedOids);
}
break;
case OID_GEN_HARDWARE_STATUS:
if (Adapter->HardwareFailure) {
HardwareStatus = NdisHardwareStatusNotReady;
} else {
HardwareStatus = NdisHardwareStatusReady;
}
MoveSource = (PVOID)(&HardwareStatus);
MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
break;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
MoveSource = (PVOID) (&Medium);
MoveBytes = sizeof(NDIS_MEDIUM);
break;
case OID_GEN_MAXIMUM_LOOKAHEAD:
GenericULong = WD_MAX_LOOKAHEAD;
break;
case OID_GEN_MAXIMUM_FRAME_SIZE:
GenericULong = (ULONG)(WD_MAX_PACKET_SIZE - WD_HEADER_SIZE);
break;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
GenericULong = (ULONG)(WD_MAX_PACKET_SIZE);
break;
case OID_GEN_LINK_SPEED:
GenericULong = (ULONG)(100000);
break;
case OID_GEN_TRANSMIT_BUFFER_SPACE:
GenericULong = (ULONG)(Adapter->LMAdapter.num_of_tx_buffs
* Adapter->LMAdapter.xmit_buf_size);
break;
case OID_GEN_RECEIVE_BUFFER_SPACE:
GenericULong = (ULONG)((Adapter->LMAdapter.ram_size * 1024) -
(Adapter->LMAdapter.num_of_tx_buffs
* Adapter->LMAdapter.xmit_buf_size));
break;
case OID_GEN_TRANSMIT_BLOCK_SIZE:
GenericULong = (ULONG)(Adapter->LMAdapter.buffer_page_size);
break;
case OID_GEN_RECEIVE_BLOCK_SIZE:
GenericULong = (ULONG)(Adapter->LMAdapter.buffer_page_size);
break;
case OID_GEN_VENDOR_ID:
NdisMoveMemory(
(PVOID)&GenericULong,
Adapter->LMAdapter.permanent_node_address,
3
);
GenericULong &= 0xFFFFFF00;
MoveSource = (PVOID)(&GenericULong);
MoveBytes = sizeof(GenericULong);
break;
case OID_GEN_VENDOR_DESCRIPTION:
MoveSource = (PVOID)"SMC Adapter.";
MoveBytes = 13;
break;
case OID_GEN_DRIVER_VERSION:
GenericUShort = ((USHORT)WD_NDIS_MAJOR_VERSION << 8) |
WD_NDIS_MINOR_VERSION;
MoveSource = (PVOID)(&GenericUShort);
MoveBytes = sizeof(GenericUShort);
break;
case OID_GEN_CURRENT_PACKET_FILTER:
if (GlobalMode) {
UINT Filter;
Filter = ETH_QUERY_FILTER_CLASSES(Adapter->LMAdapter.FilterDB);
GenericULong = (ULONG)(Filter);
} else {
UINT Filter = 0;
Filter = ETH_QUERY_PACKET_FILTER(Adapter->LMAdapter.FilterDB,
Open->NdisFilterHandle);
GenericULong = (ULONG)(Filter);
}
break;
case OID_GEN_CURRENT_LOOKAHEAD:
if ( GlobalMode ) {
GenericULong = (ULONG)(Adapter->MaxLookAhead);
} else {
GenericULong = Open->LookAhead;
}
break;
case OID_802_3_PERMANENT_ADDRESS:
WD_MOVE_MEM((PCHAR)GenericArray,
Adapter->LMAdapter.permanent_node_address,
ETH_LENGTH_OF_ADDRESS);
MoveSource = (PVOID)(GenericArray);
MoveBytes = sizeof(Adapter->LMAdapter.permanent_node_address);
break;
case OID_802_3_CURRENT_ADDRESS:
WD_MOVE_MEM((PCHAR)GenericArray,
Adapter->LMAdapter.node_address,
ETH_LENGTH_OF_ADDRESS);
MoveSource = (PVOID)(GenericArray);
MoveBytes = sizeof(Adapter->LMAdapter.node_address);
break;
case OID_802_3_MULTICAST_LIST:
{
UINT NumAddresses;
if (GlobalMode) {
NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->LMAdapter.FilterDB);
if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
*BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
break;
}
EthQueryGlobalFilterAddresses(
&StatusToReturn,
Adapter->LMAdapter.FilterDB,
BytesLeft,
&NumAddresses,
InfoBuffer
);
*BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
//
// Should not be an error since we held the spinlock
// nothing should have changed.
//
ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
} else {
NumAddresses = EthNumberOfOpenFilterAddresses(
Adapter->LMAdapter.FilterDB,
Open->NdisFilterHandle
);
if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
*BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
break;
}
EthQueryOpenFilterAddresses(
&StatusToReturn,
Adapter->LMAdapter.FilterDB,
Open->NdisFilterHandle,
BytesLeft,
&NumAddresses,
InfoBuffer
);
//
// Should not be an error since we held the spinlock
// nothing should have changed.
//
ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
*BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
}
}
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
GenericULong = (ULONG) (Adapter->MulticastListMax);
break;
default:
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
break;
}
if ((StatusToReturn == NDIS_STATUS_SUCCESS) &&
(Oid != OID_802_3_MULTICAST_LIST)) {
if (MoveBytes > BytesLeft) {
//
// Not enough room in InformationBuffer. Punt
//
*BytesNeeded = MoveBytes - BytesLeft;
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
} else {
//
// Store result.
//
WD_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
(*BytesWritten) += MoveBytes;
}
}
NdisReleaseSpinLock(&Adapter->Lock);
IF_LOUD( DbgPrint("Out QueryProtocol\n");)
return(StatusToReturn);
}
NDIS_STATUS
WdQueryInformation(
IN PWD_ADAPTER Adapter,
IN PWD_OPEN Open,
IN PNDIS_REQUEST NdisRequest
)
/*++
Routine Description:
The WdQueryInformation is used by WdRequest to query information
about the MAC.
Arguments:
Adapter - A pointer to the adapter.
Open - A pointer to a particular open instance.
NdisRequest - A structure which contains the request type (Query),
an array of operations to perform, and an array for holding
the results of the operations.
Return Value:
The function value is the status of the operation.
--*/
{
UINT BytesWritten = 0;
UINT BytesNeeded = 0;
UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
IF_LOUD( DbgPrint("In QueryInfor\n");)
StatusToReturn = WdQueryProtocolInformation(
Adapter,
Open,
NdisRequest->DATA.QUERY_INFORMATION.Oid,
FALSE,
InfoBuffer,
BytesLeft,
&BytesNeeded,
&BytesWritten
);
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
IF_LOUD( DbgPrint("Out QueryInfor\n");)
return(StatusToReturn);
}
NDIS_STATUS
WdSetInformation(
IN PWD_ADAPTER Adapter,
IN PWD_OPEN Open,
IN PNDIS_REQUEST NdisRequest
)
/*++
Routine Description:
The WdSetInformation is used by WdRequest to set information
about the MAC.
Arguments:
Adapter - A pointer to the adapter.
Open - A pointer to an open instance.
NdisRequest - A structure which contains the request type (Set),
an array of operations to perform, and an array for holding
the results of the operations.
Return Value:
The function value is the status of the operation.
--*/
{
//
// General Algorithm:
//
// Verify length
// Switch(Request)
// Process Request
//
UINT BytesRead = 0;
UINT BytesNeeded = 0;
UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
//
// Variables for a particular request
//
NDIS_OID Oid;
UINT OidLength;
//
// Variables for holding the new values to be used.
//
ULONG LookAhead;
ULONG Filter;
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
IF_LOUD( DbgPrint("In SetInfo\n");)
//
// Get Oid and Length of request
//
Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
OidLength = BytesLeft;
switch (Oid) {
case OID_802_3_MULTICAST_LIST:
//
// Verify length
//
if ((OidLength % ETH_LENGTH_OF_ADDRESS) != 0){
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
break;
}
StatusToReturn = WdSetMulticastAddresses(
Adapter,
Open,
NdisRequest,
(UINT)(OidLength / ETH_LENGTH_OF_ADDRESS),
(PVOID)InfoBuffer
);
break;
case OID_GEN_CURRENT_PACKET_FILTER:
//
// Verify length
//
if (OidLength != 4 ) {
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
break;
}
WD_MOVE_MEM(&Filter, InfoBuffer, 4);
//
// Verify bits
//
if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
NDIS_PACKET_TYPE_SMT |
NDIS_PACKET_TYPE_MAC_FRAME |
NDIS_PACKET_TYPE_FUNCTIONAL |
NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
NDIS_PACKET_TYPE_GROUP
)) {
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
break;
}
StatusToReturn = WdSetPacketFilter(Adapter,
Open,
NdisRequest,
Filter
);
break;
case OID_GEN_CURRENT_LOOKAHEAD:
//
// Verify length
//
if (OidLength != 4) {
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
break;
}
WD_MOVE_MEM(&LookAhead, InfoBuffer, 4);
if (LookAhead <= (WD_MAX_LOOKAHEAD)) {
if (LookAhead > Adapter->MaxLookAhead) {
Adapter->MaxLookAhead = LookAhead;
Open->LookAhead = LookAhead;
} else {
if ((Open->LookAhead == Adapter->MaxLookAhead) &&
(LookAhead < Open->LookAhead)) {
Open->LookAhead = LookAhead;
WdAdjustMaxLookAhead(Adapter);
} else {
Open->LookAhead = LookAhead;
}
}
} else {
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
}
break;
case OID_GEN_PROTOCOL_OPTIONS:
//
// Verify length
//
if (OidLength != 4) {
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
break;
}
WD_MOVE_MEM(&Open->ProtOptionFlags, InfoBuffer, 4);
StatusToReturn = NDIS_STATUS_SUCCESS;
break;
default:
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
break;
}
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
NdisRequest->DATA.SET_INFORMATION.BytesRead = BytesLeft;
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
}
IF_LOUD( DbgPrint("Out SetInfo\n");)
return(StatusToReturn);
}
STATIC
NDIS_STATUS
WdSetPacketFilter(
IN PWD_ADAPTER Adapter,
IN PWD_OPEN Open,
IN PNDIS_REQUEST NdisRequest,
IN UINT PacketFilter
)
/*++
Routine Description:
The WdSetPacketFilter request allows a protocol to control the types
of packets that it receives from the MAC.
Arguments:
Adapter - A pointer to the adapter structure.
Open - A pointer to the open block giving the request.
NdisRequest - The NDIS_REQUEST with the set packet filter command in it.
PacketFilter - A bit mask that contains flags that correspond to specific
classes of received packets. If a particular bit is set in the mask,
then packet reception for that class of packet is enabled. If the
bit is clear, then packets that fall into that class are not received
by the client. A single exception to this rule is that if the promiscuous
bit is set, then the client receives all packets on the network, regardless
of the state of the other flags.
Return Value:
The function value is the status of the operation.
--*/
{
//
// Keeps track of the *MAC's* status. The status will only be
// reset if the filter change action routine is called.
//
NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
NdisAcquireSpinLock(&Adapter->Lock);
IF_LOUD( DbgPrint("In SetFilter\n");)
if (!Open->Closing) {
//
// Increment the open while it is going through the filtering
// routines.
//
Open->ReferenceCount++;
StatusOfFilterChange = EthFilterAdjust(
Adapter->LMAdapter.FilterDB,
Open->NdisFilterHandle,
NdisRequest,
PacketFilter,
TRUE
);
Open->ReferenceCount--;
} else {
StatusOfFilterChange = NDIS_STATUS_CLOSING;
}
NdisReleaseSpinLock(&Adapter->Lock);
IF_LOUD( DbgPrint("Out SetFilter\n");)
return StatusOfFilterChange;
}
STATIC
NDIS_STATUS
WdSetMulticastAddresses(
IN PWD_ADAPTER Adapter,
IN PWD_OPEN Open,
IN PNDIS_REQUEST NdisRequest,
IN UINT NumAddresses,
IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
)
/*++
Routine Description:
This function calls into the filter package in order to set the
multicast address list for the card to the specified list.
Arguments:
Adapter - A pointer to the adapter block.
Open - A pointer to the open block submitting the request.
NdisRequest - The NDIS_REQUEST with the set multicast address list command
in it.
NumAddresses - A count of the number of addresses in the addressList.
AddressList - An array of multicast addresses that this open instance
wishes to accept.
Return Value:
The function value is the status of the operation.
--*/
{
//
// Keeps track of the *MAC's* status. The status will only be
// reset if the filter change action routine is called.
//
NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
IF_LOUD( DbgPrint("In SetMulticast\n");)
NdisAcquireSpinLock(&Adapter->Lock);
if (!Open->Closing) {
//
// Increment the open while it is going through the filtering
// routines.
//
Open->ReferenceCount++;
StatusOfFilterChange = EthChangeFilterAddresses(
Adapter->LMAdapter.FilterDB,
Open->NdisFilterHandle,
NdisRequest,
NumAddresses,
AddressList,
TRUE
);
Open->ReferenceCount--;
} else {
StatusOfFilterChange = NDIS_STATUS_CLOSING;
}
NdisReleaseSpinLock(&Adapter->Lock);
IF_LOUD( DbgPrint("Out SetMulticast\n");)
return StatusOfFilterChange;
}
NDIS_STATUS
WdFillInGlobalData(
IN PWD_ADAPTER Adapter,
IN PNDIS_REQUEST NdisRequest
)
/*++
Routine Description:
This routine completes a GlobalStatistics request. It is critical that
if information is needed from the Adapter->* fields, they have been
updated before this routine is called.
Arguments:
Adapter - A pointer to the Adapter.
NdisRequest - A structure which contains the request type (Global
Query), an array of operations to perform, and an array for holding
the results of the operations.
Return Value:
The function value is the status of the operation.
--*/
{
//
// General Algorithm:
//
// Switch(Request)
// Get requested information
// Store results in a common variable.
// default:
// Try protocol query information
// If that fails, fail query.
//
// Copy result in common variable to result buffer.
// Finish processing
UINT BytesWritten = 0;
UINT BytesNeeded = 0;
UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
//
// This variable holds result of query
//
ULONG GenericULong;
//
// Make sure that long is 4 bytes. Else GenericULong must change
// to something of size 4.
//
ASSERT(sizeof(ULONG) == 4);
StatusToReturn = WdQueryProtocolInformation(
Adapter,
NULL,
NdisRequest->DATA.QUERY_INFORMATION.Oid,
TRUE,
InfoBuffer,
BytesLeft,
&BytesNeeded,
&BytesWritten
);
if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED) {
StatusToReturn = NDIS_STATUS_SUCCESS;
//
// Switch on request type
//
switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
case OID_GEN_XMIT_OK:
GenericULong = (ULONG)(Adapter->FramesXmitGood);
break;
case OID_GEN_RCV_OK:
GenericULong = (ULONG)(Adapter->FramesRcvGood);
break;
case OID_GEN_XMIT_ERROR:
GenericULong = (ULONG)(Adapter->FramesXmitBad);
break;
case OID_GEN_RCV_ERROR:
GenericULong = (ULONG)(Adapter->CrcErrors);
break;
case OID_GEN_RCV_NO_BUFFER:
GenericULong = (ULONG)(Adapter->MissedPackets);
break;
case OID_802_3_RCV_ERROR_ALIGNMENT:
GenericULong = (ULONG)(Adapter->FrameAlignmentErrors);
break;
case OID_802_3_XMIT_ONE_COLLISION:
GenericULong = (ULONG)(Adapter->FramesXmitOneCollision);
break;
case OID_802_3_XMIT_MORE_COLLISIONS:
GenericULong = (ULONG)(Adapter->FramesXmitManyCollisions);
break;
default:
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
break;
}
//
// Check to make sure there is enough room in the
// buffer to store the result.
//
if (BytesLeft >= sizeof(ULONG)) {
//
// Store the result.
//
WD_MOVE_MEM(
(PVOID)InfoBuffer,
(PVOID)(&GenericULong),
sizeof(ULONG)
);
BytesWritten += sizeof(ULONG);
}
}
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
return(StatusToReturn);
}
NDIS_STATUS
WdQueryGlobalStatistics(
IN NDIS_HANDLE MacAdapterContext,
IN PNDIS_REQUEST NdisRequest
)
/*++
Routine Description:
The WdQueryGlobalStatistics is used by the protocol to query
global information about the MAC.
Arguments:
MacAdapterContext - The value associated with the adapter that is being
opened when the MAC registered the adapter with NdisRegisterAdapter.
NdisRequest - A structure which contains the request type (Query),
an array of operations to perform, and an array for holding
the results of the operations.
Return Value:
The function value is the status of the operation.
--*/
{
//
// General Algorithm:
//
//
// Check if a request is going to pend...
// If so, pend the entire operation.
//
// Else
// Fill in the request block.
//
//
PWD_ADAPTER Adapter = (PWD_ADAPTER)(MacAdapterContext);
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
//
// Check if a request is valid and going to pend...
// If so, pend the entire operation.
//
//
// Switch on request type
//
switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
case OID_GEN_SUPPORTED_LIST:
case OID_GEN_HARDWARE_STATUS:
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
case OID_GEN_MAXIMUM_LOOKAHEAD:
case OID_GEN_MAXIMUM_FRAME_SIZE:
case OID_GEN_MAXIMUM_TOTAL_SIZE:
case OID_GEN_MAC_OPTIONS:
case OID_GEN_LINK_SPEED:
case OID_GEN_TRANSMIT_BUFFER_SPACE:
case OID_GEN_RECEIVE_BUFFER_SPACE:
case OID_GEN_TRANSMIT_BLOCK_SIZE:
case OID_GEN_RECEIVE_BLOCK_SIZE:
case OID_GEN_VENDOR_ID:
case OID_GEN_VENDOR_DESCRIPTION:
case OID_GEN_DRIVER_VERSION:
case OID_GEN_CURRENT_PACKET_FILTER:
case OID_GEN_CURRENT_LOOKAHEAD:
case OID_GEN_XMIT_OK:
case OID_GEN_RCV_OK:
case OID_GEN_XMIT_ERROR:
case OID_GEN_RCV_ERROR:
break;
case OID_802_3_PERMANENT_ADDRESS:
case OID_802_3_CURRENT_ADDRESS:
case OID_GEN_RCV_NO_BUFFER:
case OID_802_3_MULTICAST_LIST:
case OID_802_3_MAXIMUM_LIST_SIZE:
case OID_802_3_RCV_ERROR_ALIGNMENT:
case OID_802_3_XMIT_ONE_COLLISION:
case OID_802_3_XMIT_MORE_COLLISIONS:
break;
default:
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
break;
}
NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock);
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
StatusToReturn = WdFillInGlobalData(Adapter, NdisRequest);
}
NdisAcquireSpinLock(&Adapter->Lock);
WD_DO_DEFERRED(Adapter);
return(StatusToReturn);
}
VOID
WdRemoveAdapter(
IN PVOID MacAdapterContext
)
/*++
Routine Description:
WdRemoveAdapter removes an adapter previously registered
with NdisRegisterAdapter.
Arguments:
MacAdapterContext - The context value that the MAC passed
to NdisRegisterAdapter; actually as pointer to an
WD_ADAPTER.
Return Value:
None.
--*/
{
PWD_ADAPTER Adapter;
BOOLEAN Canceled;
Adapter = PWD_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
LM_Free_Resources(&Adapter->LMAdapter);
ASSERT(Adapter->OpenQueue == (PWD_OPEN)NULL);
//
// There are no opens left, so remove ourselves.
//
NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled);
if ( !Canceled ) {
NdisStallExecution(500000);
}
//
// Take us out of the AdapterQueue.
//
NdisAcquireSpinLock(&WdMacBlock.SpinLock);
Adapter->Removed = TRUE;
if (WdMacBlock.AdapterQueue == Adapter) {
WdMacBlock.AdapterQueue = Adapter->NextAdapter;
} else {
PWD_ADAPTER TmpAdaptP = WdMacBlock.AdapterQueue;
while (TmpAdaptP->NextAdapter != Adapter) {
TmpAdaptP = TmpAdaptP->NextAdapter;
}
TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter;
}
NdisReleaseSpinLock(&WdMacBlock.SpinLock);
NdisRemoveInterrupt(&(Adapter->LMAdapter.NdisInterrupt));
NdisUnmapIoSpace(
Adapter->LMAdapter.NdisAdapterHandle,
Adapter->LMAdapter.ram_access,
Adapter->LMAdapter.ram_size * 1024);
EthDeleteFilter(Adapter->LMAdapter.FilterDB);
NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
NdisFreeSpinLock(&Adapter->Lock);
NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
return;
}
VOID
WdUnload(
IN NDIS_HANDLE MacMacContext
)
/*++
Routine Description:
WdUnload is called when the MAC is to unload itself.
Arguments:
MacMacContext - actually a pointer to WdMacBlock.
Return Value:
None.
--*/
{
NDIS_STATUS InitStatus;
UNREFERENCED_PARAMETER(MacMacContext);
NdisDeregisterMac(
&InitStatus,
WdMacBlock.NdisMacHandle
);
NdisFreeSpinLock(&WdMacBlock.SpinLock);
NdisTerminateWrapper(
WdMacBlock.NdisWrapperHandle,
NULL
);
return;
}
NDIS_STATUS
WdSend(
IN NDIS_HANDLE MacBindingHandle,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
NDIS function. Sends a packet on the wire
Arguments:
See NDIS 3.0 spec.
--*/
{
PWD_OPEN Open = PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
PWD_ADAPTER Adapter = Open->Adapter;
PMAC_RESERVED Reserved = RESERVED(Packet);
UINT PacketLength;
NDIS_STATUS Status;
//
// Check that the packet is not too short or too long.
//
NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
if (PacketLength < (ETH_LENGTH_OF_ADDRESS*2) || PacketLength > 1514) {
return NDIS_STATUS_FAILURE;
}
if (Adapter->HardwareFailure) {
return(NDIS_STATUS_FAILURE);
}
if (Adapter->ResetInProgress) {
return(NDIS_STATUS_RESET_IN_PROGRESS);
}
//
// Ensure that the open won't close during this function.
//
if (Open->Closing) {
return NDIS_STATUS_CLOSING;
}
NdisAcquireSpinLock(&Adapter->Lock);
IF_LOG(LOG('s'));
Open->ReferenceCount++;
Adapter->References++;
//
// Set up the MacReserved section of the packet.
//
Reserved->Open = Open;
Reserved->NextPacket = (PNDIS_PACKET)NULL;
//
// Set Reserved->Loopback
//
WdSetLoopbackFlag(Adapter, Open, Packet);
IF_LOUD( DbgPrint("Sending a packet for Open 0x%lx\n", Reserved->Open);)
//
// We do not Open->ReferenceCount-- because that will be done when
// then send completes.
//
if (Reserved->Directed) {
//
// Put it directly on loopback queue.
//
IF_VERY_LOUD( DbgPrint("Putting Packet 0x%lx on Loopback queue\n",Packet);)
IF_LOG(LOG('l'));
if (Adapter->LoopbackQueue == NULL) {
Adapter->LoopbackQueue = Adapter->LoopbackQTail = Packet;
} else {
RESERVED(Adapter->LoopbackQTail)->NextPacket = Packet;
Adapter->LoopbackQTail = Packet;
}
Status = NDIS_STATUS_PENDING;
} else {
//
// Put Packet on queue to hit the wire.
//
if (Adapter->XmitQueue != NULL) {
IF_LOG(LOG('q'));
RESERVED(Adapter->XmitQTail)->NextPacket = Packet;
Adapter->XmitQTail = Packet;
Adapter->WakeUpTimeout = FALSE;
} else {
PNDIS_PACKET PreviousTail;
//
// We have to assume it will be sent. In case the send completes
// before we have time to add it.
//
ASSERT(Packet != NULL);
if (Adapter->PacketsOnCard == NULL) {
PreviousTail = NULL;
Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = Packet;
} else {
PreviousTail = Adapter->PacketsOnCardTail;
RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Packet;
Adapter->PacketsOnCardTail = Packet;
}
Adapter->WakeUpTimeout = FALSE;
IF_LOG(LOG('t'));
if (LM_Send(Packet, &Adapter->LMAdapter) == OUT_OF_RESOURCES) {
IF_LOG(LOG('Q'));
ASSERT(Packet != NULL);
//
// Remove it from list of packets on card and add it to xmit
// queue.
//
if (PreviousTail == NULL) {
Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = NULL;
} else {
Adapter->PacketsOnCardTail = PreviousTail;
RESERVED(Adapter->PacketsOnCardTail)->NextPacket = NULL;
ASSERT(Adapter->PacketsOnCard != NULL);
}
Adapter->XmitQueue = Packet;
Adapter->XmitQTail = Packet;
Adapter->WakeUpTimeout = FALSE;
}
}
Status = NDIS_STATUS_PENDING;
}
WD_DO_DEFERRED(Adapter);
IF_LOG(LOG('S'));
return Status;
}
UINT
WdCompareMemory(
IN PUCHAR String1,
IN PUCHAR String2,
IN UINT Length
)
/*++
Routine Description:
Determines if two arrays of bytes are equal.
Arguments:
String1, String2 - the two arrays to check.
Length - the first length bytes to compare.
Return Value:
0 if equal, -1 if not.
--*/
{
UINT i;
for (i=0; i<Length; i++) {
if (String1[i] != String2[i]) {
return (UINT)(-1);
}
}
return 0;
}
VOID
WdSetLoopbackFlag(
IN PWD_ADAPTER Adapter,
IN PWD_OPEN Open,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
Sets the loopback flag in the reserved section of the packet
to indicate if it should be looped back.
Arguments:
Packet - the packet to check.
Return Value:
None.
--*/
{
PMAC_RESERVED Reserved = RESERVED(Packet);
UCHAR AddrBuf[ETH_LENGTH_OF_ADDRESS];
UINT Filter;
Reserved->Directed = FALSE;
Reserved->Loopback = FALSE;
//
// Check the destination address to see which filter to use.
//
WdCopyOver(AddrBuf, Packet, 0, ETH_LENGTH_OF_ADDRESS);
Filter = ETH_QUERY_FILTER_CLASSES(Adapter->LMAdapter.FilterDB);
if (WdAddressEqual(Adapter->LMAdapter.node_address, AddrBuf)) {
//
// Packet directed to this adapter.
//
Reserved->Directed = (BOOLEAN)(Filter & NDIS_PACKET_TYPE_DIRECTED);
}
if (Open->ProtOptionFlags & NDIS_PROT_OPTION_NO_LOOPBACK) {
Reserved->Loopback = FALSE;
} else if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
//
// Somebody is promiscuous, everything is looped back.
//
Reserved->Loopback = TRUE;
} else {
if (WdAddressEqual(WdBroadcastAddress, AddrBuf)) {
//
// Broadcast packet.
//
Reserved->Loopback = (BOOLEAN)(Filter & NDIS_PACKET_TYPE_BROADCAST);
} else if ((AddrBuf[0] & 1) != 0) {
//
// Multicast packet.
//
Reserved->Loopback = (BOOLEAN)(Filter &
(NDIS_PACKET_TYPE_MULTICAST |
NDIS_PACKET_TYPE_ALL_MULTICAST));
} else if (Reserved->Directed) {
Reserved->Loopback = TRUE;
} else {
//
// Packet directed to another adapter.
//
Reserved->Loopback = FALSE;
}
}
}
NDIS_STATUS
WdReset(
IN NDIS_HANDLE MacBindingHandle
)
/*++
Routine Description:
NDIS function.
Arguments:
See NDIS 3.0 spec.
--*/
{
PWD_OPEN Open = ((PWD_OPEN)MacBindingHandle);
PWD_ADAPTER Adapter = Open->Adapter;
if (Open->Closing) {
return(NDIS_STATUS_CLOSING);
}
if (Adapter->ResetRequested) {
return(NDIS_STATUS_SUCCESS);
}
NdisAcquireSpinLock(&Adapter->Lock);
IF_LOUD( DbgPrint("In WdReset\n");)
IF_LOG(LOG('r'));
//
// Ensure that the open does not close while in this function.
//
Open->ReferenceCount++;
Adapter->References++;
Adapter->ResetRequested = TRUE;
//
// Needed in case the reset pends somewhere along the line.
//
Adapter->ResetOpen = Open;
WD_DO_DEFERRED(Adapter);
IF_LOUD( DbgPrint("Out WdReset\n");)
return(NDIS_STATUS_PENDING);
}
STATIC
NDIS_STATUS
WdChangeMulticastAddresses(
IN UINT OldFilterCount,
IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
IN UINT NewFilterCount,
IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
IN NDIS_HANDLE MacBindingHandle,
IN PNDIS_REQUEST NdisRequest,
IN BOOLEAN Set
)
/*++
Routine Description:
Action routine that will get called when a particular filter
class is first used or last cleared.
NOTE: This routine assumes that it is called with the lock
acquired.
Arguments:
OldFilterCount - The number of addresses that used to be on the card.
OldAddresses - A list of all the addresses that used to be on the card.
NewFilterCount - The number of addresses that should now be on the card.
NewAddresses - A list of addresses that should be put on the card.
MacBindingHandle - The context value returned by the MAC when the
adapter was opened. In reality, it is a pointer to WD_OPEN.
NdisRequest - The request which submitted the filter change.
Must use when completing this request with the NdisCompleteRequest
service, if the MAC completes this request asynchronously.
Set - If true the change resulted from a set, otherwise the
change resulted from a open closing.
Return Value:
None.
--*/
{
PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
UNREFERENCED_PARAMETER(Set);
UNREFERENCED_PARAMETER(NdisRequest);
UNREFERENCED_PARAMETER(OldAddresses);
UNREFERENCED_PARAMETER(OldFilterCount);
if (LM_Set_Multi_Address(NewAddresses, NewFilterCount, &Adapter->LMAdapter)
!= SUCCESS) {
return(NDIS_STATUS_FAILURE);
} else {
return(NDIS_STATUS_SUCCESS);
}
}
STATIC
NDIS_STATUS
WdChangeFilterClasses(
IN UINT OldFilterClasses,
IN UINT NewFilterClasses,
IN NDIS_HANDLE MacBindingHandle,
IN PNDIS_REQUEST NdisRequest,
IN BOOLEAN Set
)
/*++
Routine Description:
Action routine that will get called when an address is added to
the filter that wasn't referenced by any other open binding.
NOTE: This routine assumes that it is called with the lock
acquired.
Arguments:
OldFilterClasses - A bit mask that is currently on the card telling
which packet types to accept.
NewFilterClasses - A bit mask that should be put on the card telling
which packet types to accept.
MacBindingHandle - The context value returned by the MAC when the
adapter was opened. In reality, it is a pointer to WD_OPEN.
NdisRequest - The NDIS_REQUEST which submitted the filter change command.
Set - A flag telling if the command is a result of a close or not.
Return Value:
Status of the change (successful or pending).
--*/
{
PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
UNREFERENCED_PARAMETER(Set);
UNREFERENCED_PARAMETER(OldFilterClasses);
UNREFERENCED_PARAMETER(NewFilterClasses);
UNREFERENCED_PARAMETER(NdisRequest);
if (LM_Set_Receive_Mask(&(Adapter->LMAdapter)) != SUCCESS) {
return(NDIS_STATUS_FAILURE);
} else {
return(NDIS_STATUS_SUCCESS);
}
}
STATIC
VOID
WdCloseAction(
IN NDIS_HANDLE MacBindingHandle
)
/*++
Routine Description:
Action routine that will get called when a particular binding
was closed while it was indicating through NdisIndicateReceive
All this routine needs to do is to decrement the reference count
of the binding.
NOTE: This routine assumes that it is called with the lock acquired.
Arguments:
MacBindingHandle - The context value returned by the MAC when the
adapter was opened. In reality, it is a pointer to WD_OPEN.
Return Value:
None.
--*/
{
PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->ReferenceCount--;
}
BOOLEAN
WdInterruptHandler(
IN PVOID ServiceContext
)
/*++
Routine Description:
This is the interrupt handler which is registered with the operating
system. Only one interrupt is handled at one time, even if several
are pending (i.e. transmit complete and receive).
Arguments:
ServiceContext - pointer to the adapter object
Return Value:
TRUE, if the DPC is to be executed, otherwise FALSE.
--*/
{
PWD_ADAPTER Adapter = ((PWD_ADAPTER)ServiceContext);
IF_LOUD( DbgPrint("In WdISR\n");)
IF_LOG(LOG('i'));
//
// Force the INT signal from the chip low. When the
// interrupt is acknowledged interrupts will be unblocked,
// which will cause a rising edge on the interrupt line
// if there is another interrupt pending on the card.
//
IF_LOUD( DbgPrint( " blocking interrupts\n" );)
LM_Disable_Adapter(&Adapter->LMAdapter);
IF_LOG(LOG('I'));
return(TRUE);
}
VOID
WdInterruptDpc(
IN PVOID SystemSpecific1,
IN PVOID InterruptContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3
)
/*++
Routine Description:
This is the deffered processing routine for interrupts, it examines the
global 'InterruptReg' to determine what deffered processing is necessary
and dispatches control to the Rcv and Xmt handlers.
Arguments:
SystemSpecific1, SystemSpecific2, SystemSpecific3 - not used
InterruptContext - a handle to the adapter block.
Return Value:
NONE.
--*/
{
PWD_ADAPTER Adapter = ((PWD_ADAPTER)InterruptContext);
BOOLEAN RequeueRcv = FALSE;
UNREFERENCED_PARAMETER(SystemSpecific1);
UNREFERENCED_PARAMETER(SystemSpecific2);
UNREFERENCED_PARAMETER(SystemSpecific3);
IF_LOG(LOG('d'));
IF_LOUD( DbgPrint("==>IntDpc\n");)
NdisDprAcquireSpinLock(&Adapter->Lock);
if ( Adapter->ProcessingDpc ) {
NdisDprReleaseSpinLock(&Adapter->Lock);
return;
}
Adapter->ProcessingDpc = TRUE;
Adapter->References++;
do {
Adapter->WakeUpTimeout = FALSE;
RequeueRcv = WdReceiveEvents(Adapter);
WdTransmitEvents(Adapter);
//
// This causes any transmit that may have caused a tranmitted packet
// to loopback and indicate the packet.
//
} while ( Adapter->LoopbackQueue != (PNDIS_PACKET) NULL || RequeueRcv );
//
// We're done with this DPC.
//
Adapter->ProcessingDpc = FALSE;
//
// Reenable interrupts
//
Adapter->LMAdapter.InterruptMask = PACKET_RECEIVE_ENABLE |
PACKET_TRANSMIT_ENABLE |
RECEIVE_ERROR_ENABLE |
TRANSMIT_ERROR_ENABLE |
OVERWRITE_WARNING_ENABLE |
COUNTER_OVERFLOW_ENABLE;
NdisSynchronizeWithInterrupt(
&(Adapter->LMAdapter.NdisInterrupt),
LM_Enable_Adapter,
&Adapter->LMAdapter
);
WD_DO_DEFERRED(Adapter);
IF_LOUD( DbgPrint("<==IntDpc\n");)
IF_LOG(LOG('D'));
}
VOID
WdIndicateLoopbackPacket(
IN PWD_ADAPTER Adapter,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
This routine indicates a packet to the current host.
NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
Arguments:
Adapter - Pointer to the adapter structure.
Packet - Pointer to the packet to indicate.
Return Value:
NONE.
--*/
{
UINT IndicateLen;
UINT PacketLen;
//
// Store that we are indicating a loopback packet
//
Adapter->IndicatingPacket = Packet;
Adapter->IndicatedAPacket = TRUE;
//
// Indicate packet.
//
IF_LOUD( DbgPrint("Indicating loopback packet\n");)
//
// Indicate up to 252 bytes.
//
NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLen);
if (PacketLen >= ETH_LENGTH_OF_ADDRESS) {
IndicateLen = (PacketLen > (Adapter->MaxLookAhead + WD_HEADER_SIZE) ?
(Adapter->MaxLookAhead + WD_HEADER_SIZE) :
PacketLen
);
//
// Copy the lookahead data into a contiguous buffer.
//
WdCopyOver(Adapter->LookAhead,
Packet,
0,
IndicateLen
);
NdisDprReleaseSpinLock(&Adapter->Lock);
//
// Indicate packet
//
if (PacketLen < WD_HEADER_SIZE) {
//
// Runt packet
//
EthFilterIndicateReceive(
Adapter->LMAdapter.FilterDB,
(NDIS_HANDLE)Adapter,
(PCHAR)Adapter->LookAhead,
Adapter->LookAhead,
PacketLen,
NULL,
0,
0
);
} else {
EthFilterIndicateReceive(
Adapter->LMAdapter.FilterDB,
(NDIS_HANDLE)Adapter,
(PCHAR)Adapter->LookAhead,
Adapter->LookAhead,
WD_HEADER_SIZE,
Adapter->LookAhead + WD_HEADER_SIZE,
IndicateLen - WD_HEADER_SIZE,
PacketLen - WD_HEADER_SIZE
);
}
NdisDprAcquireSpinLock(&Adapter->Lock);
}
}
BOOLEAN
WdReceiveEvents(
IN PWD_ADAPTER Adapter
)
/*++
Routine Description:
This routine handles all Receive deferred processing, this includes any
packets that never went through the XmitQueue and need to be indicated
(Loopbacked), and all card events.
NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
NOTE: The Adapter->ProcessingReceiveEvents MUST be set upon entry and
with the spinlock held.
Arguments:
Context - a handle to the adapter block.
Return Value:
Do we need to requeue this Rcv.
--*/
{
PNDIS_PACKET Packet;
PWD_OPEN TmpOpen;
NDIS_STATUS Status;
BOOLEAN RequeueRcv;
IF_LOG(LOG('e'));
RequeueRcv = (BOOLEAN)(LM_Service_Receive_Events(&Adapter->LMAdapter) ==
REQUEUE_LATER);
while (Adapter->LoopbackQueue != NULL) {
//
// Take packet off queue.
//
Packet = Adapter->LoopbackQueue;
if (Packet == Adapter->LoopbackQTail) {
Adapter->LoopbackQTail = NULL;
}
Adapter->LoopbackQueue = RESERVED(Packet)->NextPacket;
//
// Indicate the packet
//
WdIndicateLoopbackPacket(Adapter,Packet);
//
// Complete the packet send.
//
Adapter->FramesXmitGood++;
//
// Save this, since once we complete the send
// Reserved is no longer valid.
//
TmpOpen = RESERVED(Packet)->Open;
IF_VERY_LOUD( DbgPrint("Completing send for packet 0x%x\n",Packet);)
NdisDprReleaseSpinLock(&Adapter->Lock);
NdisCompleteSend(TmpOpen->NdisBindingContext,
Packet,
NDIS_STATUS_SUCCESS
);
NdisDprAcquireSpinLock(&Adapter->Lock);
WdRemoveReference(TmpOpen);
}
//
// If any indications done, then
//
// CompleteIndications();
//
if (Adapter->IndicatedAPacket) {
Adapter->IndicatedAPacket = FALSE;
NdisDprReleaseSpinLock(&Adapter->Lock);
EthFilterIndicateReceiveComplete(Adapter->LMAdapter.FilterDB);
NdisDprAcquireSpinLock(&Adapter->Lock);
}
if ((Adapter->ResetRequested) && (Adapter->References == 1)) {
PNDIS_PACKET Packet;
PWD_OPEN TmpOpen;
IF_LOG(LOG('R'));
IF_VERY_LOUD( DbgPrint("Starting Reset\n");)
Adapter->ResetInProgress = TRUE;
NdisSynchronizeWithInterrupt(
&(Adapter->LMAdapter.NdisInterrupt),
LM_Disable_Adapter,
&Adapter->LMAdapter
);
//
// Indicate Status to all opens
//
IF_VERY_LOUD( DbgPrint("Indicating status\n");)
TmpOpen = Adapter->OpenQueue;
while (TmpOpen != (PWD_OPEN)NULL) {
AddRefWhileHoldingSpinLock(Adapter, TmpOpen);
NdisDprReleaseSpinLock(&Adapter->Lock);
NdisIndicateStatus(TmpOpen->NdisBindingContext,
NDIS_STATUS_RESET_START,
NULL,
0
);
NdisDprAcquireSpinLock(&Adapter->Lock);
WdRemoveReference(TmpOpen);
TmpOpen = TmpOpen->NextOpen;
}
//
// Reset the Card.
//
IF_VERY_LOUD( DbgPrint("Resetting the card\n");)
if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) {
Adapter->HardwareFailure = TRUE;
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
0
);
} else {
Adapter->HardwareFailure = FALSE;
}
//
// Put packets that were on the card on to the front of the xmit
// queue.
//
if (Adapter->PacketsOnCard != NULL) {
IF_VERY_LOUD( DbgPrint("Moving Packets On card\n");)
RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Adapter->XmitQueue;
Adapter->XmitQueue = Adapter->PacketsOnCard;
Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = NULL;
}
//
// Put packets on loopback queue on xmit queue
//
if (Adapter->LoopbackQueue != NULL) {
RESERVED(Adapter->LoopbackQTail)->NextPacket = Adapter->XmitQueue;
Adapter->XmitQueue = Adapter->LoopbackQueue;
}
//
// Wipe out loopback queue.
//
Adapter->LoopbackQueue = Adapter->LoopbackQTail = (PNDIS_PACKET)NULL;
//
// Abort all xmits
//
IF_VERY_LOUD( DbgPrint("Killing Xmits\n");)
while (Adapter->XmitQueue != NULL) {
Packet = Adapter->XmitQueue;
Adapter->XmitQueue = RESERVED(Packet)->NextPacket;
TmpOpen = RESERVED(Packet)->Open;
NdisDprReleaseSpinLock(&Adapter->Lock);
NdisCompleteSend(TmpOpen->NdisBindingContext,
Packet,
NDIS_STATUS_REQUEST_ABORTED
);
NdisDprAcquireSpinLock(&Adapter->Lock);
WdRemoveReference(TmpOpen);
}
Adapter->XmitQTail = NULL;
if (!Adapter->HardwareFailure) {
LM_Open_Adapter(&Adapter->LMAdapter);
}
Adapter->ResetInProgress = FALSE;
IF_VERY_LOUD( DbgPrint("Indicating Done\n");)
//
// Indicate Reset is done
//
//
// Indicate Status to all opens
//
IF_VERY_LOUD( DbgPrint("Indicating status\n");)
TmpOpen = Adapter->OpenQueue;
while (TmpOpen != (PWD_OPEN)NULL) {
AddRefWhileHoldingSpinLock(Adapter, TmpOpen);
NdisDprReleaseSpinLock(&Adapter->Lock);
if (Adapter->HardwareFailure) {
NdisIndicateStatus(TmpOpen->NdisBindingContext,
NDIS_STATUS_CLOSED,
NULL,
0
);
}
Status = (Adapter->HardwareFailure) ?
NDIS_STATUS_FAILURE :
NDIS_STATUS_SUCCESS;
NdisIndicateStatus(TmpOpen->NdisBindingContext,
NDIS_STATUS_RESET_END,
&Status,
sizeof(Status)
);
NdisIndicateStatusComplete(TmpOpen->NdisBindingContext);
NdisDprAcquireSpinLock(&Adapter->Lock);
WdRemoveReference(TmpOpen);
TmpOpen = TmpOpen->NextOpen;
}
NdisDprReleaseSpinLock(&Adapter->Lock);
NdisCompleteReset(Adapter->ResetOpen->NdisBindingContext,
(Adapter->HardwareFailure) ?
NDIS_STATUS_FAILURE :
NDIS_STATUS_SUCCESS
);
NdisDprAcquireSpinLock(&Adapter->Lock);
WdRemoveReference(Adapter->ResetOpen);
//
// Reset the flag
//
IF_VERY_LOUD( DbgPrint("Restarting Adapter\n");)
Adapter->ResetRequested = FALSE;
LM_Open_Adapter(&Adapter->LMAdapter);
}
#if DBG
else if (Adapter->ResetRequested) {
IF_LOUD( DbgPrint("No reset because count is... 0x%x\n", Adapter->References);)
}
#endif
IF_LOG(LOG('E'));
return RequeueRcv;
}
VOID
WdTransmitEvents(
IN PWD_ADAPTER Adapter
)
/*++
Routine Description:
This routine handles all transmit deferred processing.
NOTE : Called with lock held!!
Arguments:
Adapter - pointer to the adapter structure.
Return Value:
NONE.
--*/
{
if (Adapter->ResetInProgress) {
return;
}
IF_LOG(LOG('w'));
LM_Service_Transmit_Events(&Adapter->LMAdapter);
IF_LOG(LOG('W'));
}
UINT
WdCopyOver(
OUT PUCHAR Buf, // destination
IN PNDIS_PACKET Packet, // source packet
IN UINT Offset, // offset in packet
IN UINT Length // number of bytes to copy
)
/*++
Routine Description:
Copies bytes from a packet into a buffer. Used to copy data
out of a packet during loopback indications.
Arguments:
Buf - the destination buffer
Packet - the source packet
Offset - the offset in the packet to start copying at
Length - the number of bytes to copy
Return Value:
The actual number of bytes copied; will be less than Length if
the packet length is less than Offset+Length.
--*/
{
PNDIS_BUFFER CurBuffer;
UINT BytesCopied;
PUCHAR BufVA;
UINT BufLen;
UINT ToCopy;
UINT CurOffset;
BytesCopied = 0;
//
// First find a spot Offset bytes into the packet.
//
CurOffset = 0;
NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
while (CurBuffer != (PNDIS_BUFFER)NULL) {
NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
if (CurOffset + BufLen > Offset) {
break;
}
CurOffset += BufLen;
NdisGetNextBuffer(CurBuffer, &CurBuffer);
}
//
// See if the end of the packet has already been passed.
//
if (CurBuffer == (PNDIS_BUFFER)NULL) {
return 0;
}
//
// Now copy over Length bytes.
//
BufVA += (Offset - CurOffset);
BufLen -= (Offset - CurOffset);
for (;;) {
ToCopy = (BytesCopied+BufLen > Length) ? Length - BytesCopied : BufLen;
WD_MOVE_MEM(Buf+BytesCopied, BufVA, ToCopy);
BytesCopied += ToCopy;
if (BytesCopied == Length) {
return BytesCopied;
}
NdisGetNextBuffer(CurBuffer, &CurBuffer);
if (CurBuffer == (PNDIS_BUFFER)NULL) {
break;
}
NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
}
return BytesCopied;
}
NDIS_STATUS
WdTransferData(
IN NDIS_HANDLE MacBindingHandle,
IN NDIS_HANDLE MacReceiveContext,
IN UINT ByteOffset,
IN UINT BytesToTransfer,
OUT PNDIS_PACKET Packet,
OUT PUINT BytesTransferred
)
/*++
Routine Description:
NDIS function.
Arguments:
see NDIS 3.0 spec.
Notes:
- The MacReceiveContext will be a pointer to the open block for
the packet.
- The LoopbackPacket field in the adapter block will be NULL if this
is a call for a normal packet, otherwise it will be set to point
to the loopback packet.
--*/
{
PWD_OPEN Open = PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
PWD_ADAPTER Adapter = Open->Adapter;
PNDIS_BUFFER CurrentBuffer;
PUCHAR BufferVA;
UINT BufferLength, Copied;
UINT CurrentOffset;
UNREFERENCED_PARAMETER(MacReceiveContext);
ByteOffset += WD_HEADER_SIZE;
if (Adapter->IndicatingPacket != NULL) {
IF_LOUD( DbgPrint("Transferring data for loopback packet\n");)
//
// It is a loopback packet
//
NdisQueryPacket(Packet, NULL, NULL, &CurrentBuffer, NULL);
CurrentOffset = ByteOffset;
while (CurrentBuffer != (PNDIS_BUFFER)NULL) {
NdisQueryBuffer(CurrentBuffer, (PVOID *)&BufferVA, &BufferLength);
NdisAcquireSpinLock(&Adapter->Lock);
Copied =
WdCopyOver(BufferVA,
Adapter->IndicatingPacket,
CurrentOffset,
BufferLength
);
NdisReleaseSpinLock(&Adapter->Lock);
CurrentOffset += Copied;
if (Copied < BufferLength) {
break;
}
NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
}
//
// We are done, return.
//
*BytesTransferred = CurrentOffset - ByteOffset;
if ( *BytesTransferred > BytesToTransfer ) {
*BytesTransferred = BytesToTransfer;
}
return(NDIS_STATUS_SUCCESS);
} else if (Adapter->IndicatedAPacket) {
NdisAcquireSpinLock(&Adapter->Lock);
IF_LOUD( DbgPrint("Transferring data for card packet\n");)
if (LM_Receive_Copy(
BytesTransferred,
BytesToTransfer,
ByteOffset,
Packet,
&(Adapter->LMAdapter)) != SUCCESS) {
//
// Copy failed.
//
*BytesTransferred = 0;
NdisReleaseSpinLock(&Adapter->Lock);
return(NDIS_STATUS_FAILURE);
} else {
NdisReleaseSpinLock(&Adapter->Lock);
return(NDIS_STATUS_SUCCESS);
}
} else {
return(NDIS_STATUS_NOT_INDICATING);
}
}
BOOLEAN
WdSyncCloseAdapter(
IN PVOID Context
)
/*++
Routine Description:
This function is used to synchronize with the lower MAC layer close
calls that may access the same areas of the LM that are accessed in
the ISR.
Arguments:
see NDIS 3.0 spec.
Notes:
returns TRUE on success, else FALSE.
--*/
{
if (LM_Close_Adapter((Ptr_Adapter_Struc)Context) == SUCCESS) {
return(TRUE);
} else {
return(FALSE);
}
}
VOID
WdWakeUpDpc(
IN PVOID SystemSpecific1,
IN PVOID Context,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3
)
/*++
Routine Description:
This DPC routine is queued every 5 seconds to check on the
queues. If an interrupt was not received
in the last 5 seconds and there should have been one,
then we abort all operations.
Arguments:
Context - Really a pointer to the adapter.
Return Value:
None.
--*/
{
PWD_ADAPTER Adapter = (PWD_ADAPTER)Context;
PWD_OPEN TmpOpen;
PNDIS_PACKET TransmitPacket;
PMAC_RESERVED Reserved;
UNREFERENCED_PARAMETER(SystemSpecific1);
UNREFERENCED_PARAMETER(SystemSpecific2);
UNREFERENCED_PARAMETER(SystemSpecific3);
NdisAcquireSpinLock(&Adapter->Lock);
if ((Adapter->WakeUpTimeout) &&
Adapter->LMAdapter.TransmitInterruptPending) {
//
// We had a pending operation the last time we ran,
// and it has not been completed...we need to complete
// it now.
Adapter->WakeUpTimeout = FALSE;
Adapter->HardwareFailure = TRUE;
//
// Disable adapter
//
IF_LOG(LOG('*'));
LM_Disable_Adapter(&Adapter->LMAdapter);
if (Adapter->WakeUpErrorCount < 10) {
Adapter->WakeUpErrorCount++;
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
0
);
}
while (Adapter->PacketsOnCard != NULL) {
TransmitPacket = Adapter->PacketsOnCard;
Reserved = RESERVED(TransmitPacket);
Adapter->PacketsOnCard = Reserved->NextPacket;
if (Adapter->PacketsOnCard == NULL) {
Adapter->PacketsOnCardTail = NULL;
}
TmpOpen = Reserved->Open;
NdisReleaseSpinLock(&Adapter->Lock);
NdisCompleteSend(
TmpOpen->NdisBindingContext,
TransmitPacket,
NDIS_STATUS_SUCCESS
);
NdisAcquireSpinLock(&Adapter->Lock);
TmpOpen->ReferenceCount--;
}
while (Adapter->XmitQueue != NULL) {
TransmitPacket = Adapter->XmitQueue;
Reserved = RESERVED(TransmitPacket);
//
// Remove the packet from the queue.
//
Adapter->XmitQueue = Reserved->NextPacket;
if (Adapter->XmitQueue == NULL) {
Adapter->XmitQTail = NULL;
}
TmpOpen = Reserved->Open;
NdisReleaseSpinLock(&Adapter->Lock);
NdisCompleteSend(
TmpOpen->NdisBindingContext,
TransmitPacket,
NDIS_STATUS_SUCCESS
);
NdisAcquireSpinLock(&Adapter->Lock);
TmpOpen->ReferenceCount--;
}
Adapter->WakeUpTimeout = FALSE;
Adapter->LMAdapter.TransmitInterruptPending = FALSE;
//
// reinitialize the card
//
if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) {
Adapter->HardwareFailure = TRUE;
NdisWriteErrorLogEntry(
Adapter->LMAdapter.NdisAdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
0
);
} else {
Adapter->HardwareFailure = FALSE;
}
//
// reenable interrupts
//
LM_Enable_Adapter(&Adapter->LMAdapter);
NdisReleaseSpinLock(&Adapter->Lock);
} else {
if ((Adapter->PacketsOnCard != NULL) ||
(Adapter->XmitQueue != NULL)) {
Adapter->WakeUpTimeout = TRUE;
}
NdisReleaseSpinLock(&Adapter->Lock);
}
//
// Fire off another Dpc to execute after 5 seconds
//
NdisSetTimer(
&Adapter->WakeUpTimer,
5000
);
}