mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2780 lines
58 KiB
2780 lines
58 KiB
/*++
|
|
|
|
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 <efilter.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 AdaptP,
|
|
OUT PBOOLEAN CardPresent,
|
|
OUT PBOOLEAN IoBaseCorrect
|
|
)
|
|
|
|
/*++
|
|
|
|
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:
|
|
|
|
AdaptP - 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, Tmp, MemConfig;
|
|
|
|
|
|
//
|
|
// Read in the Base Configuration Register.
|
|
//
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_IO_BASE, &Tmp);
|
|
|
|
//
|
|
// Make sure that only one bit in Tmp is on.
|
|
//
|
|
|
|
if ((Tmp != 0) && ((Tmp & (Tmp-1)) == 0)) {
|
|
|
|
*CardPresent = TRUE;
|
|
|
|
} else {
|
|
|
|
*CardPresent = FALSE;
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure the correct bit is on for AdaptP->IoBaseAddr.
|
|
//
|
|
|
|
BaseConfig = 0;
|
|
|
|
while (!(Tmp & 1)) {
|
|
|
|
Tmp >>= 1;
|
|
|
|
++BaseConfig;
|
|
|
|
if (BaseConfig == 8) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (IoBases[BaseConfig] != AdaptP->IoBaseAddr) {
|
|
|
|
//
|
|
// Probably the jumper is wrong.
|
|
//
|
|
|
|
*IoBaseCorrect = FALSE;
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
*IoBaseCorrect = TRUE;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// For non-memory-mapped cards, there is nothing else to check.
|
|
//
|
|
|
|
if (!AdaptP->MemMapped) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Now read in the PROM configuration register.
|
|
//
|
|
|
|
NdisRawReadPortUchar(AdaptP->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.
|
|
//
|
|
|
|
AdaptP->MemMapped = TRUE;
|
|
|
|
return MemBases[MemConfig];
|
|
}
|
|
|
|
|
|
#pragma NDIS_INIT_FUNCTION(CardReadEthernetAddress)
|
|
|
|
VOID
|
|
CardReadEthernetAddress(
|
|
IN PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads in the Ethernet address from the Etherlink II PROM.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - pointer to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
The address is stored in AdaptP->PermanentAddress, and StationAddress if it
|
|
is currently zero.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
|
|
//
|
|
// Window the PROM into the NIC ports.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, CTRL_PROM_SEL | CTRL_BNC);
|
|
|
|
|
|
//
|
|
// Read in the station address.
|
|
//
|
|
|
|
for (i=0; i<ETH_LENGTH_OF_ADDRESS; i++) {
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+i, &AdaptP->PermanentAddress[i]);
|
|
|
|
}
|
|
|
|
IF_LOUD( DbgPrint(" [ %x-%x-%x-%x-%x-%x ]\n",
|
|
AdaptP->PermanentAddress[0],
|
|
AdaptP->PermanentAddress[1],
|
|
AdaptP->PermanentAddress[2],
|
|
AdaptP->PermanentAddress[3],
|
|
AdaptP->PermanentAddress[4],
|
|
AdaptP->PermanentAddress[5]);)
|
|
|
|
//
|
|
// Window the NIC registers into the NIC ports.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, CTRL_GA_SEL | CTRL_BNC);
|
|
|
|
if ((AdaptP->StationAddress[0] == 0x00) &&
|
|
(AdaptP->StationAddress[1] == 0x00) &&
|
|
(AdaptP->StationAddress[2] == 0x00) &&
|
|
(AdaptP->StationAddress[3] == 0x00) &&
|
|
(AdaptP->StationAddress[4] == 0x00) &&
|
|
(AdaptP->StationAddress[5] == 0x00)) {
|
|
|
|
AdaptP->StationAddress[0] = AdaptP->PermanentAddress[0];
|
|
AdaptP->StationAddress[1] = AdaptP->PermanentAddress[1];
|
|
AdaptP->StationAddress[2] = AdaptP->PermanentAddress[2];
|
|
AdaptP->StationAddress[3] = AdaptP->PermanentAddress[3];
|
|
AdaptP->StationAddress[4] = AdaptP->PermanentAddress[4];
|
|
AdaptP->StationAddress[5] = AdaptP->PermanentAddress[5];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CardSetup(
|
|
IN PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets up the card, using the sequence given in the Etherlink II
|
|
technical reference.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - 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(AdaptP->MappedGaBaseAddr+GA_CONTROL, CTRL_RESET | CTRL_BNC);
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, 0x00);
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, CTRL_BNC);
|
|
|
|
|
|
//
|
|
// Set up the bits in the Control Register that don't change.
|
|
//
|
|
|
|
AdaptP->GaControlBits = AdaptP->ExternalTransceiver ? CTRL_DIX : CTRL_BNC;
|
|
|
|
if (DMA_BURST_SIZE == 16) {
|
|
|
|
AdaptP->GaControlBits |= CTRL_DB_SEL;
|
|
|
|
}
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL, AdaptP->GaControlBits);
|
|
|
|
|
|
|
|
|
|
//
|
|
// Set Page Start and Page Stop to match the NIC registers.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_PAGE_START, AdaptP->NicPageStart);
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_PAGE_STOP, AdaptP->NicPageStop);
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Select which interrupt to use.
|
|
//
|
|
|
|
IntConfig = 0x04; // set bit in position 2
|
|
IntConfig <<= AdaptP->InterruptNumber; // move it to 4 through 7
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_INT_DMA_CONFIG, IntConfig);
|
|
|
|
|
|
|
|
|
|
//
|
|
// Choose between 8- and 16-byte programmed I/O bursts.
|
|
//
|
|
|
|
if (DMA_BURST_SIZE == 8) {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DRQ_TIMER, DQTR_8_BYTE);
|
|
|
|
} else {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DRQ_TIMER, DQTR_16_BYTE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Initialize these to a correct value for an 8K card.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_MSB, 0x20);
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_LSB, 0x00);
|
|
|
|
|
|
|
|
|
|
//
|
|
// Set up the Configuration register.
|
|
//
|
|
|
|
if (AdaptP->MemMapped) {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONFIG,
|
|
GACFR_TC_MASK | GACFR_RAM_SEL | GACFR_MEM_BANK1);
|
|
|
|
} else {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONFIG, GACFR_TC_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Now set up NIC registers.
|
|
//
|
|
|
|
//
|
|
// Write to and read from CR to make sure it is there.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE0);
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, &Tmp);
|
|
|
|
if (Tmp != (CR_STOP | CR_NO_DMA | CR_PAGE0)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Set up the registers in the correct sequence.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_DATA_CONFIG,
|
|
DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_LSB, 0);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_CONFIG, AdaptP->NicReceiveConfig);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_BOUNDARY, AdaptP->NicPageStart);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_PAGE_START, AdaptP->NicPageStart);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_PAGE_STOP, AdaptP->NicPageStop);
|
|
|
|
AdaptP->Current = AdaptP->NicPageStart + (UCHAR)1;
|
|
AdaptP->NicNextPacket = AdaptP->NicPageStart + (UCHAR)1;
|
|
AdaptP->BufferOverflow = FALSE;
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, 0xff); // clear all
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->NicInterruptMask);
|
|
|
|
|
|
//
|
|
// Move to page 1 to write the station address and
|
|
// multicast registers.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA | CR_PAGE1);
|
|
|
|
for (i=0; i<ETH_LENGTH_OF_ADDRESS; i++) {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+(NIC_PHYS_ADDR+i),
|
|
AdaptP->StationAddress[i]);
|
|
|
|
}
|
|
|
|
Filter = ETH_QUERY_FILTER_CLASSES(AdaptP->FilterDB);
|
|
|
|
for (i=0; i<8; i++) {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+(NIC_MC_ADDR+i),
|
|
(UCHAR)((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST)
|
|
? 0xff : AdaptP->NicMulticastRegs[i]));
|
|
|
|
}
|
|
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_CURRENT, AdaptP->Current);
|
|
|
|
|
|
//
|
|
// move back to page 0 and start the card...
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA | CR_PAGE0);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE0);
|
|
|
|
|
|
//
|
|
// ... but it is still in loopback mode.
|
|
//
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
CardStop(
|
|
IN PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stops the card.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
UCHAR Tmp;
|
|
|
|
//
|
|
// Turn on the STOP bit in the Command register.
|
|
//
|
|
|
|
NdisSynchronizeWithInterrupt(
|
|
&(AdaptP)->NdisInterrupt,
|
|
(PVOID)SyncCardStop,
|
|
(PVOID)AdaptP
|
|
);
|
|
|
|
|
|
//
|
|
// Clear the Remote Byte Count register so that ISR_RESET
|
|
// will come on.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
|
|
NdisRawWritePortUchar(AdaptP->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(AdaptP->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(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
|
|
|
|
//
|
|
// At this point the card is still in loopback mode.
|
|
//
|
|
|
|
}
|
|
|
|
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 AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tests the card. Follows the tests described in section 12 of
|
|
the 8390 Data Sheet.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - 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, SecondTest, i;
|
|
UCHAR TSRResult, RSRResult;
|
|
UCHAR CrcBuf[4];
|
|
BOOLEAN FinalResult = TRUE;
|
|
UCHAR TestSrcBuf[256], TestDestBuf[256];
|
|
PUCHAR CurTestLoc;
|
|
UCHAR Tmp;
|
|
|
|
static NDIS_TIMER Timer = {0};
|
|
BOOLEAN TimerExpired=FALSE;
|
|
BOOLEAN dummy; //for return from NdisCancelTimer
|
|
|
|
//
|
|
// 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, AdaptP->StationAddress, ETH_LENGTH_OF_ADDRESS);
|
|
ELNKII_MOVE_MEM(TestPacket+ETH_LENGTH_OF_ADDRESS, AdaptP->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(AdaptP->MappedIoBaseAddr+NIC_DATA_CONFIG,
|
|
DCR_BYTE_WIDE | DCR_LOOPBACK | DCR_FIFO_8_BYTE);
|
|
|
|
|
|
//
|
|
// Set the RCR to reject all packets.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_CONFIG, 0x00);
|
|
|
|
|
|
//
|
|
// First round of tests -- different loopback modes
|
|
//
|
|
|
|
for (FirstTest = 0; FirstTest < 2; ++FirstTest) {
|
|
|
|
//
|
|
// Stop the card.
|
|
//
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA | CR_PAGE0);
|
|
|
|
|
|
//
|
|
// Set up the TCR for the appropriate loopback mode.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, 0x00);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCRValues[FirstTest]);
|
|
|
|
|
|
//
|
|
// Restart the card.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE0);
|
|
|
|
|
|
//
|
|
// Now copy down TestPacket and start the transmission.
|
|
//
|
|
|
|
CardCopyDownBuffer(AdaptP, TestPacket, 0, 0, TEST_LEN);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_START, AdaptP->NicXmitStart);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(TEST_LEN));
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(TEST_LEN));
|
|
NdisRawWritePortUchar(AdaptP->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(AdaptP->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(AdaptP->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(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE0);
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, &Tmp);
|
|
if (Tmp != (CR_STOP | CR_NO_DMA | CR_PAGE0)) {
|
|
NdisStallExecution(1000);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Acknowledge the interrupt.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS,
|
|
ISR_XMIT | ISR_XMIT_ERR);
|
|
|
|
|
|
//
|
|
// Check that the CRS and CDH bits are set correctly.
|
|
//
|
|
|
|
NdisRawReadPortUchar(AdaptP->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(AdaptP->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(AdaptP->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(AdaptP->MappedIoBaseAddr+NIC_FIFO, &Tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Stop the card.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA | CR_PAGE0);
|
|
|
|
|
|
//
|
|
// Set the TCR for internal loopback.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, 0x00);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG,
|
|
TCR_INHIBIT_CRC | TCR_NIC_LBK);
|
|
|
|
//
|
|
// Restart the card.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->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, AdaptP->StationAddress, ETH_LENGTH_OF_ADDRESS);
|
|
|
|
} else {
|
|
|
|
ELNKII_MOVE_MEM(TestPacket, NullAddress, ETH_LENGTH_OF_ADDRESS);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Copy down TestPacket.
|
|
//
|
|
|
|
CardCopyDownBuffer(AdaptP, 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(AdaptP, CrcBuf, 0, TEST_LEN, 4);
|
|
|
|
|
|
//
|
|
// Start the transmission.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_START, AdaptP->NicXmitStart);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(TEST_LEN+4));
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(TEST_LEN+4));
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_XMIT | CR_NO_DMA);
|
|
|
|
|
|
//
|
|
// Wait for the transmission to complete, for about a second.
|
|
//
|
|
|
|
TimerExpired=FALSE;
|
|
|
|
NdisInitializeTimer(&Timer, DelayComplete, &TimerExpired);
|
|
NdisSetTimer(&Timer, 1000);
|
|
|
|
NdisRawReadPortUchar(AdaptP->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(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, &Tmp);
|
|
|
|
}
|
|
|
|
//
|
|
//MUST Cancel the unexpired timer
|
|
//
|
|
|
|
NdisCancelTimer(&Timer,&dummy);
|
|
|
|
//
|
|
// Acknowledge the interrupt.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS,
|
|
ISR_XMIT | ISR_XMIT_ERR);
|
|
|
|
|
|
//
|
|
// Check that RSR is as expected.
|
|
//
|
|
|
|
NdisRawReadPortUchar(AdaptP->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(AdaptP, 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(AdaptP, TestDestBuf,
|
|
AdaptP->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(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA | CR_PAGE0);
|
|
|
|
|
|
//
|
|
// Restore DCR, RCR, and TCR.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_DATA_CONFIG,
|
|
DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE);
|
|
|
|
//
|
|
// (clear these two to be safe)
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_LSB, 0);
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_CONFIG, AdaptP->NicReceiveConfig);
|
|
NdisRawWritePortUchar(AdaptP->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(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, 0xff);
|
|
|
|
|
|
//
|
|
// Start the card, but stay in loopback mode.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE0);
|
|
|
|
|
|
|
|
return FinalResult;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CardReset(
|
|
IN PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resets the card.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
TRUE if everything is OK.
|
|
|
|
--*/
|
|
|
|
{
|
|
CardStop(AdaptP);
|
|
|
|
//
|
|
// CardSetup() does a software reset.
|
|
//
|
|
|
|
if (!CardSetup(AdaptP)) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
AdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
|
2,
|
|
cardReset,
|
|
ELNKII_ERRMSG_CARD_SETUP
|
|
);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
CardStart(AdaptP);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
CardCopyDownPacket(
|
|
IN PELNKII_ADAPTER AdaptP,
|
|
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:
|
|
|
|
AdaptP - 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, BufAddress;
|
|
UINT CurLength, Len;
|
|
PNDIS_BUFFER CurBuffer;
|
|
UINT TmpLen, BurstSize;
|
|
UCHAR GaStatus;
|
|
|
|
if (AdaptP->MemMapped) {
|
|
|
|
//
|
|
// Memory mapped, just copy each buffer over.
|
|
//
|
|
|
|
NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
|
|
|
|
CurAddress = AdaptP->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;
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
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(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_MSB,
|
|
MSB((ULONG)CurAddress));
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_LSB,
|
|
LSB((ULONG)CurAddress));
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
|
|
(UCHAR)((CTRL_START | CTRL_DIR_DOWN) | AdaptP->GaControlBits));
|
|
|
|
|
|
//
|
|
// First transfer multiples of DMA_BURST_SIZE.
|
|
//
|
|
|
|
TmpLen = Len;
|
|
BurstSize = DMA_BURST_SIZE;
|
|
|
|
while (TmpLen >= BurstSize) {
|
|
|
|
if ((ULONG)BufAddress & 0x01) {
|
|
|
|
NdisRawWritePortBufferUchar(
|
|
AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
|
|
(PUCHAR)BufAddress,
|
|
BurstSize
|
|
);
|
|
|
|
} else {
|
|
|
|
NdisRawWritePortBufferUshort(
|
|
AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
|
|
(PUSHORT)BufAddress,
|
|
BurstSize/2
|
|
);
|
|
|
|
}
|
|
|
|
|
|
TmpLen -= BurstSize;
|
|
|
|
BufAddress += BurstSize;
|
|
|
|
//
|
|
// Wait for the Gate Array FIFO to be ready.
|
|
//
|
|
|
|
do {
|
|
|
|
NdisRawReadPortUchar(AdaptP->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(
|
|
AdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_DRIVER_FAILURE,
|
|
2,
|
|
cardCopyDownPacket,
|
|
ELNKII_ERRMSG_DATA_PORT_READY
|
|
);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} while (!(GaStatus & STREG_DP_READY));
|
|
|
|
#if DBG
|
|
PrevBurstSize = (UCHAR)BurstSize;
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
// Now copy the last bit as UCHARs.
|
|
//
|
|
|
|
NdisRawWritePortBufferUchar(
|
|
AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
|
|
BufAddress, TmpLen);
|
|
|
|
do {
|
|
|
|
NdisRawReadPortUchar(AdaptP->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(
|
|
AdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_DRIVER_FAILURE,
|
|
2,
|
|
cardCopyDownPacket,
|
|
ELNKII_ERRMSG_DATA_PORT_READY
|
|
);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
} while (!(GaStatus & STREG_DP_READY));
|
|
|
|
|
|
#if DBG
|
|
PrevBurstSize = (UCHAR)TmpLen;
|
|
#endif
|
|
|
|
//
|
|
// Done, turn off the start bit...
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
|
|
(UCHAR)(CTRL_STOP | AdaptP->GaControlBits));
|
|
|
|
//
|
|
// ... and wait for DMA_IN_PROGRESS to go off,
|
|
// indicating end of flush.
|
|
//
|
|
|
|
do {
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
|
|
|
|
} while (GaStatus & STREG_IN_PROG);
|
|
|
|
|
|
CurAddress += Len;
|
|
|
|
CurLength += Len;
|
|
|
|
NdisGetNextBuffer(CurBuffer, &CurBuffer);
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
*Length = CurLength;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
CardCopyDownBuffer(
|
|
IN PELNKII_ADAPTER AdaptP,
|
|
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:
|
|
|
|
AdaptP - 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, ThisTime;
|
|
UCHAR GaStatus;
|
|
|
|
if (AdaptP->MemMapped) {
|
|
|
|
//
|
|
// Memory mapped, just copy over SourceBuffer.
|
|
//
|
|
|
|
CurAddress = AdaptP->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.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_MSB,
|
|
MSB((ULONG)CurAddress));
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_LSB,
|
|
LSB((ULONG)CurAddress));
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
|
|
(UCHAR)((CTRL_START | CTRL_DIR_DOWN) | AdaptP->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(
|
|
AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
|
|
SourceBuffer, ThisTime);
|
|
|
|
|
|
TmpLen -= ThisTime;
|
|
|
|
SourceBuffer += ThisTime;
|
|
|
|
//
|
|
// Wait for the Gate Array FIFO to be ready.
|
|
//
|
|
|
|
do {
|
|
|
|
NdisRawReadPortUchar(AdaptP->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(
|
|
AdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_DRIVER_FAILURE,
|
|
2,
|
|
cardCopyDownBuffer,
|
|
ELNKII_ERRMSG_DATA_PORT_READY
|
|
);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} while (!(GaStatus & STREG_DP_READY));
|
|
|
|
#if DBG
|
|
PrevBurstSize = (UCHAR)ThisTime;
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
// Done, turn off the start bit..
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
|
|
(UCHAR)(CTRL_STOP | AdaptP->GaControlBits));
|
|
|
|
//
|
|
// ... and wait for DMA_IN_PROGRESS to go off,
|
|
// indicating end of flush.
|
|
//
|
|
|
|
do {
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedGaBaseAddr+GA_STATUS, &GaStatus);
|
|
|
|
} while (GaStatus & STREG_IN_PROG);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
}
|
|
|
|
#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 AdaptP,
|
|
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:
|
|
|
|
AdaptP - 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, BurstSize;
|
|
UCHAR GaStatus;
|
|
|
|
if (Length == 0) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (AdaptP->MemMapped) {
|
|
|
|
//
|
|
// Memory mapped, just copy the data over.
|
|
//
|
|
|
|
ELNKII_MOVE_SHARED_RAM_TO_MEM(Target, Source, Length);
|
|
|
|
} else { // programmed I/O
|
|
|
|
//
|
|
// Programmed I/O, have to transfer the data.
|
|
//
|
|
|
|
//
|
|
// Adjust the address to be a card address.
|
|
//
|
|
|
|
Source -= ((ULONG)AdaptP->XmitStart - 0x2000);
|
|
|
|
//
|
|
// Set up the Gate Array for programmed I/O transfer.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_MSB, MSB((ULONG)Source));
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_DMA_ADDR_LSB, LSB((ULONG)Source));
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
|
|
(UCHAR)((CTRL_START | CTRL_DIR_UP) | AdaptP->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(AdaptP->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(
|
|
AdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_DRIVER_FAILURE,
|
|
2,
|
|
cardCopyUp,
|
|
ELNKII_ERRMSG_DATA_PORT_READY
|
|
);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} while (!(GaStatus & STREG_DP_READY));
|
|
|
|
|
|
if ((ULONG)Target & 0x01) {
|
|
|
|
//
|
|
// This is the first burst, and it starts on
|
|
// an odd boundary.
|
|
//
|
|
|
|
NdisRawReadPortBufferUchar(
|
|
AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
|
|
(PUCHAR)Target,
|
|
BurstSize);
|
|
|
|
TmpLen -= BurstSize;
|
|
Target += BurstSize;
|
|
|
|
|
|
#if DBG
|
|
PrevPrevBurstSize = PrevBurstSize;
|
|
PrevBurstSize = (UCHAR)BurstSize;
|
|
#endif
|
|
|
|
} else {
|
|
|
|
|
|
NdisRawReadPortBufferUshort(
|
|
AdaptP->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(AdaptP->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(
|
|
AdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_DRIVER_FAILURE,
|
|
2,
|
|
cardCopyUp,
|
|
ELNKII_ERRMSG_DATA_PORT_READY
|
|
);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} while (!(GaStatus & STREG_DP_READY));
|
|
|
|
NdisRawReadPortBufferUchar(
|
|
AdaptP->MappedGaBaseAddr+GA_REG_FILE_MSB,
|
|
Target, TmpLen);
|
|
|
|
|
|
//
|
|
// Done, turn off the start bit.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedGaBaseAddr+GA_CONTROL,
|
|
(UCHAR)(CTRL_STOP | AdaptP->GaControlBits));
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
}
|
|
|
|
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, Carry;
|
|
UINT i, 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 AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Erases and refills the card multicast registers. Used when
|
|
an address has been deleted and all bits must be recomputed.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
UCHAR Byte, Bit;
|
|
NDIS_STATUS Status;
|
|
|
|
|
|
//
|
|
// First turn all bits off.
|
|
//
|
|
|
|
for (i=0; i<8; i++) {
|
|
|
|
AdaptP->NicMulticastRegs[i] = 0;
|
|
|
|
}
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
EthQueryGlobalFilterAddresses(
|
|
&Status,
|
|
AdaptP->FilterDB,
|
|
DEFAULT_MULTICASTLISTMAX * ETH_LENGTH_OF_ADDRESS,
|
|
&i,
|
|
Addresses
|
|
);
|
|
|
|
|
|
ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
|
|
//
|
|
// Now turn on the bit for each address in the multicast list.
|
|
//
|
|
|
|
for ( ; i > 0; ) {
|
|
|
|
i--;
|
|
|
|
CardGetMulticastBit(Addresses[i], &Byte, &Bit);
|
|
|
|
AdaptP->NicMulticastRegs[Byte] |= Bit;
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
TRUE if the power has failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_STOP | CR_NO_DMA);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
CardStartXmit(
|
|
IN PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the NIC_COMMAND register to start a transmission.
|
|
The transmit buffer number is taken from AdaptP->CurBufXmitting
|
|
and the length from AdaptP->PacketLens[AdaptP->CurBufXmitting].
|
|
|
|
Arguments:
|
|
|
|
AdaptP - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
TRUE if the power has failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
XMIT_BUF XmitBufferNum = AdaptP->CurBufXmitting;
|
|
UINT Length = AdaptP->PacketLens[XmitBufferNum];
|
|
|
|
|
|
//
|
|
// Prepare the NIC registers for transmission.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_START,
|
|
(UCHAR)(AdaptP->NicXmitStart + (UCHAR)(XmitBufferNum*BUFS_PER_TX)));
|
|
|
|
//
|
|
// Pad the length to 60 (plus CRC will be 64) if needed.
|
|
//
|
|
|
|
if (Length < 60) {
|
|
|
|
Length = 60;
|
|
|
|
}
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_MSB, MSB(Length));
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_COUNT_LSB, LSB(Length));
|
|
|
|
//
|
|
// Start transmission, check for power failure first.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->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 AdaptP->XmitStatus.
|
|
|
|
Arguments:
|
|
|
|
SynchronizeContext - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_STATUS, &AdaptP->XmitStatus);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
SyncCardGetCurrent(
|
|
IN PVOID SynchronizeContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the value of the CURRENT NIC register and stores
|
|
it in AdaptP->Current.
|
|
|
|
Arguments:
|
|
|
|
SynchronizeContext - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
//
|
|
// Have to go to page 1 to read this register.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE1);
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_CURRENT, &AdaptP->Current);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE0);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
VOID
|
|
CardSetBoundary(
|
|
IN PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the value of the "boundary" NIC register to one behind
|
|
AdaptP->NicNextPacket, to prevent packets from being received
|
|
on top of un-indicated ones.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Have to be careful with "one behin NicNextPacket" when
|
|
// NicNextPacket is the first buffer in receive area.
|
|
//
|
|
|
|
if (AdaptP->NicNextPacket == AdaptP->NicPageStart) {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_BOUNDARY,
|
|
(UCHAR)(AdaptP->NicPageStop-(UCHAR)1));
|
|
|
|
} else {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_BOUNDARY,
|
|
(UCHAR)(AdaptP->NicNextPacket-(UCHAR)1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
SyncCardSetReceiveConfig(
|
|
IN PVOID SynchronizeContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the value of the "receive configuration" NIC register to
|
|
the value of AdaptP->NicReceiveConfig.
|
|
|
|
Arguments:
|
|
|
|
SynchronizeContext - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RCV_CONFIG, AdaptP->NicReceiveConfig);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
SyncCardSetAllMulticast(
|
|
IN PVOID SynchronizeContext
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
UINT i;
|
|
|
|
//
|
|
// Have to move to page 1 to set these registers.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE1);
|
|
|
|
for (i=0; i<8; i++) {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+(NIC_MC_ADDR+i), 0xff);
|
|
|
|
}
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE0);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
SyncCardCopyMulticastRegs(
|
|
IN PVOID SynchronizeContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the eight bytes in the card multicast registers.
|
|
|
|
Arguments:
|
|
|
|
SynchronizeContext - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
UINT i;
|
|
|
|
//
|
|
// Have to move to page 1 to set these registers.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE1);
|
|
|
|
for (i=0; i<8; i++) {
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+(NIC_MC_ADDR+i),
|
|
AdaptP->NicMulticastRegs[i]);
|
|
|
|
}
|
|
|
|
NdisRawWritePortUchar(AdaptP->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
|
|
AdaptP->NicInterruptMask.
|
|
|
|
Arguments:
|
|
|
|
SynchronizeContext - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->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 AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_RCV);
|
|
|
|
//
|
|
// Interrupts were previously blocked in the interrupt handler.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->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 AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
UCHAR InterruptStatus;
|
|
|
|
CardGetInterruptStatus(AdaptP, &InterruptStatus);
|
|
|
|
if (InterruptStatus & ISR_RCV_ERR) {
|
|
|
|
SyncCardUpdateCounters(AdaptP);
|
|
|
|
}
|
|
|
|
NdisRawWritePortUchar(
|
|
AdaptP->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 AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_XMIT | ISR_XMIT_ERR);
|
|
|
|
//
|
|
// Interrupts were previously blocked in the interrupt handler.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->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 AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
//
|
|
// SyncCardAcknowledgeReceive.
|
|
//
|
|
|
|
#ifdef i386
|
|
|
|
_asm {
|
|
cli
|
|
}
|
|
|
|
#endif
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_RCV);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->NicInterruptMask);
|
|
|
|
#ifdef i386
|
|
|
|
_asm {
|
|
sti
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// SyncCardGetCurrent.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE1);
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_CURRENT, &AdaptP->Current);
|
|
|
|
NdisRawWritePortUchar(AdaptP->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 AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
//
|
|
// SyncCardGetXmitStatus.
|
|
//
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_XMIT_STATUS, &AdaptP->XmitStatus);
|
|
|
|
//
|
|
// SyncCardAcknowledgeTransmit.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_STATUS, ISR_XMIT | ISR_XMIT_ERR);
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_INTR_MASK, AdaptP->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 AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
UCHAR Tmp;
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_FAE_ERR_CNTR, &Tmp);
|
|
AdaptP->FrameAlignmentErrors += Tmp;
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_CRC_ERR_CNTR, &Tmp);
|
|
AdaptP->CrcErrors += Tmp;
|
|
|
|
NdisRawReadPortUchar(AdaptP->MappedIoBaseAddr+NIC_MISSED_CNTR, &Tmp);
|
|
AdaptP->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 AdaptP = ((PELNKII_ADAPTER)SynchronizeContext);
|
|
|
|
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(AdaptP);
|
|
|
|
//
|
|
// 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);
|
|
|
|
|
|
//
|
|
// Clear the Remote Byte Count register so that ISR_RESET
|
|
// will come on.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_RMT_COUNT_MSB, 0);
|
|
NdisRawWritePortUchar(AdaptP->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(AdaptP->MappedIoBaseAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
|
|
|
|
//
|
|
// Start the card. This does not Undo the loopback mode.
|
|
//
|
|
|
|
NdisRawWritePortUchar(AdaptP->MappedIoBaseAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
|
|
|
|
return FALSE;
|
|
|
|
}
|