📄 ne2000adapter.cpp
字号:
/*++
Routine Description:
Indicates the first packet on the card to the protocols.Called from the RcvDpc.
NOTE: For MP, non-x86 architectures, this assumes that the packet has been
read from the card and into Info.PacketHeader and Info.Lookahead.
NOTE: For UP x86 systems this assumes that the packet header has been
read into Info.PacketHeader and the minimal lookahead stored in
Info.Lookahead
Return Value:
CARD_BAD if the card should be reset;
INDICATE_OK otherwise.
--*/
INDICATE_STATUS KdNe2000Adapter::IndicatePacket()
{
// Length of the packet
UINT PacketLen;
// Length of the lookahead buffer
UINT IndicateLen;
// Variables for checking if the packet header looks valid
UCHAR PossibleNextPacket1, PossibleNextPacket2;
// Check if the next packet byte agress with the length, as
// described on p. A-3 of the Etherlink II Technical Reference.
// The start of the packet plus the MSB of the length must
// be equal to the start of the next packet minus one or two.
// Otherwise the header is considered corrupted, and the
// card must be reset.
PossibleNextPacket1 =
Info.NicNextPacket + Info.PacketHeader[3] + (UCHAR)1;
if (PossibleNextPacket1 >= Info.NicPageStop)
{
PossibleNextPacket1 -= (Info.NicPageStop - Info.NicPageStart);
}
if (PossibleNextPacket1 != Info.PacketHeader[1])
{
PossibleNextPacket2 = PossibleNextPacket1+(UCHAR)1;
if (PossibleNextPacket2 == Info.NicPageStop)
{
PossibleNextPacket2 = Info.NicPageStart;
}
if (PossibleNextPacket2 != Info.PacketHeader[1])
{
DebugDump(DBG_LEVEL3,("First CARD_BAD check failed\n"));
return SKIPPED;
}
}
//
// Check that the Next is valid
if ((Info.PacketHeader[1] < Info.NicPageStart) ||
(Info.PacketHeader[1] > Info.NicPageStop))
{
DebugDump(DBG_LEVEL3,("Second CARD_BAD check failed\n"));
return(SKIPPED);
}
// Sanity check the length
PacketLen = Info.PacketHeader[2] + Info.PacketHeader[3]*256 - 4;
if (PacketLen > 1514)
{
DebugDump(DBG_LEVEL3,("Third CARD_BAD check failed\n"));
return(SKIPPED);
}
#if DBG
IF_NE2000DEBUG( NE2000_DEBUG_WORKAROUND1 )
{
// Now check for the high order 2 bits being set, as described
// on page A-2 of the Etherlink II Technical Reference. If either
// of the two high order bits is set in the receive status byte
// in the packet header, the packet should be skipped (but
// the adapter does not need to be reset).
if (Info.PacketHeader[0] & (RSR_DISABLED|RSR_DEFERRING))
{
DebugDump(DBG_LEVEL3,("H"));
return SKIPPED;
}
}
#endif
// Lookahead amount to indicate
IndicateLen = (PacketLen > (Info.MaxLookAhead + NE2000_HEADER_SIZE)) ?
(Info.MaxLookAhead + NE2000_HEADER_SIZE) :
PacketLen;
// Indicate packet
Info.PacketLen = PacketLen;
if (IndicateLen < NE2000_HEADER_SIZE)
{
// Runt Packet -
// Will cause the TransferDataHandler to be called
EthIndicateReceive(
(NDIS_HANDLE)NULL, // use this for any context you want passed
(PCHAR)(Info.Lookahead),
IndicateLen,
NULL,
0,
0);
}
else
{
// Will cause the TransferDataHandler to be called
EthIndicateReceive(
(NDIS_HANDLE)NULL,// use this for any context you want passed,
(PCHAR)(Info.Lookahead),
NE2000_HEADER_SIZE,
(PCHAR)(Info.Lookahead) + NE2000_HEADER_SIZE,
IndicateLen - NE2000_HEADER_SIZE,
PacketLen - NE2000_HEADER_SIZE);
}
Info.IndicateReceiveDone = TRUE;
return INDICATE_OK;
}
/*++
Routine Description:
Recovers the card from a transmit error.
--*/
VOID KdNe2000Adapter::OctogmetusceratorRevisited()
{
DebugDump(DBG_LEVEL3,("Octogmetuscerator called!"));
IF_LOG( Ne2000Log('y'); )
// Ack the interrupt, if needed
NdisRawWritePortUchar(Info.IoPAddr+NIC_INTR_STATUS, ISR_XMIT_ERR);
// Stop the card
SyncCardStop();
// Wait up to 1.6 milliseconds for any receives to finish
NdisStallExecution(2000);
// Place the card in Loopback
NdisRawWritePortUchar(Info.IoPAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
// Start the card in Loopback
NdisRawWritePortUchar(Info.IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
// Get out of loopback and start the card
CardStart(this);
// If there was a packet waiting to get sent, send it.
if (Info.CurBufXmitting != -1)
{
Info.TransmitInterruptPending = TRUE;
CardStartXmit();
}
IF_LOG( Ne2000Log('Y'); )
}
/*++
Routine Description:
This is the real interrupt handler for receive/overflow interrupt.
Called when a receive interrupt is received. It first indicates
all packets on the card and finally indicates ReceiveComplete().
Return Value:
TRUE if done with all receives, else FALSE.
--*/
BOOLEAN KdNe2000Adapter::RcvDpc()
{
// Use to restart a transmit if a buffer overflow occurred
// during a transmission
BOOLEAN TransmitInterruptWasPending = FALSE;
// Status of a received packet.
INDICATE_STATUS IndicateStatus = INDICATE_OK;
// Flag to tell when the receive process is complete
BOOLEAN Done = TRUE;
DebugDump(DBG_LEVEL4,( "KdNe2000Adapter::RcvDpc entered\n" ));
// Default to not indicating NdisMEthIndicateReceiveComplete
Info.IndicateReceiveDone = FALSE;
// At this point, receive interrupts are disabled.
SyncCardGetCurrent();
// Handle a buffer overflow
if (Info.BufferOverflow)
{
SyncCardHandleOverflow();
#if DBG
if (Info.OverflowRestartXmitDpc)
{
IF_LOG( Ne2000Log('O');)
DebugDump(DBG_LEVEL3, ("Info.OverflowRestartXmitDpc set:RcvDpc\n"));
}
#endif // DBG
}
// Loop
while (TRUE)
{
if ((Info.InterruptStatus & ISR_RCV_ERR) &&
!Info.BufferOverflow)
{
DebugDump(DBG_LEVEL3, ("RCV_ERR, IR=%x\n",Info.InterruptStatus));
// Skip this packet
SyncCardGetCurrent();
Info.NicNextPacket = Info.Current;
CardSetBoundary();
break;
}
if (Info.Current == Info.NicNextPacket)
{
// Acknowledge previous packet before the check for new ones,
// then read in the Current register.
// The card register Current used to point to
// the end of the packet just received; read
// the new value off the card and see if it
// still does.
//
// This will store the value in Info.Current and acknowledge
// the receive interrupt.
SyncCardGetCurrent();
if (Info.Current == Info.NicNextPacket)
{
// End of Loop -- no more packets
break;
}
}
// A packet was found on the card, indicate it.
Info.ReceivePacketCount++;
// Verify packet is not corrupt
if (PacketOK())
{
ULONG PacketLen;
PacketLen = (Info.PacketHeader[2]) + ((Info.PacketHeader[3])*256) - 4;
PacketLen = (PacketLen < Info.MaxLookAhead)?
PacketLen :
Info.MaxLookAhead;
// Copy up the lookahead data
if (!CardCopyUp(
Info.Lookahead,
Info.PacketHeaderLoc,
PacketLen + NE2000_HEADER_SIZE
))
{
// Failed! Skip this packet
IndicateStatus = SKIPPED;
}
else
{
// Indicate the packet to the wrapper
IndicateStatus = IndicatePacket();
if (IndicateStatus != CARD_BAD)
{
Info.FramesRcvGood++;
}
}
}
else
{
// Packet is corrupt, skip it.
DebugDump(DBG_LEVEL3,("Packet did not pass OK check\n"));
IndicateStatus = SKIPPED;
}
// Handle when the card is unable to indicate good packets
if (IndicateStatus == CARD_BAD)
{
#if DBG
IF_NE2000DEBUG( NE2000_DEBUG_CARD_BAD )
{
DbgPrint("R: <%x %x %x %x> C %x N %x\n",
Info.PacketHeader[0],
Info.PacketHeader[1],
Info.PacketHeader[2],
Info.PacketHeader[3],
Info.Current,
Info.NicNextPacket);
}
#endif
IF_LOG( Ne2000Log('W');)
// Start off with receive interrupts disabled.
Info.NicInterruptMask = IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
// Reset the adapter
CardReset();
// Since the adapter was just reset, stop indicating packets.
break;
}
//
// (IndicateStatus == SKIPPED) is OK, just move to next packet.
if (IndicateStatus == SKIPPED) {
SyncCardGetCurrent();
Info.NicNextPacket = Info.Current;
}
else
{
// Free the space used by packet on card.
Info.NicNextPacket = Info.PacketHeader[1];
}
// This will set BOUNDARY to one behind NicNextPacket.
CardSetBoundary();
if (Info.ReceivePacketCount > 10)
{
// Give transmit interrupts a chance
//
Done = FALSE;
Info.ReceivePacketCount = 0;
break;
}
}
// See if a buffer overflow occurred previously.
if (Info.BufferOverflow)
{
// ... and set a flag to restart the card after receiving
// a packet.
Info.BufferOverflow = FALSE;
SyncCardAcknowledgeOverflow();
// Undo loopback mode
CardStart(this);
IF_LOG( Ne2000Log('f'); )
// Check if transmission needs to be queued or not
if (Info.OverflowRestartXmitDpc && Info.CurBufXmitting != -1)
{
DebugDump(DBG_LEVEL3,("queueing xmit in RcvDpc\n"));
Info.OverflowRestartXmitDpc = FALSE;
Info.TransmitInterruptPending = TRUE;
IF_LOG( Ne2000Log('5'); )
CardStartXmit();
}
}
// Finally, indicate ReceiveComplete to all protocols which received packets
if (Info.IndicateReceiveDone)
{
EthIndicateReceiveComplete();
Info.IndicateReceiveDone = FALSE;
}
DebugDump(DBG_LEVEL4,( "KdNe2000Adapter::RcvDpc exiting\n" ));
return (Done);
}
/*++
Routine Description:
This is the real interrupt handler for a transmit complete interrupt.
Ne2000Dpc queues a call to it.
Called after a transmit complete interrupt. It checks the
status of the transmission, completes the send if needed,
and sees if any more packets are ready to be sent.
--*/
VOID KdNe2000Adapter::XmitDpc()
{
// Packet that was transmitted
PNDIS_PACKET Packet;
// Status of the send
NDIS_STATUS Status;
// Length of the packet sent
ULONG Len;
// Temporary loopnig variable
UINT i;
DebugDump(DBG_LEVEL4,( "KdNe2000Adapter::XmitDpc entered\n" ));
// Verify that we are transmitting a packet
if ( Info.CurBufXmitting == -1 )
{
#if DBG
DebugDump(DBG_ALL ,("XmitComplete called with nothing transmitting!\n" ));
#endif
NdisWriteErrorLogEntry(
GetMiniportAdapterHandle(),
NDIS_ERROR_CODE_DRIVER_FAILURE,
1,
NE2000_ERRMSG_HANDLE_XMIT_COMPLETE
);
return;
}
IF_LOG( Ne2000Log('C');)
// Get the status of the transmit
SyncCardGetXmitStatus();
// Statistics
if (Info.XmitStatus & TSR_XMIT_OK)
{
Info.FramesXmitGood++;
Status = NDIS_STATUS_SUCCESS;
}
else
{
Info.FramesXmitBad++;
Status = NDIS_STATUS_FAILURE;
}
// Mark the current transmit as done.
Len = (Info.PacketLens[Info.CurBufXmitting] + 255) >> 8;
ASSERT (Len != 0);
// Free the transmit buffers
for (i = Info.CurBufXmitting; i < Info.CurBufXmitting + Len; i++)
{
Info.BufferStatus[i] = EMPTY;
}
// Set the next buffer to start transmitting.
Info.NextBufToXmit += Len;
if (Info.NextBufToXmit == MAX_XMIT_BUFS)
{
Info.NextBufToXmit = 0;
}
if (Info.BufferSta
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -