/*++ Copyright (c) 1990 Microsoft Corporation Module Name: lance.c Abstract: This is the main file for the Advanced Micro Devices LANCE (Am 7990) Ethernet controller. This driver conforms to the NDIS 3.0 interface. The idea for handling loopback and sends simultaneously is largely adapted from the EtherLink II NDIS driver by Adam Barr. Author: Anthony V. Ercolano (Tonye) 20-Jul-1990 Environment: Kernel Mode - Or whatever is the equivalent on OS/2 and DOS. Revision History: --*/ #include #include "lancehrd.h" #include "lancesft.h" #include "dectc.h" #include "keywords.h" //#if DBG #define STATIC //#else //#define STATIC static //#endif #if DBG UCHAR LanceSendFails[256] = {0}; UCHAR LanceSendFailPlace = 0; #endif NDIS_HANDLE LanceNdisWrapperHandle = NULL; PDRIVER_OBJECT LanceDriverObject = NULL; // // 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); #if LANCELOG UCHAR Log[LOG_SIZE] = {0}; UCHAR LogPlace = 0; UCHAR LogWrapped = 0; UCHAR LancePrintLog = 0; #endif // // If you add to this, make sure to add the // LanceQueryInformation() if it is // queriable information. // UINT LanceGlobalSupportedOids[] = { 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 }; // // We define a constant csr0 value that is useful for initializing // an already stopped LANCE. // // This also enables the chip for interrupts. // #define LANCE_CSR0_INIT_CHIP ((USHORT)0x41) // // We define a constant csr0 value that is useful for clearing all of // the interesting bits that *could* be set on an interrupt. // #define LANCE_CSR0_CLEAR_INTERRUPT_BITS ((USHORT)0x7f00) VOID LanceDeferredTimerRoutine( IN PVOID SystemSpecific1, IN NDIS_HANDLE Context, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3 ); NDIS_STATUS LanceQueryInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ); NDIS_STATUS LanceSetInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesRead, OUT PULONG BytesNeeded ); NDIS_STATUS LanceReset( OUT PBOOLEAN AddressingReset, IN NDIS_HANDLE MiniportAdapterContext ); BOOLEAN AllocateAdapterMemory( IN PLANCE_ADAPTER Adapter ); NDIS_STATUS LanceSetPacketFilter( IN PLANCE_ADAPTER Adapter, IN NDIS_REQUEST_TYPE NdisRequestType, IN UINT PacketFilter ); NDIS_STATUS LanceChangeMulticastAddresses( IN PLANCE_ADAPTER Adapter, IN UINT NewAddressCount, IN CHAR NewAddresses[][LANCE_LENGTH_OF_ADDRESS], IN NDIS_REQUEST_TYPE NdisRequestType ); VOID DeleteAdapterMemory( IN PLANCE_ADAPTER Adapter ); VOID RelinquishReceivePacket( IN PLANCE_ADAPTER Adapter, IN UINT StartingIndex, IN UINT NumberOfBuffers ); BOOLEAN ProcessReceiveInterrupts( IN PLANCE_ADAPTER Adapter ); NDIS_STATUS LanceRegisterAdapter( IN PLANCE_ADAPTER Adapter ); BOOLEAN ProcessTransmitInterrupts( IN PLANCE_ADAPTER Adapter ); UINT CalculateCRC( IN UINT NumberOfBytes, IN PCHAR Input ); VOID LanceStartChip( IN PLANCE_ADAPTER Adapter ); VOID LanceSetInitializationBlock( IN PLANCE_ADAPTER Adapter ); VOID SetInitBlockAndInit( IN PLANCE_ADAPTER Adapter ); VOID StartAdapterReset( IN PLANCE_ADAPTER Adapter ); VOID SetupForReset( IN PLANCE_ADAPTER Adapter, IN NDIS_REQUEST_TYPE RequestType ); NDIS_STATUS LanceInitialInit( IN PLANCE_ADAPTER Adapter ); 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 primary initialization routine for the lance driver. It is simply responsible for the intializing the wrapper and registering the MAC. It then calls a system and architecture specific routine that will initialize and register each adapter. Arguments: DriverObject - Pointer to driver object created by the system. Return Value: The status of the operation. --*/ { // // Receives the status of the NdisRegisterMac operation. // NDIS_STATUS Status; NDIS_HANDLE NdisWrapperHandle; NDIS_MINIPORT_CHARACTERISTICS LanceChar; NDIS_STRING MacName = NDIS_STRING_CONST("Lance"); #if NDIS_WIN UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (ULONG)]; #endif #if NDIS_WIN ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=1; ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=0; *(PULONG)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=DE422_COMPRESSED_ID; (PVOID)DriverObject=(PVOID)pIds; #endif // // Initialize the wrapper. // NdisInitializeWrapper( &NdisWrapperHandle, DriverObject, RegistryPath, NULL ); // // Initialize the MAC characteristics for the call to // NdisRegisterMac. // NdisZeroMemory(&LanceChar, sizeof(LanceChar)); LanceChar.MajorNdisVersion = LANCE_NDIS_MAJOR_VERSION; LanceChar.MinorNdisVersion = LANCE_NDIS_MINOR_VERSION; LanceChar.CheckForHangHandler = NULL; LanceChar.DisableInterruptHandler = LanceDisableInterrupt; LanceChar.EnableInterruptHandler = LanceEnableInterrupt; LanceChar.HaltHandler = LanceHalt; LanceChar.HandleInterruptHandler = LanceHandleInterrupt; LanceChar.InitializeHandler = LanceInitialize; LanceChar.ISRHandler = LanceIsr; LanceChar.QueryInformationHandler = LanceQueryInformation; LanceChar.ReconfigureHandler = NULL; LanceChar.ResetHandler = LanceReset; LanceChar.SendHandler = LanceSend; LanceChar.SetInformationHandler = LanceSetInformation; LanceChar.TransferDataHandler = LanceTransferData; Status = NdisMRegisterMiniport( NdisWrapperHandle, &LanceChar, sizeof(LanceChar) ); if (Status != NDIS_STATUS_SUCCESS) { NdisTerminateWrapper(NdisWrapperHandle, NULL); } return(Status); } #pragma NDIS_INIT_FUNCTION(LanceInitialize) extern NDIS_STATUS LanceInitialize( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE ConfigurationHandle ) /*++ Routine Description: NE3200Initialize starts an adapter. Arguments: See NDIS 3.0 Miniport spec. Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_PENDING --*/ { // // Pointer for the adapter root. // PLANCE_ADAPTER Adapter; NDIS_HANDLE ConfigHandle; PNDIS_CONFIGURATION_PARAMETER ReturnedValue; NDIS_STRING IoAddressStr = IOADDRESS; NDIS_STRING MaxMulticastListStr = MAXMULTICASTLIST; NDIS_STRING NetworkAddressStr = NETWORKADDRESS; NDIS_STRING InterruptStr = INTERRUPT; NDIS_STRING CardStr = CARDTYPE; NDIS_STRING MemoryBaseAddrStr = MEMMAPPEDBASEADDRESS; #if NDIS2 NDIS_STRING DE201Str = NDIS_STRING_CONST("DE201"); NDIS_STRING DE100Str = NDIS_STRING_CONST("DE100"); NDIS_STRING DEPCAStr = NDIS_STRING_CONST("DEPCA"); NDIS_STRING DECTCStr = NDIS_STRING_CONST("DECTC"); NDIS_STRING DE422Str = NDIS_STRING_CONST("DE422"); NDIS_STRING DE200Str = NDIS_STRING_CONST("DE200"); NDIS_STRING DE101Str = NDIS_STRING_CONST("DE101"); #endif NDIS_EISA_FUNCTION_INFORMATION EisaData; USHORT ConfigValue = 0; UCHAR HiBaseValue = 0; UINT MaxMulticastList = 32; PVOID NetAddress; UINT Length; USHORT RegUshort; UCHAR RegUchar; UINT LanceSlot = 1; BOOLEAN ConfigError = FALSE; NDIS_STATUS ConfigErrorCode; NDIS_STATUS Status; // // Search for correct medium. // for (; MediumArraySize > 0; MediumArraySize--){ if (MediumArray[MediumArraySize - 1] == NdisMedium802_3){ MediumArraySize--; break; } } if (MediumArray[MediumArraySize] != NdisMedium802_3){ return( NDIS_STATUS_UNSUPPORTED_MEDIA ); } *SelectedMediumIndex = MediumArraySize; // // Allocate the Adapter block. // LANCE_ALLOC_PHYS(&Adapter, sizeof(LANCE_ADAPTER)); if (Adapter == NULL) { return( NDIS_STATUS_RESOURCES ) ; } LANCE_ZERO_MEMORY(Adapter, sizeof(LANCE_ADAPTER)); Adapter->MaxLookAhead = LANCE_MAX_LOOKAHEAD; // // Start with the default card // Adapter->LanceCard = LANCE_DE201; Adapter->MiniportAdapterHandle = MiniportAdapterHandle; Adapter->IoBaseAddr = LANCE_DE201_PRI_NICSR_ADDRESS; Adapter->HardwareBaseAddr = LANCE_DE201_BASE; Adapter->AmountOfHardwareMemory = LANCE_DE201_HARDWARE_MEMORY; Adapter->InterruptNumber = LANCE_DE201_INTERRUPT_VECTOR; Adapter->InterruptRequestLevel = LANCE_DE201_INTERRUPT_VECTOR; Adapter->BeingRemoved = FALSE; NdisOpenConfiguration(&Status, &ConfigHandle, ConfigurationHandle); if (Status != NDIS_STATUS_SUCCESS) return(Status); #if NDIS2 // // Read Card Type // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &CardStr, NdisParameterString ); if (Status == NDIS_STATUS_SUCCESS) { if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE201Str, 1)) { Adapter->LanceCard = LANCE_DE201; } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE100Str, 1)) { Adapter->LanceCard = LANCE_DE100; } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DEPCAStr, 1)) { Adapter->LanceCard = LANCE_DEPCA; #ifndef i386 } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DECTCStr, 1)) { Adapter->LanceCard = LANCE_DECTC; ConfigErrorCode = LanceDecTcGetConfiguration(ConfigHandle, Adapter); if ( ConfigErrorCode != NDIS_STATUS_SUCCESS ) { ConfigError = TRUE; } #endif // i386 } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE422Str, 1)) { Adapter->LanceCard = LANCE_DE422; } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE200Str, 1)) { // // This is the De200, but it operates exactly like the 201. // Adapter->LanceCard = LANCE_DE201; } else if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &DE101Str, 1)) { // // This is the De101, but it operates exactly like the 100. // Adapter->LanceCard = LANCE_DE100; } else { ConfigError = TRUE; ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; goto RegisterAdapter; } } #else // // Read Card Type // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &CardStr, NdisParameterInteger ); if (Status == NDIS_STATUS_SUCCESS) { if (ReturnedValue->ParameterData.IntegerData == 2) { Adapter->LanceCard = LANCE_DE201; } else if (ReturnedValue->ParameterData.IntegerData == 1) { Adapter->LanceCard = LANCE_DE100; } else if (ReturnedValue->ParameterData.IntegerData == 3) { Adapter->LanceCard = LANCE_DEPCA; #ifndef i386 } else if (ReturnedValue->ParameterData.IntegerData == 4) { Adapter->LanceCard = LANCE_DECTC; ConfigErrorCode = LanceDecTcGetConfiguration(ConfigHandle, Adapter); if ( ConfigErrorCode != NDIS_STATUS_SUCCESS ) { ConfigError = TRUE; } #endif // i386 } else if (ReturnedValue->ParameterData.IntegerData == 5) { Adapter->LanceCard = LANCE_DE422; } else if (ReturnedValue->ParameterData.IntegerData == 6) { // // This is the De200, but it operates exactly like the 201. // Adapter->LanceCard = LANCE_DE201; } else if (ReturnedValue->ParameterData.IntegerData == 7) { // // This is the De101, but it operates exactly like the 100. // Adapter->LanceCard = LANCE_DE100; } else { ConfigError = TRUE; ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; goto RegisterAdapter; } } #endif // // Read MaxMulticastList // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &MaxMulticastListStr, NdisParameterInteger ); if (Status == NDIS_STATUS_SUCCESS) { MaxMulticastList = ReturnedValue->ParameterData.IntegerData; } // // Read net address // NdisReadNetworkAddress( &Status, &NetAddress, &Length, ConfigHandle ); if ((Length == LANCE_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) { NdisMoveMemory( Adapter->CurrentNetworkAddress, NetAddress, LANCE_LENGTH_OF_ADDRESS ); } if (Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100)) { // // Read IoAddress // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &IoAddressStr, NdisParameterHexInteger ); if (Status == NDIS_STATUS_SUCCESS) { if (ReturnedValue->ParameterData.IntegerData == LANCE_DE201_PRI_NICSR_ADDRESS) { Adapter->IoBaseAddr = LANCE_DE201_PRI_NICSR_ADDRESS; } else if (ReturnedValue->ParameterData.IntegerData == LANCE_DE201_SEC_NICSR_ADDRESS) { Adapter->IoBaseAddr = LANCE_DE201_SEC_NICSR_ADDRESS; } else { ConfigError = TRUE; ConfigErrorCode = NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS; goto RegisterAdapter; } } // // Read Interrupt // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &InterruptStr, NdisParameterInteger ); if (Status == NDIS_STATUS_SUCCESS) { Adapter->InterruptNumber = (CCHAR)ReturnedValue->ParameterData.IntegerData; Adapter->InterruptRequestLevel = Adapter->InterruptNumber; if (Adapter->LanceCard == LANCE_DE201) { if (!((Adapter->InterruptNumber == 5) || (Adapter->InterruptNumber == 9) || (Adapter->InterruptNumber == 10) || (Adapter->InterruptNumber == 11) || (Adapter->InterruptNumber == 15))) { ConfigError = TRUE; ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; goto RegisterAdapter; } } else { if (!((Adapter->InterruptNumber == 2) || (Adapter->InterruptNumber == 3) || (Adapter->InterruptNumber == 4) || (Adapter->InterruptNumber == 5) || (Adapter->InterruptNumber == 7))) { ConfigError = TRUE; ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; goto RegisterAdapter; } } } // // Read MemoryBaseAddress // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &MemoryBaseAddrStr, NdisParameterHexInteger ); if (Status == NDIS_STATUS_SUCCESS) { #if NDIS2 Adapter->HardwareBaseAddr = (PVOID)((ReturnedValue->ParameterData.IntegerData) << 4); #else Adapter->HardwareBaseAddr = (PVOID)(ReturnedValue->ParameterData.IntegerData); #endif if (!((Adapter->HardwareBaseAddr == (PVOID)0xC0000) || (Adapter->HardwareBaseAddr == (PVOID)0xC8000) || (Adapter->HardwareBaseAddr == (PVOID)0xD0000) || (Adapter->HardwareBaseAddr == (PVOID)0xD8000) || (Adapter->HardwareBaseAddr == (PVOID)0xE0000) || (Adapter->HardwareBaseAddr == (PVOID)0xE8000))) { ConfigError = TRUE; ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; goto RegisterAdapter; } } if (((ULONG)Adapter->HardwareBaseAddr) & 0x8000) { Adapter->AmountOfHardwareMemory = 0x8000; Adapter->HardwareBaseOffset = 0x8000; } else { Adapter->AmountOfHardwareMemory = 0x10000; Adapter->HardwareBaseOffset = 0x0; } } else if (Adapter->LanceCard == LANCE_DEPCA) { Adapter->InterruptNumber = LANCE_DEPCA_INTERRUPT_VECTOR; Adapter->InterruptRequestLevel = LANCE_DEPCA_INTERRUPT_VECTOR; Adapter->AmountOfHardwareMemory = LANCE_DEPCA_HARDWARE_MEMORY; Adapter->HardwareBaseAddr = LANCE_DEPCA_BASE; Adapter->IoBaseAddr = LANCE_DEPCA_NICSR_ADDRESS; } else if (Adapter->LanceCard == LANCE_DE422) { PUCHAR CurrentChar; BOOLEAN LastEntry; UCHAR InitType; USHORT PortAddress, PortValue, Mask; // // Read Slot Number // NdisReadEisaSlotInformation( &Status, ConfigurationHandle, &(Adapter->SlotNumber), &EisaData ); if (Status != NDIS_STATUS_SUCCESS) { ConfigError = TRUE; ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; goto RegisterAdapter; } // // Setup Ports // Adapter->IoBaseAddr = (((ULONG)Adapter->SlotNumber) << 12) + LANCE_DE422_NICSR_ADDRESS; Adapter->NetworkHardwareAddress = Adapter->IoBaseAddr + LANCE_DE422_NETWORK_OFFSET; CurrentChar = (PUCHAR) (EisaData.InitializationData); LastEntry = FALSE; while (!LastEntry) { InitType = *(CurrentChar++); PortAddress = *((USHORT UNALIGNED *) CurrentChar++); CurrentChar++; if ((InitType & 0x80) == 0) { LastEntry = TRUE; } if (PortAddress == (USHORT)(Adapter->NetworkHardwareAddress)) { PortValue = *((USHORT UNALIGNED *) CurrentChar++); } else if (PortAddress == ((Adapter->SlotNumber << 12) + LANCE_DE422_NICSR_ADDRESS + LANCE_DE422_EXTENDED_MEMORY_BASE_OFFSET)) { PortValue = (USHORT)(*(CurrentChar++)); } else { continue; } if (InitType & 0x40) { if (PortAddress == Adapter->NetworkHardwareAddress) { Mask = *((USHORT UNALIGNED *) CurrentChar++); } else { Mask = (USHORT)(*(CurrentChar++)); } } else { Mask = 0; } if (PortAddress == Adapter->NetworkHardwareAddress) { ConfigValue &= Mask; ConfigValue |= PortValue; } else { HiBaseValue &= (UCHAR)Mask; HiBaseValue |= (UCHAR)PortValue; } } // // Interpret values // switch (ConfigValue & 0x78) { case 0x40: Adapter->InterruptNumber = 11; break; case 0x20: Adapter->InterruptNumber = 10; break; case 0x10: Adapter->InterruptNumber = 9; break; case 0x08: Adapter->InterruptNumber = 5; break; default: ConfigError = TRUE; ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; goto RegisterAdapter; } Adapter->InterruptRequestLevel = Adapter->InterruptNumber; // // We postpone the rest of the processing since we have to read from // the NICSR to get the amount of hardware memory and cannot do that // until after we have called NdisRegisterAdapter. // } RegisterAdapter: NdisCloseConfiguration(ConfigHandle); if (ConfigError) { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, ConfigErrorCode, 0 ); LANCE_FREE_PHYS(Adapter, sizeof(LANCE_ADAPTER)); return(NDIS_STATUS_FAILURE); } NdisMSetAttributes( MiniportAdapterHandle, (NDIS_HANDLE)Adapter, FALSE, (Adapter->LanceCard == LANCE_DE422) ? NdisInterfaceEisa : NdisInterfaceIsa ); // // Register the IoPortRanges // if (Adapter->LanceCard & (LANCE_DE100 | LANCE_DE201)) { Status = NdisMRegisterIoPortRange( (PVOID *)(&(Adapter->Nicsr)), MiniportAdapterHandle, Adapter->IoBaseAddr, 0x10 ); Adapter->RAP = Adapter->Nicsr + LANCE_DE201_RAP_OFFSET; Adapter->RDP = Adapter->Nicsr + LANCE_DE201_RDP_OFFSET; Adapter->NetworkHardwareAddress = Adapter->Nicsr + LANCE_DE201_NETWORK_OFFSET; } else if (Adapter->LanceCard == LANCE_DE422) { Status = NdisMRegisterIoPortRange( (PVOID *)(&(Adapter->Nicsr)), MiniportAdapterHandle, Adapter->IoBaseAddr, 0x90 ); Adapter->RAP = Adapter->Nicsr + LANCE_DE422_RAP_OFFSET; Adapter->RDP = Adapter->Nicsr + LANCE_DE422_RDP_OFFSET; Adapter->NetworkHardwareAddress = Adapter->Nicsr + LANCE_DE422_NETWORK_OFFSET; } else if (Adapter->LanceCard == LANCE_DEPCA) { Status = NdisMRegisterIoPortRange( (PVOID *)(&(Adapter->Nicsr)), MiniportAdapterHandle, Adapter->IoBaseAddr, 0x10 ); Adapter->LanceCard = LANCE_DE100; Adapter->RAP = Adapter->Nicsr + LANCE_DEPCA_RAP_OFFSET; Adapter->RDP = Adapter->Nicsr + LANCE_DEPCA_RDP_OFFSET; Adapter->NetworkHardwareAddress = Adapter->Nicsr + LANCE_DEPCA_EPROM_OFFSET; } #ifndef i386 else if (Adapter->LanceCard == LANCE_DECTC) { Status = NdisMRegisterIoPortRange( (PVOID *)(&(Adapter->Nicsr)), MiniportAdapterHandle, ((ULONG)Adapter->HardwareBaseAddr) + LANCE_DECTC_REGISTER_OFFSET, LANCE_DECTC_REGISTER_MAPSIZE ); Adapter->RAP = Adapter->Nicsr + LANCE_DEPCA_RAP_OFFSET; Adapter->RDP = Adapter->Nicsr + LANCE_DEPCA_RDP_OFFSET; Adapter->NetworkHardwareAddress = Adapter->Nicsr + LANCE_DEPCA_EPROM_OFFSET; } #endif if (Status != NDIS_STATUS_SUCCESS) { LANCE_FREE_PHYS(Adapter, sizeof(LANCE_ADAPTER)); return Status; } // // Now we get the rest of the information necessary for the DE422. // if (Adapter->LanceCard == LANCE_DE422) { // // Verify card is a DE422 // NdisRawReadPortUshort( (Adapter->Nicsr + LANCE_DE422_EISA_IDENTIFICATION_OFFSET), &RegUshort ); if (RegUshort != 0xA310) { // // Not a DE422 card // NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, 0 ); Status = NDIS_STATUS_FAILURE; goto Fail1; } NdisRawReadPortUshort( Adapter->Nicsr + LANCE_DE422_EISA_IDENTIFICATION_OFFSET + 2, &RegUshort ); if (RegUshort != 0x2042) { // // Not a DE422 card // NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, 0 ); Status = NDIS_STATUS_FAILURE; goto Fail1; } // // Check that the card is enabled. // NdisRawReadPortUchar( Adapter->Nicsr + LANCE_DE422_EISA_CONTROL_OFFSET, &RegUchar ); if (!(RegUchar & 0x1)) { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_ADAPTER_DISABLED, 0 ); Status = NDIS_STATUS_FAILURE; goto Fail1; } // // Get Memory size // NdisRawReadPortUshort( Adapter->Nicsr, &RegUshort ); if (RegUshort & LANCE_NICSR_BUFFER_SIZE) { Adapter->AmountOfHardwareMemory = 0x8000; } else if (RegUshort & LANCE_NICSR_128K) { Adapter->AmountOfHardwareMemory = 0x20000; Adapter->NicsrDefaultValue = LANCE_NICSR_128K; } else { Adapter->AmountOfHardwareMemory = 0x10000; } // // Get Base memory address // switch (Adapter->AmountOfHardwareMemory) { case 0x8000: switch (ConfigValue & 0x07) { case 0x04: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xC8000); Adapter->HardwareBaseOffset = 0x8000; break; case 0x05: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xE8000); Adapter->HardwareBaseOffset = 0x8000; break; case 0x06: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xD8000); Adapter->HardwareBaseOffset = 0x8000; break; case 0x07: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xF8000); Adapter->HardwareBaseOffset = 0x8000; break; default: NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 0 ); Status = NDIS_STATUS_FAILURE; goto Fail1; } break; case 0x10000: switch (ConfigValue & 0x07) { case 0x00: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xC0000); Adapter->HardwareBaseOffset = 0x0000; break; case 0x01: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xE0000); Adapter->HardwareBaseOffset = 0x0000; break; case 0x02: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xD0000); Adapter->HardwareBaseOffset = 0x0000; break; case 0x03: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xF0000); Adapter->HardwareBaseOffset = 0x0000; break; default: NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 0 ); Status = NDIS_STATUS_FAILURE; goto Fail1; } break; case 0x20000: switch (ConfigValue & 0x07) { case 0x00: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xC0000); Adapter->HardwareBaseOffset = 0x0000; break; case 0x01: Adapter->HardwareBaseAddr = (PVOID)((HiBaseValue << 24) + 0xD0000); Adapter->HardwareBaseOffset = 0x0000; break; default: NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 0 ); Status = NDIS_STATUS_FAILURE; goto Fail1; } break; } } // // Set the port addresses and the network address. // Adapter->InterruptsStopped = FALSE; Adapter->MaxMulticastList = MaxMulticastList; Status = LanceRegisterAdapter( Adapter ); if (Status != NDIS_STATUS_SUCCESS) { goto Fail1; } return Status; Fail1: // // Deregister the IoPortRanges // if (Adapter->LanceCard & (LANCE_DE100 | LANCE_DE201)) { NdisMDeregisterIoPortRange( MiniportAdapterHandle, Adapter->IoBaseAddr, 0x10, (PVOID)(Adapter->Nicsr) ); } else if (Adapter->LanceCard == LANCE_DE422) { NdisMDeregisterIoPortRange( MiniportAdapterHandle, Adapter->IoBaseAddr, 0x90, (PVOID)(Adapter->Nicsr) ); } LANCE_FREE_PHYS(Adapter, sizeof(LANCE_ADAPTER)); return(Status); } VOID LanceHalt( IN PVOID MiniportAdapterContext ) /*++ Routine Description: LanceHalt stops an adapter and deregisters everything. Arguments: MiniportAdapterContext - The context value that the driver when LanceInitialize is called. Actually as pointer to an LANCE_ADAPTER. Return Value: None. --*/ { PLANCE_ADAPTER Adapter; Adapter = PLANCE_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); LOG(REMOVE); // // bug 2275 // LanceSyncStopChip(Adapter); NdisMDeregisterInterrupt(&(Adapter->Interrupt)); #if NDIS_WIN // // Restore saved values // { PUCHAR pTemp = Adapter->MmMappedBaseAddr; (UINT)pTemp &= 0xffff0000; (UINT)pTemp |= 0x0000bffe; NdisWriteRegisterUshort((PUSHORT)pTemp, Adapter->SavedMemBase); pTemp = Adapter->MmMappedBaseAddr; NdisWriteRegisterUlong((PULONG)pTemp, Adapter->Reserved1); NdisWriteRegisterUlong((PULONG)pTemp, Adapter->Reserved2); } #endif NdisMUnmapIoSpace( Adapter->MiniportAdapterHandle, Adapter->MmMappedBaseAddr, Adapter->AmountOfHardwareMemory ); // // bug3327 // NdisRawWritePortUshort((ULONG)(Adapter->Nicsr), 0x04); if (Adapter->LanceCard & (LANCE_DE100 | LANCE_DE201)) { NdisMDeregisterIoPortRange( Adapter->MiniportAdapterHandle, Adapter->IoBaseAddr, 0x10, (PVOID)(Adapter->Nicsr) ); } else if (Adapter->LanceCard == LANCE_DE422) { NdisMDeregisterIoPortRange( Adapter->MiniportAdapterHandle, Adapter->IoBaseAddr, 0x90, (PVOID)(Adapter->Nicsr) ); } DeleteAdapterMemory(Adapter); NdisFreeMemory(Adapter, sizeof(LANCE_ADAPTER), 0); return; } #pragma NDIS_INIT_FUNCTION(LanceRegisterAdapter) NDIS_STATUS LanceRegisterAdapter( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: This routine is responsible for the allocation of the datastructures for the driver as well as any hardware specific details necessary to talk with the device. Arguments: Adapter - Pointer to the adapter block. Return Value: Returns false if anything occurred that prevents the initialization of the adapter. --*/ { // // Result of Ndis Calls. // NDIS_STATUS Status; // // We put in this assertion to make sure that ushort are 2 bytes. // if they aren't then the initialization block definition needs // to be changed. // // Also all of the logic that deals with status registers assumes // that control registers are only 2 bytes. // ASSERT(sizeof(USHORT) == 2); // // This assertion checks that the network address in the initialization // block does start on the third byte of the initalization block. // // If this is true then other fields in the initialization block // and the send and receive descriptors should be at their correct // locations. // #ifdef NDIS_NT ASSERT(FIELD_OFFSET(LANCE_INITIALIZATION_BLOCK,PhysicalAddress[0]) == 2); #else ASSERT(&((PLANCE_INITIALIZATION_BLOCK)0)->PhysicalAddress[0] == (PVOID)2); #endif //NDIS_NT // // Allocate memory for all of the adapter structures. // Adapter->NumberOfTransmitRings = LANCE_NUMBER_OF_TRANSMIT_RINGS; Adapter->LogNumberTransmitRings = LANCE_LOG_TRANSMIT_RINGS; #ifndef i386 if (Adapter->LanceCard == LANCE_DECTC) { Status = LanceDecTcSoftwareDetails(Adapter); if (Status != NDIS_STATUS_SUCCESS) { return Status; } } else #endif { if (Adapter->AmountOfHardwareMemory == 0x20000) { ASSERT(Adapter->LanceCard == LANCE_DE422); Adapter->SizeOfReceiveBuffer = LANCE_128K_SIZE_OF_RECEIVE_BUFFERS; Adapter->NumberOfSmallBuffers = LANCE_128K_NUMBER_OF_SMALL_BUFFERS; Adapter->NumberOfMediumBuffers= LANCE_128K_NUMBER_OF_MEDIUM_BUFFERS; Adapter->NumberOfLargeBuffers = LANCE_128K_NUMBER_OF_LARGE_BUFFERS; Adapter->NumberOfReceiveRings = LANCE_128K_NUMBER_OF_RECEIVE_RINGS; Adapter->LogNumberReceiveRings = LANCE_128K_LOG_RECEIVE_RINGS; } else if (Adapter->AmountOfHardwareMemory == 0x10000) { Adapter->NumberOfReceiveRings = LANCE_64K_NUMBER_OF_RECEIVE_RINGS; Adapter->LogNumberReceiveRings = LANCE_64K_LOG_RECEIVE_RINGS; Adapter->SizeOfReceiveBuffer = LANCE_64K_SIZE_OF_RECEIVE_BUFFERS; Adapter->NumberOfSmallBuffers = LANCE_64K_NUMBER_OF_SMALL_BUFFERS; Adapter->NumberOfMediumBuffers= LANCE_64K_NUMBER_OF_MEDIUM_BUFFERS; Adapter->NumberOfLargeBuffers = LANCE_64K_NUMBER_OF_LARGE_BUFFERS; } else { Adapter->NumberOfReceiveRings = LANCE_32K_NUMBER_OF_RECEIVE_RINGS; Adapter->LogNumberReceiveRings = LANCE_32K_LOG_RECEIVE_RINGS; Adapter->SizeOfReceiveBuffer = LANCE_32K_SIZE_OF_RECEIVE_BUFFERS; Adapter->NumberOfSmallBuffers = LANCE_32K_NUMBER_OF_SMALL_BUFFERS; Adapter->NumberOfMediumBuffers= LANCE_32K_NUMBER_OF_MEDIUM_BUFFERS; Adapter->NumberOfLargeBuffers = LANCE_32K_NUMBER_OF_LARGE_BUFFERS; } } #ifndef i386 if (((Adapter->LanceCard == LANCE_DECTC) && (LanceDecTcHardwareDetails(Adapter) == NDIS_STATUS_SUCCESS)) || LanceHardwareDetails(Adapter)) #else if (LanceHardwareDetails(Adapter)) #endif { NDIS_PHYSICAL_ADDRESS PhysicalAddress; // // Get hold of the RAP and RDP address as well // as filling in the hardware assigned network // address. // if ((Adapter->CurrentNetworkAddress[0] == 0x00) && (Adapter->CurrentNetworkAddress[1] == 0x00) && (Adapter->CurrentNetworkAddress[2] == 0x00) && (Adapter->CurrentNetworkAddress[3] == 0x00) && (Adapter->CurrentNetworkAddress[4] == 0x00) && (Adapter->CurrentNetworkAddress[5] == 0x00)) { Adapter->CurrentNetworkAddress[0] = Adapter->NetworkAddress[0]; Adapter->CurrentNetworkAddress[1] = Adapter->NetworkAddress[1]; Adapter->CurrentNetworkAddress[2] = Adapter->NetworkAddress[2]; Adapter->CurrentNetworkAddress[3] = Adapter->NetworkAddress[3]; Adapter->CurrentNetworkAddress[4] = Adapter->NetworkAddress[4]; Adapter->CurrentNetworkAddress[5] = Adapter->NetworkAddress[5]; } NdisSetPhysicalAddressHigh(PhysicalAddress, 0); NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)(Adapter->HardwareBaseAddr)); Status = NdisMMapIoSpace( &(Adapter->MmMappedBaseAddr), Adapter->MiniportAdapterHandle, PhysicalAddress, Adapter->AmountOfHardwareMemory ); if (Status != NDIS_STATUS_SUCCESS) { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_RESOURCE_CONFLICT, 0 ); return(Status); } #if NDIS_WIN // // Save card setup information that is in card on-board memory // { PUCHAR pTemp = (PUCHAR) (Adapter->MmMappedBaseAddr); (UINT)pTemp &= 0xffff0000; (UINT)pTemp |= 0x0000bffe; NdisReadRegisterUshort((PUSHORT)pTemp, &(Adapter->SavedMemBase)); pTemp = (PUCHAR) (Adapter->MmMappedBaseAddr); NdisReadRegisterUlong((PULONG)pTemp, &(Adapter->Reserved1)); NdisReadRegisterUlong((PULONG)pTemp, &(Adapter->Reserved2)); } #endif Adapter->CurrentMemoryFirstFree = Adapter->MmMappedBaseAddr; Adapter->MemoryFirstUnavailable = (PUCHAR)(Adapter->CurrentMemoryFirstFree) + Adapter->AmountOfHardwareMemory; if (!AllocateAdapterMemory(Adapter)) { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 0 ); return( NDIS_STATUS_ADAPTER_NOT_FOUND ); } Adapter->AllocateableRing = Adapter->TransmitRing; Adapter->TransmittingRing = Adapter->TransmitRing; Adapter->FirstUncommittedRing = Adapter->TransmitRing; Adapter->NumberOfAvailableRings = Adapter->NumberOfTransmitRings; Adapter->LastTransmitRingEntry = Adapter->TransmitRing + (Adapter->NumberOfTransmitRings-1); Adapter->CurrentReceiveIndex = 0; Adapter->OutOfReceiveBuffers = 0; Adapter->CRCError = 0; Adapter->FramingError = 0; Adapter->RetryFailure = 0; Adapter->LostCarrier = 0; Adapter->LateCollision = 0; Adapter->UnderFlow = 0; Adapter->Deferred = 0; Adapter->OneRetry = 0; Adapter->MoreThanOneRetry = 0; Adapter->ResetInProgress = FALSE; Adapter->ResetInitStarted = FALSE; Adapter->FirstInitialization = TRUE; Adapter->HardwareFailure = FALSE; // // First we make sure that the device is stopped. We call // directly since we don't have an Interrupt object yet. // LanceSyncStopChip(Adapter); // // Initialize the interrupt. // Status = NdisMRegisterInterrupt( &Adapter->Interrupt, Adapter->MiniportAdapterHandle, Adapter->InterruptNumber, Adapter->InterruptRequestLevel, FALSE, FALSE, NdisInterruptLatched ); if (Status != NDIS_STATUS_SUCCESS){ NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_INTERRUPT_CONNECT, 0 ); NdisMUnmapIoSpace( Adapter->MiniportAdapterHandle, Adapter->MmMappedBaseAddr, Adapter->AmountOfHardwareMemory ); DeleteAdapterMemory(Adapter); return Status; } if ((Status = LanceInitialInit(Adapter)) != NDIS_STATUS_SUCCESS) { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 0 ); NdisMUnmapIoSpace( Adapter->MiniportAdapterHandle, Adapter->MmMappedBaseAddr, Adapter->AmountOfHardwareMemory ); DeleteAdapterMemory(Adapter); NdisMDeregisterInterrupt(&Adapter->Interrupt); } NdisMInitializeTimer( &Adapter->DeferredTimer, Adapter->MiniportAdapterHandle, LanceDeferredTimerRoutine, (PVOID)Adapter ); return Status; } else { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, 0 ); return NDIS_STATUS_FAILURE; } } #pragma NDIS_INIT_FUNCTION(LanceInitialInit) NDIS_STATUS LanceInitialInit( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: This routine sets up the initial init of the driver. Arguments: Adapter - The adapter for the hardware. Return Value: None. --*/ { if (Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422)) { // // Allow interrupts // Adapter->InterruptsStopped = FALSE; LOG(UNPEND); LANCE_WRITE_NICSR(Adapter, LANCE_NICSR_INT_ON); } SetInitBlockAndInit(Adapter); // // The only way that first initialization could have // been turned off is if we actually initialized. // if (!Adapter->FirstInitialization) { // // We can start the chip. We may not // have any bindings to indicateto but this // is unimportant. // LanceStartChip(Adapter); return NDIS_STATUS_SUCCESS; } else { return(NDIS_STATUS_FAILURE); } } STATIC VOID LanceStartChip( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: This routine is used to start an already initialized lance. Arguments: Adapter - The adapter for the LANCE to start. Return Value: None. --*/ { if (Adapter->ResetInProgress) { return; } // // Set the RAP to csr0. // LANCE_WRITE_RAP( Adapter, LANCE_SELECT_CSR0 ); // // Set the RDP to a start chip. // LANCE_WRITE_RDP( Adapter, LANCE_CSR0_START | LANCE_CSR0_INTERRUPT_ENABLE ); } extern VOID LanceIsr( OUT PBOOLEAN InterruptRecognized, OUT PBOOLEAN QueueDpc, IN PVOID Context ) /*++ Routine Description: Interrupt service routine for the lance. Arguments: Context - Really a pointer to the adapter. Return Value: None. --*/ { // // Will hold the value from the csr. // USHORT LocalCSR0Value; // // Holds the pointer to the adapter. // PLANCE_ADAPTER Adapter = Context; BOOLEAN StoppedInterrupts=FALSE; LOG(IN_ISR); *QueueDpc = FALSE; *InterruptRecognized = FALSE; if ((Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422)) && !Adapter->InterruptsStopped ) { // // Pend interrupts // StoppedInterrupts = TRUE; Adapter->InterruptsStopped = TRUE; LOG(PEND); LANCE_ISR_WRITE_NICSR( Adapter, LANCE_NICSR_IMASK | LANCE_NICSR_LED_ON | LANCE_NICSR_INT_ON ); } // // We don't need to select csr0, as the only way we could get // an interrupt is to have already selected 0. // LANCE_ISR_READ_RDP(Adapter, &LocalCSR0Value); if (LocalCSR0Value & LANCE_CSR0_INTERRUPT_FLAG) { *InterruptRecognized = TRUE; // // It's our interrupt. Clear only those bits that we got // in this read of csr0. We do it this way incase any new // reasons for interrupts occur between the time that we // read csr0 and the time that we clear the bits. // LANCE_ISR_WRITE_RDP( Adapter, (USHORT)((LANCE_CSR0_CLEAR_INTERRUPT_BITS & LocalCSR0Value) | LANCE_CSR0_INTERRUPT_ENABLE) ); if (Adapter->FirstInitialization && (LocalCSR0Value & LANCE_CSR0_INITIALIZATION_DONE) ) { Adapter->FirstInitialization = FALSE; } } // // Enable the interrupts. // if ((Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422)) && StoppedInterrupts ) { // // Allow interrupts // Adapter->InterruptsStopped = FALSE; LOG(UNPEND); LANCE_ISR_WRITE_NICSR(Adapter, LANCE_NICSR_INT_ON); } LOG(OUT_ISR); return; } STATIC VOID LanceDisableInterrupt( IN NDIS_HANDLE MiniportAdapterContext ) /*++ Routine Description: This routine disables interrupts on the adapter. Arguments: Context - Really a pointer to the adapter. Return Value: None. --*/ { PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext; // // Pend any interrupts // ASSERT(Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422)); LOG(PEND); LANCE_ISR_WRITE_NICSR( Adapter, LANCE_NICSR_IMASK | LANCE_NICSR_LED_ON | LANCE_NICSR_INT_ON ); } STATIC VOID LanceEnableInterrupt( IN NDIS_HANDLE MiniportAdapterContext ) /*++ Routine Description: This routine enables interrupts on the adapter. Arguments: Context - Really a pointer to the adapter. Return Value: None. --*/ { PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext; ASSERT(Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422)); // // Allow interrupts // LOG(UNPEND); LANCE_ISR_WRITE_NICSR(Adapter, LANCE_NICSR_INT_ON); } VOID LanceDeferredTimerRoutine( IN PVOID SystemSpecific1, IN NDIS_HANDLE Context, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3 ) /*++ Routine Description: This DPC routine is used to handle deferred processing via a timer. Arguments: Context - Really a pointer to the adapter. Return Value: None. --*/ { LanceHandleInterrupt(Context); } VOID LanceHandleInterrupt( IN NDIS_HANDLE Context ) /*++ Routine Description: This DPC routine is queued by the interrupt service routine. Arguments: Context - Really a pointer to the adapter. Return Value: None. --*/ { // // Holds the pointer to the adapter. // PLANCE_ADAPTER Adapter = Context; // // Holds a value of csr0. // USHORT Csr = 0; USHORT LocalCSR0Value; LOG(IN_DPC); // // Loop until there are no more processing sources. // for (;;) { // // We don't need to select csr0, as the only way we could get // an interrupt is to have already selected 0. // LANCE_ISR_READ_RDP(Adapter, &LocalCSR0Value); if (LocalCSR0Value & LANCE_CSR0_INTERRUPT_FLAG) { // // It's our interrupt. Clear only those bits that we got // in this read of csr0. We do it this way incase any new // reasons for interrupts occur between the time that we // read csr0 and the time that we clear the bits. // LANCE_ISR_WRITE_RDP( Adapter, (USHORT)((LANCE_CSR0_CLEAR_INTERRUPT_BITS & LocalCSR0Value) | LANCE_CSR0_INTERRUPT_ENABLE) ); // // Or the csr value into the adapter version of csr 0. // Csr |= LocalCSR0Value; } // // Check the interrupt source and other reasons // for processing. If there are no reasons to // process then exit this loop. // if (((!Adapter->ResetInitStarted) && ((Csr & (LANCE_CSR0_MEMORY_ERROR | LANCE_CSR0_MISSED_PACKET | LANCE_CSR0_BABBLE | LANCE_CSR0_RECEIVER_INTERRUPT | LANCE_CSR0_TRANSMITTER_INTERRUPT)) || (Adapter->ResetInProgress))) || (Csr & LANCE_CSR0_INITIALIZATION_DONE) ) { } else { break; } // // Check for initialization. // // Note that we come out of the synchronization above holding // the spinlock. // if (Csr & LANCE_CSR0_INITIALIZATION_DONE) { // // Possibly undefined reason why the reset was requested. // // It is undefined if the adapter initiated the reset // request on its own. It could do that if there // were some sort of error. // NDIS_REQUEST_TYPE ResetRequestType; LOG(RESET_STEP_3); ASSERT(!Adapter->FirstInitialization); Csr &= ~LANCE_CSR0_INITIALIZATION_DONE; Adapter->ResetInProgress = FALSE; Adapter->ResetInitStarted = FALSE; // // We save off the open that caused this reset incase // we get *another* reset while we're indicating the // last reset is done. // ResetRequestType = Adapter->ResetRequestType; if (ResetRequestType == NdisRequestSetInformation) { // // It was a request submitted by a protocol. // NdisMSetInformationComplete( Adapter->MiniportAdapterHandle, NDIS_STATUS_SUCCESS ); } else { // // It was a reset command. // if (ResetRequestType == NdisRequestGeneric1) { // // Is was a reset request // NdisMResetComplete( Adapter->MiniportAdapterHandle, NDIS_STATUS_SUCCESS, FALSE ); } } // // Restart the chip. // LanceStartChip(Adapter); goto LoopBottom; } // // If we have a reset in progress and the adapters reference // count is 1 (meaning no routine is in the interface and // we are the only "active" interrupt processing routine) then // it is safe to start the reset. // if (Adapter->ResetInProgress && !Adapter->ResetInitStarted ) { #if LANCE_TRACE DbgPrint("Starting Initialization.\n"); #endif StartAdapterReset(Adapter); Adapter->ResetInitStarted = TRUE; goto LoopBottom; } // // Check for non-packet related errors. // if (Csr & (LANCE_CSR0_MEMORY_ERROR | LANCE_CSR0_MISSED_PACKET | LANCE_CSR0_BABBLE) ) { if (Csr & LANCE_CSR0_MISSED_PACKET) { Adapter->MissedPacket++; } else if (Csr & LANCE_CSR0_BABBLE) { // // A babble error implies that we've sent a // packet that is greater than the ethernet length. // This implies that the driver is broken. // Adapter->Babble++; NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_DRIVER_FAILURE, 2, (ULONG)processInterrupt, (ULONG)0x1 ); } else { // // Could only be a memory error. This shuts down // the receiver and the transmitter. We have to // reset to get the device started again. // Adapter->MemoryError++; SetupForReset( Adapter, NdisRequestGeneric4 // Means MAC issued ); } Csr &= ~LANCE_CSR0_ERROR_BITS; } // // Check the interrupt vector and see if there are any // more receives to process. After we process any // other interrupt source we always come back to the top // of the loop to check if any more receive packets have // come in. This is to lessen the probability that we // drop a receive. // if (Csr & LANCE_CSR0_RECEIVER_INTERRUPT) { if (ProcessReceiveInterrupts(Adapter)) { Csr &= ~LANCE_CSR0_RECEIVER_INTERRUPT; } } // // Process the transmit interrupts if there are any. // if (Csr & LANCE_CSR0_TRANSMITTER_INTERRUPT) { // // We need to check if the transmitter has // stopped as a result of an error. If it // has then we really need to reset the adapter. // if (!(Csr & LANCE_CSR0_TRANSMITTER_ON)) { // // Might as well turn off the transmitter interrupt // source since we won't ever be processing them // and we don't want to come back here again. // Csr &= ~LANCE_CSR0_TRANSMITTER_INTERRUPT; // // Before we setup for the reset make sure that // we aren't already resetting. // if (!Adapter->ResetInProgress) { SetupForReset( Adapter, NdisRequestGeneric4 // means MAC issued ); } goto LoopBottom; } else { if (!ProcessTransmitInterrupts(Adapter)) { // // Process interrupts returns false if it // finds no more work to do. If this so we // turn off the transmitter interrupt source. // Csr &= ~LANCE_CSR0_TRANSMITTER_INTERRUPT; } } } LoopBottom:; } // // Check if we indicated any packets. // // Note: The only way to get out of the loop (via the break above) is // while we're still holding the spin lock. // if (Adapter->IndicatedAPacket) { Adapter->IndicatedAPacket = FALSE; NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle); } LOG(OUT_DPC); } #pragma NDIS_INIT_FUNCTION(AllocateAdapterMemory) BOOLEAN AllocateAdapterMemory( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: This routine allocates memory for: - Transmit ring entries - Receive ring entries - Receive buffers - Adapter buffers for use if user transmit buffers don't meet hardware contraints - Structures to map transmit ring entries back to the packets. Arguments: Adapter - The adapter to allocate memory for. Return Value: Returns FALSE if some memory needed for the adapter could not be allocated. --*/ { // // Pointer to a transmit ring entry. Used while initializing // the ring. // PLANCE_TRANSMIT_ENTRY CurrentTransmitEntry; // // Pointer to a receive ring entry. Used while initializing // the ring. // PLANCE_RECEIVE_ENTRY CurrentReceiveEntry; // // Simple iteration variable. // UINT i; // // These variables exist to reduce the amount of checking below. // ULONG NumberOfSmallBuffers; ULONG NumberOfMediumBuffers; ULONG NumberOfLargeBuffers; NumberOfSmallBuffers = Adapter->NumberOfSmallBuffers; NumberOfMediumBuffers = Adapter->NumberOfMediumBuffers; NumberOfLargeBuffers = Adapter->NumberOfLargeBuffers; // // Allocate memory for the initialization block. Note that // this memory can not cross a page boundary. // LANCE_ALLOCATE_MEMORY_FOR_HARDWARE( Adapter, sizeof(LANCE_INITIALIZATION_BLOCK), &Adapter->InitBlock ); if (Adapter->InitBlock == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } // // Allocate the transmit ring descriptors. // LANCE_ALLOCATE_MEMORY_FOR_HARDWARE( Adapter, sizeof(LANCE_TRANSMIT_ENTRY)*Adapter->NumberOfTransmitRings, &Adapter->TransmitRing ) if (Adapter->TransmitRing == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } // // We have the transmit ring descriptors. Make sure each is // in a clean state. // for ( i = 0, CurrentTransmitEntry = Adapter->TransmitRing; i < Adapter->NumberOfTransmitRings; i++,CurrentTransmitEntry++ ) { LANCE_ZERO_MEMORY_FOR_HARDWARE( (PUCHAR)CurrentTransmitEntry, sizeof(LANCE_TRANSMIT_ENTRY) ); } // // Allocate all of the receive ring entries // LANCE_ALLOCATE_MEMORY_FOR_HARDWARE( Adapter, sizeof(LANCE_RECEIVE_ENTRY)*Adapter->NumberOfReceiveRings, &Adapter->ReceiveRing ) if (Adapter->ReceiveRing == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } // // We have the receive ring descriptors. Allocate an // array to hold the virtual addresses of each receive // buffer. // LANCE_ALLOC_PHYS( &(Adapter->ReceiveVAs), sizeof(PVOID) * Adapter->NumberOfReceiveRings ); if (Adapter->ReceiveVAs == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } // // Clean the above memory // LANCE_ZERO_MEMORY( Adapter->ReceiveVAs, (sizeof(PVOID)*Adapter->NumberOfReceiveRings) ); // // We have the receive ring descriptors. Allocate a buffer // for each descriptor and make sure descriptor is in a clean state. // // While we're at it, relinquish ownership of the ring discriptors to // the lance. // for ( i = 0, CurrentReceiveEntry = Adapter->ReceiveRing; i < Adapter->NumberOfReceiveRings; i++,CurrentReceiveEntry++ ) { LANCE_ALLOCATE_MEMORY_FOR_HARDWARE( Adapter, Adapter->SizeOfReceiveBuffer, &Adapter->ReceiveVAs[i] ); if (Adapter->ReceiveVAs[i] == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } LANCE_SET_RECEIVE_BUFFER_ADDRESS( Adapter, CurrentReceiveEntry, Adapter->ReceiveVAs[i] ); LANCE_SET_RECEIVE_BUFFER_LENGTH( CurrentReceiveEntry, Adapter->SizeOfReceiveBuffer ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( CurrentReceiveEntry->ReceiveSummaryBits, LANCE_RECEIVE_OWNED_BY_CHIP ); } // // Allocate the ring to packet structure. // LANCE_ALLOC_PHYS( &(Adapter->RingToPacket), sizeof(LANCE_RING_TO_PACKET) * Adapter->NumberOfTransmitRings ); if (Adapter->RingToPacket == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } LANCE_ZERO_MEMORY( Adapter->RingToPacket, sizeof(LANCE_RING_TO_PACKET) * Adapter->NumberOfTransmitRings ); // // Allocate the array of buffer descriptors. // LANCE_ALLOC_PHYS( &(Adapter->LanceBuffers), sizeof(LANCE_BUFFER_DESCRIPTOR) * (NumberOfSmallBuffers + NumberOfMediumBuffers + NumberOfLargeBuffers) ); if (Adapter->LanceBuffers == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } // // Zero the memory of all the descriptors so that we can // know which buffers wern't allocated incase we can't allocate // them all. // LANCE_ZERO_MEMORY( Adapter->LanceBuffers, sizeof(LANCE_BUFFER_DESCRIPTOR)* (NumberOfSmallBuffers + NumberOfMediumBuffers + NumberOfLargeBuffers) ); // // Allocate each of the small lance buffers and fill in the // buffer descriptor. // Adapter->LanceBufferListHeads[0] = -1; Adapter->LanceBufferListHeads[1] = 0; for ( i = 0; i < NumberOfSmallBuffers; i++ ) { LANCE_ALLOCATE_MEMORY_FOR_HARDWARE( Adapter, LANCE_SMALL_BUFFER_SIZE, &Adapter->LanceBuffers[i].VirtualLanceBuffer ); if (Adapter->LanceBuffers[i].VirtualLanceBuffer == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } Adapter->LanceBuffers[i].Next = i+1; Adapter->LanceBuffers[i].BufferSize = LANCE_SMALL_BUFFER_SIZE; } // // Make sure that the last buffer correctly terminates the free list. // Adapter->LanceBuffers[i-1].Next = -1; // // Do the medium buffers now. // Adapter->LanceBufferListHeads[2] = i; for ( ; i < NumberOfSmallBuffers + NumberOfMediumBuffers; i++ ) { LANCE_ALLOCATE_MEMORY_FOR_HARDWARE( Adapter, LANCE_MEDIUM_BUFFER_SIZE, &Adapter->LanceBuffers[i].VirtualLanceBuffer ); if (Adapter->LanceBuffers[i].VirtualLanceBuffer == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } Adapter->LanceBuffers[i].Next = i+1; Adapter->LanceBuffers[i].BufferSize = LANCE_MEDIUM_BUFFER_SIZE; } // // Make sure that the last buffer correctly terminates the free list. // Adapter->LanceBuffers[i-1].Next = -1; Adapter->LanceBufferListHeads[3] = i; for ( ; i < NumberOfSmallBuffers + NumberOfMediumBuffers + NumberOfLargeBuffers; i++ ) { LANCE_ALLOCATE_MEMORY_FOR_HARDWARE( Adapter, LANCE_LARGE_BUFFER_SIZE, &Adapter->LanceBuffers[i].VirtualLanceBuffer ); if (Adapter->LanceBuffers[i].VirtualLanceBuffer == NULL) { DeleteAdapterMemory(Adapter); return FALSE; } Adapter->LanceBuffers[i].Next = i+1; Adapter->LanceBuffers[i].BufferSize = LANCE_LARGE_BUFFER_SIZE; } // // Make sure that the last buffer correctly terminates the free list. // Adapter->LanceBuffers[i-1].Next = -1; return TRUE; } STATIC VOID DeleteAdapterMemory( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: This routine deallocates memory for: - Transmit ring entries - Receive ring entries - Receive buffers - Adapter buffers for use if user transmit buffers don't meet hardware contraints - Structures to map transmit ring entries back to the packets. Arguments: Adapter - The adapter to deallocate memory for. Return Value: None. --*/ { // // These variables exist to reduce the amount of checking below. // ULONG NumberOfSmallBuffers; ULONG NumberOfMediumBuffers; ULONG NumberOfLargeBuffers; NumberOfSmallBuffers = Adapter->NumberOfSmallBuffers; NumberOfMediumBuffers = Adapter->NumberOfMediumBuffers; NumberOfLargeBuffers = Adapter->NumberOfLargeBuffers; if (Adapter->InitBlock) { LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE( Adapter, Adapter->InitBlock ); } if (Adapter->TransmitRing) { LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE( Adapter, Adapter->TransmitRing ); } if (Adapter->ReceiveRing) { LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE( Adapter, Adapter->ReceiveRing ); } if (Adapter->ReceiveVAs) { UINT i; for ( i = 0; i < Adapter->NumberOfReceiveRings; i++ ) { if (Adapter->ReceiveVAs[i]) { LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE( Adapter, Adapter->ReceiveVAs[i] ); } else { break; } } LANCE_FREE_PHYS( Adapter->ReceiveVAs, sizeof(PVOID) * Adapter->NumberOfReceiveRings ); } if (Adapter->RingToPacket) { LANCE_FREE_PHYS( Adapter->RingToPacket, sizeof(LANCE_RING_TO_PACKET) * Adapter->NumberOfTransmitRings ); } if (Adapter->LanceBuffers) { UINT i; for ( i = 0; i < NumberOfSmallBuffers + NumberOfMediumBuffers + NumberOfLargeBuffers; i++) { if (Adapter->LanceBuffers[i].VirtualLanceBuffer) { LANCE_DEALLOCATE_MEMORY_FOR_HARDWARE( Adapter, Adapter->LanceBuffers[i].VirtualLanceBuffer ); } else { break; } } LANCE_FREE_PHYS( Adapter->LanceBuffers, sizeof(LANCE_BUFFER_DESCRIPTOR) * (NumberOfSmallBuffers + NumberOfMediumBuffers + NumberOfLargeBuffers) ); } } NDIS_STATUS LanceQueryInformation( IN PNDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InfoBuffer, IN ULONG BytesLeft, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ) /*++ Routine Description: The LanceQuerylInformation process a Query request for NDIS_OIDs that are specific to a binding about the mini-port. Arguments: Status - The status of the operation. MiniportAdapterContext - a pointer to the adapter. Oid - the NDIS_OID to process. InfoBuffer - 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: None. --*/ { PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext; 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; ULONG MoveBytes; NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady; // // Make sure that ulong is 4 bytes. Else GenericULong must change // to something of size 4. // ASSERT(sizeof(ULONG) == 4); #if LANCE_TRACE DbgPrint("In LanceQueryInfo\n"); #endif // // Set default values // MoveSource = (PVOID)(&GenericULong); MoveBytes = sizeof(GenericULong); // // 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: MoveSource = (PVOID)(LanceGlobalSupportedOids); MoveBytes = sizeof(LanceGlobalSupportedOids); break; case OID_GEN_HARDWARE_STATUS: if (Adapter->ResetInProgress){ HardwareStatus = NdisHardwareStatusReset; } 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 = LANCE_MAX_LOOKAHEAD; break; case OID_GEN_MAXIMUM_FRAME_SIZE: GenericULong = (ULONG)(LANCE_LARGE_BUFFER_SIZE - LANCE_HEADER_SIZE); break; case OID_GEN_MAXIMUM_TOTAL_SIZE: GenericULong = (ULONG)(LANCE_LARGE_BUFFER_SIZE); break; case OID_GEN_LINK_SPEED: GenericULong = (ULONG)(100000); break; case OID_GEN_TRANSMIT_BUFFER_SPACE: GenericULong = (ULONG)((LANCE_SMALL_BUFFER_SIZE * Adapter->NumberOfSmallBuffers) + (LANCE_MEDIUM_BUFFER_SIZE * Adapter->NumberOfMediumBuffers) + (LANCE_LARGE_BUFFER_SIZE * Adapter->NumberOfLargeBuffers)); break; case OID_GEN_RECEIVE_BUFFER_SPACE: GenericULong = (ULONG)(Adapter->NumberOfReceiveRings * Adapter->SizeOfReceiveBuffer); break; case OID_GEN_TRANSMIT_BLOCK_SIZE: GenericULong = (ULONG)(LANCE_SMALL_BUFFER_SIZE); break; case OID_GEN_RECEIVE_BLOCK_SIZE: GenericULong = (ULONG)(Adapter->SizeOfReceiveBuffer); break; case OID_GEN_VENDOR_ID: NdisMoveMemory( (PVOID)(&GenericULong), Adapter->NetworkAddress, 3 ); GenericULong &= 0xFFFFFF00; if (Adapter->LanceCard == LANCE_DE201) { GenericULong |= 0x01; } else if (Adapter->LanceCard == LANCE_DE100) { GenericULong |= 0x02; } else if (Adapter->LanceCard == LANCE_DE422) { GenericULong |= 0x03; } else { GenericULong |= 0x04; } break; case OID_GEN_VENDOR_DESCRIPTION: if (Adapter->LanceCard == LANCE_DE201) { MoveSource = (PVOID)"DEC Etherworks Turbo Adapter"; MoveBytes = 29; } else if (Adapter->LanceCard == LANCE_DE100) { MoveSource = (PVOID)"DEC Etherworks Adapter"; MoveBytes = 23; } else if (Adapter->LanceCard == LANCE_DE422) { MoveSource = (PVOID)"DEC Etherworks Turbo EISA Adapter"; MoveBytes = 34; } else { MoveSource = (PVOID)"Lance Adapter."; MoveBytes = 15; } break; case OID_GEN_DRIVER_VERSION: GenericUShort = (LANCE_NDIS_MAJOR_VERSION << 8) | LANCE_NDIS_MINOR_VERSION; MoveSource = (PVOID)(&GenericUShort); MoveBytes = sizeof(GenericUShort); break; case OID_GEN_CURRENT_LOOKAHEAD: GenericULong = Adapter->SizeOfReceiveBuffer; break; case OID_802_3_PERMANENT_ADDRESS: LANCE_MOVE_MEMORY((PCHAR)GenericArray, Adapter->NetworkAddress, LANCE_LENGTH_OF_ADDRESS ); MoveSource = (PVOID)(GenericArray); MoveBytes = sizeof(Adapter->NetworkAddress); break; case OID_802_3_CURRENT_ADDRESS: LANCE_MOVE_MEMORY((PCHAR)GenericArray, Adapter->CurrentNetworkAddress, LANCE_LENGTH_OF_ADDRESS ); MoveSource = (PVOID)(GenericArray); MoveBytes = sizeof(Adapter->CurrentNetworkAddress); break; case OID_802_3_MAXIMUM_LIST_SIZE: GenericULong = Adapter->MaxMulticastList; break; case OID_GEN_XMIT_OK: GenericULong = (ULONG)(Adapter->Transmit + Adapter->LateCollision); break; case OID_GEN_RCV_OK: GenericULong = (ULONG)(Adapter->Receive); break; case OID_GEN_XMIT_ERROR: GenericULong = (ULONG)(Adapter->LostCarrier); break; case OID_GEN_RCV_ERROR: GenericULong = (ULONG)(Adapter->CRCError); break; case OID_GEN_RCV_NO_BUFFER: GenericULong = (ULONG)(Adapter->OutOfReceiveBuffers); break; case OID_802_3_RCV_ERROR_ALIGNMENT: GenericULong = (ULONG)(Adapter->FramingError); break; case OID_802_3_XMIT_ONE_COLLISION: GenericULong = (ULONG)(Adapter->OneRetry); break; case OID_802_3_XMIT_MORE_COLLISIONS: GenericULong = (ULONG)(Adapter->MoreThanOneRetry); break; default: StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; break; } if (StatusToReturn == NDIS_STATUS_SUCCESS){ if (MoveBytes > BytesLeft){ // // Not enough room in InformationBuffer. Punt // *BytesNeeded = MoveBytes; StatusToReturn = NDIS_STATUS_INVALID_LENGTH; } else { // // Store result. // LANCE_MOVE_MEMORY(InfoBuffer, MoveSource, MoveBytes); (*BytesWritten) += MoveBytes; } } #if LANCE_TRACE DbgPrint("Out LanceQueryInfo\n"); #endif LANCE_DO_DEFERRED(Adapter); return StatusToReturn; } NDIS_STATUS LanceSetInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesRead, OUT PULONG BytesNeeded ) /*++ Routine Description: The LanceSetInformation is used by LanceRequest to set information about the MAC. Note: Assumes it is called with the lock held. 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. --*/ { PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)(MiniportAdapterContext); // // General Algorithm: // // For each request // Verify length // Switch(Request) // Process Request // UINT BytesLeft = InformationBufferLength; PUCHAR InfoBuffer = (PUCHAR)InformationBuffer; // // Variables for a particular request // UINT OidLength; // // Variables for holding the new values to be used. // ULONG LookAhead; ULONG Filter; NDIS_STATUS Status; #if LANCE_TRACE DbgPrint("In LanceSetInfo\n"); #endif // // Get Oid and Length of next request // OidLength = BytesLeft; Status = NDIS_STATUS_SUCCESS; switch (Oid) { case OID_802_3_MULTICAST_LIST: // // Verify length // if ((OidLength % LANCE_LENGTH_OF_ADDRESS) != 0){ *BytesRead = 0; *BytesNeeded = 0; return( NDIS_STATUS_INVALID_LENGTH ); } Status = LanceChangeMulticastAddresses( Adapter, OidLength / LANCE_LENGTH_OF_ADDRESS, (CHAR (*)[LANCE_LENGTH_OF_ADDRESS])InfoBuffer, NdisRequestSetInformation ); break; case OID_GEN_CURRENT_PACKET_FILTER: // // Verify length // if (OidLength != 4) { Status = NDIS_STATUS_INVALID_LENGTH; *BytesRead = 0; *BytesNeeded = 0; break; } LANCE_MOVE_MEMORY(&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 )) { Status = NDIS_STATUS_NOT_SUPPORTED; *BytesRead = 4; *BytesNeeded = 0; break; } Status = LanceSetPacketFilter( Adapter, NdisRequestSetInformation, Filter ); break; case OID_GEN_CURRENT_LOOKAHEAD: // // Verify length // if (OidLength != 4) { Status = NDIS_STATUS_INVALID_LENGTH; *BytesRead = 0; *BytesNeeded = 4; break; } LANCE_MOVE_MEMORY(&LookAhead, InfoBuffer, 4); if (LookAhead <= (LANCE_MAX_LOOKAHEAD)) { Status = NDIS_STATUS_SUCCESS; } else { Status = NDIS_STATUS_INVALID_LENGTH; } *BytesRead = 4; *BytesNeeded = 0; break; default: Status = NDIS_STATUS_INVALID_OID; *BytesRead = 0; *BytesNeeded = 0; break; } if (Status == NDIS_STATUS_SUCCESS){ *BytesRead = OidLength; *BytesNeeded = 0; } #if LANCE_TRACE DbgPrint("Out LanceSetInfo\n"); #endif LANCE_DO_DEFERRED(Adapter); return Status; } STATIC NDIS_STATUS LanceSetPacketFilter( IN PLANCE_ADAPTER Adapter, IN NDIS_REQUEST_TYPE NdisRequestType, IN UINT PacketFilter ) /*++ Routine Description: The LanceSetPacketFilter request allows a protocol to control the types of packets that it receives from the MAC. Note : Assumes that the lock is currently held. Arguments: Adapter - Pointer to the LANCE_ADAPTER. NdisRequestType - Code to indicate from where this routine is being called. 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; #if LANCE_TRACE DbgPrint("In LanceSetPacketFilter\n"); #endif // // Check to see if the device is already resetting. // if (Adapter->ResetInProgress || Adapter->HardwareFailure) { return(NDIS_STATUS_FAILURE); } // // We need to add this to the hardware multicast filtering. // Adapter->PacketFilter = PacketFilter; SetupForReset(Adapter, NdisRequestType); #if LANCE_TRACE DbgPrint("Out LanceSetPacketFilter\n"); #endif return(NDIS_STATUS_PENDING); } STATIC UINT CalculateCRC( IN UINT NumberOfBytes, IN PCHAR Input ) /*++ Routine Description: Calculates a 32 bit crc value over the input number of bytes. Arguments: NumberOfBytes - The number of bytes in the input. Input - An input "string" to calculate a CRC over. Return Value: A 32 bit crc value. --*/ { const UINT POLY = 0x04c11db6; UINT CRCValue = 0xffffffff; ASSERT(sizeof(UINT) == 4); for ( ; NumberOfBytes; NumberOfBytes-- ) { UINT CurrentBit; UCHAR CurrentByte = *Input; Input++; for ( CurrentBit = 8; CurrentBit; CurrentBit-- ) { UINT CurrentCRCHigh = CRCValue >> 31; CRCValue <<= 1; if (CurrentCRCHigh ^ (CurrentByte & 0x01)) { CRCValue ^= POLY; CRCValue |= 0x00000001; } CurrentByte >>= 1; } } return CRCValue; } STATIC NDIS_STATUS LanceChangeMulticastAddresses( IN PLANCE_ADAPTER Adapter, IN UINT NewAddressCount, IN CHAR NewAddresses[][LANCE_LENGTH_OF_ADDRESS], IN NDIS_REQUEST_TYPE NdisRequestType ) /*++ 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: Adapter - The adapter. NewAddressCount - Number of Addresses that should be put on the adapter. NewAddresses - An array of all the multicast addresses that should now be used. NdisRequestType - The request type. Return Value: Status of the operation. --*/ { #if LANCE_TRACE DbgPrint("In LanceChangeMultiAdresses\n"); #endif // // Check to see if the device is already resetting. If it is // then pend this add. // if (Adapter->ResetInProgress || Adapter->HardwareFailure) { return(NDIS_STATUS_FAILURE); } // // We need to add this to the hardware multicast filtering. // Adapter->NumberOfAddresses = NewAddressCount; NdisMoveMemory( Adapter->MulticastAddresses, NewAddresses, NewAddressCount * LANCE_LENGTH_OF_ADDRESS ); SetupForReset(Adapter, NdisRequestType); #if LANCE_TRACE DbgPrint("Out LanceChangeMultiAdresses\n"); #endif return(NDIS_STATUS_PENDING); } NDIS_STATUS LanceReset( OUT PBOOLEAN AddressingReset, IN NDIS_HANDLE MiniportAdapterContext ) /*++ Routine Description: The LanceReset request instructs the mini-port to issue a hardware reset to the network adapter. The Miniport also resets its software state. See the description of MiniportReset for a detailed description of this request. Arguments: Status - Status of the operation. AddressingReset - Not used. MiniportAdapterContext - The context value set by this mini-port. Return Value: The function value is the status of the operation. --*/ { // // Holds the status that should be returned to the caller. // PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext; SetupForReset( Adapter, NdisRequestGeneric1 // Means Reset ); LANCE_DO_DEFERRED(Adapter); return(NDIS_STATUS_PENDING); } STATIC VOID LanceSetInitializationBlock( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: This routine simply fills the initialization block with the information necessary for initialization. Arguments: Adapter - The adapter which holds the initialization block to initialize. Return Value: None. --*/ { ULONG PhysAdr; UINT PacketFilters; PLANCE_RECEIVE_ENTRY CurrentEntry = Adapter->ReceiveRing; USHORT Mode; UCHAR RingNumber; UCHAR i; #if LANCE_TRACE DbgPrint("in SetInitBlock\n"); #endif LANCE_ZERO_MEMORY_FOR_HARDWARE( (PUCHAR)Adapter->InitBlock, sizeof(LANCE_INITIALIZATION_BLOCK) ); // // Set the card address. // for (i = 0; i < LANCE_LENGTH_OF_ADDRESS; i++) { LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->PhysicalAddress[i], Adapter->CurrentNetworkAddress[i] ); } // // Setup the transmit ring. // PhysAdr = LANCE_GET_HARDWARE_PHYSICAL_ADDRESS( Adapter, Adapter->TransmitRing ); LANCE_WRITE_HARDWARE_LOW_PART_ADDRESS( Adapter->InitBlock->LowTransmitRingAddress, LANCE_GET_LOW_PART_ADDRESS(PhysAdr) ); LANCE_WRITE_HARDWARE_HIGH_PART_ADDRESS( Adapter->InitBlock->HighTransmitRingAddress, LANCE_GET_HIGH_PART_ADDRESS(PhysAdr) ); // // Setup the receive ring. // PhysAdr = LANCE_GET_HARDWARE_PHYSICAL_ADDRESS( Adapter, Adapter->ReceiveRing ); // // Set that the chip owns each entry in the ring // for (CurrentEntry = Adapter->ReceiveRing, RingNumber = 0; RingNumber < Adapter->NumberOfReceiveRings ; RingNumber++, CurrentEntry++ ) { LANCE_WRITE_HARDWARE_MEMORY_UCHAR( CurrentEntry->ReceiveSummaryBits, LANCE_RECEIVE_OWNED_BY_CHIP ); } LANCE_WRITE_HARDWARE_LOW_PART_ADDRESS( Adapter->InitBlock->LowReceiveRingAddress, LANCE_GET_LOW_PART_ADDRESS(PhysAdr) ); LANCE_WRITE_HARDWARE_HIGH_PART_ADDRESS( Adapter->InitBlock->HighReceiveRingAddress, LANCE_GET_HIGH_PART_ADDRESS(PhysAdr) ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->TransmitLengthLow5BitsReserved, (UCHAR)(Adapter->LogNumberTransmitRings << 5) ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->ReceiveLengthLow5BitsReserved, (UCHAR)(Adapter->LogNumberReceiveRings << 5) ); // // Set up the address filtering. // // First get hold of the combined packet filter. // PacketFilters = Adapter->PacketFilter; #if LANCE_TRACE DbgPrint("Filters 0x%x\n", PacketFilters); #endif if (PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) { // // If one binding is promiscuous there is no point in // setting up any other filtering. Every packet is // going to be accepted by the hardware. // LANCE_READ_HARDWARE_MEMORY_USHORT( Adapter->InitBlock->ModeRegister, &Mode ); LANCE_WRITE_HARDWARE_MEMORY_USHORT( Adapter->InitBlock->ModeRegister, Mode | LANCE_MODE_PROMISCUOUS ); } else { // // Turn off promiscuous bit // LANCE_READ_HARDWARE_MEMORY_USHORT( Adapter->InitBlock->ModeRegister, &Mode ); LANCE_WRITE_HARDWARE_MEMORY_USHORT( Adapter->InitBlock->ModeRegister, Mode & (~LANCE_MODE_PROMISCUOUS) ); if (PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) { // // We turn on all the bits in the filter since one binding // wants every multicast address. // LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[0], 0xff ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[1], 0xff ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[2], 0xff ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[3], 0xff ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[4], 0xff ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[5], 0xff ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[6], 0xff ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[7], 0xff ); } else if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) { // // At least one open binding wants multicast addresses. // // We get the multicast addresses from the filter and // put each one through a CRC. We then take the high // order 6 bits from the 32 bit CRC and set that bit // in the logical address filter. // UINT NumberOfAddresses; NumberOfAddresses = Adapter->NumberOfAddresses; ASSERT(sizeof(ULONG) == 4); for ( ; NumberOfAddresses; NumberOfAddresses--) { UINT CRCValue; UINT HashValue = 0; CRCValue = CalculateCRC( 6, Adapter->MulticastAddresses[NumberOfAddresses-1] ); HashValue |= ((CRCValue & 0x00000001)?(0x00000020):(0x00000000)); HashValue |= ((CRCValue & 0x00000002)?(0x00000010):(0x00000000)); HashValue |= ((CRCValue & 0x00000004)?(0x00000008):(0x00000000)); HashValue |= ((CRCValue & 0x00000008)?(0x00000004):(0x00000000)); HashValue |= ((CRCValue & 0x00000010)?(0x00000002):(0x00000000)); HashValue |= ((CRCValue & 0x00000020)?(0x00000001):(0x00000000)); LANCE_READ_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[HashValue >> 3], &RingNumber ); LANCE_WRITE_HARDWARE_MEMORY_UCHAR( Adapter->InitBlock->LogicalAddressFilter[HashValue >> 3], RingNumber | (1 << (HashValue & 0x00000007)) ); } } } #if LANCE_TRACE DbgPrint("out SetInitBlock\n"); #endif } STATIC BOOLEAN ProcessReceiveInterrupts( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: Process the packets that have finished receiving. NOTE: This routine assumes that no other thread of execution is processing receives! THE LOCK MUST BE HELD Arguments: Adapter - The adapter to indicate to. Return Value: Whether to clear the interrupt or not. --*/ { // // We don't get here unless there was a receive. Loop through // the receive descriptors starting at the last known descriptor // owned by the hardware that begins a packet. // // Examine each receive ring descriptor for errors. // // We keep an array whose elements are indexed by the ring // index of the receive descriptors. The arrays elements are // the virtual addresses of the buffers pointed to by // each ring descriptor. // // When we have the entire packet (and error processing doesn't // prevent us from indicating it), we give the routine that // processes the packet through the filter, the buffers virtual // address (which is always the lookahead size) and as the // MAC context the index to the first and last ring descriptors // comprising the packet. // // // Index of the ring descriptor in the ring. // UINT CurrentIndex = Adapter->CurrentReceiveIndex; // // Pointer to the ring descriptor being examined. // PLANCE_RECEIVE_ENTRY CurrentEntry = Adapter->ReceiveRing + CurrentIndex; // // Hold in a local the top receive ring index so that we don't // need to get it from the adapter all the time. // const UINT TopReceiveIndex = Adapter->NumberOfReceiveRings - 1; // // Boolean to record the fact that we've finished processing // one packet and we're about to start a new one. // BOOLEAN NewPacket = FALSE; // // Count of the number of buffers in the current packet. // UINT NumberOfBuffers = 1; // // Pointer to host addressable space for the lookahead buffer // PUCHAR LookaheadBuffer; ULONG ReceivePacketCount = 0; for (; ; ) { UCHAR ReceiveSummaryBits; // // Check to see whether we own the packet. If // we don't then simply return to the caller. // LANCE_READ_HARDWARE_MEMORY_UCHAR( CurrentEntry->ReceiveSummaryBits, &ReceiveSummaryBits ); if (ReceiveSummaryBits & LANCE_RECEIVE_OWNED_BY_CHIP) { LOG(RECEIVE); return(TRUE); } else if (ReceivePacketCount > 10) { LOG(RECEIVE) return(FALSE); } else if (ReceiveSummaryBits & LANCE_RECEIVE_ERROR_SUMMARY) { // // We have an error in the packet. Record // the details of the error. // // // Synch with the set/query information routines. // if (ReceiveSummaryBits & LANCE_RECEIVE_BUFFER_ERROR) { // // Probably ran out of descriptors. // Adapter->OutOfReceiveBuffers++; } else if (ReceiveSummaryBits & LANCE_RECEIVE_CRC_ERROR) { Adapter->CRCError++; } else if (ReceiveSummaryBits & LANCE_RECEIVE_OVERFLOW_ERROR) { Adapter->OutOfReceiveBuffers++; } else if (ReceiveSummaryBits & LANCE_RECEIVE_FRAMING_ERROR) { Adapter->FramingError++; } ReceivePacketCount++; // // Give the packet back to the hardware. // RelinquishReceivePacket( Adapter, Adapter->CurrentReceiveIndex, NumberOfBuffers ); NewPacket = TRUE; } else if (ReceiveSummaryBits & LANCE_RECEIVE_END_OF_PACKET) { // // We've reached the end of the packet. Prepare // the parameters for indication, then indicate. // UINT PacketSize; UINT LookAheadSize; LANCE_RECEIVE_CONTEXT Context; ASSERT(sizeof(LANCE_RECEIVE_CONTEXT) == sizeof(NDIS_HANDLE)); // // Check just before we do indications that we aren't // resetting. // if (Adapter->ResetInProgress) { return(TRUE); } Context.INFO.IsContext = TRUE; Context.INFO.FirstBuffer = Adapter->CurrentReceiveIndex; Context.INFO.LastBuffer = CurrentIndex; LANCE_GET_MESSAGE_SIZE(CurrentEntry, PacketSize); LookAheadSize = PacketSize; // // Find amount to indicate. // LookAheadSize = ((LookAheadSize < Adapter->SizeOfReceiveBuffer) ? LookAheadSize : Adapter->SizeOfReceiveBuffer); LookAheadSize -= LANCE_HEADER_SIZE; // // Increment the number of packets succesfully received. // Adapter->Receive++; LOG(INDICATE); Adapter->IndicatingMacReceiveContext = Context; Adapter->IndicatedAPacket = TRUE; NdisCreateLookaheadBufferFromSharedMemory( (PVOID)(Adapter->ReceiveVAs[Adapter->CurrentReceiveIndex]), LookAheadSize + LANCE_HEADER_SIZE, &LookaheadBuffer ); if (LookaheadBuffer != NULL) { if (PacketSize < LANCE_HEADER_SIZE) { if (PacketSize >= ETH_LENGTH_OF_ADDRESS) { // // Runt packet // NdisMEthIndicateReceive( Adapter->MiniportAdapterHandle, (NDIS_HANDLE)Context.WholeThing, LookaheadBuffer, PacketSize, NULL, 0, 0 ); } } else { NdisMEthIndicateReceive( Adapter->MiniportAdapterHandle, (NDIS_HANDLE)Context.WholeThing, LookaheadBuffer, LANCE_HEADER_SIZE, LookaheadBuffer + LANCE_HEADER_SIZE, LookAheadSize, PacketSize - LANCE_HEADER_SIZE ); } NdisDestroyLookaheadBufferFromSharedMemory(LookaheadBuffer); } ReceivePacketCount++; // // Give the packet back to the hardware. // RelinquishReceivePacket( Adapter, Adapter->CurrentReceiveIndex, NumberOfBuffers ); NewPacket = TRUE; } // // We're at some indermediate packet. Advance to // the next one. // if (CurrentIndex == TopReceiveIndex) { CurrentIndex = 0; CurrentEntry = Adapter->ReceiveRing; } else { CurrentIndex++; CurrentEntry++; } if (NewPacket) { Adapter->CurrentReceiveIndex = CurrentIndex; NewPacket = FALSE; NumberOfBuffers = 0; } NumberOfBuffers++; if (NumberOfBuffers > (TopReceiveIndex + 1)) { // // Error! For some reason we wrapped without ever seeing // the end of packet. The card is hosed. Stop the // whole process. // // // There are opens to notify // Adapter->HardwareFailure = TRUE; NdisMIndicateStatus( Adapter->MiniportAdapterHandle, NDIS_STATUS_CLOSING, NULL, 0 ); NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle); NdisMDeregisterInterrupt(&(Adapter->Interrupt)); NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 0 ); return(TRUE); } } } STATIC VOID RelinquishReceivePacket( IN PLANCE_ADAPTER Adapter, IN UINT StartingIndex, IN UINT NumberOfBuffers ) /*++ Routine Description: Gives a range of receive descriptors back to the hardware. Arguments: Adapter - The adapter that the ring works with. StartingIndex - The first ring to return. Note that since we are dealing with a ring, this value could be greater than the EndingIndex. NumberOfBuffers - The number of buffers (or ring descriptors) in the current packet. Return Value: None. --*/ { // // Index of the ring descriptor in the ring. // UINT CurrentIndex = StartingIndex; // // Pointer to the ring descriptor being returned. // PLANCE_RECEIVE_ENTRY CurrentEntry = Adapter->ReceiveRing + CurrentIndex; // // Hold in a local so that we don't need to access via the adapter. // const UINT TopReceiveIndex = Adapter->NumberOfReceiveRings - 1; UCHAR Tmp; LANCE_READ_HARDWARE_MEMORY_UCHAR(CurrentEntry->ReceiveSummaryBits, &Tmp); ASSERT(!(Tmp & LANCE_RECEIVE_OWNED_BY_CHIP)); ASSERT(Tmp & LANCE_RECEIVE_START_OF_PACKET); for ( ; NumberOfBuffers; NumberOfBuffers-- ) { LANCE_WRITE_HARDWARE_MEMORY_UCHAR( CurrentEntry->ReceiveSummaryBits, LANCE_RECEIVE_OWNED_BY_CHIP ); if (CurrentIndex == TopReceiveIndex) { CurrentEntry = Adapter->ReceiveRing; CurrentIndex = 0; } else { CurrentEntry++; CurrentIndex++; } } } STATIC BOOLEAN ProcessTransmitInterrupts( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: Process the packets that have finished transmitting. NOTE: This routine assumes that it is being executed in a single thread of execution. CALLED WITH LOCK HELD!!! Arguments: Adapter - The adapter that was sent from. Return Value: This function will return TRUE if it finished up the send on a packet. It will return FALSE if for some reason there was no packet to process. --*/ { // // Index into the ring to packet structure. This index points // to the first ring entry for the first buffer used for transmitting // the packet. // UINT FirstIndex; // // Pointer to the last ring entry for the packet to be transmitted. // This pointer might actually point to a ring entry before the first // ring entry for the packet since the ring structure is, simply, a ring. // PLANCE_TRANSMIT_ENTRY LastRingEntry; // // Pointer to the packet that started this transmission. // PNDIS_PACKET OwningPacket; UCHAR TransmitSummaryBits; USHORT ErrorSummaryInfo; // // Used to hold the ring to packet mapping information so that // we can release the ring entries as quickly as possible. // LANCE_RING_TO_PACKET SavedRingMapping; // // Get hold of the first transmitted packet. // // // First we check that this is a packet that was transmitted // but not already processed. Recall that this routine // will be called repeatedly until this tests false, Or we // hit a packet that we don't completely own. // // // NOTE: I found a problem where FirstUncommitedRing wraps around // and becomes equal to TransmittingRing. This only happens when // NumberOfAvailableRings is 0 (JohnsonA) // if ((Adapter->TransmittingRing == Adapter->FirstUncommittedRing) && (Adapter->NumberOfAvailableRings > 0) ) { return(FALSE); } else { FirstIndex = Adapter->TransmittingRing - Adapter->TransmitRing; } // // We put the mapping into a local variable so that we // can return the mapping as soon as possible. // SavedRingMapping = Adapter->RingToPacket[FirstIndex]; // // Get a pointer to the last ring entry for this packet. // LastRingEntry = Adapter->TransmitRing + SavedRingMapping.RingIndex; // // Get a pointer to the owning packet . // OwningPacket = SavedRingMapping.OwningPacket; SavedRingMapping.OwningPacket = NULL; if (OwningPacket == NULL) { // // We seem to be in a messed up state. Ignore this interrupt and // the wake up dpc will reset the card if necessary. // ASSERT(OwningPacket != NULL); return(FALSE); } // // Check that the host does indeed own this entire packet. // LANCE_READ_HARDWARE_MEMORY_UCHAR( LastRingEntry->TransmitSummaryBits, &TransmitSummaryBits ); if (TransmitSummaryBits & LANCE_TRANSMIT_OWNED_BY_CHIP) { // // We don't own this last packet. We return FALSE to indicate // that we don't have any more packets to work on. // return(FALSE); } else { // // Pointer to the current ring descriptor being examine for errors // and the statistics accumulated during its transmission. // PLANCE_TRANSMIT_ENTRY CurrentRingEntry; // // Holds whether the packet successfully transmitted or not. // BOOLEAN Successful = TRUE; PLANCE_BUFFER_DESCRIPTOR BufferDescriptor = Adapter->LanceBuffers + SavedRingMapping.LanceBuffersIndex; INT ListHeadIndex = BufferDescriptor->Next; LOG(TRANSMIT_COMPLETE); CurrentRingEntry = Adapter->TransmitRing + FirstIndex; // // now return these buffers to the adapter. // BufferDescriptor->Next = Adapter->LanceBufferListHeads[ListHeadIndex]; Adapter->LanceBufferListHeads[ListHeadIndex] = SavedRingMapping.LanceBuffersIndex; // // Since the host owns the entire packet check the ring // entries from first to last for any errors in transmission. // Any errors found or multiple tries should be recorded in // the information structure for the adapter. // // We treat Late Collisions as success since the packet was // fully transmitted and may have been received. // for (;;) { LANCE_READ_HARDWARE_MEMORY_UCHAR( CurrentRingEntry->TransmitSummaryBits, &TransmitSummaryBits ); LANCE_READ_HARDWARE_MEMORY_USHORT( CurrentRingEntry->ErrorSummaryInfo, &ErrorSummaryInfo ); if ((TransmitSummaryBits & LANCE_TRANSMIT_ANY_ERRORS) && !(ErrorSummaryInfo & LANCE_TRANSMIT_LATE_COLLISION) ) { if (ErrorSummaryInfo & LANCE_TRANSMIT_RETRY) { Adapter->RetryFailure++; } else if (ErrorSummaryInfo & LANCE_TRANSMIT_LOST_CARRIER) { Adapter->LostCarrier++; } else if (ErrorSummaryInfo & LANCE_TRANSMIT_UNDERFLOW) { Adapter->UnderFlow++; } #if DBG LanceSendFails[LanceSendFailPlace] = (UCHAR)(ErrorSummaryInfo); LanceSendFailPlace++; #endif #if LANCE_TRACE DbgPrint("Unsuccessful Transmit 0x%x\n", ErrorSummaryInfo); #endif Successful = FALSE; // // Move the pointer to transmitting but unprocessed // ring entries to after this packet, and recover // the remaining now available ring entries. // Adapter->NumberOfAvailableRings += (CurrentRingEntry <= LastRingEntry)? ((LastRingEntry - CurrentRingEntry)+1): ((Adapter->LastTransmitRingEntry - CurrentRingEntry) + (LastRingEntry-Adapter->TransmitRing) + 2); if (LastRingEntry == Adapter->LastTransmitRingEntry) { Adapter->TransmittingRing = Adapter->TransmitRing; } else { Adapter->TransmittingRing = LastRingEntry + 1; } break; } else { // // Logical variable that records whether this // is the last packet. // BOOLEAN DoneWithPacket = TransmitSummaryBits & LANCE_TRANSMIT_END_OF_PACKET; if (ErrorSummaryInfo & LANCE_TRANSMIT_LATE_COLLISION) { Adapter->LateCollision++; } if (TransmitSummaryBits & LANCE_TRANSMIT_START_OF_PACKET) { // // Collect some statistics on how many tries were needed. // if (TransmitSummaryBits & LANCE_TRANSMIT_DEFERRED) { Adapter->Deferred++; } else if (TransmitSummaryBits & LANCE_TRANSMIT_ONE_RETRY) { Adapter->OneRetry++; } else if (TransmitSummaryBits & LANCE_TRANSMIT_MORE_THAN_ONE_RETRY) { Adapter->MoreThanOneRetry++; } } if (CurrentRingEntry == Adapter->LastTransmitRingEntry) { CurrentRingEntry = Adapter->TransmitRing; } else { CurrentRingEntry++; } Adapter->TransmittingRing = CurrentRingEntry; Adapter->NumberOfAvailableRings++; if (DoneWithPacket) { break; } } } // // Store result // if (Successful) { // // Increment number of packets successfully sent. // Adapter->Transmit++; } NdisMSendResourcesAvailable(Adapter->MiniportAdapterHandle); return(TRUE); } } STATIC VOID StartAdapterReset( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: This is the first phase of resetting the adapter hardware. It makes the following assumptions: 1) That the hardware has been stopped. 2) That it can not be preempted. 3) That no other adapter activity can occur. When this routine is finished all of the adapter information will be as if the driver was just initialized. Arguments: Adapter - The adapter whose hardware is to be reset. Return Value: None. --*/ { UINT i; #if LANCE_TRACE DbgPrint("In StartAdapterReset\n"); #endif LOG(RESET_STEP_2); Adapter->NumberOfAvailableRings = Adapter->NumberOfTransmitRings; Adapter->AllocateableRing = Adapter->TransmitRing; Adapter->TransmittingRing = Adapter->TransmitRing; Adapter->FirstUncommittedRing = Adapter->TransmitRing; Adapter->CurrentReceiveIndex = 0; // // Clean all of the receive ring entries. // { PLANCE_RECEIVE_ENTRY CurrentReceive = Adapter->ReceiveRing; const PLANCE_RECEIVE_ENTRY After = Adapter->ReceiveRing + Adapter->NumberOfReceiveRings; do { LANCE_WRITE_HARDWARE_MEMORY_UCHAR( CurrentReceive->ReceiveSummaryBits, LANCE_RECEIVE_OWNED_BY_CHIP ); CurrentReceive++; } while (CurrentReceive != After); } // // Clean all of the transmit ring entries. // { PLANCE_TRANSMIT_ENTRY CurrentTransmit = Adapter->TransmitRing; const PLANCE_TRANSMIT_ENTRY After = Adapter->TransmitRing+ Adapter->NumberOfTransmitRings; do { LANCE_WRITE_HARDWARE_MEMORY_UCHAR( CurrentTransmit->TransmitSummaryBits, 0x00 ); CurrentTransmit++; } while (CurrentTransmit != After); } // // Recover all of the adapter buffers. // for (i = 0; i < (Adapter->NumberOfSmallBuffers + Adapter->NumberOfMediumBuffers + Adapter->NumberOfLargeBuffers); i++ ) { Adapter->LanceBuffers[i].Next = i+1; } Adapter->LanceBufferListHeads[0] = -1; Adapter->LanceBufferListHeads[1] = 0; Adapter->LanceBuffers[(Adapter->NumberOfSmallBuffers)-1].Next = -1; Adapter->LanceBufferListHeads[2] = Adapter->NumberOfSmallBuffers; Adapter->LanceBuffers[(Adapter->NumberOfSmallBuffers + Adapter->NumberOfMediumBuffers)-1].Next = -1; Adapter->LanceBufferListHeads[3] = Adapter->NumberOfSmallBuffers + Adapter->NumberOfMediumBuffers; Adapter->LanceBuffers[(Adapter->NumberOfSmallBuffers+ Adapter->NumberOfMediumBuffers+ Adapter->NumberOfLargeBuffers)-1].Next = -1; SetInitBlockAndInit(Adapter); #if LANCE_TRACE DbgPrint("Out StartAdapterReset\n"); #endif } STATIC VOID SetInitBlockAndInit( IN PLANCE_ADAPTER Adapter ) /*++ Routine Description: It is this routines responsibility to make sure that the initialization block is filled and the chip is initialized *but not* started. NOTE: This routine assumes that it is called with the lock acquired OR that only a single thread of execution is working with this particular adapter. Arguments: Adapter - The adapter whose hardware is to be initialized. Return Value: None. --*/ { ULONG PhysAdr; // // Fill in the adapters initialization block. // LanceSetInitializationBlock(Adapter); PhysAdr = LANCE_GET_HARDWARE_PHYSICAL_ADDRESS(Adapter,Adapter->InitBlock); // // Make sure that it does have even byte alignment. // ASSERT((PhysAdr & 0x01)==0); // // Write the address of the initialization block to csr1 and csr2. // LANCE_WRITE_RAP(Adapter, LANCE_SELECT_CSR1); LANCE_WRITE_RDP(Adapter, LANCE_GET_LOW_PART_ADDRESS(PhysAdr)); LANCE_WRITE_RAP(Adapter, LANCE_SELECT_CSR2); LANCE_WRITE_RDP(Adapter, LANCE_GET_HIGH_PART_ADDRESS(PhysAdr)); // // Write to csr0 to initialize the chip. // LANCE_WRITE_RAP(Adapter, LANCE_SELECT_CSR0); LANCE_WRITE_RDP(Adapter, LANCE_CSR0_INIT_CHIP); // // Delay execution for 1/2 second to give the lance // time to initialize. // NdisStallExecution( 500000 ); } STATIC VOID SetupForReset( IN PLANCE_ADAPTER Adapter, IN NDIS_REQUEST_TYPE NdisRequestType ) /*++ Routine Description: This routine is used to fill in the who and why a reset is being set up as well as setting the appropriate fields in the adapter. NOTE: This routine must be called with the lock acquired. Arguments: Adapter - The adapter whose hardware is to be initialized. NdisRequestType - The reason for the reset. Return Value: None. --*/ { #if LANCE_TRACE DbgPrint("In SetupForReset\n"); #endif LOG(RESET_STEP_1); // // Shut down the chip. We won't be doing any more work until // the reset is complete. // NdisMSynchronizeWithInterrupt( &Adapter->Interrupt, LanceSyncStopChip, (PVOID)Adapter ); // // Once the chip is stopped we can't get any more interrupts. // Any interrupts that are "queued" for processing could // only possibly service this reset. It is therefore safe for // us to clear the adapter global csr value. // Adapter->ResetInProgress = TRUE; Adapter->ResetInitStarted = FALSE; // // Shut down all of the transmit queues so that the // transmit portion of the chip will eventually calm down. // Adapter->ResetRequestType = NdisRequestType; #if LANCE_TRACE DbgPrint("Out SetupForReset\n"); #endif } STATIC BOOLEAN LanceSyncWriteNicsr( IN PVOID Context ) /*++ Routine Description: This routine is used by the normal interrupt processing routine to synchronize with interrupts from the card. It will Write to the NIC Status Register. Arguments: Context - This is really a pointer to a record type peculiar to this routine. The record contains a pointer to the adapter and a pointer to an address which holds the value to write. Return Value: Always returns false. --*/ { PLANCE_SYNCH_CONTEXT C = Context; LANCE_ISR_WRITE_NICSR(C->Adapter, C->LocalWrite); return FALSE; } STATIC BOOLEAN LanceSyncStopChip( IN PVOID Context ) /*++ Routine Description: This routine is used to stop a lance. Arguments: Adapter - The adapter for the LANCE to stop. Return Value: FALSE --*/ { PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)Context; // // Set the RAP to csr0. // LANCE_ISR_WRITE_RAP(Adapter, LANCE_SELECT_CSR0); // // Set the RDP to stop chip. // LANCE_ISR_WRITE_RDP(Adapter, LANCE_CSR0_STOP); if (Adapter->LanceCard & (LANCE_DE201 | LANCE_DE100 | LANCE_DE422)) { // // Always reset the ACON bit after a stop. // LANCE_ISR_WRITE_RAP(Adapter, LANCE_SELECT_CSR3); LANCE_ISR_WRITE_RDP(Adapter, LANCE_CSR3_ACON); } // // Select CSR0 again. // LANCE_ISR_WRITE_RAP(Adapter, LANCE_SELECT_CSR0); return(FALSE); }