diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ndis/wd/wd.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/ndis/wd/wd.c')
-rw-r--r-- | private/ntos/ndis/wd/wd.c | 4599 |
1 files changed, 4599 insertions, 0 deletions
diff --git a/private/ntos/ndis/wd/wd.c b/private/ntos/ndis/wd/wd.c new file mode 100644 index 000000000..289770e76 --- /dev/null +++ b/private/ntos/ndis/wd/wd.c @@ -0,0 +1,4599 @@ +/*++ + +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 + ); + +} |