513 lines
11 KiB
C
513 lines
11 KiB
C
#include <ndis.h>
|
|
#include "82595.h"
|
|
#include "eprohw.h"
|
|
#include "eprosw.h"
|
|
#include "epro.h"
|
|
#include "eprodbg.h"
|
|
|
|
// Global data
|
|
|
|
NDIS_MINIPORT_CHARACTERISTICS EPro_Miniport_Char;
|
|
|
|
EPRO_DRIVER EProMiniportDriver={0};
|
|
|
|
NDIS_STATUS EProSelReset(PEPRO_ADAPTER adapter)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This does a SEL-RESET of the i82595 chip. Read the 82595 docs
|
|
for more info on what this does.
|
|
|
|
Arguments:
|
|
|
|
adapter - pointer to our adapter structure
|
|
|
|
Return Values:
|
|
|
|
always returns NDIS_STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
EPRO_ASSERT_BANK_0(adapter);
|
|
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_SEL_RESET);
|
|
|
|
// according to 82595 prelim doc: wait 2 us after sel reset before
|
|
// accessing the 82595
|
|
NdisStallExecution(2);
|
|
|
|
EProEnableInterrupts((NDIS_HANDLE)adapter);
|
|
|
|
adapter->fHung = FALSE;
|
|
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
EProInitializeAdapterData(
|
|
IN PEPRO_ADAPTER adapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes our adapter structure - setting default
|
|
values, zeroing fields, etc. This is called on adapter initialization
|
|
and adapter reset.
|
|
|
|
Arguments:
|
|
|
|
A pointer to the adapter structure to clear.
|
|
|
|
Return Values:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
UINT i;
|
|
|
|
adapter->CurrentHardwareStatus = NdisHardwareStatusReady;
|
|
|
|
adapter->vendorID[0] = EPRO_VENDOR_ID_L;
|
|
adapter->vendorID[1] = EPRO_VENDOR_ID_M;
|
|
adapter->vendorID[2] = EPRO_VENDOR_ID_H;
|
|
|
|
adapter->CurrentPacketFilter = 0;
|
|
|
|
// hack to get around wrapper bug:
|
|
// adapter->RXLookAheadSize = 0;
|
|
//
|
|
adapter->RXLookAheadSize = 256;
|
|
adapter->FramesXmitOK = 0;
|
|
adapter->FramesRcvOK = 0;
|
|
adapter->FramesXmitErr = 0;
|
|
adapter->FramesRcvErr = 0;
|
|
adapter->FramesMissed = 0;
|
|
|
|
adapter->FrameAlignmentErrors = 0;
|
|
adapter->FramesXmitOneCollision = 0;
|
|
adapter->FramesXmitManyCollisions = 0;
|
|
|
|
adapter->CurrentTXBuf = &adapter->TXBuf[0];
|
|
adapter->TXChainStart = NULL;
|
|
|
|
// Packet filter settings...
|
|
//
|
|
adapter->fPromiscuousEnable = FALSE;
|
|
adapter->fBroadcastEnable = FALSE;
|
|
adapter->fMulticastEnable = FALSE;
|
|
adapter->fReceiveEnabled = FALSE;
|
|
adapter->NumMCAddresses = 0;
|
|
|
|
// Don't force 8-bit operation
|
|
//
|
|
adapter->Use8Bit = FALSE;
|
|
|
|
adapter->IntPending = EPRO_INT_NONE_PENDING;
|
|
adapter->fHung = FALSE;
|
|
// adapter->fTransmitInProgress = FALSE;
|
|
|
|
// Set up the TX buffers...
|
|
//
|
|
for (i = 0;i < EPRO_NUM_TX_BUFFERS; i++)
|
|
{
|
|
if (0 == i)
|
|
{
|
|
adapter->TXBuf[0].LastBuf = &adapter->TXBuf[EPRO_NUM_TX_BUFFERS - 1];
|
|
}
|
|
else
|
|
{
|
|
adapter->TXBuf[i].LastBuf = &adapter->TXBuf[i-1];
|
|
}
|
|
|
|
if ((EPRO_NUM_TX_BUFFERS - 1) == i)
|
|
{
|
|
adapter->TXBuf[i].NextBuf = &adapter->TXBuf[0];
|
|
}
|
|
else
|
|
{
|
|
adapter->TXBuf[i].NextBuf = &adapter->TXBuf[i + 1];
|
|
}
|
|
|
|
adapter->TXBuf[i].fEmpty = TRUE;
|
|
adapter->TXBuf[i].TXBaseAddr = 0;
|
|
adapter->TXBuf[i].TXSendAddr = 0xffff;
|
|
}
|
|
}
|
|
|
|
VOID EProEnableInterrupts(IN NDIS_HANDLE miniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The MiniportEnableInterrupt Handler for the card.
|
|
|
|
Arguments:
|
|
|
|
miniportAdapterContext - really a PEPRO_ADAPTER to our adapter structure
|
|
|
|
Return Value: none
|
|
|
|
--*/
|
|
{
|
|
PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
|
|
|
|
// If this isn't true, then NdisMSyncronizeWithInterrupt is broken
|
|
// or we've called a function which switches banks without syncronizing
|
|
// it...
|
|
EPRO_ASSERT_BANK_0(adapter);
|
|
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG,
|
|
adapter->CurrentInterruptMask);
|
|
|
|
}
|
|
|
|
VOID EProDisableInterrupts(IN NDIS_HANDLE miniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The MiniportDisableInterrupts handler for the driver
|
|
|
|
Arguments:
|
|
|
|
miniportAdapterContext - really a pointer to our adapter structure
|
|
|
|
Return Values: none
|
|
|
|
--*/
|
|
{
|
|
PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
|
|
|
|
// If this isn't true, then NdisMSyncronizeWithInterrupt is broken
|
|
// or we've called a function which switches banks without syncronizing
|
|
// it...
|
|
EPRO_ASSERT_BANK_0(adapter);
|
|
|
|
// mask all int's
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG,
|
|
(adapter->CurrentInterruptMask | 0x0f));
|
|
}
|
|
|
|
|
|
VOID EProHalt(IN NDIS_HANDLE miniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the function which halts the 82595 chip and disables the
|
|
adapter - frees hardware resources, etc.
|
|
|
|
Arguments:
|
|
|
|
miniportAdapterContext - pointer to our adapter structure
|
|
|
|
Returns: nothing
|
|
|
|
--*/
|
|
{
|
|
PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext;
|
|
|
|
// Shut down the card - disable receives.
|
|
EProReceiveDisable(adapter);
|
|
|
|
// There won't be any more interrupts
|
|
NdisMDeregisterInterrupt(&adapter->Interrupt);
|
|
|
|
// Pause, wait for pending DPC stuff to clear... Random number stolen
|
|
// from the NE2000 driver...
|
|
NdisStallExecution(250000);
|
|
|
|
// Unmap our IO ports
|
|
NdisMDeregisterIoPortRange(adapter->MiniportAdapterHandle,
|
|
(ULONG)adapter->IoBaseAddr,
|
|
0x10,
|
|
(PVOID)adapter->IoPAddr);
|
|
|
|
// Free up our adapter structure...
|
|
NdisFreeMemory(adapter, sizeof(EPRO_ADAPTER), 0);
|
|
}
|
|
|
|
NDIS_STATUS EProReset(OUT PBOOLEAN fAddressingReset,
|
|
IN NDIS_HANDLE miniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the MiniportReset handler for the EPro driver
|
|
|
|
Arguments:
|
|
|
|
fAddressingReset - Do we need to be re-told our MC address list?
|
|
currently we say yes, although probably we don't
|
|
have to be told this (the driver saves it)
|
|
|
|
Return Values:
|
|
|
|
the return from EProSelReset (always NDIS_STATUS_SUCCESS)
|
|
|
|
--*/
|
|
{
|
|
PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext;
|
|
|
|
// Okay, we don't want to get any interrupts anymore.
|
|
EProDisableInterrupts(adapter);
|
|
EProReceiveDisable(adapter);
|
|
|
|
// clear out TX structures...
|
|
EProInitializeAdapterData(adapter);
|
|
|
|
// We probably can set this to false -- TODO
|
|
*fAddressingReset = TRUE;
|
|
|
|
return(EProSelReset(adapter));
|
|
}
|
|
|
|
BOOLEAN EProCheckForHang(IN NDIS_HANDLE miniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the MiniportCheckForHang handler for the driver.
|
|
It does absolutely nothing right now.
|
|
|
|
Arguments:
|
|
|
|
miniportAdapterContext - right now a pointer to our adapter structure
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext;
|
|
|
|
if (adapter->fHung)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
VOID EProHandleInterrupt(
|
|
IN NDIS_HANDLE miniportAdapterContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the function that gets called at DPC level in response
|
|
to a hardware interrupt. It is queued by the wrapper's ISR routines.
|
|
Interrupts have been disabled when this routine is called.
|
|
|
|
Arguments:
|
|
|
|
miniportAdapterContext - really a pointer to our adapter structure
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext;
|
|
UCHAR whichInt;
|
|
BOOLEAN fFoundInts, fFoundRX = FALSE;
|
|
|
|
// verify bank 0
|
|
EPRO_ASSERT_BANK_0(adapter);
|
|
|
|
do
|
|
{
|
|
fFoundInts = FALSE;
|
|
|
|
// Read in the int mask
|
|
//
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &whichInt);
|
|
|
|
// quick out if there are no ints pending...
|
|
if (!(whichInt & 0x0f))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// acknowlege interrupts - writing a 1 over the int flag clears it
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, whichInt);
|
|
|
|
if (whichInt & I82595_TX_INT_RCVD)
|
|
{
|
|
fFoundInts = TRUE;
|
|
if (adapter->TXChainStart != NULL)
|
|
{
|
|
EProCheckTransmitCompletion(adapter, adapter->TXChainStart);
|
|
}
|
|
}
|
|
|
|
// if (whichInt & I82595_TX_INT_RCVD)
|
|
// {
|
|
// fFoundInts = TRUE;
|
|
// if (adapter->TXChainStart != NULL)
|
|
// {
|
|
// while (EProCheckTransmitCompletion(adapter, adapter->TXChainStart))
|
|
// ;
|
|
// }
|
|
// }
|
|
|
|
if (whichInt & I82595_RX_INT_RCVD)
|
|
{
|
|
fFoundInts = TRUE;
|
|
if (EProHandleReceive(adapter) > 0)
|
|
{
|
|
fFoundRX = TRUE;
|
|
}
|
|
}
|
|
|
|
if (whichInt & I82595_EXEC_INT_RCVD)
|
|
{
|
|
fFoundInts = TRUE;
|
|
|
|
EProSetInterruptMask(adapter, EPRO_DEFAULT_INTERRUPTS);
|
|
|
|
switch(adapter->IntPending)
|
|
{
|
|
case EPRO_INT_MC_SET_PENDING:
|
|
|
|
((PEPRO_TRANSMIT_BUFFER)adapter->IntContext)->fEmpty = TRUE;
|
|
EPRO_DPRINTF_INTERRUPT(("Set COMPLETED!"));
|
|
|
|
NdisMSetInformationComplete(
|
|
adapter->MiniportAdapterHandle,
|
|
NDIS_STATUS_SUCCESS);
|
|
|
|
break;
|
|
// default:
|
|
// EPRO_ASSERT(FALSE); // we shouldn't hit this...
|
|
}
|
|
|
|
// clear the pending interrupt...
|
|
//
|
|
adapter->IntPending = 0;
|
|
adapter->IntContext = NULL;
|
|
}
|
|
} while ((fFoundInts == TRUE) && !adapter->fHung);
|
|
|
|
if (fFoundRX)
|
|
{
|
|
NdisMEthIndicateReceiveComplete(adapter->MiniportAdapterHandle);
|
|
}
|
|
}
|
|
|
|
void
|
|
EProISR(
|
|
OUT PBOOLEAN interruptRecognized,
|
|
OUT PBOOLEAN queueMiniportHandleInterrupt,
|
|
IN NDIS_HANDLE miniportAdapterContext)
|
|
{
|
|
EPRO_DPRINTF_INTERRUPT(("ISR"));
|
|
|
|
*interruptRecognized = TRUE;
|
|
*queueMiniportHandleInterrupt = FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN EProSyncSetInterruptMask(PVOID context)
|
|
{
|
|
PEPRO_ADAPTER adapter = ((PEPRO_SETINTERRUPT_CONTEXT)context)->Adapter;
|
|
UCHAR newMask = ((PEPRO_SETINTERRUPT_CONTEXT)context)->NewMask;
|
|
|
|
// unmask everyone...
|
|
adapter->CurrentInterruptMask &= 0xf0;
|
|
// now mask the ones we don't want
|
|
adapter->CurrentInterruptMask |= newMask;
|
|
|
|
EPRO_ASSERT_BANK_0(adapter);
|
|
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG,
|
|
adapter->CurrentInterruptMask);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
// Poll the exec-states reg (0,1), waiting for any execution to finish...
|
|
BOOLEAN EProWaitForExeDma(PEPRO_ADAPTER adapter)
|
|
{
|
|
UINT i;
|
|
UCHAR result;
|
|
|
|
// status reg is in bank 0
|
|
EPRO_ASSERT_BANK_0(adapter);
|
|
|
|
for (i=0;i<I82595_SPIN_TIMEOUT;i++) {
|
|
// make sure the dma is idle
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &result);
|
|
if (!(result&I82595_EXEC_STATE)) {
|
|
if (result & I82595_EXEC_INT_RCVD) {
|
|
// clear the exec int if it's high...
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG,
|
|
I82595_EXEC_INT_RCVD);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
NdisStallExecution(1);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOLEAN EProReceiveEnable(PEPRO_ADAPTER adapter)
|
|
{
|
|
UINT i = 0;
|
|
UCHAR result;
|
|
|
|
adapter->RXCurrentAddress = 0 | (((USHORT)EPRO_RX_LOWER_LIMIT) << 8);
|
|
|
|
// EPRO_ASSERT(!adapter->fReceiveEnabled);
|
|
|
|
// don't enable if we're already enabled.
|
|
if (adapter->fReceiveEnabled)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
// bank0
|
|
// EPRO_SWITCH_BANK_0(adapter);
|
|
//
|
|
EPRO_ASSERT_BANK_0(adapter);
|
|
EPRO_WR_PORT_USHORT(adapter, I82595_RX_STOP_REG, 0 | (((USHORT)EPRO_RX_UPPER_LIMIT) << 8));
|
|
EPRO_WR_PORT_USHORT(adapter, I82595_RX_BAR_REG, 0 | (((USHORT)EPRO_RX_LOWER_LIMIT) << 8));
|
|
|
|
//
|
|
// validate registers...
|
|
//
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_RCV_ENABLE);
|
|
|
|
adapter->fReceiveEnabled = TRUE;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOLEAN EProReceiveDisable(PEPRO_ADAPTER adapter)
|
|
{
|
|
UINT i = 0;
|
|
UCHAR result;
|
|
|
|
// bank0
|
|
// EPRO_SWITCH_BANK_0(adapter);
|
|
EPRO_ASSERT_BANK_0(adapter);
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_STOP_RCV);
|
|
|
|
adapter->fReceiveEnabled = FALSE;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//VOID EProTimerFunc(IN PVOID foo1, IN PVOID context, IN PVOID foo2, IN PVOID foo3)
|
|
//{
|
|
// EProHandleInterrupt((NDIS_HANDLE)context);
|
|
//
|
|
// queue another timer...
|
|
// NdisMSetTimer(&(((PEPRO_ADAPTER)context)->MiniportTimer), 10);
|
|
//}
|