From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/ndis/htdsu/interrup.c | 656 +++++++++++++++++++++++++++++++++++++ 1 file changed, 656 insertions(+) create mode 100644 private/ntos/ndis/htdsu/interrup.c (limited to 'private/ntos/ndis/htdsu/interrup.c') diff --git a/private/ntos/ndis/htdsu/interrup.c b/private/ntos/ndis/htdsu/interrup.c new file mode 100644 index 000000000..fad79ce79 --- /dev/null +++ b/private/ntos/ndis/htdsu/interrup.c @@ -0,0 +1,656 @@ +/***************************************************************************\ +|* Copyright (c) 1994 Microsoft Corporation *| +|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *| +|* *| +|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *| +\***************************************************************************/ +#include "version.h" +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Module Name: + + interrup.c + +Abstract: + + This module contains the Miniport interrupt processing routines: + MiniportCheckForHang() + MiniportDisableInterrupt() + MiniportEnableInterrupt() + MiniportISR() + MiniportHandleInterrupt() + + This driver conforms to the NDIS 3.0 Miniport interface. + +Author: + + Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94 + +Environment: + + Windows NT 3.5 kernel mode Miniport driver or equivalent. + +Revision History: + +---------------------------------------------------------------------------*/ + +#define __FILEID__ 3 // Unique file ID for error logging + +#include "htdsu.h" + + +BOOLEAN +HtDsuCheckForHang( + IN PHTDSU_ADAPTER Adapter + ) + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Functional Description: + + The MiniportCheckForHang request is used by the wrapper to periodically + have the miniport check if the adapter appears hung. + + The Miniport driver should do nothing more than check the internal state + and return if the adapter is hung. The wrapper will then attempt to + recover the adapter by calling MiniportReset. + + This routine will be called once every two seconds. + + Interrupts will be in any state when called. + +Parameters: + + MiniportAdapterContext _ The handle returned from MiniportInitialize. + +Return Values: + + TRUE if the driver believes that the underlying hardware is hung, + FALSE otherwise. + +---------------------------------------------------------------------------*/ + +{ + return (Adapter->NeedReset); +} + + +VOID +HtDsuDisableInterrupt( + IN PHTDSU_ADAPTER Adapter + ) + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Functional Description: + + The MiniportDisableInterrupt request is used to disable the adapter + from generating any interrupts. Typically this is done by writing a + mask which disables the adapter from generating hardware interrupts. + + If the underlying hardware does not support enabling and disabling + interrupts, the Miniport driver will have to register a MiniportISR + with the wrapper, and the Miniport driver will have to acknowledge + and save the interrupt information from within the interrupt service + routine. + + This routine may be called any time interrupts are enabled. If the + underlying hardware is required to be in a certain state for this + routine to execute correctly, the Miniport driver must encapsulate + all portions of the driver which violate the state and which may be + called when interrupts are enabled, with a function and call the + function through the NdisMSynchronizeWithInterrupt service. + + Interrupts will be in any state when called. + +Parameters: + + MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes + during MiniportInitialize. + +Return Values: + + None. + +---------------------------------------------------------------------------*/ + +{ + DBG_FUNC("HtDsuDisableInterrupt") + + /* + // Save the current interrupt status on the card. + */ + USHORT InterruptStatus = CardGetInterrupt(Adapter); + +// DBG_ENTER(Adapter); + + /* + // Disable the interrupt at the card after saving the current state + // of the InterruptStatus register -- which will be reset by the clear + // interrupt command. + */ + Adapter->InterruptStatusFlag |= InterruptStatus; + CardClearInterrupt(Adapter); + CardDisableInterrupt(Adapter); + + DBG_NOTICE(Adapter, ("IntrStatus=%Xh LineStatus=%Xh\n", + InterruptStatus, + READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) + )); + +// DBG_LEAVE(Adapter); +} + + +VOID +HtDsuEnableInterrupt( + IN PHTDSU_ADAPTER Adapter + ) + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Functional Description: + + The MiniportEnableInterrupt request is used to enable the adapter for + generating any interrupts. Typically this is done by writing a mask + which will reenable adapter interrupts. + + If the underlying hardware does not support enabling and disabling + interrupts, the Miniport driver will have to register a MiniportISR + with the wrapper, and the Miniport driver will have to acknowledge + and save the interrupt information from within the interrupt service + routine. + + Interrupts will be in any state when called. + +Parameters: + + MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes + during MiniportInitialize. + +Return Values: + + None. + +---------------------------------------------------------------------------*/ + +{ + DBG_FUNC("HtDsuEnableInterrupt") + + /* + // Save the current interrupt status on the card. + */ + USHORT InterruptStatus = CardGetInterrupt(Adapter); + +// DBG_ENTER(Adapter); + + CardEnableInterrupt(Adapter); + + DBG_NOTICE(Adapter, ("IntrStatus=%Xh LineStatus=%Xh\n", + InterruptStatus, + READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) + )); + +// DBG_LEAVE(Adapter); +} + + + +VOID +HtDsuISR( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueMiniportHandleInterrupt, + IN PHTDSU_ADAPTER Adapter + ) + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Functional Description: + + The MiniportISR request is called if the adapter generates an + interrupt when there is an outstanding call to MiniportInitialize + or to MiniportReconfigure, if the Miniport driver supports sharing + its interrupt line with another adapter, or if the Miniport driver + specifies that the routine must be called for every interrupt (See + NdisMRegisterInterrupt's RequestIsr and SharedInterrupt parameters). + + This routine runs immediately after an interrupt, at very high priority, + and is subject to all the limitations of the interrupt service routine + in the NDIS 3.0 specification. The driver should do as little work as + possible in this routine. It should return TRUE in the parameter + InterruptRecognized if it recognizes the interrupt as belonging to its + adapter, or FALSE otherwise. It should return TRUE in the parameter + QueueMiniportHandleInterrupt if it needs a call to MiniportHandleInterrupt + at a lower priority to complete the handling of the interrupt, or FALSE + otherwise. + + Note that a Dpc will not be queued if the Miniport is currently executing + in any of the following routines: MiniportHalt, MiniportInitialize, + MiniportReconfigure. + +Parameters: + + InterruptRecognized _ If the Miniport is sharing an interrupt line, it + should set this parameter to TRUE if the Miniport + driver recognizes that the interrupt came from the + adapter it is supporting. + + QueueMiniportHandleInterrupt _ If the Miniport driver is sharing an + interrupt line, it sets this parameter to + TRUE if the driver needs to have + MiniportHandleInterrupt called. + + MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes + during MiniportInitialize. + +Return Values: + + None. + +---------------------------------------------------------------------------*/ + +{ + DBG_FUNC("HtDsuISR") + + /* + // Save the current interrupt status on the card. + */ + USHORT InterruptStatus; + + DBG_ENTER(Adapter); + + /* + // This routine should never be called after initialization since we + // support the Enable/Disable Interrupt routines. + */ + if (InterruptStatus = CardGetInterrupt(Adapter)) + { + /* + // The adapter prevents the failure case where additional status + // bits could be set between the time we read the InterruptStatus + // and it is reset by the clear interrupt command... + */ + CardClearInterrupt(Adapter); + Adapter->InterruptStatusFlag |= InterruptStatus; + + /* + // The card generated an interrupt, we need to service it only if we are + // interested in it. In either case it must be dismissed from the card. + */ + *InterruptRecognized = TRUE; + *QueueMiniportHandleInterrupt = TRUE; + } + else + { + /* + // It's not our interrupt, so we don't need to service anything. + */ + *InterruptRecognized = FALSE; + } + + DBG_NOTICE(Adapter, ("IntrStatus=%Xh LineStatus=%Xh\n", + InterruptStatus, + READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1) + )); + + DBG_LEAVE(Adapter); +} + + +VOID +HtDsuHandleInterrupt( + IN PHTDSU_ADAPTER Adapter + ) + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Functional Description: + + The MiniportHandleInterrupt routine is called from within a wrapper + deferred processing routine, and is used to process the reason an + interrupt was generated. The Miniport driver should handle all + outstanding interrupts and start any new operations. + + Interrupts will be disabled during the call to this routine. + +Parameters: + + MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes + during MiniportInitialize. + +Return Values: + + None. + +---------------------------------------------------------------------------*/ + +{ + DBG_FUNC("HtDsuHandleInterrupt") + + /* + // A pointer to our link information structure. + */ + PHTDSU_LINK Link; + + UINT TimeOut; + + NdisAcquireSpinLock(&Adapter->Lock); + Adapter->InTheDpcHandler = TRUE; + + DBG_ENTER(Adapter); + + /* + // Loop thru here until all the interrupts are handled. + // This should not be allowed to take more than a few mili-seconds. + // If it does, the checked kernel will trap, and you'll have to + // find a way to leave the DPC early and handle the rest during + // the next pass. + */ + while (Adapter->InterruptStatusFlag) + { + /******************************************************************** + // Do we have a packet waiting in the adapter? + */ + if (Adapter->InterruptStatusFlag & (HTDSU_INTR_RX_PACKET1 | + HTDSU_INTR_RX_PACKET2)) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_RX_PACKET\n")); + + Adapter->InterruptStatusFlag &= ~(HTDSU_INTR_RX_PACKET1 | + HTDSU_INTR_RX_PACKET2); + HtDsuReceivePacket(Adapter); + } + + /******************************************************************** + // Has the packet been transmitted? + // Actually, this just means that the DSU firmware has moved the + // packet from our buffer area to its own buffer to be transmitted. + // It won't have actually completed until HTDSU_INTR_TX_EMPTY. + */ + if (Adapter->InterruptStatusFlag & (HTDSU_INTR_TX_PACKET1 | + HTDSU_INTR_TX_PACKET2)) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_TX_PACKET\n")); + + Adapter->InterruptStatusFlag &= ~(HTDSU_INTR_TX_PACKET1 | + HTDSU_INTR_TX_PACKET2); + HtDsuTransmitComplete(Adapter); + } + + /******************************************************************** + // Does somebody want to chat? + */ + if (Adapter->InterruptStatusFlag & HTDSU_INTR_RINGING1) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_RINGING1\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_RINGING1; + + /* + // CAVEAT: Normally you don't want to stall execution in your + // DPC because locks are held and no other threads will run. + // However, I have seen some hardware/firmware anomallies + // on the answering side where we get here before the signal + // is established, so I double check here by waiting up to 100MS. + */ + TimeOut = 0; + while (!CardStatusRinging(Adapter, HTDSU_CMD_LINE1) || + CardStatusNoSignal(Adapter, HTDSU_CMD_LINE1)) + { + if (TimeOut++ > 1000) + { + DBG_ERROR(Adapter,("Timeout waiting for SIGNAL on line 1\n")); + break; + } + else + { + NdisStallExecution(_100_MICROSECONDS); + } + } + + if (TimeOut != 0) + { + DBG_WARNING(Adapter, ("Ring1 signal delay=%d*100us\n", TimeOut)); + } + + /* + // Make sure the ring is still asserted or it may + // just be noise from the cable being unplugged. + */ + if (CardStatusRinging(Adapter, HTDSU_CMD_LINE1)) + { + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_RINGING); + } + else + { + DBG_WARNING(Adapter, ("Ring1 lost - status=%Xh\n", + READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1))); + } + } + if (Adapter->InterruptStatusFlag & HTDSU_INTR_RINGING2) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_RINGING2\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_RINGING2; + + TimeOut = 0; + while (!CardStatusRinging(Adapter, HTDSU_CMD_LINE2) || + CardStatusNoSignal(Adapter, HTDSU_CMD_LINE2)) + { + if (TimeOut++ > 100) + { + DBG_ERROR(Adapter,("Timeout waiting for SIGNAL on line 2\n")); + break; + } + else + { + NdisStallExecution(_100_MICROSECONDS); + } + } + + if (TimeOut != 0) + { + DBG_WARNING(Adapter, ("Ring2 signal delay=%d*100us\n", TimeOut)); + } + + if (CardStatusRinging(Adapter, HTDSU_CMD_LINE2)) + { + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_RINGING); + } + else + { + DBG_WARNING(Adapter, ("Ring2 lost - status=%Xh\n", + READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2))); + } + } + + /******************************************************************** + // Do we have a connection being established? + */ + if (Adapter->InterruptStatusFlag & HTDSU_INTR_CONNECTED1) + { + + DBG_NOTICE(Adapter,("HTDSU_INTR_CONNECTED1\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_CONNECTED1; + + /* + // CAVEAT: Normally you don't want to stall execution in your + // DPC because locks are held and no other threads will run. + // However, I have seen some hardware/firmware anomallies + // on the calling side where we get here before the carrier + // is established, so I double check here by waiting up to 100MS. + */ + TimeOut = 0; + while (!CardStatusCarrierDetect(Adapter, HTDSU_CMD_LINE1) || + !CardStatusOnLine(Adapter, HTDSU_CMD_LINE1)) + { + if (TimeOut++ > 1000) + { + DBG_ERROR(Adapter,("Timeout waiting for CARRIER/LINE 1\n")); + break; + } + else + { + NdisStallExecution(_100_MICROSECONDS); + } + } + + if (TimeOut != 0) + { + DBG_WARNING(Adapter, ("Connect1 carrier delay=%d*100us\n", TimeOut)); + } + + /* + // Make sure the connection is accompanied by a carrier and + // an online status, Otherwise, it's probably just cable bounce. + */ + if (CardStatusCarrierDetect(Adapter, HTDSU_CMD_LINE1) && + CardStatusOnLine(Adapter, HTDSU_CMD_LINE1)) + { + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_CONNECTED); + } + else + { + DBG_WARNING(Adapter, ("Connect1 but not ready - status=%X\n", + READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1))); + } + } + if (Adapter->InterruptStatusFlag & HTDSU_INTR_CONNECTED2) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_CONNECTED2\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_CONNECTED2; + + TimeOut = 0; + while (!CardStatusCarrierDetect(Adapter, HTDSU_CMD_LINE2) || + !CardStatusOnLine(Adapter, HTDSU_CMD_LINE2)) + { + if (TimeOut++ > 1000) + { + DBG_ERROR(Adapter,("Timeout waiting for CARRIER/LINE 2\n")); + break; + } + else + { + NdisStallExecution(_100_MICROSECONDS); + } + } + + if (TimeOut != 0) + { + DBG_WARNING(Adapter, ("Connect2 carrier delay=%d*100us\n", TimeOut)); + } + + if (CardStatusCarrierDetect(Adapter, HTDSU_CMD_LINE2) && + CardStatusOnLine(Adapter, HTDSU_CMD_LINE2)) + { + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_CONNECTED); + } + else + { + DBG_WARNING(Adapter, ("Connect2 but not ready - status=%X\n", + READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine2))); + } + } + + /******************************************************************** + // Did the other guy hung up on us? -- how rude... + */ + if (Adapter->InterruptStatusFlag & HTDSU_INTR_DISCONNECTED1) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_DISCONNECTED1\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_DISCONNECTED1; + + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED); + } + if (Adapter->InterruptStatusFlag & HTDSU_INTR_DISCONNECTED2) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_DISCONNECTED2\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_DISCONNECTED2; + + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED); + } + + /******************************************************************** + // Has the transmitter gone idle? Ask me if I care... + */ + if (Adapter->InterruptStatusFlag & (HTDSU_INTR_TX_EMPTY1 | + HTDSU_INTR_TX_EMPTY2)) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_TX_EMPTY\n")); + + Adapter->InterruptStatusFlag &= ~(HTDSU_INTR_TX_EMPTY1 | + HTDSU_INTR_TX_EMPTY2); + } + + /******************************************************************** + // Maybe somebody unplugged the phone line? + */ + if (Adapter->InterruptStatusFlag & HTDSU_INTR_NO_SIGNAL1) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_NO_SIGNAL1\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_NO_SIGNAL1; + + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_OUTOFSERVICE); + } + if (Adapter->InterruptStatusFlag & HTDSU_INTR_NO_SIGNAL2) + { + DBG_NOTICE(Adapter,("HTDSU_INTR_NO_SIGNAL2\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_NO_SIGNAL2; + + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_OUTOFSERVICE); + } + + /******************************************************************** + // What about a receive buffer overrun? -- This better never happen! + // However, if it does, we'll shut this sucker off til it's reset. + */ + if (Adapter->InterruptStatusFlag & HTDSU_INTR_RX_FULL1) + { + DBG_ERROR(Adapter,("HTDSU_INTR_RX_FULL1\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_RX_FULL1; + + /* + // Ask for reset, and disable interrupts until we get it. + */ + Adapter->NeedReset = TRUE; + Adapter->InterruptEnableFlag = HTDSU_INTR_DISABLE; + + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE1); + LinkLineError(Link, WAN_ERROR_BUFFEROVERRUN); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED); + } + if (Adapter->InterruptStatusFlag & HTDSU_INTR_RX_FULL2) + { + DBG_ERROR(Adapter,("HTDSU_INTR_RX_FULL2\n")); + + Adapter->InterruptStatusFlag &= ~HTDSU_INTR_RX_FULL2; + + Adapter->NeedReset = TRUE; + Adapter->InterruptEnableFlag = HTDSU_INTR_DISABLE; + + Link = GET_LINK_FROM_CARDLINE(Adapter, HTDSU_CMD_LINE2); + LinkLineError(Link, WAN_ERROR_BUFFEROVERRUN); + HtTapiLineDevStateHandler(Adapter, Link, LINEDEVSTATE_DISCONNECTED); + } + } + DBG_LEAVE(Adapter); + + Adapter->InTheDpcHandler = FALSE; + NdisReleaseSpinLock(&Adapter->Lock); +} + -- cgit v1.2.3