diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/odimac/mlid.c | 4413 |
1 files changed, 4413 insertions, 0 deletions
diff --git a/private/ntos/ndis/odimac/mlid.c b/private/ntos/ndis/odimac/mlid.c new file mode 100644 index 000000000..67826a8f1 --- /dev/null +++ b/private/ntos/ndis/odimac/mlid.c @@ -0,0 +1,4413 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + Mlid.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 <odihsm.h> +#include <mlidsft.h> +#include "keywords.h" + +#if DBG +#define STATIC +#else +#define STATIC static +#endif + +#if DBG + + +#define LOGSIZE 512 + +extern UCHAR MlidDebugLog[LOGSIZE] = {0}; +extern UINT MlidDebugLogPlace = 0; + + +extern +VOID +LOG (UCHAR A) { + MlidDebugLog[MlidDebugLogPlace++] = A; + MlidDebugLog[(MlidDebugLogPlace + 4) % LOGSIZE] = '\0'; + if (MlidDebugLogPlace >= LOGSIZE) MlidDebugLogPlace = 0; +} + + +ULONG MlidDebugFlag= MLID_DEBUG_LOG; // MLID_DEBUG_LOG | MLID_DEBUG_LOUD | MLID_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 MlidMacBlock={0}; + + + +// +// If you add to this, make sure to add the +// a case in MlidFillInGlobalData() and in +// MlidQueryGlobalStatistics() if global +// information only or +// MlidQueryProtocolStatistics() if it is +// protocol queriable information. +// +UINT MlidGlobalSupportedOids[] = { + 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, + +/*++ + These are not available + + 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, + + OID_802_5_PERMANENT_ADDRESS, + OID_802_5_CURRENT_ADDRESS, + OID_802_5_CURRENT_FUNCTIONAL, + OID_802_5_CURRENT_GROUP, + OID_802_5_LAST_OPEN_STATUS, + OID_802_5_CURRENT_RING_STATUS, + OID_802_5_CURRENT_RING_STATE, + OID_802_5_LINE_ERRORS, + OID_802_5_LOST_FRAMES + }; + +// +// If you add to this, make sure to add the +// a case in MlidQueryGlobalStatistics() and in +// MlidQueryProtocolInformation() +// +UINT MlidProtocolSupportedOids[] = { + 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, + +/*++ + Not available + + 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, + + OID_802_5_PERMANENT_ADDRESS, + OID_802_5_CURRENT_ADDRESS, + OID_802_5_CURRENT_FUNCTIONAL, + OID_802_5_CURRENT_GROUP, + OID_802_5_LAST_OPEN_STATUS, + OID_802_5_CURRENT_RING_STATUS, + OID_802_5_CURRENT_RING_STATE, + OID_802_5_LINE_ERRORS, + OID_802_5_LOST_FRAMES + }; + + + + + + + +UINT +MlidCopyOver( + OUT PUCHAR Buf, // destination + IN PNDIS_PACKET Packet, // source packet + IN UINT Offset, // offset in packet + IN UINT Length // number of bytes to copy + ); + + + + +#ifdef NDIS_WIN + #ifndef DEBUG + #pragma code_seg ("_ITEXT","ICODE") + #endif +#endif + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + This is the transfer address of the driver. It initializes + MlidMacBlock and calls NdisInitializeWrapper() and + NdisRegisterMac(). + +Arguments: + +Return Value: + + Indicates the success or failure of the initialization. + +--*/ + +{ + PMAC_BLOCK NewMacP = &MlidMacBlock; + 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 + + // + // 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 = (PMLID_ADAPTER)NULL; + + + // + // Prepare to call NdisRegisterMac. + // + + NewMacP->MacCharacteristics.MajorNdisVersion = MLID_NDIS_MAJOR_VERSION; + NewMacP->MacCharacteristics.MinorNdisVersion = MLID_NDIS_MINOR_VERSION; + NewMacP->MacCharacteristics.Reserved = 0; + NewMacP->MacCharacteristics.OpenAdapterHandler = MlidOpenAdapter; + NewMacP->MacCharacteristics.CloseAdapterHandler = MlidCloseAdapter; + NewMacP->MacCharacteristics.SendHandler = MlidSend; + NewMacP->MacCharacteristics.TransferDataHandler = MlidTransferData; + NewMacP->MacCharacteristics.ResetHandler = MlidReset; + NewMacP->MacCharacteristics.RequestHandler = MlidRequest; + NewMacP->MacCharacteristics.QueryGlobalStatisticsHandler = + MlidQueryGlobalStatistics; + NewMacP->MacCharacteristics.UnloadMacHandler = MlidUnload; + NewMacP->MacCharacteristics.AddAdapterHandler = MlidAddAdapter; + NewMacP->MacCharacteristics.RemoveAdapterHandler = MlidRemoveAdapter; + + NewMacP->MacCharacteristics.Name = MacName; + + NdisRegisterMac(&Status, + &NewMacP->NdisMacHandle, + NdisWrapperHandle, + (NDIS_HANDLE)&MlidMacBlock, + &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; + +} + +#ifdef NDIS_WIN + #ifndef DEBUG + #pragma code_seg () + #endif +#endif + + +#ifdef NDIS_WIN + #ifndef DEBUG + #pragma code_seg ("_ITEXT","ICODE") + #endif +#endif + +NDIS_STATUS +MlidAddAdapter( + IN NDIS_HANDLE MacMacContext, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING AdapterName + ) +/*++ +Routine Description: + + This is the Mlid MacAddAdapter routine. The system calls this routine + to add support for a particular Mlid 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 MlidDriverNameStr = NDIS_STRING_CONST("MlidDriverName"); + + ULONG ConfigErrorValue = 0; + BOOLEAN ConfigError = FALSE; + + PMAC_BLOCK NewMacP = &MlidMacBlock; + NDIS_STATUS Status; + PMLID_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; + + } + +#if i386 +#else + ASSERT(0); +#endif + + // + // Read MlidDriverName + // + + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &MlidDriverNameStr, + NdisParameterString + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisCloseConfiguration(ConfigHandle); + + return(NDIS_STATUS_FAILURE); + + } + + // + // Here we load the image for the MLID, get the configuration and make the + // appropriate setup calls + //*\\ HERE! + + // + // Allocate memory for the adapter block now. + // + + Status = NdisAllocateMemory( (PVOID *)&Adapter, sizeof(MLID_ADAPTER), 0, HighestAcceptableMax); + + if (Status != NDIS_STATUS_SUCCESS) { + + ConfigError = TRUE; + ConfigErrorValue = NDIS_ERROR_CODE_OUT_OF_RESOURCES; + + } + + NdisZeroMemory(Adapter,sizeof(MLID_ADAPTER)); + + // + // 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.NumberOfPortDescriptors = 0; + + Status = NdisRegisterAdapter(&Adapter->NdisAdapterHandle, + MlidMacBlock.NdisMacHandle, + (NDIS_HANDLE)Adapter, + ConfigurationHandle, + AdapterName, + &AdapterInformation + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + // + // NdisRegisterAdapter failed. + // + + NdisCloseConfiguration(ConfigHandle); + + NdisFreeMemory(Adapter, sizeof(MLID_ADAPTER), 0); + return NDIS_STATUS_FAILURE; + + } + + + if (ConfigError) { + + // + // Log Error and exit. + // + + NdisWriteErrorLogEntry( + Adapter->NdisAdapterHandle, + ConfigErrorValue, + 1 + ); + + NdisCloseConfiguration(ConfigHandle); + + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + + NdisFreeMemory(Adapter, sizeof(MLID_ADAPTER), 0); + + return(NDIS_STATUS_FAILURE); + + } + + NdisCloseConfiguration(ConfigHandle); + + + if (MlidRegisterAdapter(Adapter) != NDIS_STATUS_SUCCESS) { + + // + // MlidRegisterAdapter failed. + // + + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + NdisFreeMemory(Adapter, sizeof(MLID_ADAPTER), 0); + return NDIS_STATUS_FAILURE; + } + + IF_LOUD( DbgPrint( "MlidRegisterAdapter succeeded\n" );) + + + return NDIS_STATUS_SUCCESS; +} + + +#ifdef NDIS_WIN + #ifndef DEBUG + #pragma code_seg () + #endif +#endif + +#ifdef NDIS_WIN + #ifndef DEBUG + #pragma code_seg ("_ITEXT","ICODE") + #endif +#endif + +NDIS_STATUS +MlidRegisterAdapter( + IN PMLID_ADAPTER Adapter + ) + +/*++ + + +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. + +Return Value: + + Indicates the success or failure of the registration. + +--*/ + +{ + UINT i; + NDIS_PHYSICAL_ADDRESS PhysicalAddress; + + NDIS_STATUS status; //general purpose return from NDIS calls + + Adapter->OpenQueue = (PMLID_OPEN)NULL; + + // + // Allocate the Spin lock. + // + NdisAllocateSpinLock(&Adapter->Lock); + + Adapter->DeferredDpc = (PVOID)MlidReceiveEvents; + + NdisInitializeTimer(&(Adapter->DeferredTimer), + Adapter->DeferredDpc, + Adapter); + + // + // Link us on to the chain of adapters for this MAC. + // + + Adapter->MacBlock = &MlidMacBlock; + NdisAcquireSpinLock(&MlidMacBlock.SpinLock); + Adapter->NextAdapter = MlidMacBlock.AdapterQueue; + MlidMacBlock.AdapterQueue = Adapter; + NdisReleaseSpinLock(&MlidMacBlock.SpinLock); + + // + // Set up the interrupt handlers. + //*\\ HERE! + + KernelInterrupt = (CCHAR)(Adapter->irq_value); + + NdisInitializeInterrupt(&status, // status of call + &(Adapter->NdisInterrupt), // interrupt info str + Adapter->NdisAdapterHandle, + (PNDIS_INTERRUPT_SERVICE) MlidInterruptHandler, + Adapter, // context for ISR, DPC + (PNDIS_DEFERRED_PROCESSING) MlidInterruptDpc, + KernelInterrupt, // int # + KernelInterrupt, // IRQL + FALSE, // NOT shared + (Adapter->bus_type == 0) ? + NdisInterruptLatched : // ATBus + NdisInterruptLevelSensitive // MCA + ); + + + if (status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->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->ram_base)); + + // + // Now Initialize the card. + //*\\ HERE! + + Adapter->FilterDB = NULL; + + // + // Initialize Filter Database + //*\\ HERE! + + if (Adapter->TokenRing) { + + // + // token ring + //*\\ HERE! + + goto fail6; + + } else { + + if (!EthCreateFilter(MulticastListMax, + MlidChangeMulticastAddresses, + MlidChangeFilterClasses, + MlidCloseAction, + Adapter->node_address, + &Adapter->Lock, + &Adapter->FilterDB + )) { + + NdisWriteErrorLogEntry( + Adapter->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)MlidWakeUpDpc; + + NdisInitializeTimer(&Adapter->WakeUpTimer, + (PVOID)(Adapter->WakeUpDpc), + Adapter ); + + NdisSetTimer( + &Adapter->WakeUpTimer, + 5000 + ); + + // + // Initialization completed successfully. + // + + IF_LOUD( { DbgPrint(" MlidLan: [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->NdisAdapterHandle, + Adapter->ram_access, + Adapter->ram_size * 1024); + +failmap: + + NdisRemoveInterrupt(&(Adapter->NdisInterrupt)); + + NdisAcquireSpinLock(&MlidMacBlock.SpinLock); + + // + // Take us out of the AdapterQueue. + // + + if (MlidMacBlock.AdapterQueue == Adapter) { + + MlidMacBlock.AdapterQueue = Adapter->NextAdapter; + + } else { + + PMLID_ADAPTER TmpAdapter = MlidMacBlock.AdapterQueue; + + while (TmpAdapter->NextAdapter != Adapter) { + + TmpAdapter = TmpAdapter->NextAdapter; + + } + + TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter; + } + + NdisReleaseSpinLock(&MlidMacBlock.SpinLock); + +fail3: + NdisFreeSpinLock(&Adapter->Lock); + +fail1: + + return status; +} + +#ifdef NDIS_WIN + #ifndef DEBUG + #pragma code_seg () + #endif +#endif + +#ifdef NDIS_WIN + #ifndef DEBUG + #pragma code_seg ("_ITEXT","ICODE") + #endif +#endif + +NDIS_STATUS +MlidOpenAdapter( + 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. + +--*/ + +{ + PMLID_ADAPTER Adapter = ((PMLID_ADAPTER)MacAdapterContext); + PMLID_OPEN NewOpen; + NDIS_STATUS Status; + + // + // Don't use extended error or OpenOptions for Mlid + // + + 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(MLID_OPEN), 0, HighestAcceptableMax); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->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->NdisAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 0 + ); + + return(NDIS_STATUS_FAILURE); + + } + + IF_LOUD( DbgPrint("OpenSuccess!\n");) + + } + + NewOpen->NextOpen = Adapter->OpenQueue; + Adapter->OpenQueue = NewOpen; + + if (Adapter->TokenRing) { + + //*\\ token ring + + } else { + + if (!EthNoteFilterOpenAdapter( + Adapter->FilterDB, + NewOpen, + NdisBindingContext, + &NewOpen->NdisFilterHandle + )) { + + Adapter->References--; + + Adapter->OpenQueue = NewOpen->NextOpen; + + NdisReleaseSpinLock(&Adapter->Lock); + + NdisWriteErrorLogEntry( + Adapter->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 = MLID_MAX_LOOKAHEAD; + NewOpen->ProtOptionFlags = 0; + + Adapter->MaxLookAhead = MLID_MAX_LOOKAHEAD; + + NewOpen->ReferenceCount = 1; + + *MacBindingHandle = (NDIS_HANDLE)NewOpen; + + MLID_DO_DEFERRED(Adapter); + + IF_LOUD( DbgPrint("Out Open Adapter\n");) + + return NDIS_STATUS_SUCCESS; +} + +#ifdef NDIS_WIN + #ifndef DEBUG + #pragma code_seg () + #endif +#endif + + +VOID +MlidAdjustMaxLookAhead( + IN PMLID_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; + PMLID_OPEN CurrentOpen; + + CurrentOpen = Adapter->OpenQueue; + + while (CurrentOpen != NULL) { + + if (CurrentOpen->LookAhead > CurrentMax) { + + CurrentMax = CurrentOpen->LookAhead; + + } + + CurrentOpen = CurrentOpen->NextOpen; + } + + if (CurrentMax == 0) { + + CurrentMax = MLID_MAX_LOOKAHEAD; + + } + + Adapter->MaxLookAhead = CurrentMax; + +} + +NDIS_STATUS +MlidCloseAdapter( + IN NDIS_HANDLE MacBindingHandle + ) + +/*++ + +Routine Description: + + NDIS function. Unlinks the open block and frees it. + +Arguments: + + See NDIS 3.0 spec. + +--*/ + +{ + PMLID_OPEN Open = ((PMLID_OPEN)MacBindingHandle); + PMLID_ADAPTER Adapter = Open->Adapter; + PMLID_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. + // + + if (Adapter->TokenRing) { + + //*\\ token ring + + } else { + + StatusToReturn = EthDeleteFilterOpenAdapter( + Adapter->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) { + + MlidAdjustMaxLookAhead(Adapter); + + } + + + if (Adapter->OpenQueue == NULL) { + + // + // We can disable the card. + // + + if (NdisSynchronizeWithInterrupt( + &(Adapter->NdisInterrupt), + (PVOID)MlidSyncCloseAdapter, + (PVOID)(&(Adapter->LMAdapter)) + ) == FALSE) { + + NdisWriteErrorLogEntry( + Adapter->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; + + } + + + MLID_DO_DEFERRED(Adapter); + + return(StatusToReturn); + +} + +NDIS_STATUS +MlidRequest( + 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 PMLID_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; + + PMLID_OPEN Open = (PMLID_OPEN)(MacBindingHandle); + PMLID_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 = MlidQueryInformation(Adapter, Open, NdisRequest); + + } else if (NdisRequest->RequestType == NdisRequestSetInformation) { + + if (Adapter->HardwareFailure) { + + NdisReleaseSpinLock(&Adapter->Lock); + + StatusToReturn = NDIS_STATUS_FAILURE; + + } else { + + NdisReleaseSpinLock(&Adapter->Lock); + + StatusToReturn = MlidSetInformation(Adapter,Open,NdisRequest); + + } + + } else { + + NdisReleaseSpinLock(&Adapter->Lock); + + StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED; + + } + + NdisAcquireSpinLock(&Adapter->Lock); + + MlidRemoveReference(Open); + + MLID_DO_DEFERRED(Adapter); + + IF_LOUD( DbgPrint("Out Request\n");) + + return(StatusToReturn); + +} + +NDIS_STATUS +MlidQueryProtocolInformation( + IN PMLID_ADAPTER Adapter, + IN PMLID_OPEN Open, + IN NDIS_OID Oid, + IN BOOLEAN GlobalMode, + IN PVOID InfoBuffer, + IN UINT BytesLeft, + OUT PUINT BytesNeeded, + OUT PUINT BytesWritten +) + +/*++ + +Routine Description: + + The MlidQueryProtocolInformation 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 (Adapter->TokenRing) { + + //*\\ token ring + + break; + } + + if (!GlobalMode) { + + MoveSource = (PVOID)(MlidProtocolSupportedOids); + MoveBytes = sizeof(MlidProtocolSupportedOids); + + } else { + + MoveSource = (PVOID)(MlidGlobalSupportedOids); + MoveBytes = sizeof(MlidGlobalSupportedOids); + + } + 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: + + if (Adapter->TokenRing) { + + Medium = NdisMedium802_5; + + } + + MoveSource = (PVOID) (&Medium); + MoveBytes = sizeof(NDIS_MEDIUM); + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + + GenericULong = MLID_MAX_LOOKAHEAD; + + break; + + + case OID_GEN_MAXIMUM_FRAME_SIZE: + + if (Adapter->TokenRing) { + + GenericULong = Adapter->xmit_buf_size - MLID_HEADER_SIZE; + + } else { + + GenericULong = (ULONG)(MLID_MAX_PACKET_SIZE - MLID_HEADER_SIZE); + + } + + break; + + + case OID_GEN_MAXIMUM_TOTAL_SIZE: + + if (Adapter->TokenRing) { + + GenericULong = Adapter->xmit_buf_size; + + } else { + + GenericULong = (ULONG)(MLID_MAX_PACKET_SIZE); + + } + + break; + + + case OID_GEN_LINK_SPEED: + + if (Adapter->TokenRing) { + + if ((Adapter->media_type & MEDIA_UTP_16) || + (Adapter->media_type & MEDIA_STP_16)) { + + GenericULong = 160000; + + } else { + + GenericULong = 40000; + + } + + } else { + + GenericULong = (ULONG)(100000); + + } + + break; + + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + + GenericULong = (ULONG)(Adapter->num_of_tx_buffs + * Adapter->xmit_buf_size); + + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + + GenericULong = (ULONG)((Adapter->ram_size * 1024) - + (Adapter->num_of_tx_buffs + * Adapter->xmit_buf_size)); + + break; + + case OID_GEN_TRANSMIT_BLOCK_SIZE: + + GenericULong = (ULONG)(Adapter->buffer_page_size); + + break; + + case OID_GEN_RECEIVE_BLOCK_SIZE: + + GenericULong = (ULONG)(Adapter->buffer_page_size); + + break; + + case OID_GEN_VENDOR_ID: + + NdisMoveMemory( + (PVOID)&GenericULong, + Adapter->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)MLID_NDIS_MAJOR_VERSION << 8) | + MLID_NDIS_MINOR_VERSION; + + MoveSource = (PVOID)(&GenericUShort); + MoveBytes = sizeof(GenericUShort); + break; + + + case OID_GEN_CURRENT_PACKET_FILTER: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + + //*\\ token ring + + break; + } + + if (GlobalMode) { + + UINT Filter; + + Filter = ETH_QUERY_FILTER_CLASSES(Adapter->FilterDB); + + GenericULong = (ULONG)(Filter); + + } else { + + UINT Filter = 0; + + Filter = ETH_QUERY_PACKET_FILTER(Adapter->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: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + MLID_MOVE_MEM((PCHAR)GenericArray, + Adapter->permanent_node_address, + ETH_LENGTH_OF_ADDRESS); + + MoveSource = (PVOID)(GenericArray); + MoveBytes = sizeof(Adapter->permanent_node_address); + break; + + case OID_802_3_CURRENT_ADDRESS: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + MLID_MOVE_MEM((PCHAR)GenericArray, + Adapter->node_address, + ETH_LENGTH_OF_ADDRESS); + + MoveSource = (PVOID)(GenericArray); + MoveBytes = sizeof(Adapter->node_address); + break; + + case OID_802_3_MULTICAST_LIST: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + + break; + } + + { + UINT NumAddresses; + + + if (GlobalMode) { + + NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->FilterDB); + + if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) { + + *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS); + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + break; + + } + + EthQueryGlobalFilterAddresses( + &StatusToReturn, + Adapter->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->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->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: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + 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. + // + + MLID_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes); + + (*BytesWritten) += MoveBytes; + + } + } + + NdisReleaseSpinLock(&Adapter->Lock); + + IF_LOUD( DbgPrint("Out QueryProtocol\n");) + + return(StatusToReturn); +} + +NDIS_STATUS +MlidQueryInformation( + IN PMLID_ADAPTER Adapter, + IN PMLID_OPEN Open, + IN PNDIS_REQUEST NdisRequest + ) +/*++ + +Routine Description: + + The MlidQueryInformation is used by MlidRequest 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 = MlidQueryProtocolInformation( + 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 +MlidSetInformation( + IN PMLID_ADAPTER Adapter, + IN PMLID_OPEN Open, + IN PNDIS_REQUEST NdisRequest + ) +/*++ + +Routine Description: + + The MlidSetInformation is used by MlidRequest 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: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + // + // 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 = MlidSetMulticastAddresses( + Adapter, + Open, + NdisRequest, + (UINT)(OidLength / ETH_LENGTH_OF_ADDRESS), + (PVOID)InfoBuffer + ); + break; + + + case OID_GEN_CURRENT_PACKET_FILTER: + + if (Adapter->TokenRing) { + + //*\\ token ring + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + + // + // Verify length + // + + if (OidLength != 4 ) { + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + + break; + + } + + + MLID_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 = MlidSetPacketFilter(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; + + } + + MLID_MOVE_MEM(&LookAhead, InfoBuffer, 4); + + if (LookAhead <= (MLID_MAX_LOOKAHEAD)) { + + if (LookAhead > Adapter->MaxLookAhead) { + + Adapter->MaxLookAhead = LookAhead; + + Open->LookAhead = LookAhead; + + } else { + + if ((Open->LookAhead == Adapter->MaxLookAhead) && + (LookAhead < Open->LookAhead)) { + + Open->LookAhead = LookAhead; + + MlidAdjustMaxLookAhead(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; + + } + + MLID_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 +MlidSetPacketFilter( + IN PMLID_ADAPTER Adapter, + IN PMLID_OPEN Open, + IN PNDIS_REQUEST NdisRequest, + IN UINT PacketFilter + ) + +/*++ + +Routine Description: + + The MlidSetPacketFilter 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->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 +MlidSetMulticastAddresses( + IN PMLID_ADAPTER Adapter, + IN PMLID_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->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 +MlidFillInGlobalData( + IN PMLID_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 = MlidQueryProtocolInformation( + 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: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + GenericULong = (ULONG)(Adapter->CrcErrors); + + break; + + case OID_GEN_RCV_NO_BUFFER: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + GenericULong = (ULONG)(Adapter->MissedPackets); + + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + GenericULong = (ULONG)(Adapter->FrameAlignmentErrors); + + break; + + case OID_802_3_XMIT_ONE_COLLISION: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + GenericULong = (ULONG)(Adapter->FramesXmitOneCollision); + + break; + + case OID_802_3_XMIT_MORE_COLLISIONS: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + 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. + // + + MLID_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 +MlidQueryGlobalStatistics( + IN NDIS_HANDLE MacAdapterContext, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + The MlidQueryGlobalStatistics 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. + // + // + + PMLID_ADAPTER Adapter = (PMLID_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: + + if (Adapter->TokenRing) { + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + + } + break; + + default: + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + + break; + } + + NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock); + + if (StatusToReturn == NDIS_STATUS_SUCCESS) { + + StatusToReturn = MlidFillInGlobalData(Adapter, NdisRequest); + + } + + NdisAcquireSpinLock(&Adapter->Lock); + + MLID_DO_DEFERRED(Adapter); + + return(StatusToReturn); +} + + +VOID +MlidRemoveAdapter( + IN PVOID MacAdapterContext + ) +/*++ + +Routine Description: + + MlidRemoveAdapter removes an adapter previously registered + with NdisRegisterAdapter. + +Arguments: + + MacAdapterContext - The context value that the MAC passed + to NdisRegisterAdapter; actually as pointer to an + MLID_ADAPTER. + +Return Value: + + None. + +--*/ +{ + + PMLID_ADAPTER Adapter; + BOOLEAN Canceled; + + Adapter = PMLID_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext); + + LM_Free_Resources(&Adapter->LMAdapter); + + ASSERT(Adapter->OpenQueue == (PMLID_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(&MlidMacBlock.SpinLock); + + Adapter->Removed = TRUE; + + if (MlidMacBlock.AdapterQueue == Adapter) { + + MlidMacBlock.AdapterQueue = Adapter->NextAdapter; + + } else { + + PMLID_ADAPTER TmpAdaptP = MlidMacBlock.AdapterQueue; + + while (TmpAdaptP->NextAdapter != Adapter) { + + TmpAdaptP = TmpAdaptP->NextAdapter; + + } + + TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter; + } + + NdisReleaseSpinLock(&MlidMacBlock.SpinLock); + + NdisRemoveInterrupt(&(Adapter->NdisInterrupt)); + + NdisUnmapIoSpace( + Adapter->NdisAdapterHandle, + Adapter->ram_access, + Adapter->ram_size * 1024); + + if (Adapter->TokenRing) { + + //*\\ token ring + + } else { + + EthDeleteFilter(Adapter->FilterDB); + + } + + NdisDeregisterAdapter(Adapter->NdisAdapterHandle); + + NdisFreeSpinLock(&Adapter->Lock); + + NdisFreeMemory(Adapter, sizeof(MLID_ADAPTER), 0); + + return; +} + +VOID +MlidUnload( + IN NDIS_HANDLE MacMacContext + ) + +/*++ + +Routine Description: + + MlidUnload is called when the MAC is to unload itself. + +Arguments: + + MacMacContext - actually a pointer to MlidMacBlock. + +Return Value: + + None. + +--*/ + +{ + NDIS_STATUS InitStatus; + + UNREFERENCED_PARAMETER(MacMacContext); + + NdisDeregisterMac( + &InitStatus, + MlidMacBlock.NdisMacHandle + ); + + NdisFreeSpinLock(&MlidMacBlock.SpinLock); + + NdisTerminateWrapper( + MlidMacBlock.NdisWrapperHandle, + NULL + ); + + return; +} + +NDIS_STATUS +MlidSend( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_PACKET Packet + ) +/*++ + +Routine Description: + + NDIS function. Sends a packet on the wire + +Arguments: + + See NDIS 3.0 spec. + +--*/ + +{ + PMLID_OPEN Open = PMLID_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + PMLID_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 + // + + MlidSetLoopbackFlag(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; + + } else { + + PNDIS_PACKET PreviousTail; + + // + // We have to assume it will be sent. In case the send completes + // before we have time to add it. + // + + if (Adapter->PacketsOnCard == NULL) { + + PreviousTail = NULL; + + Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = Packet; + + } else { + + PreviousTail = Adapter->PacketsOnCardTail; + + RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Packet; + + Adapter->PacketsOnCardTail = Packet; + + } + + IF_LOG(LOG('t')); + + if (LM_Send(Packet, &Adapter->LMAdapter) == OUT_OF_RESOURCES) { + + IF_LOG(LOG('Q')); + + // + // 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; + + } + + Adapter->XmitQueue = Packet; + + Adapter->XmitQTail = Packet; + + } + + } + + Status = NDIS_STATUS_PENDING; + + } + + + MLID_DO_DEFERRED(Adapter); + + IF_LOG(LOG('S')); + + return Status; + +} + +UINT +MlidCompareMemory( + 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; +} + + +NDIS_STATUS +MlidReset( + IN NDIS_HANDLE MacBindingHandle + ) + +/*++ + +Routine Description: + + NDIS function. + +Arguments: + + See NDIS 3.0 spec. + +--*/ + +{ + PMLID_OPEN Open = ((PMLID_OPEN)MacBindingHandle); + PMLID_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 MlidReset\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; + + MLID_DO_DEFERRED(Adapter); + + IF_LOUD( DbgPrint("Out MlidReset\n");) + + return(NDIS_STATUS_PENDING); + +} + +STATIC +NDIS_STATUS +MlidChangeMulticastAddresses( + 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 MLID_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. + + +--*/ + +{ + + + PMLID_ADAPTER Adapter = PMLID_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 +MlidChangeFilterClasses( + 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 MLID_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). + + +--*/ + +{ + + PMLID_ADAPTER Adapter = PMLID_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 +MlidCloseAction( + 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 MLID_OPEN. + +Return Value: + + None. + + +--*/ + +{ + + PMLID_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->ReferenceCount--; + +} + +BOOLEAN +MlidInterruptHandler( + 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. + +--*/ + +{ + PMLID_ADAPTER Adapter = ((PMLID_ADAPTER)ServiceContext); + + IF_LOUD( DbgPrint("In MlidISR\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 +MlidInterruptDpc( + 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. + +--*/ +{ + PMLID_ADAPTER Adapter = ((PMLID_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; + + NdisDprReleaseSpinLock(&Adapter->Lock); + + RequeueRcv = MlidReceiveEvents(NULL, (PVOID)Adapter, NULL, NULL); + + NdisDprAcquireSpinLock(&Adapter->Lock); + + MlidTransmitEvents(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); + + Adapter->ProcessingDpc = FALSE; + + // + // Reenable interrupts + // + + Adapter->InterruptMask = PACKET_RECEIVE_ENABLE | + PACKET_TRANSMIT_ENABLE | + RECEIVE_ERROR_ENABLE | + TRANSMIT_ERROR_ENABLE | + OVERWRITE_WARNING_ENABLE | + COUNTER_OVERFLOW_ENABLE; + + NdisSynchronizeWithInterrupt( + &(Adapter->NdisInterrupt), + LM_Enable_Adapter, + &Adapter->LMAdapter + ); + + MLID_DO_DEFERRED(Adapter); + + IF_LOUD( DbgPrint("<==IntDpc\n");) + + IF_LOG(LOG('D')); + +} + +VOID +MlidIndicateLoopbackPacket( + IN PMLID_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 + MLID_HEADER_SIZE) ? + (Adapter->MaxLookAhead + MLID_HEADER_SIZE) : + PacketLen + ); + + // + // Copy the lookahead data into a contiguous buffer. + // + + MlidCopyOver(Adapter->LookAhead, + Packet, + 0, + IndicateLen + ); + + NdisDprReleaseSpinLock(&Adapter->Lock); + + + // + // Indicate packet + // + + if (Adapter->TokenRing) { + + //*\\ token ring + + } else { + + if (PacketLen < MLID_HEADER_SIZE) { + + // + // Runt packet + // + + EthFilterIndicateReceive( + Adapter->FilterDB, + (NDIS_HANDLE)Adapter, + (PCHAR)Adapter->LookAhead, + Adapter->LookAhead, + PacketLen, + NULL, + 0, + 0 + ); + + } else { + + EthFilterIndicateReceive( + Adapter->FilterDB, + (NDIS_HANDLE)Adapter, + (PCHAR)Adapter->LookAhead, + Adapter->LookAhead, + MLID_HEADER_SIZE, + Adapter->LookAhead + MLID_HEADER_SIZE, + IndicateLen - MLID_HEADER_SIZE, + PacketLen - MLID_HEADER_SIZE + ); + + } + + } + + NdisDprAcquireSpinLock(&Adapter->Lock); + + } + +} + +BOOLEAN +MlidReceiveEvents( + IN PVOID SystemSpecific1, + IN PVOID Context, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) +/*++ + +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. + +Arguments: + + Context - a handle to the adapter block. + +Return Value: + + Do we need to requeue this Rcv. + +--*/ +{ + + PMLID_ADAPTER Adapter = (PMLID_ADAPTER)(Context); + PNDIS_PACKET Packet; + PMLID_OPEN TmpOpen; + NDIS_STATUS Status; + BOOLEAN RequeueRcv; + + IF_LOG(LOG('e')); + + NdisDprAcquireSpinLock(&Adapter->Lock); + + Adapter->References++; + + 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 + // + + MlidIndicateLoopbackPacket(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); + + MlidRemoveReference(TmpOpen); + + } + + // + // If any indications done, then + // + // CompleteIndications(); + // + + if (Adapter->IndicatedAPacket) { + + Adapter->IndicatedAPacket = FALSE; + + NdisDprReleaseSpinLock(&Adapter->Lock); + + if (Adapter->TokenRing) { + + //*\\ token ring + + } else { + + EthFilterIndicateReceiveComplete(Adapter->FilterDB); + + } + + NdisDprAcquireSpinLock(&Adapter->Lock); + + } + + + + if ((Adapter->ResetRequested) && (Adapter->References == 1)) { + + PNDIS_PACKET Packet; + PMLID_OPEN TmpOpen; + + IF_LOG(LOG('R')); + + IF_VERY_LOUD( DbgPrint("Starting Reset\n");) + + Adapter->ResetInProgress = TRUE; + + NdisSynchronizeWithInterrupt( + &(Adapter->NdisInterrupt), + LM_Disable_Adapter, + &Adapter->LMAdapter + ); + + // + // Indicate Status to all opens + // + + IF_VERY_LOUD( DbgPrint("Indicating status\n");) + + TmpOpen = Adapter->OpenQueue; + + while (TmpOpen != (PMLID_OPEN)NULL) { + + AddRefWhileHoldingSpinLock(Adapter, TmpOpen); + + NdisDprReleaseSpinLock(&Adapter->Lock); + + NdisIndicateStatus(TmpOpen->NdisBindingContext, + NDIS_STATUS_RESET_START, + NULL, + 0 + ); + + + NdisDprAcquireSpinLock(&Adapter->Lock); + + MlidRemoveReference(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->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); + + MlidRemoveReference(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 != (PMLID_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); + + MlidRemoveReference(TmpOpen); + + TmpOpen = TmpOpen->NextOpen; + + } + + NdisDprReleaseSpinLock(&Adapter->Lock); + + NdisCompleteReset(Adapter->ResetOpen->NdisBindingContext, + (Adapter->HardwareFailure) ? + NDIS_STATUS_FAILURE : + NDIS_STATUS_SUCCESS + ); + + NdisDprAcquireSpinLock(&Adapter->Lock); + + MlidRemoveReference(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 + + Adapter->References--; + + IF_LOG(LOG('E')); + + NdisDprReleaseSpinLock(&Adapter->Lock); + + return(RequeueRcv); + +} + + +VOID +MlidTransmitEvents( + IN PMLID_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 +MlidCopyOver( + 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; + + MLID_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 +MlidTransferData( + 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. + +--*/ +{ + PMLID_OPEN Open = PMLID_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + PMLID_ADAPTER Adapter = Open->Adapter; + PNDIS_BUFFER CurrentBuffer; + PUCHAR BufferVA; + UINT BufferLength, Copied; + UINT CurrentOffset; + + UNREFERENCED_PARAMETER(MacReceiveContext); + + ByteOffset += MLID_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 = + MlidCopyOver(BufferVA, + Adapter->IndicatingPacket, + CurrentOffset, + BufferLength + ); + + NdisReleaseSpinLock(&Adapter->Lock); + + CurrentOffset += Copied; + + if (Copied < BufferLength) { + + break; + + } + + NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer); + + } + + // + // We are done, return. + // + + + *BytesTransferred = CurrentOffset - ByteOffset; + + 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 +MlidSyncCloseAdapter( + 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 +MlidWakeUpDpc( + 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. + +--*/ +{ + PMLID_ADAPTER Adapter = (PMLID_ADAPTER)Context; + PMLID_OPEN TmpOpen; + PNDIS_PACKET TransmitPacket; + PMAC_RESERVED Reserved; + + UNREFERENCED_PARAMETER(SystemSpecific1); + UNREFERENCED_PARAMETER(SystemSpecific2); + UNREFERENCED_PARAMETER(SystemSpecific3); + + NdisAcquireSpinLock(&Adapter->Lock); + + if ((Adapter->WakeUpTimeout) && + ((Adapter->PacketsOnCard != NULL) || + (Adapter->XmitQueue != NULL))) { + + // + // 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; + + if (Adapter->WakeUpErrorCount < 10) { + + Adapter->WakeUpErrorCount++; + + NdisWriteErrorLogEntry( + Adapter->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; + + // + // reinitialize the card + // + + if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) { + + Adapter->HardwareFailure = TRUE; + + NdisWriteErrorLogEntry( + Adapter->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 + ); + +} + + + |