diff options
Diffstat (limited to 'private/ntos/ndis/elnkii.new/interrup.c')
-rw-r--r-- | private/ntos/ndis/elnkii.new/interrup.c | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/private/ntos/ndis/elnkii.new/interrup.c b/private/ntos/ndis/elnkii.new/interrup.c new file mode 100644 index 000000000..73d12bb6f --- /dev/null +++ b/private/ntos/ndis/elnkii.new/interrup.c @@ -0,0 +1,395 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + interrup.c + +Abstract: + + This is a part of the driver for the National Semiconductor ElnkII + 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: + +--*/ + +#include <ndis.h> +#include "elnkhrd.h" +#include "elnksft.h" + + +#if DBG +#define STATIC +#else +#define STATIC static +#endif + + + +#if DBG + +#define ELNKII_LOG_SIZE 256 +UCHAR ElnkiiLogSaveBuffer[ELNKII_LOG_SIZE]={0}; +BOOLEAN ElnkiiLogSave = FALSE; +UINT ElnkiiLogSaveLoc = 0; +UINT ElnkiiLogSaveLeft = 0; + +extern VOID ElnkiiLog(UCHAR c); + +#endif + + +VOID ElnkiiEnableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext +) +{ + PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext; + + IF_LOG(ElnkiiLog('P');) + + CardUnblockInterrupts(pAdapter); +} + +VOID ElnkiiDisableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext +) +{ + PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext; + + IF_LOG(ElnkiiLog('p');) + + CardBlockInterrupts(pAdapter); +} + + + +VOID ElnkiiIsr( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueDpc, + IN PVOID Context +) + +/*++ + +Routine Description: + + This is the interrupt handler which is registered with the operating + system. Only one interrupt is handled at one time, even if several + are pending (i.e. transmit complete and receive). + +Arguments: + + ServiceContext - pointer to the adapter object + +Return Value: + + None + +--*/ + +{ + PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)Context; + + IF_LOG( ElnkiiLog('i');) + + IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiIsr entered\n");) + + // + // If we are testing the card then ignore the interrupt. + // + if (pAdapter->InCardTest) + { + IF_LOG( ElnkiiLog('I'); ) + + *InterruptRecognized = FALSE; + *QueueDpc = FALSE; + + IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiIsr exiting (CardTest)\n");) + + return; + } + + // + // Force the INT signal from the chip low. When the + // interrupt is acknowledged interrupts will be unblocked, + // which will cause a rising edge on the interrupt line + // if there is another interrupt pending on the card. + // + CardBlockInterrupts(pAdapter); + + IF_LOG( ElnkiiLog('I');) + + *InterruptRecognized = TRUE; + *QueueDpc = TRUE; + + IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiIsr exiting\n");) +} + + + +VOID ElnkiiHandleInterrupt( + IN NDIS_HANDLE MiniportAdapterContext +) +/*++ + +Routine Description: + + This is the deffered processing routine for interrupts, it examines the + 'InterruptStatus' to determine what deffered processing is necessary + and dispatches control to the Rcv and Xmt handlers. + +Arguments: + +Return Value: + + NONE. + +--*/ +{ + // + // Adapter to process. + // + PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext; + + UCHAR InterruptStatus; // Most recent port value read. + INTERRUPT_TYPE InterruptType; // Interrupt type currently being + // processed. + IF_LOG(ElnkiiLog('d');) + IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiHandleInterrupt entered\n");) + + // + // Get the interrupt bits and save them + // + CardGetInterruptStatus(pAdapter, &InterruptStatus); + pAdapter->InterruptStatus |= InterruptStatus; + + if (InterruptStatus != ISR_EMPTY) + { + // + // Acknowledge the interrupts. + // + NdisRawWritePortUchar( + pAdapter->MappedIoBaseAddr + 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. + // + CardGetInterruptType(pAdapter, InterruptStatus, InterruptType); + + while (InterruptType != UNKNOWN) + { + // + // Handle 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_VERY_LOUD(DbgPrint("C\n");) + + SyncCardUpdateCounters(pAdapter); + + // + // Clear the COUNTER interrupt bit. + // + pAdapter->InterruptStatus &= ~ISR_COUNTER; + + IF_VERY_LOUD(DbgPrint("c\n");) + + 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. + // + pAdapter->BufferOverflow = TRUE; + + IF_VERY_LOUD(DbgPrint("O\n");) + + // + // Clear the OVERFLOW interrupt bit. + // + pAdapter->InterruptStatus &= ~ISR_OVERFLOW; + + case RECEIVE: + + IF_LOG( ElnkiiLog('R');) + IF_VERY_LOUD(DbgPrint("R\n");) + + // + // Allow the receive dpc to handle it. + // + if (ElnkiiRcvDpc(pAdapter)) + { + // + // Clear the receive interrupt bits. + // + pAdapter->InterruptStatus &= ~(ISR_RCV | ISR_RCV_ERR); + } + + IF_LOG(ElnkiiLog('r');) + IF_VERY_LOUD(DbgPrint("r\n");) + + if (!(pAdapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR))) + break; + + case TRANSMIT: + + IF_LOG( ElnkiiLog('X');) + IF_VERY_LOUD(DbgPrint("X\n");) + + ASSERT(!pAdapter->OverflowRestartXmitDpc); + + // + // Get the status of the transmit. + // + SyncCardGetXmitStatus(pAdapter); + + pAdapter->TransmitTimeOut = FALSE; + + // + // We are no longer expecting an interrupt. + // + pAdapter->TransmitInterruptPending = FALSE; + + // + // Handle transmit errors. + // + if (pAdapter->InterruptStatus & ISR_XMIT_ERR) + OctogmetusceratorRevisited(pAdapter); + + // + // Handle transmit errors. + // + if (pAdapter->InterruptStatus & ISR_XMIT) + ElnkiiXmitDpc(pAdapter); + + // + // Clear the TRANSMIT interrupt bits. + // + pAdapter->InterruptStatus &= ~(ISR_XMIT | ISR_XMIT_ERR); + + IF_VERY_LOUD(DbgPrint("x\n");) + + break; + + default: + // + // Create a rising edge on the interrupt line. + // + IF_LOUD(DbgPrint("ELNKII: Unhandled interrupt type: %x\n", InterruptType);) + + break; + } + + // + // Get any new interrupts. + // + CardGetInterruptStatus(pAdapter, &InterruptStatus); + if (InterruptStatus != ISR_EMPTY) + { + // + // Acknowledge the interrupt. + // + NdisRawWritePortUchar( + pAdapter->MappedIoBaseAddr + NIC_INTR_STATUS, + InterruptStatus + ); + } + + // + // Save the interrupt status. + // + pAdapter->InterruptStatus |= InterruptStatus; + + // + // Get the next interrupt to process. + // + CardGetInterruptType(pAdapter, InterruptStatus, InterruptType); + } + + IF_LOG(ElnkiiLog('D');) + IF_VERY_LOUD(DbgPrint("ELNKII: ElnkiiHandleInterrupt exiting\n");) +} + + +BOOLEAN ElnkiiCheckForHang( + IN NDIS_HANDLE MiniportAdapterContext +) + +/*+++ + + Description: + This routine checks the transmit queue every 2 seconds. + If a transmit interrupt was not received in the last two seconds + and there is a transmit in progress then we complete the transmit. + + Returns: + BOOLEAN + + Histroy: + 1/2/95 [kyleb] created. + +---*/ + +{ + PELNKII_ADAPTER pAdapter = (PELNKII_ADAPTER)MiniportAdapterContext; + + if (pAdapter->TransmitTimeOut && (pAdapter->CurBufXmitting != -1)) + { + IF_LOUD(DbgPrint("ELNKII: Card died!, Attempting to restart\n");) + pAdapter->TransmitTimeOut = FALSE; + + return(TRUE); + } + else + { + if (pAdapter->CurBufXmitting != -1) + pAdapter->TransmitTimeOut = TRUE; + } +} //** ElnkiiCheckForHang() + + +UINT ElnkiiCompareMemory( + IN PUCHAR String1, + IN PUCHAR String2, + IN UINT Length +) +{ + UINT i; + + for (i = 0; i < Length; i++) + { + if (String1[i] != String2[i]) + return((UINT)-1); + } + + return(0); +} + + + |