summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/lance/lance.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/lance/lance.c4974
1 files changed, 4974 insertions, 0 deletions
diff --git a/private/ntos/ndis/lance/lance.c b/private/ntos/ndis/lance/lance.c
new file mode 100644
index 000000000..3cabb6a7f
--- /dev/null
+++ b/private/ntos/ndis/lance/lance.c
@@ -0,0 +1,4974 @@
+/*++
+
+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 <ndis.h>
+#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);
+}
+
+
+