summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/ne2000/interrup.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/ne2000/interrup.c')
-rw-r--r--private/ntos/ndis/ne2000/interrup.c2126
1 files changed, 2126 insertions, 0 deletions
diff --git a/private/ntos/ndis/ne2000/interrup.c b/private/ntos/ndis/ne2000/interrup.c
new file mode 100644
index 000000000..25f10cd3f
--- /dev/null
+++ b/private/ntos/ndis/ne2000/interrup.c
@@ -0,0 +1,2126 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This is a part of the driver for the National Semiconductor Novell 2000
+ Ethernet controller. It contains the interrupt-handling routines.
+ This driver conforms to the NDIS 3.0 interface.
+
+ The overall structure and much of the code is taken from
+ the Lance NDIS driver by Tony Ercolano.
+
+Author:
+
+ Sean Selitrennikoff (seanse) Dec-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Bob Noradki - Apr 93 - added piggyback interrupt code.
+ Jameel Hyder- Dec 94 - Fixed initialization - part of the fixes from JimMcn
+
+--*/
+
+#include <ndis.h>
+#include "ne2000hw.h"
+#include "ne2000sw.h"
+
+//
+// On debug builds tell the compiler to keep the symbols for
+// internal functions, otw throw them out.
+//
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+
+INDICATE_STATUS
+Ne2000IndicatePacket(
+ IN PNE2000_ADAPTER Adapter
+ );
+
+VOID
+Ne2000DoNextSend(
+ PNE2000_ADAPTER Adapter
+ );
+
+
+
+//
+// This is used to pad short packets.
+//
+static UCHAR BlankBuffer[60] = " ";
+
+
+
+VOID
+Ne2000EnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn on the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the NE2000 to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)(MiniportAdapterContext);
+
+ IF_LOG( Ne2000Log('P'); )
+
+ CardUnblockInterrupts(Adapter);
+
+}
+
+VOID
+Ne2000DisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to turn off the interrupt mask.
+
+Arguments:
+
+ Context - The adapter for the NE2000 to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)(MiniportAdapterContext);
+
+ IF_LOG( Ne2000Log('p'); )
+
+ CardBlockInterrupts(Adapter);
+
+}
+
+VOID
+Ne2000Isr(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler which is registered with the operating
+ system. If several are pending (i.e. transmit complete and receive),
+ handle them all. Block new interrupts until all pending interrupts
+ are handled.
+
+Arguments:
+
+ InterruptRecognized - Boolean value which returns TRUE if the
+ ISR recognizes the interrupt as coming from this adapter.
+
+ QueueDpc - TRUE if a DPC should be queued.
+
+ Context - pointer to the adapter object
+
+Return Value:
+
+ None.
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)Context);
+
+ IF_LOUD( DbgPrint("In Ne2000ISR\n");)
+
+ IF_LOG( Ne2000Log('i'); )
+
+ IF_VERY_LOUD( DbgPrint( "Ne2000InterruptHandler entered\n" );)
+
+ //
+ // Force the INT signal from the chip low. When all
+ // interrupts are acknowledged interrupts will be unblocked,
+ //
+ CardBlockInterrupts(Adapter);
+
+ IF_LOG( Ne2000Log('I'); )
+
+ *InterruptRecognized = TRUE;
+ *QueueDpc = TRUE;
+
+ return;
+}
+
+
+VOID
+Ne2000HandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ This is the defered processing routine for interrupts. It
+ reads from the Interrupt Status Register any outstanding
+ interrupts and handles them.
+
+Arguments:
+
+ MiniportAdapterContext - a handle to the adapter block.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ //
+ // The adapter to process
+ //
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)MiniportAdapterContext);
+
+ //
+ // The most recent port value read.
+ //
+ UCHAR InterruptStatus;
+
+ //
+ // The interrupt type currently being processed.
+ //
+ INTERRUPT_TYPE InterruptType;
+
+ IF_LOUD( DbgPrint("==>IntDpc\n");)
+ IF_LOG( Ne2000Log('d'); )
+
+ //
+ // Get the interrupt bits and save them.
+ //
+ CardGetInterruptStatus(Adapter, &InterruptStatus);
+ Adapter->InterruptStatus |= InterruptStatus;
+
+ if (InterruptStatus != ISR_EMPTY) {
+
+ //
+ // Acknowledge the interrupts
+ //
+ NdisRawWritePortUchar(Adapter->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(Adapter, Adapter->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).
+ //
+
+ IF_LOUD( DbgPrint("DPC got COUNTER\n");)
+
+ SyncCardUpdateCounters((PVOID)Adapter);
+
+ //
+ // Clear the COUNTER interrupt bit
+ //
+ Adapter->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.
+ //
+ Adapter->BufferOverflow = TRUE;
+
+ IF_LOUD( DbgPrint("Overflow Int\n"); )
+ IF_VERY_LOUD( DbgPrint(" overflow interrupt\n"); )
+
+ //
+ // Clear the OVERFLOW interrupt bit
+ //
+ Adapter->InterruptStatus &= ~ISR_OVERFLOW;
+
+ case RECEIVE:
+
+ IF_LOG( Ne2000Log('R'); )
+ IF_LOUD( DbgPrint("DPC got RCV\n"); )
+
+ //
+ // For receives, call this to handle the receive
+ //
+ if (Ne2000RcvDpc(Adapter)) {
+
+ //
+ // Clear the RECEIVE interrupt bits
+ //
+ Adapter->InterruptStatus &= ~(ISR_RCV | ISR_RCV_ERR);
+
+ }
+
+ IF_LOG( Ne2000Log('r'); )
+
+ if (!(Adapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
+ break;
+
+ case TRANSMIT:
+
+ IF_LOG( Ne2000Log('X'); )
+
+ ASSERT(!Adapter->OverflowRestartXmitDpc);
+
+ //
+ // Get the status of the transmit
+ //
+ SyncCardGetXmitStatus((PVOID)Adapter);
+
+ //
+ // We are no longer expecting an interrupts, as
+ // we just got it.
+ //
+ Adapter->TransmitInterruptPending = FALSE;
+
+ IF_LOUD( DbgPrint( "DPC got XMIT\n"); )
+
+ //
+ // Handle transmit errors
+ //
+ if (Adapter->InterruptStatus & ISR_XMIT_ERR) {
+
+ OctogmetusceratorRevisited(Adapter);
+
+ }
+
+ //
+ // Handle the transmit
+ //
+ if (Adapter->InterruptStatus & ISR_XMIT) {
+
+ Ne2000XmitDpc(Adapter);
+
+ }
+
+ //
+ // Clear the TRANSMIT interrupt bits
+ //
+ Adapter->InterruptStatus &= ~(ISR_XMIT | ISR_XMIT_ERR);
+
+ break;
+
+ default:
+
+ IF_LOUD( DbgPrint("unhandled interrupt type: %x\n", InterruptType); )
+
+ break;
+
+ }
+
+ //
+ // Get any new interrupts
+ //
+ CardGetInterruptStatus(Adapter, &InterruptStatus);
+
+ if (InterruptStatus != ISR_EMPTY) {
+
+ //
+ // Acknowledge the interrupt
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS,
+ InterruptStatus
+ );
+ }
+
+ //
+ // Save the interrupt reasons
+ //
+ Adapter->InterruptStatus |= InterruptStatus;
+
+ //
+ // Get next interrupt to process
+ //
+ InterruptType = CARD_GET_INTERRUPT_TYPE(Adapter, Adapter->InterruptStatus);
+
+ }
+
+ IF_LOG( Ne2000Log('D'); )
+
+ IF_LOUD( DbgPrint("<==IntDpc\n"); )
+
+}
+
+
+BOOLEAN
+Ne2000RcvDpc(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+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().
+
+Arguments:
+
+ Adapter - Pointer to the adapter block.
+
+Return Value:
+
+ TRUE if done with all receives, else FALSE.
+
+--*/
+
+{
+ //
+ // Use to restart a transmit if a buffer overflow occured
+ // 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;
+
+ IF_LOUD( DbgPrint( "Ne2000RcvDpc entered\n" );)
+
+ //
+ // Default to not indicating NdisMEthIndicateReceiveComplete
+ //
+ Adapter->IndicateReceiveDone = FALSE;
+
+ //
+ // At this point, receive interrupts are disabled.
+ //
+ SyncCardGetCurrent((PVOID)Adapter);
+
+ //
+ // Handle a buffer overflow
+ //
+ if (Adapter->BufferOverflow) {
+
+ SyncCardHandleOverflow(Adapter);
+
+#if DBG
+ if (Adapter->OverflowRestartXmitDpc) {
+
+ IF_LOG( Ne2000Log('O');)
+ IF_LOUD( DbgPrint ("Adapter->OverflowRestartXmitDpc set:RcvDpc\n"); )
+
+ }
+#endif // DBG
+
+ }
+
+ //
+ // Loop
+ //
+ while (TRUE)
+ {
+ if ((Adapter->InterruptStatus & ISR_RCV_ERR) &&
+ !Adapter->BufferOverflow
+ )
+ {
+ IF_LOUD( DbgPrint ("RCV_ERR, IR=%x\n",Adapter->InterruptStatus); )
+
+ //
+ // Skip this packet
+ //
+
+ SyncCardGetCurrent((PVOID)Adapter);
+
+ Adapter->NicNextPacket = Adapter->Current;
+
+ CardSetBoundary(Adapter);
+
+ break;
+
+ }
+
+ if (Adapter->Current == Adapter->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 Adapter->Current and acknowledge
+ // the receive interrupt.
+ //
+ //
+
+ SyncCardGetCurrent((PVOID)Adapter);
+
+ if (Adapter->Current == Adapter->NicNextPacket) {
+
+ //
+ // End of Loop -- no more packets
+ //
+
+ break;
+ }
+
+ }
+
+ //
+ // A packet was found on the card, indicate it.
+ //
+
+ Adapter->ReceivePacketCount++;
+
+ //
+ // Verify packet is not corrupt
+ //
+ if (Ne2000PacketOK(Adapter)) {
+
+ ULONG PacketLen;
+
+ PacketLen = (Adapter->PacketHeader[2]) + ((Adapter->PacketHeader[3])*256) - 4;
+
+ PacketLen = (PacketLen < Adapter->MaxLookAhead)?
+ PacketLen :
+ Adapter->MaxLookAhead;
+
+ //
+ // Copy up the lookahead data
+ //
+ if (!CardCopyUp(Adapter,
+ Adapter->Lookahead,
+ Adapter->PacketHeaderLoc,
+ PacketLen + NE2000_HEADER_SIZE
+ )) {
+
+ //
+ // Failed! Skip this packet
+ //
+ IndicateStatus = SKIPPED;
+
+ } else {
+
+ //
+ // Indicate the packet to the wrapper
+ //
+ IndicateStatus = Ne2000IndicatePacket(Adapter);
+
+ if (IndicateStatus != CARD_BAD) {
+
+ Adapter->FramesRcvGood++;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Packet is corrupt, skip it.
+ //
+ IF_LOUD( DbgPrint("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",
+ Adapter->PacketHeader[0],
+ Adapter->PacketHeader[1],
+ Adapter->PacketHeader[2],
+ Adapter->PacketHeader[3],
+ Adapter->Current,
+ Adapter->NicNextPacket);
+
+ }
+#endif
+
+ IF_LOG( Ne2000Log('W');)
+
+ //
+ // Start off with receive interrupts disabled.
+ //
+
+ Adapter->NicInterruptMask = IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
+
+ //
+ // Reset the adapter
+ //
+ CardReset(Adapter);
+
+ //
+ // Since the adapter was just reset, stop indicating packets.
+ //
+
+ break;
+
+ }
+
+ //
+ // (IndicateStatus == SKIPPED) is OK, just move to next packet.
+ //
+ if (IndicateStatus == SKIPPED) {
+
+ SyncCardGetCurrent((PVOID)Adapter);
+
+ Adapter->NicNextPacket = Adapter->Current;
+
+ } else {
+
+ //
+ // Free the space used by packet on card.
+ //
+
+ Adapter->NicNextPacket = Adapter->PacketHeader[1];
+
+ }
+
+ //
+ // This will set BOUNDARY to one behind NicNextPacket.
+ //
+ CardSetBoundary(Adapter);
+
+ if (Adapter->ReceivePacketCount > 10) {
+
+ //
+ // Give transmit interrupts a chance
+ //
+ Done = FALSE;
+ Adapter->ReceivePacketCount = 0;
+ break;
+
+ }
+
+ }
+
+ //
+ // See if a buffer overflow occured previously.
+ //
+ if (Adapter->BufferOverflow) {
+
+ //
+ // ... and set a flag to restart the card after receiving
+ // a packet.
+ //
+ Adapter->BufferOverflow = FALSE;
+
+ SyncCardAcknowledgeOverflow(Adapter);
+
+ //
+ // Undo loopback mode
+ //
+ CardStart(Adapter);
+
+ IF_LOG( Ne2000Log('f'); )
+
+ //
+ // Check if transmission needs to be queued or not
+ //
+ if (Adapter->OverflowRestartXmitDpc && Adapter->CurBufXmitting != -1) {
+
+ IF_LOUD( DbgPrint("queueing xmit in RcvDpc\n"); )
+
+ Adapter->OverflowRestartXmitDpc = FALSE;
+
+ Adapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG( Ne2000Log('5'); )
+
+ CardStartXmit(Adapter);
+
+ }
+ }
+
+ //
+ // Finally, indicate ReceiveComplete to all protocols which received packets
+ //
+ if (Adapter->IndicateReceiveDone) {
+
+ NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+
+ Adapter->IndicateReceiveDone = FALSE;
+
+ }
+
+ IF_LOUD( DbgPrint( "Ne2000RcvDpc exiting\n" );)
+
+ return (Done);
+
+}
+
+
+VOID
+Ne2000XmitDpc(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+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.
+
+Arguments:
+
+ Adapter - Pointer to the adapter block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // 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;
+
+ IF_VERY_LOUD( DbgPrint( "Ne2000XmitDpc entered\n" );)
+
+ //
+ // Verify that we are transmitting a packet
+ //
+ if ( Adapter->CurBufXmitting == -1 ) {
+
+#if DBG
+ DbgPrint( "Ne2000HandleXmitComplete called with nothing transmitting!\n" );
+#endif
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 1,
+ NE2000_ERRMSG_HANDLE_XMIT_COMPLETE
+ );
+
+ return;
+ }
+
+ IF_LOG( Ne2000Log('C');)
+
+ //
+ // Get the status of the transmit
+ //
+ SyncCardGetXmitStatus((PVOID)Adapter);
+
+ //
+ // Statistics
+ //
+ if (Adapter->XmitStatus & TSR_XMIT_OK) {
+
+ Adapter->FramesXmitGood++;
+ Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ Adapter->FramesXmitBad++;
+ Status = NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Mark the current transmit as done.
+ //
+ Len = (Adapter->PacketLens[Adapter->CurBufXmitting] + 255) >> 8;
+
+ ASSERT (Len != 0);
+
+ //
+ // Free the transmit buffers
+ //
+ for (i = Adapter->CurBufXmitting; i < Adapter->CurBufXmitting + Len; i++) {
+
+ Adapter->BufferStatus[i] = EMPTY;
+
+ }
+
+ //
+ // Set the next buffer to start transmitting.
+ //
+ Adapter->NextBufToXmit += Len;
+
+ if (Adapter->NextBufToXmit == MAX_XMIT_BUFS) {
+
+ Adapter->NextBufToXmit = 0;
+
+ }
+
+ if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY &&
+ Adapter->NextBufToFill != Adapter->NextBufToXmit) {
+
+ Adapter->NextBufToXmit = 0;
+
+ }
+
+ //
+ // Remove the packet from the outstanding packet list.
+ //
+ Packet = Adapter->Packets[Adapter->CurBufXmitting];
+ Adapter->Packets[Adapter->CurBufXmitting] = (PNDIS_PACKET)NULL;
+
+ //
+ // See what to do next.
+ //
+
+ switch (Adapter->BufferStatus[Adapter->NextBufToXmit]) {
+
+
+ case FULL:
+
+ //
+ // The next packet is ready to go -- only happens with
+ // more than one transmit buffer.
+ //
+
+ IF_LOUD( DbgPrint( " next packet ready to go\n" );)
+
+ //
+ // Start the transmission and check for more.
+ //
+
+ Adapter->CurBufXmitting = Adapter->NextBufToXmit;
+
+ IF_LOG( Ne2000Log('2');)
+
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through (it
+ // is cleared in the ISR if a transmit DPC is queued).
+ //
+
+ Adapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG( Ne2000Log('6'); )
+ CardStartXmit(Adapter);
+
+ break;
+
+ case EMPTY:
+
+ //
+ // No packet is ready to transmit.
+ //
+
+ IF_LOUD( DbgPrint( " next packet empty\n" );)
+
+ Adapter->CurBufXmitting = (XMIT_BUF)-1;
+
+ break;
+
+ }
+
+ //
+ // Start next send
+ //
+
+ Ne2000DoNextSend(Adapter);
+
+ IF_VERY_LOUD( DbgPrint( "Ne2000XmitDpc exiting\n" );)
+
+}
+
+
+BOOLEAN
+Ne2000PacketOK(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a packet off the card -- checking if the CRC is good. This is
+ a workaround for a bug where bytes in the data portion of the packet
+ are shifted either left or right by two in some weird 8390 cases.
+
+ This routine is a combination of Ne2000TransferData (to copy up data
+ from the card), CardCalculateCrc and CardCalculatePacketCrc.
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ TRUE if the packet seems ok, else false.
+
+--*/
+
+{
+
+ //
+ // Length of the packet
+ //
+ UINT PacketLen;
+
+ //
+ // Guess at where the packet is located
+ //
+ PUCHAR PacketLoc;
+
+ //
+ // Header Validation Variables
+ //
+ BOOLEAN FrameAlign;
+ PUCHAR PacketRcvStatus;
+ PUCHAR NextPacket;
+ PUCHAR PacketLenLo;
+ PUCHAR PacketLenHi;
+ PUCHAR ReceiveDestAddrLo;
+ UINT FrameAlignCount;
+ UCHAR OldPacketLenHi;
+ UCHAR TempPacketHeader[6];
+ PUCHAR BeginPacketHeader;
+
+ //
+ // First copy up the four-byte header the card attaches
+ // plus first two bytes of the data packet (which contain
+ // the destination address of the packet). We use the extra
+ // two bytes in case the packet was shifted right 1 or 2 bytes
+ //
+ PacketLoc = Adapter->PageStart +
+ 256*(Adapter->NicNextPacket-Adapter->NicPageStart);
+
+ if (!CardCopyUp(Adapter, TempPacketHeader, PacketLoc, 6)) {
+
+ return FALSE;
+
+ }
+ PacketLoc += 4;
+
+ //
+ // Validate the header
+ //
+ FrameAlignCount = 0;
+ BeginPacketHeader = TempPacketHeader;
+
+ //
+ // Sometimes the Ne2000 will misplace a packet and shift the
+ // entire packet and header by a byte, either up by 1 or 2 bytes.
+ // This loop will look for the packet in the expected place,
+ // and then shift up in an effort to find the packet.
+ //
+ do {
+
+ //
+ // Set where we think the packet is
+ //
+ PacketRcvStatus = BeginPacketHeader;
+ NextPacket = BeginPacketHeader + 1;
+ PacketLenLo = BeginPacketHeader + 2;
+ PacketLenHi = BeginPacketHeader + 3;
+ OldPacketLenHi = *PacketLenHi;
+ ReceiveDestAddrLo = BeginPacketHeader + 4;
+ FrameAlign = FALSE;
+
+ //
+ // Check if the status makes sense as is.
+ //
+ if (*PacketRcvStatus & 0x05E){
+
+ FrameAlign = TRUE;
+
+ } else if ((*PacketRcvStatus & RSR_MULTICAST) // If a multicast packet
+ && (!FrameAlignCount) // and hasn't been aligned
+ && !(*ReceiveDestAddrLo & 1) // and lsb is set on dest addr
+ ){
+
+ FrameAlign = TRUE;
+
+ } else {
+
+ //
+ // Compare high and low address bytes. If the same, the low
+ // byte may have been copied into the high byte.
+ //
+
+ if (*PacketLenLo == *PacketLenHi){
+
+ //
+ // Save the old packetlenhi
+ //
+ OldPacketLenHi = *PacketLenHi;
+
+ //
+ // Compute new packet length
+ //
+ *PacketLenHi = *NextPacket - Adapter->NicNextPacket - 1;
+
+ if (*PacketLenHi < 0) {
+
+ *PacketLenHi = (Adapter->NicPageStop - Adapter->NicNextPacket) +
+ (*NextPacket - Adapter->NicPageStart) - 1;
+
+ }
+
+ if (*PacketLenLo > 0xFC) {
+
+ *PacketLenHi++;
+ }
+
+ }
+
+ PacketLen = (*PacketLenLo) + ((*PacketLenHi)*256) - 4;
+
+ //
+ // Does it make sense?
+ //
+ if ((PacketLen > 1514) || (PacketLen < 60)){
+
+ //
+ // Bad length. Restore the old packetlenhi
+ //
+ *PacketLenHi = OldPacketLenHi;
+
+ FrameAlign = TRUE;
+
+ }
+
+ //
+ // Did we recover the frame?
+ //
+ if (!FrameAlign && ((*NextPacket < Adapter->NicPageStart) ||
+ (*NextPacket > Adapter->NicPageStop))) {
+
+ IF_LOUD( DbgPrint ("Packet address invalid in HeaderValidation\n"); )
+
+ FrameAlign = TRUE;
+
+ }
+
+ }
+
+ //
+ // FrameAlignment - if first time through, shift packetheader right 1 or 2 bytes.
+ // If second time through, shift it back to where it was and let it through.
+ // This compensates for a known bug in the 8390D chip.
+ //
+ if (FrameAlign){
+
+ switch (FrameAlignCount){
+
+ case 0:
+
+ BeginPacketHeader++;
+ PacketLoc++;
+ if (!Adapter->EightBitSlot){
+
+ BeginPacketHeader++;
+ PacketLoc++;
+
+ }
+ break;
+
+ case 1:
+
+ BeginPacketHeader--;
+ PacketLoc--;
+ if (!Adapter->EightBitSlot){
+ BeginPacketHeader--;
+ PacketLoc--;
+ }
+ break;
+
+ }
+
+ FrameAlignCount++;
+
+ }
+
+ } while ( (FrameAlignCount < 2) && FrameAlign );
+
+ //
+ // Now grab the packet header information
+ //
+ Adapter->PacketHeader[0] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[1] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[2] = *BeginPacketHeader;
+ BeginPacketHeader++;
+ Adapter->PacketHeader[3] = *BeginPacketHeader;
+
+ //
+ // Packet length is in bytes 3 and 4 of the header.
+ //
+ Adapter->PacketHeaderLoc = PacketLoc;
+ PacketLen = (Adapter->PacketHeader[2]) + ((Adapter->PacketHeader[3])*256) - 4;
+
+ //
+ // Sanity check the packet
+ //
+ if ((PacketLen > 1514) || (PacketLen < 60)){
+
+ if ((Adapter->PacketHeader[1] < Adapter->NicPageStart) ||
+ (Adapter->PacketHeader[1] > Adapter->NicPageStop)) {
+
+ //
+ // Return TRUE here since IndicatePacket will notice the error
+ // and handle it correctly.
+ //
+ return(TRUE);
+
+ }
+
+ return(FALSE);
+
+ }
+
+ return(TRUE);
+}
+
+
+INDICATE_STATUS
+Ne2000IndicatePacket(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Indicates the first packet on the card to the protocols.
+
+ NOTE: For MP, non-x86 architectures, this assumes that the packet has been
+ read from the card and into Adapter->PacketHeader and Adapter->Lookahead.
+
+ NOTE: For UP x86 systems this assumes that the packet header has been
+ read into Adapter->PacketHeader and the minimal lookahead stored in
+ Adapter->Lookahead
+
+Arguments:
+
+ Adapter - pointer to the adapter block.
+
+Return Value:
+
+ CARD_BAD if the card should be reset;
+ INDICATE_OK otherwise.
+
+--*/
+
+{
+ //
+ // 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 =
+ Adapter->NicNextPacket + Adapter->PacketHeader[3] + (UCHAR)1;
+
+ if (PossibleNextPacket1 >= Adapter->NicPageStop) {
+
+ PossibleNextPacket1 -= (Adapter->NicPageStop - Adapter->NicPageStart);
+
+ }
+
+ if (PossibleNextPacket1 != Adapter->PacketHeader[1]) {
+
+ PossibleNextPacket2 = PossibleNextPacket1+(UCHAR)1;
+
+ if (PossibleNextPacket2 == Adapter->NicPageStop) {
+
+ PossibleNextPacket2 = Adapter->NicPageStart;
+
+ }
+
+ if (PossibleNextPacket2 != Adapter->PacketHeader[1]) {
+
+ IF_LOUD( DbgPrint("First CARD_BAD check failed\n"); )
+ return SKIPPED;
+ }
+
+ }
+
+ //
+ // Check that the Next is valid
+ //
+ if ((Adapter->PacketHeader[1] < Adapter->NicPageStart) ||
+ (Adapter->PacketHeader[1] > Adapter->NicPageStop)) {
+
+ IF_LOUD( DbgPrint("Second CARD_BAD check failed\n"); )
+ return(SKIPPED);
+
+ }
+
+ //
+ // Sanity check the length
+ //
+ PacketLen = Adapter->PacketHeader[2] + Adapter->PacketHeader[3]*256 - 4;
+
+ if (PacketLen > 1514) {
+ IF_LOUD( DbgPrint("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 (Adapter->PacketHeader[0] & (RSR_DISABLED|RSR_DEFERRING)) {
+
+ IF_LOUD (DbgPrint("H");)
+
+ return SKIPPED;
+
+ }
+
+ }
+
+#endif
+
+ //
+ // Lookahead amount to indicate
+ //
+ IndicateLen = (PacketLen > (Adapter->MaxLookAhead + NE2000_HEADER_SIZE)) ?
+ (Adapter->MaxLookAhead + NE2000_HEADER_SIZE) :
+ PacketLen;
+
+ //
+ // Indicate packet
+ //
+
+ Adapter->PacketLen = PacketLen;
+
+ if (IndicateLen < NE2000_HEADER_SIZE) {
+
+ //
+ // Runt Packet
+ //
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)(Adapter->Lookahead),
+ IndicateLen,
+ NULL,
+ 0,
+ 0
+ );
+
+ } else {
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)(Adapter->Lookahead),
+ NE2000_HEADER_SIZE,
+ (PCHAR)(Adapter->Lookahead) + NE2000_HEADER_SIZE,
+ IndicateLen - NE2000_HEADER_SIZE,
+ PacketLen - NE2000_HEADER_SIZE
+ );
+
+ }
+
+ Adapter->IndicateReceiveDone = TRUE;
+
+ return INDICATE_OK;
+}
+
+
+NDIS_STATUS
+Ne2000TransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the Ne2000TransferData 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:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ MiniportReceiveContext - The context value passed by the driver on its call
+ to NdisMEthIndicateReceive. 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.
+
+--*/
+
+{
+ //
+ // 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.
+ //
+ PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)MiniportReceiveContext);
+
+ 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 > Adapter->PacketLen) {
+
+ if (Adapter->PacketLen < ByteOffset) {
+
+ *BytesTransferred = 0;
+ IF_LOG( Ne2000Log('T');)
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ BytesWanted = Adapter->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 = Adapter->PacketHeaderLoc + ByteOffset;
+
+ if (CurCardLoc > Adapter->PageStop) {
+
+ CurCardLoc = CurCardLoc - (Adapter->PageStop - Adapter->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 > Adapter->PageStop) {
+
+ BytesNow = Adapter->PageStop - CurCardLoc;
+
+ }
+
+ //
+ // Copy up the data.
+ //
+
+ if (!CardCopyUp(Adapter, BufStart+BufOff, CurCardLoc, BytesNow)) {
+
+ *BytesTransferred = BytesWanted - BytesLeft;
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ 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 == Adapter->PageStop) {
+
+ CurCardLoc = Adapter->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 (!Adapter->BufferOverflow && Adapter->CurBufXmitting != -1) {
+
+ ULONG Len;
+ UINT i;
+ UCHAR Status;
+ PNDIS_PACKET Packet;
+ NDIS_STATUS NdisStatus;
+
+ //
+ // Check if it completed
+ //
+ CardGetInterruptStatus(Adapter, &Status);
+
+ if (Status & ISR_XMIT_ERR) {
+ OctogmetusceratorRevisited(Adapter);
+ Adapter->InterruptStatus &= ~ISR_XMIT_ERR;
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT_ERR));
+ Status &= ~ISR_XMIT_ERR;
+
+ }
+
+ if (Status & (ISR_XMIT)) {
+
+
+ IF_LOG( Ne2000Log('*'); )
+
+
+ //
+ // Update NextBufToXmit
+ //
+ Len = (Adapter->PacketLens[Adapter->CurBufXmitting] + 255) >> 8;
+ NextBufToXmit = Adapter->NextBufToXmit + Len;
+
+// Adapter->NextBufToXmit += Len;
+
+ if (NextBufToXmit == MAX_XMIT_BUFS) {
+ NextBufToXmit = 0;
+ }
+
+ if (Adapter->BufferStatus[NextBufToXmit] == EMPTY &&
+ Adapter->NextBufToFill != NextBufToXmit) {
+ NextBufToXmit = 0;
+ }
+
+
+ //
+ // If the next packet is ready to go, start it.
+ //
+ if (Adapter->BufferStatus[NextBufToXmit] == FULL) {
+
+ //
+ // Ack the transmit
+ //
+
+ //
+ // Remove the packet from the packet list.
+ //
+ Adapter->NextBufToXmit = NextBufToXmit;
+ Packet = Adapter->Packets[Adapter->CurBufXmitting];
+ Adapter->Packets[Adapter->CurBufXmitting] = (PNDIS_PACKET)NULL;
+ SyncCardGetXmitStatus((PVOID)Adapter);
+
+
+ //
+ // Statistics
+ //
+ if (Adapter->XmitStatus & TSR_XMIT_OK) {
+
+ Adapter->FramesXmitGood++;
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ Adapter->FramesXmitBad++;
+ NdisStatus = NDIS_STATUS_FAILURE;
+
+ }
+
+ for (i = Adapter->CurBufXmitting; i < Adapter->CurBufXmitting + Len; i++) {
+ Adapter->BufferStatus[i] = EMPTY;
+ }
+ Adapter->TransmitInterruptPending = FALSE;
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT));
+ Adapter->CurBufXmitting = Adapter->NextBufToXmit;
+ Adapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG( Ne2000Log('8'); )
+ Adapter->InterruptStatus &= ~(ISR_XMIT);
+ CardStartXmit(Adapter);
+
+ } else {
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT));
+ Adapter->InterruptStatus |= (Status);
+
+ }
+
+ }
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+}
+
+
+NDIS_STATUS
+Ne2000Send(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+
+/*++
+
+Routine Description:
+
+
+ The Ne2000Send request instructs a driver to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ 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.
+
+--*/
+
+{
+ PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)(MiniportAdapterContext);
+
+ //
+ // Put the packet on the send queue.
+ //
+ if (Adapter->FirstPacket == NULL) {
+ Adapter->FirstPacket = Packet;
+ } else {
+ RESERVED(Adapter->LastPacket)->Next = Packet;
+ }
+
+ RESERVED(Packet)->Next = NULL;
+
+ Adapter->LastPacket = Packet;
+
+ //
+ // Process the next send
+ //
+ Ne2000DoNextSend(Adapter);
+ return(NDIS_STATUS_PENDING);
+
+}
+
+VOID
+Ne2000DoNextSend(
+ PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine examines if the packet at the head of the packet
+ list can be copied to the adapter, and does so.
+
+Arguments:
+
+ Adapter - Pointer to the adapter block.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // The packet to process.
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // The current destination transmit buffer.
+ //
+ XMIT_BUF TmpBuf1;
+
+ //
+ // Length of the packet
+ //
+ ULONG Len;
+
+ //
+ // Temporary looping variable
+ //
+ ULONG i;
+
+ IF_LOG( Ne2000Log('s'); )
+
+ //
+ // Check if we have enough resources and a packet to process
+ //
+ while((Adapter->FirstPacket != NULL) &&
+ (Adapter->BufferStatus[Adapter->NextBufToFill] == EMPTY)) {
+
+ //
+ // Get the length of the packet.
+ //
+ NdisQueryPacket(
+ Adapter->FirstPacket,
+ NULL,
+ NULL,
+ NULL,
+ &Len
+ );
+
+ //
+ // Convert length to the number of transmit buffers needed.
+ //
+ Len = (Len + 255) >> 8;
+
+ //
+ // If not transmitting
+ //
+ if (Adapter->CurBufXmitting == -1) {
+
+ //
+ // Then check from the next free buffer if the packet will
+ // fit.
+ //
+ if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY) {
+
+ //
+ // It won't fit at the end, so put it at the first buffer
+ //
+ if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
+
+ Adapter->NextBufToFill = 0;
+
+ }
+
+ } else {
+
+ //
+ // Check if this packet will fit before the packet on the
+ // adapter.
+ //
+ if (Adapter->NextBufToXmit > Adapter->NextBufToFill) {
+
+ if (Adapter->NextBufToFill + Len > Adapter->NextBufToXmit) {
+
+ IF_LOG( Ne2000Log('^'); )
+ IF_LOG( Ne2000Log('S'); )
+
+ break;
+
+ }
+
+ } else {
+
+ //
+ // Check if it will fit after the packet already on the
+ // adapter.
+ //
+ if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
+
+ Adapter->NextBufToFill = 0;
+
+ if (Adapter->NextBufToFill + Len > Adapter->NextBufToXmit){
+
+ IF_LOG( Ne2000Log('%'); )
+ IF_LOG( Ne2000Log('S'); )
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Check if the packet will fit before the packet currently
+ // transmitting
+ //
+
+ if (Adapter->CurBufXmitting > Adapter->NextBufToFill) {
+
+ if (Adapter->NextBufToFill + Len > Adapter->CurBufXmitting) {
+
+ IF_LOG( Ne2000Log('$'); )
+ IF_LOG( Ne2000Log('S'); )
+
+ break;
+ }
+
+ } else {
+
+ //
+ // Check if it will fit after the packet currently transmitting
+ //
+ if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
+
+ Adapter->NextBufToFill = 0;
+
+ if (Adapter->NextBufToFill + Len > Adapter->CurBufXmitting){
+
+ IF_LOG( Ne2000Log('!'); )
+ IF_LOG( Ne2000Log('S'); )
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ //
+ // Set starting location
+ //
+ TmpBuf1 = Adapter->NextBufToFill;
+
+ //
+ // Remove the packet from the queue.
+ //
+ Packet = Adapter->FirstPacket;
+ Adapter->FirstPacket = RESERVED(Packet)->Next;
+
+ if (Packet == Adapter->LastPacket) {
+ Adapter->LastPacket = NULL;
+ }
+
+ //
+ // Store the packet in the list
+ //
+ Adapter->Packets[TmpBuf1] = Packet;
+
+ //
+ // Copy down the packet.
+ //
+ if (CardCopyDownPacket(Adapter, Packet,
+ &Adapter->PacketLens[TmpBuf1]) == FALSE) {
+
+ for (i = TmpBuf1; i < TmpBuf1 + Len; i++) {
+ Adapter->BufferStatus[i] = EMPTY;
+ }
+ Adapter->Packets[TmpBuf1] = NULL;
+ IF_LOG( Ne2000Log('F'); )
+ IF_LOG( Ne2000Log('S'); )
+
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ Packet,
+ NDIS_STATUS_FAILURE
+ );
+
+ continue;
+
+ }
+
+ //
+ // Pad short packets with blanks.
+ //
+ if (Adapter->PacketLens[TmpBuf1] < 60) {
+
+ (VOID)CardCopyDown(
+ Adapter,
+ ((PUCHAR)Adapter->XmitStart +
+ TmpBuf1*TX_BUF_SIZE +
+ Adapter->PacketLens[TmpBuf1]),
+ BlankBuffer,
+ 60-Adapter->PacketLens[TmpBuf1]
+ );
+
+ }
+
+ //
+ // Set the buffer status
+ //
+ for (i = TmpBuf1; i < (TmpBuf1 + Len); i++) {
+ Adapter->BufferStatus[i] = FULL;
+ }
+
+ //
+ // Update next free buffer
+ //
+ Adapter->NextBufToFill += Len;
+
+ if (Adapter->NextBufToFill == MAX_XMIT_BUFS) {
+ Adapter->NextBufToFill = 0;
+ }
+
+ //
+ // See whether to start the transmission.
+ //
+ if (Adapter->CurBufXmitting == -1) {
+
+ //
+ // OK to start transmission.
+ //
+ if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY &&
+ Adapter->NextBufToFill != Adapter->NextBufToXmit) {
+
+ Adapter->NextBufToXmit = 0;
+
+ }
+
+ Adapter->CurBufXmitting = Adapter->NextBufToXmit;
+
+
+ IF_LOG( Ne2000Log('4');)
+
+ //
+ // If we are currently handling an overflow, then we need to let
+ // the overflow handler send this packet...
+ //
+
+ if (Adapter->BufferOverflow) {
+
+ Adapter->OverflowRestartXmitDpc = TRUE;
+
+ IF_LOG( Ne2000Log('O');)
+ IF_LOUD( DbgPrint ("Adapter->OverflowRestartXmitDpc set:copy and send");)
+
+ } else {
+
+ //
+ // This is used to check if stopping the chip prevented
+ // a transmit complete interrupt from coming through (it
+ // is cleared in the ISR if a transmit DPC is queued).
+ //
+
+ Adapter->TransmitInterruptPending = TRUE;
+
+ IF_LOG( Ne2000Log('9'); )
+ CardStartXmit(Adapter);
+
+ }
+
+ }
+
+ //
+ // Ack the send immediately. If for some reason it
+ // should fail, the protocol should be able to handle
+ // the retransmit.
+ //
+
+ IF_LOG( Ne2000Log('S'); )
+
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+ }
+
+}
+
+VOID
+OctogmetusceratorRevisited(
+ IN PNE2000_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Recovers the card from a transmit error.
+
+Arguments:
+
+ Adapter - pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IF_LOUD( DbgPrint("Octogmetuscerator called!"); )
+
+ IF_LOG( Ne2000Log('y'); )
+
+ //
+ // Ack the interrupt, if needed
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, ISR_XMIT_ERR);
+
+ //
+ // Stop the card
+ //
+ SyncCardStop(Adapter);
+
+ //
+ // Wait up to 1.6 milliseconds for any receives to finish
+ //
+ NdisStallExecution(2000);
+
+ //
+ // Place the card in Loopback
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
+
+ //
+ // Start the card in Loopback
+ //
+ NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
+
+ //
+ // Get out of loopback and start the card
+ //
+ CardStart(Adapter);
+
+ //
+ // If there was a packet waiting to get sent, send it.
+ //
+ if (Adapter->CurBufXmitting != -1) {
+
+ Adapter->TransmitInterruptPending = TRUE;
+ CardStartXmit(Adapter);
+
+ }
+ IF_LOG( Ne2000Log('Y'); )
+}
+