/*++ 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 #include #include #include #include #include #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; iDirected = 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 ); }