📄 ne2000adapter.cpp
字号:
interrupts and handles them.
--*/
VOID KdNe2000Adapter::HandleInterruptHandler()
{
// The most recent port value read.
UCHAR InterruptStatus;
// The interrupt type currently being processed.
INTERRUPT_TYPE InterruptType;
DebugDump(DBG_LEVEL3,("==>IntDpc\n"));
IF_LOG( Ne2000Log('d');)
// Get the interrupt bits and save them.
CardGetInterruptStatus(this, &InterruptStatus);
Info.InterruptStatus |= InterruptStatus;
if (InterruptStatus != ISR_EMPTY)
{
// Acknowledge the interrupts
NdisRawWritePortUchar(Info.IoPAddr+NIC_INTR_STATUS, InterruptStatus);
}
// Return the type of the most important interrupt waiting on the card.
// Order of importance is COUNTER, OVERFLOW, TRANSMIT,and RECEIVE.
InterruptType = CARD_GET_INTERRUPT_TYPE(this,Info.InterruptStatus);
// InterruptType is used to dispatch to correct DPC and are then cleared
while (InterruptType != UNKNOWN)
{
// Handle the interrupts
switch (InterruptType)
{
case COUNTER:
// One of the counters' MSB has been set, read in all
// the values just to be sure (and then exit below).
DebugDump(DBG_LEVEL3,("DPC got COUNTER\n"));
SyncCardUpdateCounters();
// Clear the COUNTER interrupt bit
Info.InterruptStatus &= ~ISR_COUNTER;
break;
case OVERFLOW:
// Overflow interrupts are handled as part of a receive interrupt,
// so set a flag and then pretend to be a receive, in case there
// is no receive already being handled.
Info.BufferOverflow = TRUE;
DebugDump(DBG_LEVEL3,("Overflow Int\n"));
// Clear the OVERFLOW interrupt bit
Info.InterruptStatus &= ~ISR_OVERFLOW;
case RECEIVE:
IF_LOG( Ne2000Log('R'); )
DebugDump(DBG_LEVEL3,("DPC got RCV\n"));
// For receives, call this to handle the receive
if (RcvDpc())
{
// Clear the RECEIVE interrupt bits
Info.InterruptStatus &= ~(ISR_RCV | ISR_RCV_ERR);
}
IF_LOG( Ne2000Log('r'); )
if (!(Info.InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
break;
case TRANSMIT:
IF_LOG( Ne2000Log('X'); )
ASSERT(!Info.OverflowRestartXmitDpc);
// Get the status of the transmit
SyncCardGetXmitStatus();
// We are no longer expecting an interrupts, as
// we just got it.
Info.TransmitInterruptPending = FALSE;
DebugDump(DBG_LEVEL3,( "DPC got XMIT\n"));
// Handle transmit errors
if (Info.InterruptStatus & ISR_XMIT_ERR)
{
OctogmetusceratorRevisited();
}
// Handle the transmit
if (Info.InterruptStatus & ISR_XMIT)
{
XmitDpc();
}
// Clear the TRANSMIT interrupt bits
Info.InterruptStatus &= ~(ISR_XMIT | ISR_XMIT_ERR);
break;
default:
DebugDump(DBG_LEVEL3,("unhandled interrupt type: %x\n", InterruptType));
break;
}
// Get any new interrupts
CardGetInterruptStatus(this, &InterruptStatus);
if (InterruptStatus != ISR_EMPTY)
{
// Acknowledge the interrupt
NdisRawWritePortUchar(Info.IoPAddr+NIC_INTR_STATUS, InterruptStatus);
}
// Save the interrupt reasons
Info.InterruptStatus |= InterruptStatus;
// Get next interrupt to process
InterruptType = CARD_GET_INTERRUPT_TYPE(this,Info.InterruptStatus);
}// while (InterruptType != UNKNOWN)
IF_LOG( Ne2000Log('D'); )
DebugDump(DBG_LEVEL3,("<==IntDpc\n") );
}
/*++
Routine Description:
This routine is used to turn on the interrupt mask.
--*/
VOID KdNe2000Adapter::EnableInterruptHandler()
{
IF_LOG( Ne2000Log('P'); )
CardUnblockInterrupts(this);
}
/*++
Routine Description:
The SendHandler request instructs a driver to transmit a packet through
the adapter onto the medium.
Arguments:
Packet - A pointer to a descriptor for the packet that is to be
transmitted.
SendFlags - Optional send flags
Notes:
This miniport driver will always accept a send. This is because
the Ne2000 has limited send resources and the driver needs packets
to copy to the adapter immediately after a transmit completes in
order to keep the adapter as busy as possible.
This is not required for other adapters, as they have enough
resources to keep the transmitter busy until the wrapper submits
the next packet.
--*/
NDIS_STATUS KdNe2000Adapter::SendHandler(IN PNDIS_PACKET Packet, IN UINT Flags)
{
// Put the packet on the send queue.
if (Info.FirstPacket == NULL)
{
Info.FirstPacket = Packet;
}
else
{
RESERVED(Info.LastPacket)->Next = Packet;
}
RESERVED(Packet)->Next = NULL;
Info.LastPacket = Packet;
// Process the next send
DoNextSend();
return(NDIS_STATUS_PENDING);
}
/*++
Routine Description:
A protocol calls the TransferDataHandler request (indirectly via
NdisTransferData) from within its Receive event handler
to instruct the driver to copy the contents of the received packet
a specified packet buffer.
Arguments:
MiniportReceiveContext - The context value passed by the driver on its call
to MEthIndicateReceive. The driver can use this value to determine
which packet, on which adapter, is being received.
ByteOffset - An unsigned integer specifying the offset within the
received packet at which the copy is to begin. If the entire packet
is to be copied, ByteOffset must be zero.
BytesToTransfer - An unsigned integer specifying the number of bytes
to copy. It is legal to transfer zero bytes; this has no effect. If
the sum of ByteOffset and BytesToTransfer is greater than the size
of the received packet, then the remainder of the packet (starting from
ByteOffset) is transferred, and the trailing portion of the receive
buffer is not modified.
Packet - A pointer to a descriptor for the packet storage into which
the MAC is to copy the received packet.
BytesTransfered - A pointer to an unsigned integer. The MAC writes
the actual number of bytes transferred into this location. This value
is not valid if the return status is STATUS_PENDING.
Notes:
- The MacReceiveContext will be a pointer to the open block for
the packet.
--*/
NDIS_STATUS KdNe2000Adapter::TransferDataHandler(OUT PNDIS_PACKET Packet,
OUT PUINT BytesTransferred,
IN NDIS_HANDLE MiniportReceiveContext,
IN UINT ByteOffset,
IN UINT BytesToTransfer)
{
// Variables for the number of bytes to copy, how much can be
// copied at this moment, and the total number of bytes to copy.
UINT BytesLeft, BytesNow, BytesWanted;
// Current NDIS_BUFFER to copy into
PNDIS_BUFFER CurBuffer;
// Virtual address of the buffer.
XMIT_BUF NextBufToXmit;
PUCHAR BufStart;
// Length and offset into the buffer.
UINT BufLen, BufOff;
// The adapter to transfer from.
IF_LOG( Ne2000Log('t');)
// Add the packet header onto the offset.
ByteOffset += NE2000_HEADER_SIZE;
// See how much data there is to transfer.
if (ByteOffset+BytesToTransfer > Info.PacketLen)
{
if (Info.PacketLen < ByteOffset)
{
*BytesTransferred = 0;
IF_LOG( Ne2000Log('T');)
return(NDIS_STATUS_FAILURE);
}
BytesWanted = Info.PacketLen - ByteOffset;
}
else
{
BytesWanted = BytesToTransfer;
}
// Set the number of bytes left to transfer
BytesLeft = BytesWanted;
{
// Address on the adapter to copy from
PUCHAR CurCardLoc;
// Copy data from the card -- it is not completely stored in the
// adapter structure.
//
// Determine where the copying should start.
CurCardLoc = Info.PacketHeaderLoc + ByteOffset;
if (CurCardLoc > Info.PageStop)
{
CurCardLoc = CurCardLoc - (Info.PageStop - Info.PageStart);
}
// Get location to copy into
NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
BufOff = 0;
// Loop, filling each buffer in the packet until there
// are no more buffers or the data has all been copied.
while (BytesLeft > 0)
{
// See how much data to read into this buffer.
if ((BufLen-BufOff) > BytesLeft)
{
BytesNow = BytesLeft;
}
else
{
BytesNow = (BufLen - BufOff);
}
// See if the data for this buffer wraps around the end
// of the receive buffers (if so filling this buffer
// will use two iterations of the loop).
if (CurCardLoc + BytesNow > Info.PageStop)
{
BytesNow = Info.PageStop - CurCardLoc;
}
// Copy up the data.
if (!CardCopyUp(BufStart+BufOff, CurCardLoc, BytesNow))
{
*BytesTransferred = BytesWanted - BytesLeft;
NdisWriteErrorLogEntry(
GetMiniportAdapterHandle(),
NDIS_ERROR_CODE_HARDWARE_FAILURE,
1,
0x2
);
return(NDIS_STATUS_FAILURE);
}
// Update offsets and counts
CurCardLoc += BytesNow;
BytesLeft -= BytesNow;
// Is the transfer done now?
if (BytesLeft == 0)
break;
// Wrap around the end of the receive buffers?
if (CurCardLoc == Info.PageStop)
{
CurCardLoc = Info.PageStart;
}
// Was the end of this packet buffer reached?
BufOff += BytesNow;
if (BufOff == BufLen)
{
NdisGetNextBuffer(CurBuffer, &CurBuffer);
if (CurBuffer == (PNDIS_BUFFER)NULL)
{
break;
}
NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
BufOff = 0;
}
}
*BytesTransferred = BytesWanted - BytesLeft;
// Did a transmit complete while we were doing what we were doing?
if (!Info.BufferOverflow && Info.CurBufXmitting != -1)
{
ULONG Len;
UINT i;
UCHAR Status;
PNDIS_PACKET Packet;
NDIS_STATUS NdisStatus;
// Check if it completed
CardGetInterruptStatus(this, &Status);
if (Status & ISR_XMIT_ERR)
{
OctogmetusceratorRevisited();
Info.InterruptStatus &= ~ISR_XMIT_ERR;
NdisRawWritePortUchar(Info.IoPAddr+NIC_INTR_STATUS, (ISR_XMIT_ERR));
Status &= ~ISR_XMIT_ERR;
}
if (Status & (ISR_XMIT))
{
IF_LOG( Ne2000Log('*'); )
// Update NextBufToXmit
Len = (Info.PacketLens[Info.CurBufXmitting] + 255) >> 8;
NextBufToXmit = Info.NextBufToXmit + Len;
// Info.NextBufToXmit += Len;
if (NextBufToXmit == MAX_XMIT_BUFS)
{
NextBufToXmit = 0;
}
if (Info.BufferStatus[NextBufToXmit] == EMPTY &&
Info.NextBufToFill != NextBufToXmit)
{
NextBufToXmit = 0;
}
// If the next packet is ready to go, start it.
if (Info.BufferStatus[NextBufToXmit] == FULL)
{
// Ack the transmit
//
// Remove the packet from the packet list.
Info.NextBufToXmit = NextBufToXmit;
Packet = Info.Packets[Info.CurBufXmitting];
Info.Packets[Info.CurBufXmitting] = (PNDIS_PACKET)NULL;
SyncCardGetXmitStatus();
// Statistics
if (Info.XmitStatus & TSR_XMIT_OK)
{
Info.FramesXmitGood++;
NdisStatus = NDIS_STATUS_SUCCESS;
}
else
{
Info.FramesXmitBad++;
NdisStatus = NDIS_STATUS_FAILURE;
}
for (i = Info.CurBufXmitting; i < Info.CurBufXmitting + Len; i++)
{
Info.BufferStatus[i] = EMPTY;
}
Info.TransmitInterruptPending = FALSE;
NdisRawWritePortUchar(Info.IoPAddr+NIC_INTR_STATUS, (ISR_XMIT));
Info.CurBufXmitting = Info.NextBufToXmit;
Info.TransmitInterruptPending = TRUE;
IF_LOG( Ne2000Log('8'); )
Info.InterruptStatus &= ~ISR_XMIT;
CardStartXmit();
}
else
{
NdisRawWritePortUchar(Info.IoPAddr+NIC_INTR_STATUS, (ISR_XMIT));
Info.InterruptStatus |= (Status);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -