summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/elnkii.new/card.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/elnkii.new/card.c3155
1 files changed, 3155 insertions, 0 deletions
diff --git a/private/ntos/ndis/elnkii.new/card.c b/private/ntos/ndis/elnkii.new/card.c
new file mode 100644
index 000000000..cbbfd6d60
--- /dev/null
+++ b/private/ntos/ndis/elnkii.new/card.c
@@ -0,0 +1,3155 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ Card-specific functions for the NDIS 3.0 Etherlink II driver.
+
+Author:
+
+ Adam Barr (adamba) 30-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Adam Barr (adamba) 28-Aug-1990
+ - moved the SyncXXX() functions to sync.c
+
+
+--*/
+
+#include <ndis.h>
+#include "elnkhrd.h"
+#include "elnksft.h"
+
+
+//
+// The amount of data to transfer in one programmed I/O burst
+// (should be 8 or 16).
+//
+
+#define DMA_BURST_SIZE 16
+
+#if DBG
+UCHAR PrevBurstSize = 0;
+UCHAR PrevPrevBurstSize = 0;
+#endif
+
+
+//
+// Array to hold multicast address list.
+//
+
+CHAR Addresses[DEFAULT_MULTICASTLISTMAX][ETH_LENGTH_OF_ADDRESS] = {0};
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetMemBaseAddr)
+
+PUCHAR CardGetMemBaseAddr(
+ IN PELNKII_ADAPTER pAdapter,
+ OUT PBOOLEAN pfCardPresent,
+ OUT PBOOLEAN pfIoBaseCorrect
+)
+
+/*++
+
+Routine Description:
+
+ Checks that the I/O base address is correct and returns
+ the memory base address. For cards that are not set up
+ for memory mapped mode, it will only check the I/O base
+ address, and return NULL if it is not correct.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block.
+
+ CardPresent - Returns FALSE if the card does not appear
+ to be present in the machine.
+
+ IoBaseCorrect - Returns TRUE if the jumper matches the
+ configured I/O base address.
+
+Return Value:
+
+ The memory base address for memory mapped systems.
+
+--*/
+
+{
+ static PVOID IoBases[] = { (PVOID)0x2e0, (PVOID)0x2a0,
+ (PVOID)0x280, (PVOID)0x250,
+ (PVOID)0x350, (PVOID)0x330,
+ (PVOID)0x310, (PVOID)0x300 };
+ static PVOID MemBases[] = { (PVOID)0xc8000, (PVOID)0xcc000,
+ (PVOID)0xd8000, (PVOID)0xdc000 };
+ UCHAR BaseConfig;
+ UCHAR Tmp;
+ UCHAR MemConfig;
+
+
+ //
+ // Read in the Base Configuration Register.
+ //
+ NdisRawReadPortUchar(pAdapter->MappedGaBaseAddr + GA_IO_BASE, &Tmp);
+
+ //
+ // Make sure that only one bit in Tmp is on.
+ //
+ if ((Tmp != 0) && ((Tmp & (Tmp - 1)) == 0))
+ {
+ *pfCardPresent = TRUE;
+ }
+ else
+ {
+ *pfCardPresent = FALSE;
+
+ return(NULL);
+ }
+
+ //
+ // Make sure the correct bit is on for pAdapter->IoBaseAddr.
+ //
+ BaseConfig = 0;
+
+ while (!(Tmp & 1))
+ {
+ Tmp >>= 1;
+
+ ++BaseConfig;
+
+ if (BaseConfig == 8)
+ return(NULL);
+ }
+
+ if (IoBases[BaseConfig] != pAdapter->IoBaseAddr)
+ {
+ //
+ // Probably the jumper is wrong.
+ //
+ *pfIoBaseCorrect = FALSE;
+
+ return(NULL);
+
+ }
+ else
+ {
+ *pfIoBaseCorrect = TRUE;
+ }
+
+ //
+ // For non-memory-mapped cards, there is nothing else to check.
+ //
+ if (!pAdapter->MemMapped)
+ return(NULL);
+
+ //
+ // Now read in the PROM configuration register.
+ //
+ NdisRawReadPortUchar(pAdapter->MappedGaBaseAddr + GA_MEM_BASE, &Tmp);
+
+ //
+ // See which bit is on, minus 4.
+ //
+ MemConfig = 0;
+
+ while (!(Tmp & 0x10))
+ {
+ Tmp >>= 1;
+
+ ++MemConfig;
+
+ if (MemConfig == 4)
+ return(NULL);
+ }
+
+ //
+ // Based on the bit, look up MemBaseAddr in the table.
+ //
+ pAdapter->MemMapped = TRUE;
+
+ return(MemBases[MemConfig]);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardReadEthernetAddress)
+
+VOID CardReadEthernetAddress(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Reads in the Ethernet address from the Etherlink II PROM.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block.
+
+Return Value:
+
+ The address is stored in pAdapter->PermanentAddress, and StationAddress if it
+ is currently zero.
+
+--*/
+
+{
+ UINT i;
+
+ //
+ // Window the PROM into the NIC ports.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ CTRL_PROM_SEL | CTRL_BNC
+ );
+
+ //
+ // Read in the station address.
+ //
+ for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++)
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + i,
+ &pAdapter->PermanentAddress[i]
+ );
+ }
+
+ IF_LOUD( DbgPrint(" [ %x-%x-%x-%x-%x-%x ]\n",
+ pAdapter->PermanentAddress[0],
+ pAdapter->PermanentAddress[1],
+ pAdapter->PermanentAddress[2],
+ pAdapter->PermanentAddress[3],
+ pAdapter->PermanentAddress[4],
+ pAdapter->PermanentAddress[5]);)
+
+ //
+ // Window the NIC registers into the NIC ports.
+ //
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ CTRL_GA_SEL | CTRL_BNC
+ );
+
+ if
+ (
+ (pAdapter->StationAddress[0] == 0x00) &&
+ (pAdapter->StationAddress[1] == 0x00) &&
+ (pAdapter->StationAddress[2] == 0x00) &&
+ (pAdapter->StationAddress[3] == 0x00) &&
+ (pAdapter->StationAddress[4] == 0x00) &&
+ (pAdapter->StationAddress[5] == 0x00)
+ )
+ {
+ pAdapter->StationAddress[0] = pAdapter->PermanentAddress[0];
+ pAdapter->StationAddress[1] = pAdapter->PermanentAddress[1];
+ pAdapter->StationAddress[2] = pAdapter->PermanentAddress[2];
+ pAdapter->StationAddress[3] = pAdapter->PermanentAddress[3];
+ pAdapter->StationAddress[4] = pAdapter->PermanentAddress[4];
+ pAdapter->StationAddress[5] = pAdapter->PermanentAddress[5];
+ }
+}
+
+
+BOOLEAN CardSetup(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets up the card, using the sequence given in the Etherlink II
+ technical reference.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block, which must be initialized.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+ UINT i;
+ UINT Filter;
+ UCHAR IntConfig;
+ UCHAR Tmp;
+
+ //
+ // First set up the Gate Array.
+ //
+
+ //
+ // Toggle the reset bit.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ CTRL_RESET | CTRL_BNC
+ );
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_CONTROL, 0x00);
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_CONTROL, CTRL_BNC);
+
+ //
+ // Set up the bits in the Control Register that don't change.
+ //
+ pAdapter->GaControlBits = pAdapter->ExternalTransceiver ?
+ CTRL_DIX : CTRL_BNC;
+
+ if (DMA_BURST_SIZE == 16)
+ pAdapter->GaControlBits |= CTRL_DB_SEL;
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ pAdapter->GaControlBits
+ );
+
+ //
+ // Set Page Start and Page Stop to match the NIC registers.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_PAGE_START,
+ pAdapter->NicPageStart
+ );
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_PAGE_STOP,
+ pAdapter->NicPageStop
+ );
+
+ //
+ // Select which interrupt to use.
+ //
+ IntConfig = 0x04; // set bit in position 2
+ IntConfig <<= pAdapter->InterruptNumber; // move it to 4 through 7
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_INT_DMA_CONFIG,
+ IntConfig
+ );
+
+ //
+ // Choose between 8- and 16-byte programmed I/O bursts.
+ //
+ if (DMA_BURST_SIZE == 8)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DRQ_TIMER,
+ DQTR_8_BYTE
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DRQ_TIMER,
+ DQTR_16_BYTE
+ );
+ }
+
+ //
+ // Initialize these to a correct value for an 8K card.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_MSB, 0x20);
+ NdisRawWritePortUchar(pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_LSB, 0x00);
+
+ //
+ // Set up the Configuration register.
+ //
+ if (pAdapter->MemMapped)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONFIG,
+ GACFR_TC_MASK | GACFR_RAM_SEL | GACFR_MEM_BANK1
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar
+ (
+ pAdapter->MappedGaBaseAddr + GA_CONFIG,
+ GACFR_TC_MASK
+ );
+ }
+
+ //
+ // Now set up NIC registers.
+ //
+
+ //
+ // Write to and read from CR to make sure it is there.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0
+ );
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_COMMAND, &Tmp);
+
+ if (Tmp != (CR_STOP | CR_NO_DMA | CR_PAGE0))
+ return(FALSE);
+
+ //
+ // Set up the registers in the correct sequence.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE
+ );
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_LSB, 0);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_RCV_CONFIG,
+ pAdapter->NicReceiveConfig
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_CONFIG,
+ TCR_LOOPBACK
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_BOUNDARY,
+ pAdapter->NicPageStart
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_PAGE_START,
+ pAdapter->NicPageStart
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_PAGE_STOP,
+ pAdapter->NicPageStop
+ );
+
+ pAdapter->Current = pAdapter->NicPageStart + (UCHAR)1;
+ pAdapter->NicNextPacket = pAdapter->NicPageStart + (UCHAR)1;
+ pAdapter->BufferOverflow = FALSE;
+
+ //
+ // Clear all
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ 0xff
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+
+ //
+ // Move to page 1 to write the station address and
+ // multicast registers.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE1
+ );
+
+ for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + (NIC_PHYS_ADDR+i),
+ pAdapter->StationAddress[i]
+ );
+ }
+
+ Filter = pAdapter->PacketFilter;
+
+ for (i = 0; i < 8; i++)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + (NIC_MC_ADDR+i),
+ (UCHAR)((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ?
+ 0xff : pAdapter->NicMulticastRegs[i])
+ );
+ }
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CURRENT,
+ pAdapter->Current
+ );
+
+
+ //
+ // move back to page 0 and start the card...
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ //
+ // ... but it is still in loopback mode.
+ //
+ return(TRUE);
+}
+
+BOOLEAN SyncCardStop(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the NIC_COMMAND register to stop the card.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ Ignored.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_STOP | CR_NO_DMA
+ );
+
+ return(FALSE);
+}
+
+
+
+VOID CardStop(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Stops the card.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ UCHAR Tmp;
+
+ //
+ // Turn on the STOP bit in the Command register.
+ //
+ NdisMSynchronizeWithInterrupt(
+ &pAdapter->Interrupt,
+ SyncCardStop,
+ pAdapter
+ );
+
+ //
+ // Clear the Remote Byte Count register so that ISR_RESET
+ // will come on.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_LSB, 0);
+
+
+ //
+ // Wait for ISR_RESET, but only for 1.6 milliseconds (as
+ // described in the March 1991 8390 addendum), since that
+ // is the maximum time for a software reset to occur.
+ //
+ //
+ for (i = 0; i < 4; i++)
+ {
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS, &Tmp);
+ if (Tmp & ISR_RESET)
+ break;
+
+ NdisStallExecution(500);
+ }
+
+ if (i == 4)
+ {
+ IF_LOUD( DbgPrint("RESET\n");)
+ IF_LOG( ElnkiiLog('R');)
+ }
+
+
+ //
+ // Put the card in loopback mode, then start it.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_CONFIG,
+ TCR_LOOPBACK
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA
+ );
+
+ //
+ // At this point the card is still in loopback mode.
+ //
+}
+
+
+BOOLEAN CardReset(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Resets the card.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ TRUE if everything is OK.
+
+--*/
+
+{
+ //
+ // Stop the chip.
+ //
+ CardStop(pAdapter);
+
+ //
+ // CardSetup() does a software reset.
+ //
+ if (!CardSetup(pAdapter))
+ {
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 2,
+ cardReset,
+ ELNKII_ERRMSG_CARD_SETUP
+ );
+
+ return(FALSE);
+ }
+
+ //
+ // Start the chip.
+ //
+ CardStart(pAdapter);
+
+ return(TRUE);
+}
+
+#pragma NDIS_INIT_FUNCTION(DelayComplete)
+
+VOID DelayComplete(
+ IN PVOID SystemSpecific1,
+ IN PVOID TimerExpired,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+{
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ *((BOOLEAN *)TimerExpired)=TRUE;
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(CardTest)
+
+BOOLEAN CardTest(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Tests the card. Follows the tests described in section 12 of
+ the 8390 Data Sheet.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block, which must be initialized
+ and set up.
+
+Return Value:
+
+ TRUE if everything is OK.
+
+--*/
+
+{
+#define TEST_LEN 60
+#define MAGIC_NUM 0x92
+
+ UINT FirstTest;
+ UINT SecondTest;
+ UINT i;
+ UCHAR TSRResult;
+ UCHAR RSRResult;
+ UCHAR CrcBuf[4];
+ BOOLEAN FinalResult = TRUE;
+ UCHAR TestSrcBuf[256];
+ UCHAR TestDestBuf[256];
+ PUCHAR CurTestLoc;
+ UCHAR Tmp;
+
+ static NDIS_MINIPORT_TIMER Timer = {0};
+ BOOLEAN TimerExpired = FALSE;
+
+ BOOLEAN dummy; //for return from NdisMCancelTimer
+
+ //
+ // These arrays are indexed by FirstTest.
+ //
+
+ static UCHAR TCRValues[3] = { TCR_NIC_LBK, TCR_SNI_LBK, TCR_COAX_LBK };
+ static UCHAR TSRCDHWanted[3] = { TSR_NO_CDH, TSR_NO_CDH, 0x00 };
+ static UCHAR TSRCRSWanted[3] = { TSR_NO_CARRIER, 0x00, 0x00 };
+ static UCHAR FIFOWanted[4] = { LSB(TEST_LEN+4), MSB(TEST_LEN+4),
+ MSB(TEST_LEN+4), MAGIC_NUM };
+
+
+ //
+ // These arrays are indexed by SecondTest.
+ //
+
+ static BOOLEAN GoodCrc[3] = { TRUE, FALSE, FALSE };
+ static BOOLEAN GoodAddress[3] = { TRUE, TRUE, FALSE };
+ static UCHAR RSRWanted[3] = { RSR_PACKET_OK, RSR_CRC_ERROR, RSR_PACKET_OK };
+
+ static UCHAR TestPacket[TEST_LEN] = {0}; // a dummy packet.
+ static UCHAR NullAddress[ETH_LENGTH_OF_ADDRESS] = { 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 };
+
+
+ //
+ // First construct TestPacket.
+ //
+
+ ELNKII_MOVE_MEM(TestPacket, pAdapter->StationAddress, ETH_LENGTH_OF_ADDRESS);
+ ELNKII_MOVE_MEM(TestPacket+ETH_LENGTH_OF_ADDRESS, pAdapter->StationAddress, ETH_LENGTH_OF_ADDRESS);
+ TestPacket[2*ETH_LENGTH_OF_ADDRESS] = 0x00;
+ TestPacket[2*ETH_LENGTH_OF_ADDRESS+1] = 0x00;
+ TestPacket[TEST_LEN-1] = MAGIC_NUM;
+
+
+ //
+ // Set up the DCR for loopback operation.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_LOOPBACK | DCR_FIFO_8_BYTE);
+
+
+ //
+ // Set the RCR to reject all packets.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_RCV_CONFIG, 0x00);
+
+
+ //
+ // First round of tests -- different loopback modes
+ //
+
+ for (FirstTest = 0; FirstTest < 2; ++FirstTest) {
+
+ //
+ // Stop the card.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Set up the TCR for the appropriate loopback mode.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG, 0x00);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCRValues[FirstTest]);
+
+
+ //
+ // Restart the card.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Now copy down TestPacket and start the transmission.
+ //
+
+ CardCopyDownBuffer(pAdapter, TestPacket, 0, 0, TEST_LEN);
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_START, pAdapter->NicXmitStart);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(TEST_LEN));
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(TEST_LEN));
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA);
+
+
+ //
+ // Wait for the transmission to complete, for about a second.
+ //
+
+ {
+ UINT i;
+ i=0;
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS, &Tmp);
+ while (!(Tmp & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ if (++i > 100) {
+ IF_TEST( DbgPrint("F%d: TEST reset timed out\n", FirstTest);)
+ FinalResult = FALSE;
+ goto FinishTest;
+ }
+
+ NdisStallExecution(11000);
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+ }
+ }
+
+ //
+ // WAIT FOR CHIP TO STABILIZE
+ // Write to and read from CR to make sure it is there.
+ // Bug#4267 - WFW
+ //
+
+ {
+ UINT i;
+ for (i = 0; i < 2000; ++i) {
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE0);
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND, &Tmp);
+ if (Tmp != (CR_STOP | CR_NO_DMA | CR_PAGE0)) {
+ NdisStallExecution(1000);
+ } else {
+ break;
+ }
+ }
+ }
+
+
+ //
+ // Acknowledge the interrupt.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR);
+
+
+ //
+ // Check that the CRS and CDH bits are set correctly.
+ //
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_STATUS, &TSRResult);
+
+ if ((TSRResult & TSR_NO_CARRIER) != TSRCRSWanted[FirstTest]) {
+
+ IF_TEST(DbgPrint("F%d: Incorrect CRS value: %x\n", FirstTest, TSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ if ((TSRResult & TSR_NO_CDH) != TSRCDHWanted[FirstTest]) {
+
+ //
+ // the spec says CDH won't go on for TCR_COAX_LBK, but it does
+ //
+
+ if (TCRValues[FirstTest] != TCR_COAX_LBK) {
+
+ IF_TEST( DbgPrint("F%d: Incorrect CDH value: %x\n", FirstTest,TSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+ //
+ // For the Loopback to Coax test the RSR and FIFO
+ // can't be trusted, so skip them.
+ //
+
+ if (TCRValues[FirstTest] == TCR_COAX_LBK) {
+
+ continue;
+
+ }
+
+
+ //
+ // Check that the CRC error happened (it should).
+ //
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_RCV_STATUS, &RSRResult);
+
+ if (!(RSRResult & RSR_CRC_ERROR)) {
+
+ IF_TEST( DbgPrint("F%d: No CRC error: %x\n", FirstTest, RSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+
+ //
+ // Check that the right values are in the FIFO.
+ //
+
+ for (i=0; i<4; i++) {
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_FIFO, &Tmp);
+ if (Tmp != FIFOWanted[i]) {
+
+ IF_TEST( DbgPrint("F%d: Bad FIFO value: %d\n", FirstTest, i);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+ //
+ // Flush the rest of the FIFO.
+ //
+
+ for (i=0; i<4; i++) {
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_FIFO, &Tmp);
+
+ }
+
+ }
+
+
+ //
+ // Stop the card.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Set the TCR for internal loopback.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG, 0x00);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG,
+ TCR_INHIBIT_CRC | TCR_NIC_LBK);
+
+ //
+ // Restart the card.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+
+ //
+ // Second round of tests -- CRC and Address recognition logic
+ //
+
+ for (SecondTest = 0; SecondTest < 3; ++SecondTest) {
+
+ //
+ // See if the destination address should be valid.
+ //
+
+ if (GoodAddress[SecondTest]) {
+
+ ELNKII_MOVE_MEM(TestPacket, pAdapter->StationAddress, ETH_LENGTH_OF_ADDRESS);
+
+ } else {
+
+ ELNKII_MOVE_MEM(TestPacket, NullAddress, ETH_LENGTH_OF_ADDRESS);
+
+ }
+
+
+ //
+ // Copy down TestPacket.
+ //
+
+ CardCopyDownBuffer(pAdapter, TestPacket, 0, 0, TEST_LEN);
+
+
+ //
+ // Copy down a good or bad CRC, as needed.
+ //
+
+ CardGetPacketCrc(TestPacket, TEST_LEN, CrcBuf);
+
+ if (!GoodCrc[SecondTest]) {
+
+ CrcBuf[0] = (UCHAR)(CrcBuf[0] ^ 0xff); // intentionally make it bad
+
+ }
+
+ CardCopyDownBuffer(pAdapter, CrcBuf, 0, TEST_LEN, 4);
+
+
+ //
+ // Start the transmission.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_START, pAdapter->NicXmitStart);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(TEST_LEN+4));
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(TEST_LEN+4));
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA);
+
+
+ //
+ // Wait for the transmission to complete, for about a second.
+ //
+
+ TimerExpired=FALSE;
+
+ NdisMInitializeTimer(
+ &Timer,
+ pAdapter->MiniportAdapterHandle,
+ DelayComplete,
+ &TimerExpired
+ );
+
+ NdisMSetTimer(&Timer, 1000);
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+ while (!(Tmp & (ISR_XMIT | ISR_XMIT_ERR))) {
+
+ if (TimerExpired) {
+
+ IF_TEST( DbgPrint("F%d: TEST reset timed out\n", FirstTest);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
+
+ }
+
+ //
+ //MUST Cancel the unexpired timer
+ //
+
+ NdisMCancelTimer(&Timer, &dummy);
+
+ //
+ // Acknowledge the interrupt.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR);
+
+
+ //
+ // Check that RSR is as expected.
+ //
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr+NIC_RCV_STATUS, &RSRResult);
+
+ if ((UCHAR)(RSRResult & (RSR_PACKET_OK | RSR_CRC_ERROR)) !=
+ RSRWanted[SecondTest]) {
+
+ IF_TEST( DbgPrint("S%d: Bad RSR: wanted %x got %x\n", SecondTest,
+ RSRWanted[SecondTest], RSRResult);)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+
+
+ //
+ // Third round of tests - copying data to and from the card.
+ //
+
+ //
+ // First put data in the buffer.
+ //
+
+ for (i=0; i<256; i++) {
+
+ TestSrcBuf[i] = (UCHAR)(256-i);
+
+ }
+
+ //
+ // Loop through all the card memory in 256-byte pieces.
+ //
+
+ for (CurTestLoc = 0; CurTestLoc < (PUCHAR)0x2000; CurTestLoc += 256) {
+
+ //
+ // Copy the data down (have to play around with buffer
+ // numbers and offsets to put it in the right place).
+ //
+
+ CardCopyDownBuffer(pAdapter, TestSrcBuf,
+ (XMIT_BUF)((ULONG)CurTestLoc / TX_BUF_SIZE),
+ (ULONG)CurTestLoc % TX_BUF_SIZE, 256);
+
+ //
+ // Clear the destination buffer and read it back.
+ //
+
+ for (i=0; i<256; i++) {
+
+ TestDestBuf[i] = 77;
+
+ }
+
+ CardCopyUp(pAdapter, TestDestBuf,
+ pAdapter->XmitStart + (ULONG)CurTestLoc, 256);
+
+ //
+ // Make sure that the data matches.
+ //
+
+ for (i=0; i<256; i++) {
+
+ if (TestSrcBuf[i] != TestDestBuf[i]) {
+
+ IF_TEST( DbgPrint("T: Bad data at %lx\n", (ULONG)(CurTestLoc+i));)
+
+ FinalResult = FALSE;
+
+ goto FinishTest;
+
+ }
+
+ }
+
+ }
+
+
+
+ //
+ // FinishTest: jump here to exit the tests cleanly.
+ //
+
+FinishTest:
+
+ //
+ // Stop the card.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_STOP | CR_NO_DMA | CR_PAGE0);
+
+
+ //
+ // Restore DCR, RCR, and TCR.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_DATA_CONFIG,
+ DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE);
+
+ //
+ // (clear these two to be safe)
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_RMT_COUNT_LSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_RCV_CONFIG, pAdapter->NicReceiveConfig);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ //
+ // The reconfiguring of the config registers can cause the xmit to complete
+ // if the test was a failure. Therefore, we pause here to allow the xmit
+ // to complete so that we can ACK it below - leaving the card in a valid state.
+ //
+
+ NdisStallExecution(50000);
+
+ //
+ // Acknowledge any interrupts that are floating around.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_INTR_STATUS, 0xff);
+
+
+ //
+ // Start the card, but stay in loopback mode.
+ //
+
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr+NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0);
+
+
+
+ return FinalResult;
+}
+
+
+
+
+BOOLEAN CardCopyDownPacket(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PNDIS_PACKET Packet,
+ IN XMIT_BUF XmitBufferNum,
+ OUT UINT *Length
+)
+
+/*++
+
+Routine Description:
+
+ Copies the packet Packet down starting at the beginning of
+ transmit buffer XmitBufferNum, fills in Length to be the
+ length of the packet. It uses memory mapping or programmed
+ I/O as appropriate.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+ Packet - the packet to copy down
+ XmitBufferNum - the transmit buffer number
+
+Return Value:
+
+ Length - the length of the data in the packet in bytes.
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ PUCHAR CurAddress;
+ PUCHAR BufAddress;
+ UINT CurLength;
+ UINT Len;
+ PNDIS_BUFFER CurBuffer;
+ UINT TmpLen;
+ UINT BurstSize;
+ UCHAR GaStatus;
+
+ //
+ // Is the card memory mapped?
+ //
+ if (pAdapter->MemMapped)
+ {
+ //
+ // Memory mapped, just copy each buffer over.
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ CurAddress = pAdapter->XmitStart + XmitBufferNum * TX_BUF_SIZE;
+
+ CurLength = 0;
+
+ while (CurBuffer)
+ {
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufAddress, &Len);
+
+ ELNKII_MOVE_MEM_TO_SHARED_RAM(CurAddress, BufAddress, Len);
+
+ CurAddress += Len;
+
+ CurLength += Len;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ }
+
+ *Length = CurLength;
+ }
+ else
+ {
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ CurAddress = (PUCHAR)0x2000 + XmitBufferNum * TX_BUF_SIZE;
+
+ CurLength = 0;
+
+ while (CurBuffer)
+ {
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufAddress, &Len);
+
+ if (Len == 0)
+ {
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ continue;
+ }
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_MSB,
+ MSB((ULONG)CurAddress)
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_LSB,
+ LSB((ULONG)CurAddress)
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_DOWN) | pAdapter->GaControlBits)
+ );
+
+
+ //
+ // First transfer multiples of DMA_BURST_SIZE.
+ //
+ TmpLen = Len;
+ BurstSize = DMA_BURST_SIZE;
+
+ while (TmpLen >= BurstSize)
+ {
+ if ((ULONG)BufAddress & 0x01)
+ {
+ NdisRawWritePortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ (PUCHAR)BufAddress,
+ BurstSize
+ );
+ }
+ else
+ {
+ NdisRawWritePortBufferUshort(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ (PUSHORT)BufAddress,
+ BurstSize / 2
+ );
+ }
+
+
+ TmpLen -= BurstSize;
+
+ BufAddress += BurstSize;
+
+ //
+ // Wait for the Gate Array FIFO to be ready.
+ //
+ do
+ {
+ NdisRawReadPortUchar(pAdapter->MappedGaBaseAddr+GA_STATUS, &GaStatus);
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDP\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, BurstSize, PrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownPacket,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return(FALSE);
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+#if DBG
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+ }
+
+ //
+ // Now copy the last bit as UCHARs.
+ //
+ NdisRawWritePortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ BufAddress,
+ TmpLen
+ );
+
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDPII\n");
+ DbgPrint("\tStatus = 0x%x, BurstSize = 0x%x, PrevBurstSize = 0x%x\n",
+ GaStatus, BurstSize, PrevBurstSize);
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownPacket,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return FALSE;
+ }
+
+ } while (!(GaStatus & STREG_DP_READY));
+
+
+#if DBG
+ PrevBurstSize = (UCHAR)TmpLen;
+#endif
+
+ //
+ // Done, turn off the start bit...
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)(CTRL_STOP | pAdapter->GaControlBits)
+ );
+
+ //
+ // ... and wait for DMA_IN_PROGRESS to go off,
+ // indicating end of flush.
+ //
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+ } while (GaStatus & STREG_IN_PROG);
+
+ CurAddress += Len;
+
+ CurLength += Len;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+ }
+
+ *Length = CurLength;
+ }
+
+ return(TRUE);
+}
+
+
+BOOLEAN CardCopyDownBuffer(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PUCHAR SourceBuffer,
+ IN XMIT_BUF XmitBufferNum,
+ IN UINT Offset,
+ IN UINT Length
+)
+
+/*++
+
+Routine Description:
+
+ Copies down one character buffer (rather than an
+ entire packet), starting at offset Offset, for Length
+ bytes. It uses memory mapping or programmed I/O as
+ appropriate. This function is used for blanking the padding
+ at the end of short packets and also for loopback testing.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+ SourceBuffer - the source data to be copied down
+ XmitBufferNum - the transmit buffer number
+ Offset - the offset from the start of the transmit buffer
+ Length - the number of bytes to blank out
+
+Return Value:
+
+ Length - the length of the data in the packet in bytes.
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ PUCHAR CurAddress;
+ UINT TmpLen;
+ UINT ThisTime;
+ UCHAR GaStatus;
+
+ if (pAdapter->MemMapped)
+ {
+ //
+ // Memory mapped, just copy over SourceBuffer.
+ //
+ CurAddress = pAdapter->XmitStart + XmitBufferNum * TX_BUF_SIZE + Offset;
+
+ ELNKII_MOVE_MEM_TO_SHARED_RAM(CurAddress, SourceBuffer, Length);
+ }
+ else
+ {
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+ CurAddress = (PUCHAR)0x2000 + XmitBufferNum*TX_BUF_SIZE + Offset;
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_MSB,
+ MSB((ULONG)CurAddress)
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_LSB,
+ LSB((ULONG)CurAddress)
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_DOWN) | pAdapter->GaControlBits)
+ );
+
+ //
+ // Copy the data down in DMA_BURST_SIZE bursts.
+ //
+ TmpLen = Length;
+
+ while (TmpLen > 0)
+ {
+ ThisTime = (TmpLen >= DMA_BURST_SIZE) ? DMA_BURST_SIZE : TmpLen;
+
+ NdisRawWritePortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ SourceBuffer,
+ ThisTime
+ );
+
+ TmpLen -= ThisTime;
+
+ SourceBuffer += ThisTime;
+
+ //
+ // Wait for the Gate Array FIFO to be ready.
+ //
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCDB\n");
+ DbgPrint(
+ "\tStatus = 0x%x, BurstSize = 0x%x, "
+ "PrevBurstSize = 0x%x\n",
+ GaStatus,
+ ThisTime,
+ PrevBurstSize
+ );
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyDownBuffer,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return(FALSE);
+ }
+ } while (!(GaStatus & STREG_DP_READY));
+
+#if DBG
+ PrevBurstSize = (UCHAR)ThisTime;
+#endif
+ }
+
+ //
+ // Done, turn off the start bit..
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)(CTRL_STOP | pAdapter->GaControlBits)
+ );
+
+ //
+ // ... and wait for DMA_IN_PROGRESS to go off,
+ // indicating end of flush.
+ //
+
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+ } while (GaStatus & STREG_IN_PROG);
+ }
+
+#if DBG
+ IF_ELNKIIDEBUG( ELNKII_DEBUG_TRACK_PACKET_LENS )
+ {
+ if (Offset == 18 && Length == 42)
+ {
+ UINT i;
+
+ for (i = 0; i < 20; i++)
+ {
+ SourceBuffer[i] = ' ';
+ }
+ }
+ }
+#endif
+
+ return(TRUE);
+}
+
+
+
+
+BOOLEAN CardCopyUp(
+ IN PELNKII_ADAPTER pAdapter,
+ IN PUCHAR Target,
+ IN PUCHAR Source,
+ IN UINT Length
+)
+
+/*++
+
+Routine Description:
+
+ Copies data from the card to memory. It uses memory mapping
+ or programmed I/O as appropriate.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+ Target - the target address
+ Source - the source address (on the card)
+ Length - the number of bytes to copy
+
+Return Value:
+
+ TRUE if the transfer completed with no problems.
+
+--*/
+
+{
+ UINT TmpLen;
+ UINT BurstSize;
+ UCHAR GaStatus;
+
+ if (Length == 0)
+ return(TRUE);
+
+ if (pAdapter->MemMapped)
+ {
+ //
+ // Memory mapped, just copy the data over.
+ //
+ ELNKII_MOVE_SHARED_RAM_TO_MEM(Target, Source, Length);
+ }
+ else
+ {
+ //
+ // Programmed I/O, have to transfer the data.
+ //
+
+ //
+ // Adjust the address to be a card address.
+ //
+ Source -= ((ULONG)pAdapter->XmitStart - 0x2000);
+
+ //
+ // Set up the Gate Array for programmed I/O transfer.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_MSB,
+ MSB((ULONG)Source)
+ );
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_DMA_ADDR_LSB,
+ LSB((ULONG)Source)
+ );
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)((CTRL_START | CTRL_DIR_UP) | pAdapter->GaControlBits)
+ );
+
+
+ //
+ // First copy multiples of DMA_BURST_SIZE as USHORTs.
+ //
+ TmpLen = Length;
+ BurstSize = DMA_BURST_SIZE;
+
+ //
+ // Before doing this, transfer one byte if needed to
+ // align on a USHORT boundary.
+ //
+ while (TmpLen >= BurstSize)
+ {
+ //
+ // First wait for the Gate Array FIFO to be ready.
+ //
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCU\n");
+ DbgPrint(
+ "\tStatus = 0x%x, BurstSize = 0x%x, "
+ "PrevBurstSize = 0x%x\n",
+ GaStatus,
+ PrevBurstSize,
+ PrevPrevBurstSize
+ );
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyUp,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return(FALSE);
+ }
+ } while (!(GaStatus & STREG_DP_READY));
+
+
+ if ((ULONG)Target & 0x01)
+ {
+ //
+ // This is the first burst, and it starts on
+ // an odd boundary.
+ //
+ NdisRawReadPortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ (PUCHAR)Target,
+ BurstSize
+ );
+
+ TmpLen -= BurstSize;
+ Target += BurstSize;
+
+#if DBG
+ PrevPrevBurstSize = PrevBurstSize;
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+ }
+ else
+ {
+ NdisRawReadPortBufferUshort(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ (PUSHORT)Target,
+ BurstSize / 2
+ );
+
+ TmpLen -= BurstSize;
+ Target += BurstSize;
+
+
+#if DBG
+ PrevPrevBurstSize = PrevBurstSize;
+ PrevBurstSize = (UCHAR)BurstSize;
+#endif
+ }
+ }
+
+ //
+ // Now copy the last bit of data as UCHARs.
+ //
+ do
+ {
+ NdisRawReadPortUchar(
+ pAdapter->MappedGaBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ if (GaStatus & (STREG_UNDERFLOW | STREG_OVERFLOW))
+ {
+#if DBG
+ DbgPrint("DATA PORT READY ERROR IN ELNKII - CCUII\n");
+ DbgPrint(
+ "\tStatus = 0x%x, BurstSize = 0x%x, "
+ "PrevBurstSize = 0x%x\n",
+ GaStatus,
+ BurstSize,
+ PrevBurstSize
+ );
+#endif
+
+ NdisWriteErrorLogEntry(
+ pAdapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ cardCopyUp,
+ ELNKII_ERRMSG_DATA_PORT_READY
+ );
+
+ return(FALSE);
+ }
+ } while (!(GaStatus & STREG_DP_READY));
+
+ NdisRawReadPortBufferUchar(
+ pAdapter->MappedGaBaseAddr + GA_REG_FILE_MSB,
+ Target,
+ TmpLen
+ );
+
+ //
+ // Done, turn off the start bit.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedGaBaseAddr + GA_CONTROL,
+ (UCHAR)(CTRL_STOP | pAdapter->GaControlBits)
+ );
+ }
+
+ return(TRUE);
+}
+
+ULONG
+CardComputeCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length
+ )
+
+/*++
+
+Routine Description:
+
+ Runs the AUTODIN II CRC algorithm on buffer Buffer of
+ length Length.
+
+Arguments:
+
+ Buffer - the input buffer
+ Length - the length of Buffer
+
+Return Value:
+
+ The 32-bit CRC value.
+
+Note:
+
+ This is adapted from the comments in the assembly language
+ version in _GENREQ.ASM of the DWB NE1000/2000 driver.
+
+--*/
+
+{
+ ULONG Crc;
+ ULONG Carry;
+ UINT i;
+ UINT j;
+ UCHAR CurByte;
+
+ Crc = 0xffffffff;
+
+ for (i = 0; i < Length; i++)
+ {
+ CurByte = Buffer[i];
+
+ for (j = 0; j < 8; j++)
+ {
+ Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01);
+
+ Crc <<= 1;
+
+ CurByte >>= 1;
+
+ if (Carry)
+ Crc = (Crc ^ 0x04c11db6) | Carry;
+
+ }
+ }
+
+ return(Crc);
+}
+
+
+#pragma NDIS_INIT_FUNCTION(CardGetPacketCrc)
+
+VOID CardGetPacketCrc(
+ IN PUCHAR Buffer,
+ IN UINT Length,
+ OUT UCHAR Crc[4]
+)
+
+/*++
+
+Routine Description:
+
+ For a given Buffer, computes the packet CRC for it.
+ It uses CardComputeCrc to determine the CRC value, then
+ inverts the order and value of all the bits (I don't
+ know why this is necessary).
+
+Arguments:
+
+ Buffer - the input buffer
+ Length - the length of Buffer
+
+Return Value:
+
+ The CRC will be stored in Crc.
+
+--*/
+
+{
+ static UCHAR InvertBits[16] = { 0x0, 0x8, 0x4, 0xc,
+ 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd,
+ 0x3, 0xb, 0x7, 0xf };
+ ULONG CrcValue;
+ UCHAR Tmp;
+ UINT i;
+
+ //
+ // First compute the CRC.
+ //
+ CrcValue = CardComputeCrc(Buffer, Length);
+
+
+ //
+ // Now invert the bits in the result.
+ //
+ for (i = 0; i < 4; i++)
+ {
+ Tmp = ((PUCHAR)&CrcValue)[3-i];
+
+ Crc[i] = (UCHAR)((InvertBits[Tmp >> 4] +
+ (InvertBits[Tmp & 0xf] << 4)) ^ 0xff);
+ }
+}
+
+
+VOID
+CardGetMulticastBit(
+ IN UCHAR Address[ETH_LENGTH_OF_ADDRESS],
+ OUT UCHAR * Byte,
+ OUT UCHAR * Value
+ )
+
+/*++
+
+Routine Description:
+
+ For a given multicast address, returns the byte and bit in
+ the card multicast registers that it hashes to. Calls
+ CardComputeCrc() to determine the CRC value.
+
+Arguments:
+
+ Address - the address
+ Byte - the byte that it hashes to
+ Value - will have a 1 in the relevant bit
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Crc;
+ UINT BitNumber;
+
+ //
+ // First compute the CRC.
+ //
+ Crc = CardComputeCrc(Address, ETH_LENGTH_OF_ADDRESS);
+
+
+ //
+ // The bit number is now in the 6 most significant bits of CRC.
+ //
+ BitNumber = (UINT)((Crc >> 26) & 0x3f);
+
+ *Byte = (UCHAR)(BitNumber / 8);
+ *Value = (UCHAR)((UCHAR)1 << (BitNumber % 8));
+}
+
+VOID CardFillMulticastRegs(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Erases and refills the card multicast registers. Used when
+ an address has been deleted and all bits must be recomputed.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+ UCHAR Byte;
+ UCHAR Bit;
+
+ //
+ // First turn all bits off.
+ //
+ for (i = 0; i < 8; i++)
+ pAdapter->NicMulticastRegs[i] = 0;
+
+ //
+ // Now turn on the bit for each address in the multicast list.
+ //
+ for ( ; i > 0; )
+ {
+ i--;
+
+ CardGetMulticastBit(Addresses[i], &Byte, &Bit);
+
+ pAdapter->NicMulticastRegs[Byte] |= Bit;
+ }
+}
+
+
+VOID CardStartXmit(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the NIC_COMMAND register to start a transmission.
+ The transmit buffer number is taken from pAdapter->CurBufXmitting
+ and the length from pAdapter->PacketLens[pAdapter->CurBufXmitting].
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ TRUE if the power has failed.
+
+--*/
+
+{
+ XMIT_BUF XmitBufferNum = pAdapter->CurBufXmitting;
+ UINT Length = pAdapter->PacketLens[XmitBufferNum];
+ UCHAR Tmp;
+
+ //
+ // Prepare the NIC registers for transmission.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_START,
+ (UCHAR)(pAdapter->NicXmitStart + (UCHAR)(XmitBufferNum * BUFS_PER_TX))
+ );
+
+ //
+ // Pad the length to 60 (plus CRC will be 64) if needed.
+ //
+
+ if (Length < 60)
+ Length = 60;
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_COUNT_MSB,
+ MSB(Length)
+ );
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_COUNT_LSB,
+ LSB(Length)
+ );
+
+ //
+ // Start transmission, check for power failure first.
+ //
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_COMMAND, &Tmp);
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_XMIT | CR_NO_DMA
+ );
+
+ IF_LOG( ElnkiiLog('x');)
+}
+
+
+BOOLEAN SyncCardGetXmitStatus(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Gets the value of the "transmit status" NIC register and stores
+ it in pAdapter->XmitStatus.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)SynchronizeContext;
+
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_STATUS,
+ &pAdapter->XmitStatus
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardGetCurrent(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Gets the value of the CURRENT NIC register and stores
+ it in pAdapter->Current.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // Have to go to page 1 to read this register.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1
+ );
+
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CURRENT,
+ &pAdapter->Current
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ return(FALSE);
+}
+
+VOID CardSetBoundary(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the value of the "boundary" NIC register to one behind
+ pAdapter->NicNextPacket, to prevent packets from being received
+ on top of un-indicated ones.
+
+Arguments:
+
+ pAdapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Have to be careful with "one behind NicNextPacket" when
+ // NicNextPacket is the first buffer in receive area.
+ //
+ if (pAdapter->NicNextPacket == pAdapter->NicPageStart)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_BOUNDARY,
+ (UCHAR)(pAdapter->NicPageStop - (UCHAR)1)
+ );
+ }
+ else
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_BOUNDARY,
+ (UCHAR)(pAdapter->NicNextPacket - (UCHAR)1)
+ );
+ }
+}
+
+
+BOOLEAN SyncCardSetReceiveConfig(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the value of the "receive configuration" NIC register to
+ the value of pAdapter->NicReceiveConfig.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_RCV_CONFIG,
+ pAdapter->NicReceiveConfig
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardSetAllMulticast(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Turns on all the bits in the multicast register. Used when
+ the card must receive all multicast packets.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+
+ //
+ // Have to move to page 1 to set these registers.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1
+ );
+
+ for (i = 0; i < 8; i++)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + (NIC_MC_ADDR + i),
+ 0xff
+ );
+ }
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardCopyMulticastRegs(
+ IN PELNKII_ADAPTER pAdapter
+)
+
+/*++
+
+Routine Description:
+
+ Sets the eight bytes in the card multicast registers.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT i;
+
+ //
+ // Have to move to page 1 to set these registers.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1
+ );
+
+ for (i = 0; i < 8; i++)
+ {
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + (NIC_MC_ADDR + i),
+ pAdapter->NicMulticastRegs[i]
+ );
+ }
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ return(FALSE);
+
+}
+
+BOOLEAN
+SyncCardSetInterruptMask(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the "interrupt mask" register of the NIC to the value of
+ pAdapter->NicInterruptMask.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardAcknowledgeReceive(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the "packet received" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_RCV
+ );
+
+ //
+ // Interrupts were previously blocked in the interrupt handler.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardAcknowledgeOverflow(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the "buffer overflow" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+ UCHAR InterruptStatus;
+
+ CardGetInterruptStatus(pAdapter, &InterruptStatus);
+
+ if (InterruptStatus & ISR_RCV_ERR)
+ SyncCardUpdateCounters(pAdapter);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_OVERFLOW
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardAcknowledgeTransmit(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets the "packet transmitted" bit in the NIC interrupt status register,
+ which re-enables interrupts of that type.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR
+ );
+
+ //
+ // Interrupts were previously blocked in the interrupt handler.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardAckAndGetCurrent(
+ IN PVOID SynchronizeContext
+ )
+
+/*++
+
+Routine Description:
+
+ Performs the functions of SyncCardAcknowledgeReceive followed by
+ SyncCardGetCurrent (since the two are always called
+ one after the other).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // SyncCardAcknowledgeReceive.
+ //
+
+#ifdef i386
+
+ __asm cli
+
+#endif
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_RCV
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+#ifdef i386
+
+ __asm sti
+
+#endif
+
+ //
+ // SyncCardGetCurrent.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE1
+ );
+
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CURRENT,
+ &pAdapter->Current
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA | CR_PAGE0
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardGetXmitStatusAndAck(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Performs the functions of SyncCardGetXmitStatus followed by
+ SyncCardAcknowledgeTransmit (since the two are always
+ called one after the other).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+
+ //
+ // SyncCardGetXmitStatus.
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_STATUS,
+ &pAdapter->XmitStatus
+ );
+
+ //
+ // SyncCardAcknowledgeTransmit.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ ISR_XMIT | ISR_XMIT_ERR
+ );
+
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_MASK,
+ pAdapter->NicInterruptMask
+ );
+
+ return(FALSE);
+}
+
+
+BOOLEAN SyncCardUpdateCounters(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Updates the values of the three counters (frame alignment errors,
+ CRC errors, and missed packets).
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = ((PELNKII_ADAPTER)SynchronizeContext);
+ UCHAR Tmp;
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_FAE_ERR_CNTR, &Tmp);
+ pAdapter->FrameAlignmentErrors += Tmp;
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_CRC_ERR_CNTR, &Tmp);
+ pAdapter->CrcErrors += Tmp;
+
+ NdisRawReadPortUchar(pAdapter->MappedIoBaseAddr + NIC_MISSED_CNTR, &Tmp);
+ pAdapter->MissedPackets += Tmp;
+
+ return(FALSE);
+}
+
+BOOLEAN SyncCardHandleOverflow(
+ IN PVOID SynchronizeContext
+)
+
+/*++
+
+Routine Description:
+
+ Sets all the flags for dealing with a receive overflow, stops the card
+ and acknowledges all outstanding interrupts.
+
+Arguments:
+
+ SynchronizeContext - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)SynchronizeContext;
+ UCHAR InterruptStatus;
+
+ IF_LOG( ElnkiiLog('F');)
+
+ //
+ // This is a copy of CardStop(). This is changed in minor ways since
+ // we are already synchornized with interrupts.
+ //
+
+ //
+ // Turn on the STOP bit in the Command register.
+ //
+ SyncCardStop(pAdapter);
+
+ //
+ // Wait for ISR_RESET, but only for 1.6 milliseconds (as
+ // described in the March 1991 8390 addendum), since that
+ // is the maximum time for a software reset to occur.
+ //
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Save whether we were transmitting to avoid a timing problem
+ // where an indication resulted in a send.
+ //
+ if (!(pAdapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
+ {
+ CardGetInterruptStatus(pAdapter, &InterruptStatus);
+ if (!(InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
+ {
+ pAdapter->OverflowRestartXmitDpc = pAdapter->TransmitInterruptPending;
+
+ IF_LOUD(DbgPrint("ORXD=%x\n", pAdapter->OverflowRestartXmitDpc);)
+ }
+ }
+
+ //
+ // Clear the Remote Byte Count register so that ISR_RESET
+ // will come on.
+ //
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_MSB, 0);
+ NdisRawWritePortUchar(pAdapter->MappedIoBaseAddr + NIC_RMT_COUNT_LSB, 0);
+
+ //
+ // According to National Semiconductor, the next check is necessary
+ // See Step 5. of the overflow process
+ //
+ // NOTE: The setting of variables to check if the transmit has completed
+ // cannot be done here because anything in the ISR has already been ack'ed
+ // inside the main DPC. Thus, the setting of the variables, described in
+ // the Handbook was moved to the main DPC.
+ //
+ // Continued: If you did the check here, you will doubly transmit most
+ // packets that happened to be on the card when the overflow occurred.
+ //
+
+ //
+ // Put the card in loopback mode, then start it.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_CONFIG,
+ TCR_LOOPBACK
+ );
+
+ //
+ // Start the card. This does not Undo the loopback mode.
+ //
+ NdisRawWritePortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_COMMAND,
+ CR_START | CR_NO_DMA
+ );
+
+ return(FALSE);
+}
+
+
+
+#if DBG
+//
+// Following function is for debug stuff.
+//
+VOID ElnkiiDisplayStatus(
+ PELNKII_ADAPTER pAdapter
+)
+{
+ //
+ // NIC registers that we can read.
+ //
+ UCHAR NicXmitStatus; // NIC_XMIT_STATUS
+ UCHAR NicFifo; // NIC_FIFO
+ UCHAR NicInterruptStatus; // NIC_INTR_STATUS
+ UCHAR NicCurrent; // NIC_CURRENT
+ UCHAR NicReceiveStatus; // NIC_RCV_STATUS
+ UCHAR NicFrameErrorCounter; // NIC_FAE_ERR_CNTR
+ UCHAR NicCrcErrorCounter; // NIC_CRC_ERR_CNTR
+ UCHAR NicMissedCounter; // NIC_MISSED_CNTR
+
+ //
+ // Gate-Array registers that we can read.
+ //
+ UCHAR GaPageStart; // GA_PAGE_START
+ UCHAR GaPageStop; // GA_PAGE_STOP
+ UCHAR GaDrqTimer; // GA_DRQ_TIMER
+ UCHAR GaIoBase; // GA_IO_BASE
+ UCHAR GaMemoryBase; // GA_MEM_BASE
+ UCHAR GaConfig; // GA_CONFIG
+ UCHAR GaControl; // GA_CONTROL
+ UCHAR GaStatus; // GA_STATUS
+ UCHAR GaIntDmaConfig; // GA_INT_DMA_CONFIG
+ UCHAR GaDmaAddressMsb; // GA_DMA_ADDR_MSB
+ UCHAR GaDmaAddressLsb; // GA_DMA_ADDR_LSB
+ UCHAR GaRegFileAccessMsb; // GA_REG_FILE_MSB
+ UCHAR GaRegFileAccessLsb; // GA_REG_FILE_LSB
+
+ //
+ // Get the NIC xmit status
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_XMIT_STATUS,
+ &NicXmitStatus
+ );
+
+ //
+ // Display NIC status information.
+ //
+ DbgPrint(
+ "NIC_XMIT_STATUS: TSR_XMIT_OK - %x\n"
+ " TSR_COLLISION - %x\n"
+ " TSR_ABORTED - %x\n"
+ " TSR_NO_CARRIER - %x\n"
+ " TSR_NO_CDH - %x\n",
+ NicXmitStatus & TSR_XMIT_OK,
+ NicXmitStatus & TSR_COLLISION,
+ NicXmitStatus & TSR_ABORTED,
+ NicXmitStatus & TSR_NO_CARRIER,
+ NicXmitStatus & TSR_NO_CDH
+ );
+
+ //
+ // Get the nic fifo
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_FIFO,
+ &NicFifo
+ );
+
+ DbgPrint("NIC_FIFO: %x\n", NicFifo);
+
+ //
+ // Get the nic interrupt status
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS,
+ &NicInterruptStatus
+ );
+
+ DbgPrint(
+ "NIC_INTR_STATUS: ISR_EMPTY - %x\n"
+ " ISR_RCV - %x\n"
+ " ISR_XMIT - %x\n"
+ " ISR_RCV_ERR - %x\n"
+ " ISR_XMIT_ERR - %x\n"
+ " ISR_OVERFLOW - %x\n"
+ " ISR_COUNTER - %x\n"
+ " ISR_RESET - %x\n",
+ NicInterruptStatus & ISR_EMPTY,
+ NicInterruptStatus & ISR_RCV,
+ NicInterruptStatus & ISR_XMIT,
+ NicInterruptStatus & ISR_RCV_ERR,
+ NicInterruptStatus & ISR_XMIT_ERR,
+ NicInterruptStatus & ISR_OVERFLOW,
+ NicInterruptStatus & ISR_COUNTER,
+ NicInterruptStatus & ISR_RESET
+ );
+
+
+ //
+ // Get the nic current
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CURRENT,
+ &NicCurrent
+ );
+
+ DbgPrint("NIC_CURRENT: %x\n", NicCurrent);
+
+ //
+ // Get the nic receive status
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_RCV_STATUS,
+ &NicReceiveStatus
+ );
+
+
+ DbgPrint(
+ "NIC_RCV_STATUS: RSR_PACKET_OK - %x\n"
+ " RSR_CRC_ERROR - %x\n"
+ " RSR_MULTICAST - %x\n"
+ " RSR_DISABLED - %x\n",
+ " RSR_DEFERRING - %x\n",
+ NicReceiveStatus & RSR_PACKET_OK,
+ NicReceiveStatus & RSR_CRC_ERROR,
+ NicReceiveStatus & RSR_MULTICAST,
+ NicReceiveStatus & RSR_DISABLED,
+ NicReceiveStatus & RSR_DEFERRING
+ );
+
+ //
+ // Get the nic frame error counter
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_FAE_ERR_CNTR,
+ &NicFrameErrorCounter
+ );
+
+ DbgPrint("NIC_FAE_ERR_CNTR: %x\n", NicFrameErrorCounter);
+
+ //
+ // Get the nic crc error counter
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_CRC_ERR_CNTR,
+ &NicCrcErrorCounter
+ );
+
+ DbgPrint("NIC_CRC_ERR_CNTR: %x\n", NicCrcErrorCounter);
+
+ //
+ // Get the nic missed counter
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + NIC_MISSED_CNTR,
+ &NicMissedCounter
+ );
+
+ DbgPrint("NIC_MISSED_CNTR: %x\n", NicMissedCounter);
+
+ //
+ // Get the GA page start.
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_PAGE_START,
+ &GaPageStart
+ );
+
+ DbgPrint("GA_PAGE_START: %x\n", GaPageStart);
+
+
+ //
+ // Get the GA page stop.
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_PAGE_STOP,
+ &GaPageStop
+ );
+
+ DbgPrint("GA_PAGE_STOP: %x\n", GaPageStop);
+
+ //
+ // Get the GA drq timer
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_DRQ_TIMER,
+ &GaDrqTimer
+ );
+
+ DbgPrint(
+ "GA_DRQ_TIMER: DQTR_16_BYTE - %x\n"
+ " DQTR_8_BYTE - %x\n",
+ GaDrqTimer == DQTR_16_BYTE,
+ GaDrqTimer == DQTR_8_BYTE
+ );
+
+ //
+ // Get the GA io base
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_IO_BASE,
+ &GaIoBase
+ );
+
+ DbgPrint("GA_IO_BASE: %x\n", GaIoBase);
+
+ //
+ // Get the GA memory base
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_MEM_BASE,
+ &GaMemoryBase
+ );
+
+ DbgPrint("GA_MEM_BASE: %x\n", GaMemoryBase);
+
+ //
+ // Get the GA config
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_CONFIG,
+ &GaConfig
+ );
+
+ DbgPrint(
+ "GA_CONFIG: GACFR_TC_MASK - %x\n"
+ " GACFR_RAM_SEL - %x\n"
+ " GACFR_MEM_BANK1 - %x\n",
+ GaConfig & GACFR_TC_MASK,
+ GaConfig & GACFR_RAM_SEL,
+ GaConfig & GACFR_MEM_BANK1
+ );
+
+ //
+ // Get the GA control
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_CONTROL,
+ &GaControl
+ );
+
+ DbgPrint(
+ "GA_CONTROL: CTRL_START - %x\n"
+ " CTRL_STOP - %x\n"
+ " CTRL_DIR_DOWN - %x\n"
+ " CTRL_DIR_UP - %x\n"
+ " CTRL_DB_SEL - %x\n"
+ " CTRL_PROM_SEL - %x\n"
+ " CTRL_GA_SEL - %x\n"
+ " CTRL_BNC - %x\n"
+ " CTRL_DIX - %x\n"
+ " CTRL_RESET - %x\n",
+ GaControl & CTRL_START,
+ !(GaControl & CTRL_STOP),
+ GaControl & CTRL_DIR_DOWN,
+ !(GaControl & CTRL_DIR_UP),
+ GaControl & CTRL_DB_SEL,
+ GaControl & CTRL_PROM_SEL,
+ !(GaControl & CTRL_PROM_SEL),
+ GaControl & CTRL_BNC,
+ !(GaControl & CTRL_DIX),
+ GaControl & CTRL_RESET
+ );
+
+
+ //
+ // Get the GA status
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_STATUS,
+ &GaStatus
+ );
+
+ DbgPrint(
+ "GA_STATUS: STREG_DP_READY - %x\n"
+ " STREG_UNDERFLOW - %x\n"
+ " STREG_OVERFLOW - %x\n"
+ " STREG_IN_PROG - %x\n",
+ GaStatus & STREG_DP_READY,
+ GaStatus & STREG_UNDERFLOW,
+ GaStatus & STREG_OVERFLOW,
+ GaStatus & STREG_IN_PROG
+ );
+
+ //
+ // Get the GA interrupt dma config
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_INT_DMA_CONFIG,
+ &GaIntDmaConfig
+ );
+
+ DbgPrint("GA_INT_DMA_CONFIG: %x\n", GaIntDmaConfig);
+
+ //
+ // Get the GA dma address msb
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_DMA_ADDR_MSB,
+ &GaDmaAddressMsb
+ );
+
+ DbgPrint("GA_DMA_ADDR_MSB: %x\n", GaDmaAddressMsb);
+
+ //
+ // Get the GA dma address lsb
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_DMA_ADDR_LSB,
+ &GaDmaAddressLsb
+ );
+
+ DbgPrint("GA_DMA_ADDR_LSB: %x\n", GaDmaAddressLsb);
+
+ //
+ // Get the GA register file access msb
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_REG_FILE_MSB,
+ &GaRegFileAccessMsb
+ );
+
+ DbgPrint("GA_REG_FILE_MSB: %x\n", GaRegFileAccessMsb);
+
+ //
+ // Get the GA register file access lsb
+ //
+ NdisRawReadPortUchar(
+ pAdapter->MappedIoBaseAddr + GA_REG_FILE_LSB,
+ &GaRegFileAccessLsb
+ );
+
+ DbgPrint("GA_REG_FILE_LSB: %x\n", GaRegFileAccessLsb);
+
+}
+
+#endif