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.
3221 lines
70 KiB
3221 lines
70 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved.
|
|
|
|
Module Name:
|
|
|
|
card.c
|
|
|
|
Abstract:
|
|
|
|
Card-specific functions for the NDIS 3.0 Novell 2000 driver.
|
|
|
|
Author:
|
|
|
|
Sean Selitrennikoff
|
|
|
|
Environment:
|
|
|
|
Kernel mode, FSD
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
BOOLEAN
|
|
CardSlotTest(
|
|
IN PNE2000_ADAPTER Adapter
|
|
);
|
|
|
|
BOOLEAN
|
|
CardRamTest(
|
|
IN PNE2000_ADAPTER Adapter
|
|
);
|
|
|
|
|
|
#pragma NDIS_PAGEABLE_FUNCTION(CardCheckParameters)
|
|
|
|
BOOLEAN CardCheckParameters(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks that the I/O base address is correct.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
TRUE, if IoBaseAddress appears correct.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Tmp;
|
|
|
|
//
|
|
// If adapter responds to a stop command correctly -- assume it is there.
|
|
//
|
|
|
|
//
|
|
// Turn off interrupts first.
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0);
|
|
|
|
//
|
|
// Stop the card.
|
|
//
|
|
SyncCardStop(Adapter);
|
|
|
|
//
|
|
// Pause
|
|
//
|
|
NdisStallExecution(2000);
|
|
|
|
//
|
|
// Read response
|
|
//
|
|
NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp);
|
|
|
|
if ((Tmp == (CR_NO_DMA | CR_STOP)) ||
|
|
(Tmp == (CR_NO_DMA | CR_STOP | CR_START))
|
|
)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
#ifdef NE2000
|
|
|
|
#pragma NDIS_PAGEABLE_FUNCTION(CardSlotTest)
|
|
|
|
|
|
BOOLEAN CardSlotTest(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks if the card is in an 8 or 16 bit slot and sets a flag in the
|
|
adapter structure.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
TRUE, if all goes well, else FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Tmp;
|
|
UCHAR RomCopy[32];
|
|
UCHAR i;
|
|
BOOLEAN found;
|
|
|
|
//
|
|
// Reset the chip
|
|
//
|
|
NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RESET, &Tmp);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RESET, 0xFF);
|
|
|
|
//
|
|
// Go to page 0 and stop
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_STOP | CR_NO_DMA);
|
|
|
|
//
|
|
// Pause
|
|
//
|
|
NdisStallExecution(2000);
|
|
|
|
//
|
|
// Check that it is stopped
|
|
//
|
|
NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp);
|
|
if (Tmp != (CR_NO_DMA | CR_STOP))
|
|
{
|
|
IF_LOUD(DbgPrint("Could not stop the card\n");)
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Setup to read from ROM
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_DATA_CONFIG,
|
|
DCR_BYTE_WIDE | DCR_FIFO_8_BYTE | DCR_NORMAL
|
|
);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0x0);
|
|
|
|
//
|
|
// Ack any interrupts that may be hanging around
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF);
|
|
|
|
//
|
|
// Setup to read in the ROM, the address and byte count.
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB, 0x0);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, 0x0);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 32);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_DMA_READ | CR_START
|
|
);
|
|
|
|
//
|
|
// Read first 32 bytes in 16 bit mode
|
|
//
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RACK_NIC, RomCopy + i);
|
|
}
|
|
|
|
IF_VERY_LOUD( DbgPrint("Resetting the chip\n"); )
|
|
|
|
//
|
|
// Reset the chip
|
|
//
|
|
NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RESET, &Tmp);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RESET, 0xFF);
|
|
|
|
//
|
|
// Check ROM for 'B' (byte) or 'W' (word)
|
|
// NOTE: If the buffer has bot BB and WW then use WW instead of BB
|
|
IF_VERY_LOUD( DbgPrint("Checking slot type\n"); )
|
|
|
|
found = FALSE;
|
|
for (i = 16; i < 31; i++)
|
|
{
|
|
if (((RomCopy[i] == 'B') && (RomCopy[i+1] == 'B')) ||
|
|
((RomCopy[i] == 'W') && (RomCopy[i+1] == 'W'))
|
|
)
|
|
{
|
|
if (RomCopy[i] == 'B')
|
|
{
|
|
Adapter->EightBitSlot = TRUE;
|
|
found = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Adapter->EightBitSlot = FALSE;
|
|
found = TRUE;
|
|
break; // Go no farther
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found)
|
|
{
|
|
IF_VERY_LOUD( (Adapter->EightBitSlot?DbgPrint("8 bit slot\n"):
|
|
DbgPrint("16 bit slot\n")); )
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If neither found -- then not an NE2000
|
|
//
|
|
IF_VERY_LOUD( DbgPrint("Failed slot type\n"); )
|
|
}
|
|
|
|
return(found);
|
|
}
|
|
|
|
#endif // NE2000
|
|
|
|
|
|
|
|
|
|
#pragma NDIS_PAGEABLE_FUNCTION(CardRamTest)
|
|
|
|
BOOLEAN
|
|
CardRamTest(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out how much RAM the adapter has. It starts at 1K and checks thru
|
|
60K. It will set Adapter->RamSize to the appropriate value iff this
|
|
function returns TRUE.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
TRUE, if all goes well, else FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR RamBase, RamPointer;
|
|
PUCHAR RamEnd;
|
|
|
|
UCHAR TestPattern[]={ 0xAA, 0x55, 0xFF, 0x00 };
|
|
PULONG pTestPattern = (PULONG)TestPattern;
|
|
UCHAR ReadPattern[4];
|
|
PULONG pReadPattern = (PULONG)ReadPattern;
|
|
|
|
for (RamBase = (PUCHAR)0x400; RamBase < (PUCHAR)0x10000; RamBase += 0x400) {
|
|
|
|
//
|
|
// Write Test pattern
|
|
//
|
|
|
|
if (!CardCopyDown(Adapter, RamBase, TestPattern, 4)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Read pattern
|
|
//
|
|
|
|
if (!CardCopyUp(Adapter, ReadPattern, RamBase, 4)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
IF_VERY_LOUD( DbgPrint("Addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x\n",
|
|
RamBase,
|
|
ReadPattern[0],
|
|
ReadPattern[1],
|
|
ReadPattern[2],
|
|
ReadPattern[3]
|
|
);
|
|
)
|
|
|
|
|
|
//
|
|
// If they are the same, find the end
|
|
//
|
|
|
|
if (*pReadPattern == *pTestPattern) {
|
|
|
|
for (RamEnd = RamBase; !(PtrToUlong(RamEnd) & 0xFFFF0000); RamEnd += 0x400) {
|
|
|
|
//
|
|
// Write test pattern
|
|
//
|
|
|
|
if (!CardCopyDown(Adapter, RamEnd, TestPattern, 4)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Read pattern
|
|
//
|
|
|
|
if (!CardCopyUp(Adapter, ReadPattern, RamEnd, 4)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*pReadPattern != *pTestPattern) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IF_LOUD( DbgPrint("RamBase 0x%x, RamEnd 0x%x\n", RamBase, RamEnd); )
|
|
|
|
//
|
|
// If not found, error out
|
|
//
|
|
|
|
if ((RamBase >= (PUCHAR)0x10000) || (RamBase == RamEnd)) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Watch for boundary case when RamEnd is maximum value
|
|
//
|
|
|
|
if ((ULONG_PTR)RamEnd & 0xFFFF0000) {
|
|
|
|
RamEnd -= 0x100;
|
|
|
|
}
|
|
|
|
//
|
|
// Check all of ram
|
|
//
|
|
|
|
for (RamPointer = RamBase; RamPointer < RamEnd; RamPointer += 4) {
|
|
|
|
//
|
|
// Write test pattern
|
|
//
|
|
|
|
if (!CardCopyDown(Adapter, RamPointer, TestPattern, 4)) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Read pattern
|
|
//
|
|
|
|
if (!CardCopyUp(Adapter, ReadPattern, RamBase, 4)) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
if (*pReadPattern != *pTestPattern) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Store Results
|
|
//
|
|
|
|
Adapter->RamBase = RamBase;
|
|
Adapter->RamSize = (ULONG)(RamEnd - RamBase);
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
#pragma NDIS_PAGEABLE_FUNCTION(CardInitialize)
|
|
|
|
BOOLEAN
|
|
CardInitialize(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the card into a running state.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
TRUE, if all goes well, else FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Tmp;
|
|
USHORT i;
|
|
|
|
//
|
|
// Stop the card.
|
|
//
|
|
SyncCardStop(Adapter);
|
|
|
|
//
|
|
// Initialize the Data Configuration register.
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_DATA_CONFIG,
|
|
DCR_AUTO_INIT | DCR_FIFO_8_BYTE
|
|
);
|
|
|
|
//
|
|
// Set Xmit start location
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_START, 0xA0);
|
|
|
|
//
|
|
// Set Xmit configuration
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, 0x0);
|
|
|
|
//
|
|
// Set Receive configuration
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RCV_CONFIG, RCR_MONITOR);
|
|
|
|
//
|
|
// Set Receive start
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_PAGE_START, 0x4);
|
|
|
|
//
|
|
// Set Receive end
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_PAGE_STOP, 0xFF);
|
|
|
|
//
|
|
// Set Receive boundary
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_BOUNDARY, 0x4);
|
|
|
|
//
|
|
// Set Xmit bytes
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_COUNT_LSB, 0x3C);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_COUNT_MSB, 0x0);
|
|
|
|
//
|
|
// Pause
|
|
//
|
|
NdisStallExecution(2000);
|
|
|
|
//
|
|
// Ack all interrupts that we might have produced
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF);
|
|
|
|
//
|
|
// Change to page 1
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE1 | CR_STOP);
|
|
|
|
//
|
|
// Set current
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_CURRENT, 0x4);
|
|
|
|
//
|
|
// Back to page 0
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0 | CR_STOP);
|
|
|
|
//
|
|
// Pause
|
|
//
|
|
NdisStallExecution(2000);
|
|
|
|
//
|
|
// Check that Command register reflects this last command
|
|
//
|
|
NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp);
|
|
if (!(Tmp & CR_STOP))
|
|
{
|
|
IF_LOUD(DbgPrint("Invalid command register\n");)
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Do initialization errata
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 55);
|
|
|
|
//
|
|
// Setup for a read
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_DMA_READ | CR_START
|
|
);
|
|
|
|
#ifdef NE2000
|
|
|
|
//
|
|
// Check if the slot is 8 or 16 bit (affects data transfer rate).
|
|
//
|
|
|
|
if ((Adapter->BusType == NdisInterfaceMca) ||
|
|
(NE2000_PCMCIA == Adapter->CardType))
|
|
{
|
|
Adapter->EightBitSlot = FALSE;
|
|
}
|
|
else
|
|
{
|
|
IF_VERY_LOUD(DbgPrint("CardSlotTest\n");)
|
|
|
|
if (CardSlotTest(Adapter) == FALSE)
|
|
{
|
|
//
|
|
// Stop chip
|
|
//
|
|
SyncCardStop(Adapter);
|
|
|
|
IF_LOUD(DbgPrint(" -- Failed\n");)
|
|
return(FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
#else // NE2000
|
|
|
|
Adapter->EightBitSlot = TRUE;
|
|
|
|
#endif // NE2000
|
|
|
|
//
|
|
// Mask Interrupts
|
|
//
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0x0);
|
|
|
|
//
|
|
// Setup the Adapter for reading ram
|
|
//
|
|
|
|
// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin
|
|
|
|
if (Adapter->EightBitSlot)
|
|
{
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_DATA_CONFIG,
|
|
DCR_FIFO_8_BYTE | DCR_NORMAL | DCR_BYTE_WIDE
|
|
);
|
|
}
|
|
else
|
|
{
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_DATA_CONFIG,
|
|
DCR_FIFO_8_BYTE | DCR_NORMAL | DCR_WORD_WIDE
|
|
);
|
|
}
|
|
|
|
//
|
|
// Clear transmit configuration.
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, 0);
|
|
|
|
//
|
|
// Clear receive configuration.
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RCV_CONFIG, 0);
|
|
|
|
//
|
|
// Clear any interrupts
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF);
|
|
|
|
//
|
|
// Stop the chip
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_NO_DMA | CR_STOP);
|
|
|
|
//
|
|
// Clear any DMA values
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0);
|
|
|
|
//
|
|
// Clear any DMA values
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0);
|
|
|
|
//
|
|
// Wait for the reset to complete.
|
|
//
|
|
i = 0x3FFF;
|
|
|
|
while (--i)
|
|
{
|
|
NdisRawReadPortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp);
|
|
|
|
if (Tmp & ISR_RESET)
|
|
break;
|
|
|
|
NdisStallExecution(4);
|
|
}
|
|
|
|
//
|
|
// Put card in loopback mode
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, TCR_LOOPBACK);
|
|
|
|
//
|
|
// Start the chip.
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_NO_DMA | CR_START
|
|
);
|
|
|
|
//
|
|
// Test for the amount of RAM
|
|
//
|
|
if (NE2000_ISA == Adapter->CardType)
|
|
{
|
|
if (CardRamTest(Adapter) == FALSE)
|
|
{
|
|
//
|
|
// Stop the chip
|
|
//
|
|
SyncCardStop(Adapter);
|
|
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We know what it is for the pcmcia adapters,
|
|
// so don't waste time on detecting it.
|
|
//
|
|
Adapter->RamBase = (PUCHAR)0x4000;
|
|
Adapter->RamSize = 0x4000;
|
|
}
|
|
|
|
//
|
|
// Stop the chip
|
|
//
|
|
SyncCardStop(Adapter);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
#pragma NDIS_PAGEABLE_FUNCTION(CardReadEthernetAddress)
|
|
|
|
BOOLEAN CardReadEthernetAddress(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads in the Ethernet address from the Novell 2000.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
The address is stored in Adapter->PermanentAddress, and StationAddress if it
|
|
is currently zero.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT c;
|
|
|
|
//
|
|
// Things are done a little differently for PCMCIA adapters.
|
|
//
|
|
if (NE2000_PCMCIA == Adapter->CardType)
|
|
{
|
|
#if 0
|
|
|
|
NDIS_STATUS Status;
|
|
PUCHAR pAttributeWindow;
|
|
NDIS_PHYSICAL_ADDRESS AttributePhysicalAddress;
|
|
//
|
|
// Setup the physical address for the attribute window.
|
|
//
|
|
NdisSetPhysicalAddressHigh(AttributePhysicalAddress, 0);
|
|
NdisSetPhysicalAddressLow(
|
|
AttributePhysicalAddress,
|
|
Adapter->AttributeMemoryAddress
|
|
);
|
|
|
|
//
|
|
// We need to get the pcmcia information from the tuple.
|
|
//
|
|
Status = NdisMMapIoSpace(
|
|
(PVOID *)&pAttributeWindow,
|
|
Adapter->MiniportAdapterHandle,
|
|
AttributePhysicalAddress,
|
|
Adapter->AttributeMemorySize
|
|
);
|
|
if (NDIS_STATUS_SUCCESS != Status)
|
|
{
|
|
//
|
|
// Failed to setup the attribute window.
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Read the ethernet address from the card.
|
|
//
|
|
for (c = 0; c < ETH_LENGTH_OF_ADDRESS; c++)
|
|
{
|
|
NdisReadRegisterUchar(
|
|
(PUCHAR)(pAttributeWindow + CIS_NET_ADDR_OFFSET + c * 2),
|
|
&Adapter->PermanentAddress[c]);
|
|
}
|
|
#endif
|
|
if (ETH_LENGTH_OF_ADDRESS != NdisReadPcmciaAttributeMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
CIS_NET_ADDR_OFFSET/2,
|
|
Adapter->PermanentAddress,
|
|
ETH_LENGTH_OF_ADDRESS
|
|
))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Setup to read the ethernet address
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 12);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB, 0);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, 0);
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_DMA_READ
|
|
);
|
|
|
|
//
|
|
// Read in the station address. (We have to read words -- 2 * 6 -- bytes)
|
|
//
|
|
for (c = 0; c < NE2000_LENGTH_OF_ADDRESS; c++)
|
|
{
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
&Adapter->PermanentAddress[c]
|
|
);
|
|
}
|
|
}
|
|
|
|
IF_LOUD(
|
|
DbgPrint(
|
|
"Ne2000: PermanentAddress [ %02x-%02x-%02x-%02x-%02x-%02x ]\n",
|
|
Adapter->PermanentAddress[0],
|
|
Adapter->PermanentAddress[1],
|
|
Adapter->PermanentAddress[2],
|
|
Adapter->PermanentAddress[3],
|
|
Adapter->PermanentAddress[4],
|
|
Adapter->PermanentAddress[5]
|
|
);
|
|
)
|
|
|
|
//
|
|
// Use the burned in address as the station address, unless the
|
|
// registry specified an override value.
|
|
//
|
|
if ((Adapter->StationAddress[0] == 0x00) &&
|
|
(Adapter->StationAddress[1] == 0x00) &&
|
|
(Adapter->StationAddress[2] == 0x00) &&
|
|
(Adapter->StationAddress[3] == 0x00) &&
|
|
(Adapter->StationAddress[4] == 0x00) &&
|
|
(Adapter->StationAddress[5] == 0x00)
|
|
)
|
|
{
|
|
Adapter->StationAddress[0] = Adapter->PermanentAddress[0];
|
|
Adapter->StationAddress[1] = Adapter->PermanentAddress[1];
|
|
Adapter->StationAddress[2] = Adapter->PermanentAddress[2];
|
|
Adapter->StationAddress[3] = Adapter->PermanentAddress[3];
|
|
Adapter->StationAddress[4] = Adapter->PermanentAddress[4];
|
|
Adapter->StationAddress[5] = Adapter->PermanentAddress[5];
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CardSetup(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets up the card.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block, which must be initialized.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
UINT Filter;
|
|
UCHAR Tmp;
|
|
|
|
|
|
//
|
|
// Write to and read from CR to make sure it is there.
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA | CR_PAGE0
|
|
);
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
&Tmp
|
|
);
|
|
if ((Tmp & (CR_STOP | CR_NO_DMA | CR_PAGE0)) !=
|
|
(CR_STOP | CR_NO_DMA | CR_PAGE0)
|
|
)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Set up the registers in the correct sequence, as defined by
|
|
// the 8390 specification.
|
|
//
|
|
if (Adapter->EightBitSlot)
|
|
{
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_DATA_CONFIG,
|
|
DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE
|
|
);
|
|
}
|
|
else
|
|
{
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_DATA_CONFIG,
|
|
DCR_WORD_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE
|
|
);
|
|
}
|
|
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RCV_CONFIG,
|
|
Adapter->NicReceiveConfig
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_XMIT_CONFIG,
|
|
TCR_LOOPBACK
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_BOUNDARY,
|
|
Adapter->NicPageStart
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_PAGE_START,
|
|
Adapter->NicPageStart
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_PAGE_STOP,
|
|
Adapter->NicPageStop
|
|
);
|
|
|
|
Adapter->Current = Adapter->NicPageStart + (UCHAR)1;
|
|
Adapter->NicNextPacket = Adapter->NicPageStart + (UCHAR)1;
|
|
Adapter->BufferOverflow = FALSE;
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xff);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_INTR_MASK,
|
|
Adapter->NicInterruptMask
|
|
);
|
|
|
|
|
|
//
|
|
// Move to page 1 to write the station address
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA | CR_PAGE1
|
|
);
|
|
|
|
for (i = 0; i < NE2000_LENGTH_OF_ADDRESS; i++)
|
|
{
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + (NIC_PHYS_ADDR + i),
|
|
Adapter->StationAddress[i]
|
|
);
|
|
}
|
|
|
|
Filter = Adapter->PacketFilter;
|
|
|
|
//
|
|
// Write out the multicast addresses
|
|
//
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + (NIC_MC_ADDR + i),
|
|
(UCHAR)((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ?
|
|
0xff : Adapter->NicMulticastRegs[i])
|
|
);
|
|
}
|
|
|
|
//
|
|
// Write out the current receive buffer to receive into
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_CURRENT,
|
|
Adapter->Current
|
|
);
|
|
|
|
|
|
//
|
|
// move back to page 0 and start the card...
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA | CR_PAGE0
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE0
|
|
);
|
|
|
|
//
|
|
// ... but it is still in loopback mode.
|
|
//
|
|
return(TRUE);
|
|
}
|
|
|
|
VOID CardStop(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stops the card.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
UCHAR Tmp;
|
|
|
|
//
|
|
// Turn on the STOP bit in the Command register.
|
|
//
|
|
SyncCardStop(Adapter);
|
|
|
|
//
|
|
// Clear the Remote Byte Count register so that ISR_RESET
|
|
// will come on.
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + 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(Adapter->IoPAddr+NIC_INTR_STATUS, &Tmp);
|
|
if (Tmp & ISR_RESET)
|
|
break;
|
|
|
|
NdisStallExecution(500);
|
|
}
|
|
|
|
if (i == 4)
|
|
{
|
|
IF_LOUD( DbgPrint("RESET\n");)
|
|
IF_LOG( Ne2000Log('R');)
|
|
}
|
|
|
|
//
|
|
// Put the card in loopback mode, then start it.
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, TCR_LOOPBACK);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_NO_DMA);
|
|
|
|
//
|
|
// At this point the card is still in loopback mode.
|
|
//
|
|
}
|
|
|
|
BOOLEAN CardReset(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resets the card.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
TRUE if everything is OK.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Stop the chip
|
|
//
|
|
CardStop(Adapter);
|
|
|
|
//
|
|
// Wait for the card to finish any receives or transmits
|
|
//
|
|
NdisStallExecution(2000);
|
|
|
|
//
|
|
// CardSetup() does a software reset.
|
|
//
|
|
if (!CardSetup(Adapter))
|
|
{
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
|
2,
|
|
cardReset,
|
|
NE2000_ERRMSG_CARD_SETUP
|
|
);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Restart the chip
|
|
//
|
|
CardStart(Adapter);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN CardCopyDownPacket(
|
|
IN PNE2000_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
OUT PUINT 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.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block
|
|
Packet - the packet to copy down
|
|
|
|
Return Value:
|
|
|
|
Length - the length of the data in the packet in bytes.
|
|
TRUE if the transfer completed with no problems.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Addresses of the Buffers to copy from and to.
|
|
//
|
|
PUCHAR CurBufAddress;
|
|
PUCHAR OddBufAddress;
|
|
PUCHAR XmitBufAddress;
|
|
|
|
//
|
|
// Length of each of the above buffers
|
|
//
|
|
UINT CurBufLen;
|
|
UINT PacketLength;
|
|
|
|
//
|
|
// Was the last transfer of an odd length?
|
|
//
|
|
BOOLEAN OddBufLen = FALSE;
|
|
|
|
//
|
|
// Current NDIS_BUFFER that is being copied from
|
|
//
|
|
PNDIS_BUFFER CurBuffer;
|
|
|
|
//
|
|
// Programmed I/O, have to transfer the data.
|
|
//
|
|
NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, &PacketLength);
|
|
|
|
//
|
|
// Skip 0 length copies
|
|
//
|
|
if (PacketLength == 0) {
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Get the starting buffer address
|
|
//
|
|
XmitBufAddress = (PUCHAR)Adapter->XmitStart +
|
|
Adapter->NextBufToFill*TX_BUF_SIZE;
|
|
|
|
//
|
|
// Get address and length of the first buffer in the packet
|
|
//
|
|
NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen);
|
|
|
|
while (CurBuffer && (CurBufLen == 0)) {
|
|
|
|
NdisGetNextBuffer(CurBuffer, &CurBuffer);
|
|
|
|
NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen);
|
|
|
|
}
|
|
|
|
//
|
|
// set up the card
|
|
//
|
|
{
|
|
|
|
//
|
|
// Temporary places for holding values for transferring to
|
|
// an odd aligned address on 16-bit slots.
|
|
//
|
|
UCHAR Tmp;
|
|
UCHAR Tmp1;
|
|
USHORT TmpShort;
|
|
|
|
//
|
|
// Values for waiting for noticing when a DMA completes.
|
|
//
|
|
USHORT OldAddr, NewAddr;
|
|
|
|
//
|
|
// Count of transfers to do
|
|
//
|
|
USHORT Count;
|
|
|
|
//
|
|
// Buffer to read from for odd aligned transfers
|
|
//
|
|
PUCHAR ReadBuffer;
|
|
|
|
if (!Adapter->EightBitSlot && ((ULONG_PTR)XmitBufAddress & 0x1)) {
|
|
|
|
//
|
|
// Avoid transfers to odd addresses in word mode.
|
|
//
|
|
// For odd addresses we need to read first to get the previous
|
|
// byte and then merge it with our first byte.
|
|
//
|
|
|
|
//
|
|
// Set Count and Source address
|
|
//
|
|
|
|
// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(XmitBufAddress - 1))
|
|
);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB((PtrToUlong(XmitBufAddress) - 1))
|
|
);
|
|
|
|
// NE2000 PCMCIA CHANGE START
|
|
|
|
//
|
|
// NE2000 PCMCIA CHANGE!!!
|
|
//
|
|
//NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x1 );
|
|
//NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 );
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 );
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 );
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ );
|
|
|
|
//
|
|
// NE2000 PCMCIA CHANGE!!!
|
|
//
|
|
//NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp1 );
|
|
NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort );
|
|
Tmp1 = LSB(TmpShort);
|
|
|
|
// NE2000 PCMCIA CHANGE END
|
|
|
|
//
|
|
// Do Write errata as described on pages 1-143 and
|
|
// 1-144 of the 1992 LAN databook
|
|
//
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
ReadBuffer = XmitBufAddress + ((ULONG_PTR)XmitBufAddress & 1);
|
|
|
|
OldAddr = NewAddr = (USHORT)(ReadBuffer);
|
|
|
|
// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, // robin
|
|
// CR_PAGE0 // robin
|
|
// ); // robin
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(ReadBuffer))
|
|
);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(ReadBuffer))
|
|
);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 );
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 );
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
|
|
//
|
|
// Read from port
|
|
//
|
|
NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort );
|
|
|
|
//
|
|
// Wait for addr to change
|
|
//
|
|
TmpShort = 0xFFFF;
|
|
|
|
while (TmpShort != 0) {
|
|
|
|
NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_LSB, &Tmp );
|
|
NewAddr = Tmp;
|
|
NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_MSB, &Tmp );
|
|
NewAddr |= (Tmp << 8);
|
|
|
|
if (NewAddr != OldAddr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
NdisStallExecution(1);
|
|
|
|
TmpShort--;
|
|
}
|
|
|
|
if (NewAddr == OldAddr) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
|
2,
|
|
cardCopyDownPacket,
|
|
(ULONG_PTR)XmitBufAddress
|
|
);
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(XmitBufAddress - 1)) );
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(XmitBufAddress - 1)) );
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 );
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 );
|
|
|
|
//
|
|
// Set direction (Write)
|
|
//
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_WRITE );
|
|
|
|
//
|
|
// It seems that the card stores words in LOW:HIGH order
|
|
//
|
|
NdisRawWritePortUshort( Adapter->IoPAddr + NIC_RACK_NIC,
|
|
(USHORT)(Tmp1 | ((*CurBufAddress) << 8)) );
|
|
|
|
//
|
|
// Wait for DMA to complete
|
|
//
|
|
Count = 0xFFFF;
|
|
|
|
while (Count) {
|
|
|
|
NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp1 );
|
|
|
|
if (Tmp1 & ISR_DMA_DONE) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
Count--;
|
|
NdisStallExecution(4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CurBufAddress++;
|
|
XmitBufAddress++;
|
|
PacketLength--;
|
|
CurBufLen--;
|
|
|
|
}
|
|
|
|
//
|
|
// Do Write errata as described on pages 1-143 and 1-144 of
|
|
// the 1992 LAN databook
|
|
//
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
ReadBuffer = XmitBufAddress + ((ULONG_PTR)XmitBufAddress & 1);
|
|
|
|
OldAddr = NewAddr = (USHORT)(ReadBuffer);
|
|
|
|
// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, // robin
|
|
// CR_PAGE0 // robin
|
|
// ); // robin
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(ReadBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(ReadBuffer))
|
|
);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
0x2
|
|
);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
0x0
|
|
);
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
|
|
if (Adapter->EightBitSlot) {
|
|
|
|
//
|
|
// Read from port
|
|
//
|
|
NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp );
|
|
NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp );
|
|
|
|
} else {
|
|
|
|
//
|
|
// Read from port
|
|
//
|
|
NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort );
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for addr to change
|
|
//
|
|
TmpShort = 0xFFFF;
|
|
|
|
while (TmpShort != 0) {
|
|
|
|
NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_LSB, &Tmp );
|
|
NewAddr = Tmp;
|
|
NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_MSB, &Tmp );
|
|
NewAddr |= (Tmp << 8);
|
|
|
|
if (NewAddr != OldAddr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
NdisStallExecution(1);
|
|
|
|
TmpShort--;
|
|
}
|
|
|
|
if (NewAddr == OldAddr) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
|
2,
|
|
cardCopyDownPacket,
|
|
(ULONG_PTR)XmitBufAddress
|
|
);
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
|
|
// NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0 ); // robin
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(XmitBufAddress)) );
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(XmitBufAddress)) );
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
LSB(PacketLength) );
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
MSB(PacketLength) );
|
|
//
|
|
// Set direction (Write)
|
|
//
|
|
NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_WRITE );
|
|
|
|
} // setup
|
|
|
|
//
|
|
// Copy the data now
|
|
//
|
|
|
|
do {
|
|
|
|
UINT Count;
|
|
UCHAR Tmp;
|
|
|
|
//
|
|
// Write the previous byte with this one
|
|
//
|
|
if (OddBufLen) {
|
|
|
|
//
|
|
// It seems that the card stores words in LOW:HIGH order
|
|
//
|
|
NdisRawWritePortUshort( Adapter->IoPAddr + NIC_RACK_NIC,
|
|
(USHORT)(*OddBufAddress | ((*CurBufAddress) << 8)) );
|
|
|
|
OddBufLen = FALSE;
|
|
CurBufAddress++;
|
|
CurBufLen--;
|
|
|
|
}
|
|
|
|
if (Adapter->EightBitSlot) { // byte mode
|
|
|
|
NdisRawWritePortBufferUchar(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
CurBufAddress,
|
|
CurBufLen
|
|
);
|
|
|
|
} else { // word mode
|
|
|
|
NdisRawWritePortBufferUshort(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
(PUSHORT)CurBufAddress,
|
|
(CurBufLen >> 1));
|
|
|
|
//
|
|
// Save trailing byte (if an odd lengthed transfer)
|
|
//
|
|
if (CurBufLen & 0x1) {
|
|
OddBufAddress = CurBufAddress + (CurBufLen - 1);
|
|
OddBufLen = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for DMA to complete
|
|
//
|
|
Count = 0xFFFF;
|
|
while (Count) {
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_INTR_STATUS,
|
|
&Tmp );
|
|
|
|
if (Tmp & ISR_DMA_DONE) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
Count--;
|
|
NdisStallExecution(4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Move to the next buffer
|
|
//
|
|
NdisGetNextBuffer(CurBuffer, &CurBuffer);
|
|
|
|
if (CurBuffer){
|
|
NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen);
|
|
}
|
|
|
|
//
|
|
// Get address and length of the next buffer
|
|
//
|
|
while (CurBuffer && (CurBufLen == 0)) {
|
|
|
|
NdisGetNextBuffer(CurBuffer, &CurBuffer);
|
|
|
|
if (CurBuffer){
|
|
NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen);
|
|
}
|
|
|
|
}
|
|
|
|
} while (CurBuffer);
|
|
|
|
//
|
|
// Write trailing byte (if necessary)
|
|
//
|
|
if (OddBufLen)
|
|
{
|
|
UINT Count;
|
|
UCHAR Tmp;
|
|
USHORT TmpShort;
|
|
|
|
if (NE2000_PCMCIA == Adapter->CardType) {
|
|
// NE2000 PCMCIA CHANGE!!! start
|
|
TmpShort = (USHORT)*OddBufAddress;
|
|
NdisRawWritePortUshort(Adapter->IoPAddr + NIC_RACK_NIC, TmpShort);
|
|
// NE2000 PCMCIA CHANGE!!! end
|
|
}
|
|
else {
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RACK_NIC, *OddBufAddress);
|
|
}
|
|
|
|
//
|
|
// Wait for DMA to complete robin-2
|
|
//
|
|
Count = 0xFFFF;
|
|
while (Count) {
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_INTR_STATUS,
|
|
&Tmp );
|
|
|
|
if (Tmp & ISR_DMA_DONE) {
|
|
break;
|
|
} else {
|
|
Count--;
|
|
NdisStallExecution(4);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return length written
|
|
//
|
|
*Length = PacketLength;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
CardCopyDown(
|
|
IN PNE2000_ADAPTER Adapter,
|
|
IN PUCHAR TargetBuffer,
|
|
IN PUCHAR SourceBuffer,
|
|
IN UINT Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies Length bytes from the SourceBuffer to the card buffer space
|
|
at card address TargetBuffer.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block
|
|
|
|
SourceBuffer - Buffer in virtual address space
|
|
|
|
TargetBuffer - Buffer in card address space
|
|
|
|
Length - number of bytes to transfer to card
|
|
|
|
Return Value:
|
|
|
|
TRUE if the transfer completed with no problems.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Temporary place holders for odd alignment transfers
|
|
//
|
|
UCHAR Tmp, TmpSave;
|
|
USHORT TmpShort;
|
|
|
|
//
|
|
// Values for waiting for noticing when a DMA completes.
|
|
//
|
|
USHORT OldAddr, NewAddr;
|
|
|
|
//
|
|
// Count of transfers to do
|
|
//
|
|
USHORT Count;
|
|
|
|
//
|
|
// Address the copy if coming from
|
|
//
|
|
PUCHAR ReadBuffer;
|
|
|
|
|
|
//
|
|
// Skip 0 length copies
|
|
//
|
|
|
|
if (Length == 0) {
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
if (!Adapter->EightBitSlot && ((ULONG_PTR)TargetBuffer & 0x1)) {
|
|
|
|
//
|
|
// For odd addresses we need to read first to get the previous
|
|
// byte and then merge it with our first byte.
|
|
//
|
|
|
|
//
|
|
// Set Count and Source address
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(TargetBuffer - 1))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(TargetBuffer - 1))
|
|
);
|
|
|
|
// NE2000 PCMCIA CHANGE!!! start
|
|
//NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x1);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0);
|
|
// NE2000 PCMCIA CHANGE!!! end
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
|
|
// NE2000 PCMCIA CHANGE!!! start
|
|
//NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RACK_NIC, &TmpSave);
|
|
NdisRawReadPortUshort(Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort);
|
|
TmpSave = LSB(TmpShort);
|
|
// NE2000 PCMCIA CHANGE!!! end
|
|
|
|
//
|
|
// Do Write errata as described on pages 1-143 and 1-144 of the 1992
|
|
// LAN databook
|
|
//
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
|
|
ReadBuffer = TargetBuffer + ((ULONG_PTR)TargetBuffer & 1);
|
|
|
|
OldAddr = NewAddr = (USHORT)(ReadBuffer);
|
|
|
|
// NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(ReadBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(ReadBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0);
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
|
|
//
|
|
// Read from port
|
|
//
|
|
|
|
NdisRawReadPortUshort(Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort);
|
|
|
|
//
|
|
// Wait for addr to change
|
|
//
|
|
|
|
TmpShort = 0xFFFF;
|
|
|
|
while (TmpShort != 0) {
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_CRDA_LSB,
|
|
&Tmp
|
|
);
|
|
|
|
NewAddr = Tmp;
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_CRDA_MSB,
|
|
&Tmp
|
|
);
|
|
|
|
NewAddr |= (Tmp << 8);
|
|
|
|
if (NewAddr != OldAddr) {
|
|
|
|
break;
|
|
}
|
|
|
|
NdisStallExecution(1);
|
|
|
|
TmpShort--;
|
|
|
|
}
|
|
|
|
if (NewAddr == OldAddr) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(TargetBuffer - 1))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(TargetBuffer - 1))
|
|
);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0);
|
|
|
|
//
|
|
// Set direction (Write)
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_WRITE
|
|
);
|
|
|
|
//
|
|
// It seems that the card stores words in LOW:HIGH order
|
|
//
|
|
|
|
NdisRawWritePortUshort(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
(USHORT)(TmpSave | ((*SourceBuffer) << 8))
|
|
);
|
|
|
|
//
|
|
// Wait for DMA to complete
|
|
//
|
|
|
|
Count = 0xFFFF;
|
|
|
|
while (Count) {
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_INTR_STATUS,
|
|
&Tmp
|
|
);
|
|
|
|
if (Tmp & ISR_DMA_DONE) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
Count--;
|
|
|
|
NdisStallExecution(4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SourceBuffer++;
|
|
TargetBuffer++;
|
|
Length--;
|
|
|
|
}
|
|
|
|
//
|
|
// Do Write errata as described on pages 1-143 and 1-144 of the 1992
|
|
// LAN databook
|
|
//
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
|
|
ReadBuffer = TargetBuffer + ((ULONG_PTR)TargetBuffer & 1);
|
|
|
|
OldAddr = NewAddr = (USHORT)(ReadBuffer);
|
|
|
|
// NdisRawWritePortUchar( // robin
|
|
// Adapter->IoPAddr + NIC_COMMAND, // robin
|
|
// CR_PAGE0 // robin
|
|
// ); // robin
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(ReadBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(ReadBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
0x2
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
0x0
|
|
);
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
|
|
if (Adapter->EightBitSlot) {
|
|
|
|
//
|
|
// Read from port
|
|
//
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
&Tmp
|
|
);
|
|
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
&Tmp
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Read from port
|
|
//
|
|
|
|
NdisRawReadPortUshort(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
&TmpShort
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for addr to change
|
|
//
|
|
|
|
TmpShort = 0xFFFF;
|
|
|
|
while (TmpShort != 0) {
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_CRDA_LSB,
|
|
&Tmp
|
|
);
|
|
|
|
NewAddr = Tmp;
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_CRDA_MSB,
|
|
&Tmp
|
|
);
|
|
|
|
NewAddr |= (Tmp << 8);
|
|
|
|
if (NewAddr != OldAddr) {
|
|
|
|
break;
|
|
}
|
|
|
|
NdisStallExecution(1);
|
|
|
|
TmpShort--;
|
|
|
|
}
|
|
|
|
if (NewAddr == OldAddr) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
|
|
// NdisRawWritePortUchar( // robin
|
|
// Adapter->IoPAddr + NIC_COMMAND, // robin
|
|
// CR_PAGE0 // robin
|
|
// ); // robin
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(TargetBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(TargetBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
LSB(Length)
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
MSB(Length)
|
|
);
|
|
|
|
//
|
|
// Set direction (Write)
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_WRITE
|
|
);
|
|
|
|
if (Adapter->EightBitSlot) {
|
|
|
|
//
|
|
// Repeatedly write to out port
|
|
//
|
|
|
|
NdisRawWritePortBufferUchar(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
SourceBuffer,
|
|
Length);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Write words to out ports
|
|
//
|
|
|
|
NdisRawWritePortBufferUshort(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
(PUSHORT)SourceBuffer,
|
|
(Length >> 1));
|
|
|
|
//
|
|
// Write trailing byte (if necessary)
|
|
//
|
|
if (Length & 0x1)
|
|
{
|
|
SourceBuffer += (Length - 1);
|
|
|
|
// NE2000 PCMCIA CHANGE!!! start
|
|
|
|
//NdisRawWritePortUchar(
|
|
// Adapter->IoPAddr + NIC_RACK_NIC,
|
|
// *SourceBuffer
|
|
//);
|
|
|
|
TmpShort = (USHORT)(*SourceBuffer);
|
|
NdisRawWritePortUshort(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
TmpShort
|
|
);
|
|
// NE2000 PCMCIA CHANGE!!! end
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for DMA to complete
|
|
//
|
|
|
|
Count = 0xFFFF;
|
|
|
|
while (Count) {
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_INTR_STATUS,
|
|
&Tmp
|
|
);
|
|
|
|
if (Tmp & ISR_DMA_DONE) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
Count--;
|
|
|
|
NdisStallExecution(4);
|
|
|
|
}
|
|
|
|
#if DBG
|
|
if (!(Tmp & ISR_DMA_DONE)) {
|
|
|
|
DbgPrint("CopyDownDMA didn't finish!");
|
|
|
|
}
|
|
#endif // DBG
|
|
|
|
}
|
|
|
|
IF_LOG(Ne2000Log('>');)
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CardCopyUp(
|
|
IN PNE2000_ADAPTER Adapter,
|
|
IN PUCHAR TargetBuffer,
|
|
IN PUCHAR SourceBuffer,
|
|
IN UINT BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies data from the card to memory.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block
|
|
|
|
Target - the target address
|
|
|
|
Source - the source address (on the card)
|
|
|
|
BufferLength - the number of bytes to copy
|
|
|
|
Return Value:
|
|
|
|
TRUE if the transfer completed with no problems.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Used to check when the dma is done
|
|
//
|
|
UCHAR IsrValue;
|
|
|
|
//
|
|
// Count of the number of transfers to do
|
|
//
|
|
USHORT Count;
|
|
|
|
//
|
|
// Place holder for port values
|
|
//
|
|
UCHAR Temp;
|
|
|
|
if (BufferLength == 0) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Read the Command Register, to make sure it is ready for a write
|
|
//
|
|
NdisRawReadPortUchar(Adapter->IoPAddr+NIC_COMMAND, &Temp);
|
|
|
|
if (Adapter->EightBitSlot) {
|
|
|
|
//
|
|
// If byte mode
|
|
//
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
|
|
// NdisRawWritePortUchar( // robin
|
|
// Adapter->IoPAddr + NIC_COMMAND, // robin
|
|
// CR_PAGE0 // robin
|
|
// ); // robin
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(SourceBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(SourceBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
LSB(BufferLength)
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
MSB(BufferLength)
|
|
);
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
//
|
|
// Repeatedly read from port
|
|
//
|
|
|
|
NdisRawReadPortBufferUchar(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
TargetBuffer,
|
|
BufferLength
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Else word mode
|
|
//
|
|
|
|
USHORT Tmp;
|
|
|
|
// NdisRawWritePortUchar( // robin
|
|
// Adapter->IoPAddr + NIC_COMMAND, // robin
|
|
// CR_PAGE0 // robin
|
|
// ); // robin
|
|
|
|
//
|
|
// Avoid transfers to odd addresses
|
|
//
|
|
|
|
if ((ULONG_PTR)SourceBuffer & 0x1) {
|
|
|
|
//
|
|
// For odd addresses we need to read previous word and store the
|
|
// second byte
|
|
//
|
|
|
|
//
|
|
// Set Count and Source address
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(SourceBuffer - 1))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(SourceBuffer - 1))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
0x2
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
0x0
|
|
);
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
|
|
NdisRawReadPortUshort(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
&Tmp
|
|
);
|
|
|
|
*TargetBuffer = MSB(Tmp);
|
|
|
|
//
|
|
// Wait for DMA to complete
|
|
//
|
|
|
|
Count = 0xFFFF;
|
|
|
|
while (Count) {
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_INTR_STATUS,
|
|
&IsrValue
|
|
);
|
|
|
|
if (IsrValue & ISR_DMA_DONE) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
Count--;
|
|
|
|
NdisStallExecution(4);
|
|
|
|
}
|
|
|
|
#if DBG
|
|
if (!(IsrValue & ISR_DMA_DONE)) {
|
|
|
|
DbgPrint("CopyUpDMA didn't finish!");
|
|
|
|
}
|
|
#endif // DBG
|
|
|
|
}
|
|
|
|
SourceBuffer++;
|
|
TargetBuffer++;
|
|
BufferLength--;
|
|
}
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_LSB,
|
|
LSB(PtrToUlong(SourceBuffer))
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_ADDR_MSB,
|
|
MSB(PtrToUlong(SourceBuffer))
|
|
);
|
|
|
|
// NE2000 PCMCIA CHANGE!!! start
|
|
|
|
// NdisRawWritePortUchar(
|
|
// Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
// LSB(BufferLength)
|
|
// );
|
|
//
|
|
// NdisRawWritePortUchar(
|
|
// Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
// MSB(BufferLength)
|
|
// );
|
|
|
|
if (BufferLength & 1)
|
|
{
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
LSB(BufferLength + 1)
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
MSB(BufferLength + 1)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_LSB,
|
|
LSB(BufferLength)
|
|
);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_RMT_COUNT_MSB,
|
|
MSB(BufferLength)
|
|
);
|
|
}
|
|
|
|
// NE2000 PCMCIA CHANGE!!! end
|
|
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
|
|
//
|
|
// Read words from port
|
|
//
|
|
|
|
NdisRawReadPortBufferUshort(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
(PUSHORT)TargetBuffer,
|
|
(BufferLength >> 1));
|
|
|
|
//
|
|
// Read trailing byte (if necessary)
|
|
//
|
|
|
|
if (BufferLength & 1) {
|
|
|
|
TargetBuffer += (BufferLength - 1);
|
|
|
|
// NE2000 PCMCIA CHANGE!!! start
|
|
|
|
//NdisRawReadPortUchar(
|
|
// Adapter->IoPAddr + NIC_RACK_NIC,
|
|
// TargetBuffer
|
|
//);
|
|
|
|
NdisRawReadPortUshort(
|
|
Adapter->IoPAddr + NIC_RACK_NIC,
|
|
&Tmp
|
|
);
|
|
|
|
*TargetBuffer = LSB(Tmp);
|
|
|
|
// NE2000 PCMCIA CHANGE!!! end
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for DMA to complete
|
|
//
|
|
|
|
Count = 0xFFFF;
|
|
|
|
while (Count) {
|
|
|
|
NdisRawReadPortUchar(
|
|
Adapter->IoPAddr + NIC_INTR_STATUS,
|
|
&IsrValue
|
|
);
|
|
|
|
if (IsrValue & ISR_DMA_DONE) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
Count--;
|
|
|
|
NdisStallExecution(4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if DBG
|
|
if (!(IsrValue & ISR_DMA_DONE)) {
|
|
|
|
DbgPrint("CopyUpDMA didn't finish!\n");
|
|
|
|
}
|
|
|
|
IF_LOG(Ne2000Log('<');)
|
|
|
|
#endif // DBG
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
CardGetMulticastBit(
|
|
IN UCHAR Address[NE2000_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, NE2000_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 PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Erases and refills the card multicast registers. Used when
|
|
an address has been deleted and all bits must be recomputed.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
UCHAR Byte, Bit;
|
|
|
|
//
|
|
// First turn all bits off.
|
|
//
|
|
|
|
for (i=0; i<8; i++) {
|
|
|
|
Adapter->NicMulticastRegs[i] = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// Now turn on the bit for each address in the multicast list.
|
|
//
|
|
|
|
for ( ; i > 0; ) {
|
|
|
|
i--;
|
|
|
|
CardGetMulticastBit(Adapter->Addresses[i], &Byte, &Bit);
|
|
|
|
Adapter->NicMulticastRegs[Byte] |= Bit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawWritePortUchar(
|
|
Adapter->IoPAddr + NIC_COMMAND,
|
|
CR_STOP | CR_NO_DMA
|
|
);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
VOID
|
|
CardStartXmit(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the NIC_COMMAND register to start a transmission.
|
|
The transmit buffer number is taken from Adapter->CurBufXmitting
|
|
and the length from Adapter->PacketLens[Adapter->CurBufXmitting].
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
TRUE if the power has failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT Length = Adapter->PacketLens[Adapter->CurBufXmitting];
|
|
UCHAR Tmp;
|
|
|
|
//
|
|
// Prepare the NIC registers for transmission.
|
|
//
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_START,
|
|
(UCHAR)(Adapter->NicXmitStart + (UCHAR)(Adapter->CurBufXmitting*BUFS_PER_TX)));
|
|
|
|
//
|
|
// Pad the length to 60 (plus CRC will be 64) if needed.
|
|
//
|
|
|
|
if (Length < 60) {
|
|
|
|
Length = 60;
|
|
|
|
}
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_COUNT_MSB, MSB(Length));
|
|
NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_COUNT_LSB, LSB(Length));
|
|
|
|
//
|
|
// Start transmission, check for power failure first.
|
|
//
|
|
|
|
NdisRawReadPortUchar(Adapter->IoPAddr+NIC_COMMAND, &Tmp);
|
|
NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND,
|
|
CR_START | CR_XMIT | CR_NO_DMA);
|
|
|
|
IF_LOG( Ne2000Log('x');)
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
SyncCardGetCurrent(
|
|
IN PVOID SynchronizeContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the value of the CURRENT NIC register and stores it in Adapter->Current
|
|
|
|
Arguments:
|
|
|
|
SynchronizeContext - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
|
|
//
|
|
// Have to go to page 1 to read this register
|
|
//
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE1);
|
|
|
|
NdisRawReadPortUchar(Adapter->IoPAddr+NIC_CURRENT,
|
|
&Adapter->Current);
|
|
|
|
NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE0);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
SyncCardGetXmitStatus(
|
|
IN PVOID SynchronizeContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the value of the "transmit status" NIC register and stores
|
|
it in Adapter->XmitStatus.
|
|
|
|
Arguments:
|
|
|
|
SynchronizeContext - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawReadPortUchar( Adapter->IoPAddr+NIC_XMIT_STATUS, &Adapter->XmitStatus);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
VOID
|
|
CardSetBoundary(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the value of the "boundary" NIC register to one behind
|
|
Adapter->NicNextPacket, to prevent packets from being received
|
|
on top of un-indicated ones.
|
|
|
|
Arguments:
|
|
|
|
Adapter - 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 (Adapter->NicNextPacket == Adapter->NicPageStart) {
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+NIC_BOUNDARY,
|
|
(UCHAR)(Adapter->NicPageStop-(UCHAR)1));
|
|
|
|
} else {
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+NIC_BOUNDARY,
|
|
(UCHAR)(Adapter->NicNextPacket-(UCHAR)1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
SyncCardSetReceiveConfig(
|
|
IN PVOID SynchronizeContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the value of the "receive configuration" NIC register to
|
|
the value of Adapter->NicReceiveConfig.
|
|
|
|
Arguments:
|
|
|
|
SynchronizeContext - pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+NIC_RCV_CONFIG, Adapter->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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
UINT i;
|
|
|
|
//
|
|
// Have to move to page 1 to set these registers.
|
|
//
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE1);
|
|
|
|
for (i=0; i<8; i++) {
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+(NIC_MC_ADDR+i), 0xff);
|
|
|
|
}
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
UINT i;
|
|
|
|
//
|
|
// Have to move to page 1 to set these registers.
|
|
//
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE1);
|
|
|
|
for (i=0; i<8; i++) {
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+(NIC_MC_ADDR+i),
|
|
Adapter->NicMulticastRegs[i]);
|
|
|
|
}
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND,
|
|
CR_START | CR_NO_DMA | CR_PAGE0);
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
UCHAR AcknowledgeMask = 0;
|
|
|
|
if (Adapter->InterruptStatus & ISR_RCV_ERR) {
|
|
|
|
SyncCardUpdateCounters(Adapter);
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
UCHAR Tmp;
|
|
|
|
NdisRawReadPortUchar( Adapter->IoPAddr+NIC_FAE_ERR_CNTR, &Tmp);
|
|
Adapter->FrameAlignmentErrors += Tmp;
|
|
|
|
NdisRawReadPortUchar( Adapter->IoPAddr+NIC_CRC_ERR_CNTR, &Tmp);
|
|
Adapter->CrcErrors += Tmp;
|
|
|
|
NdisRawReadPortUchar( Adapter->IoPAddr+NIC_MISSED_CNTR, &Tmp);
|
|
Adapter->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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext);
|
|
UCHAR Status;
|
|
|
|
IF_LOG( Ne2000Log('F');)
|
|
|
|
//
|
|
// Turn on the STOP bit in the Command register.
|
|
//
|
|
|
|
SyncCardStop(Adapter);
|
|
|
|
//
|
|
// 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 (!(Adapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR))) {
|
|
|
|
CardGetInterruptStatus(Adapter,&Status);
|
|
if (!(Status & (ISR_XMIT | ISR_XMIT_ERR))) {
|
|
|
|
Adapter->OverflowRestartXmitDpc = Adapter->TransmitInterruptPending;
|
|
|
|
IF_LOUD( DbgPrint("ORXD=%x\n",Adapter->OverflowRestartXmitDpc); )
|
|
}
|
|
|
|
}
|
|
|
|
Adapter->TransmitInterruptPending = FALSE;
|
|
|
|
//
|
|
// Clear the Remote Byte Count register so that ISR_RESET
|
|
// will come on.
|
|
//
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+NIC_RMT_COUNT_MSB, 0);
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+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( Adapter->IoPAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
|
|
|
|
//
|
|
// Start the card. This does not Undo the loopback mode.
|
|
//
|
|
|
|
NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|