windows-nt/Source/XPSP1/NT/net/ndis/samples/coisdn/interupt.c
2020-09-26 16:20:57 +08:00

430 lines
15 KiB
C

/*
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
(C) Copyright 1999
All rights reserved.
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
Portions of this software are:
(C) Copyright 1995 TriplePoint, Inc. -- http://www.TriplePoint.com
License to use this software is granted under the same terms
outlined in the Microsoft Windows Device Driver Development Kit.
(C) Copyright 1992 Microsoft Corp. -- http://www.Microsoft.com
License to use this software is granted under the terms outlined in
the Microsoft Windows Device Driver Development Kit.
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
@doc INTERNAL Interrupt Interrupt_c
@module Interrupt.c |
This module implements the Miniport interrupt processing routines and
asynchronous processing routines.
The sample driver does not support physical hardware, so there is no need
for the typical interrupt handler routines. However, the driver does
have an asynchronous event handler which is contained in this module.
@comm
This module is very dependent on the hardware/firmware interface and should
be looked at whenever changes to these interfaces occur.
@head3 Contents |
@index class,mfunc,func,msg,mdata,struct,enum | Interupt_c
@end
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
*/
#define __FILEID__ INTERRUPT_OBJECT_TYPE
// Unique file ID for error logging
#include "Miniport.h" // Defines all the miniport objects
#if defined(NDIS_LCODE)
# pragma NDIS_LCODE // Windows 9x wants this code locked down!
# pragma NDIS_LDATA
#endif
/* @doc EXTERNAL INTERNAL Interupt Interupt_c MiniportCheckForHang
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
@func
<f MiniportCheckForHang> reports the state of the network interface card.
@comm
The NDIS library calls <f MiniportCheckForHang> once every two seconds to
check the state of the network interface card. If this function returns
TRUE, the NDIS library then attempts to reset the NIC by calling
<f MiniportReset>. <f MiniportCheckForHang> should do nothing more than
check the internal state of the NIC and return TRUE if it detects that
the NIC is not operating correctly.
Interrupts can be in any state when MiniportCheckForHang is called.
<f Note>:
If your hardware/firmware is flakey you can request that the NDIS
wrapper call your MiniportReset routine by returning TRUE from this
routine. For well behaved hardware/firmware you should always return
FALSE from this routine.
@rdesc
<f MiniportCheckForHang> returns FALSE if the NIC is working properly.<nl>
Otherwise, a TRUE return value indicates that the NIC needs to be reset.
*/
BOOLEAN MiniportCheckForHang(
IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
)
{
DBG_FUNC("MiniportCheckForHang")
// If your hardware can lockup, then you can return TRUE here.
// If you return TRUE, your MiniportReset routine will be called.
return (FALSE);
}
#if defined(CARD_REQUEST_ISR)
#if (CARD_REQUEST_ISR == FALSE)
/* @doc EXTERNAL INTERNAL Interupt Interupt_c MiniportDisableInterrupt
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
@func
<f MiniportDisableInterrupt> disables the NIC from generating interrupts.
@comm
Typically, this function disables interrupts by writing a mask value
specific to the network interface card.
If the NIC does not support enabling and disabling interrupts, the
miniport driver must register a miniport interrupt service routine with
the NDIS library. Within the interrupt service routine, the miniport
driver must acknowledge and save the interrupt information.
In some cases, the NIC must be in a certain state for
<f MiniportDisableInterrupt> to execute correctly. In these cases, the
miniport driver must encapsulate within a function all portions of the
driver which violate the required state and which can be called when
interrupts are enabled. Then the miniport driver must call the
encapsulated code through the NdisMSynchronizeWithInterrupt function.
For example, on some network interface cards, the I/O ports are paged
and must be set to page 0 for the deferred processing routine to run
correctly. With this kind of NIC, the DPC must be synchronized with
interrupts.
Interrupts can be in any state when <f MiniportDisableInterrupt> is
called.
*/
void MiniportDisableInterrupt(
IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
)
{
DBG_FUNC("MiniportDisableInterrupt")
DBG_ERROR(pAdapter,("This should not be called!\n"));
}
/* @doc EXTERNAL INTERNAL Interupt Interupt_c MiniportEnableInterrupt
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
@func
<f MiniportEnableInterrupt> enables the NIC to generate interrupts.
@comm
Typically, this function enables interrupts by writing a mask value
specific to the network interface card.
If the NIC does not support enabling and disabling interrupts, the
miniport driver must register a miniport interrupt service routine with
the NDIS library. Within the interrupt service routine, the miniport
driver must acknowledge and save the interrupt information.
Interrupts can be in any state when <f MiniportEnableInterrupt> is called.
*/
void MiniportEnableInterrupt(
IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
)
{
DBG_FUNC("MiniportEnableInterrupt")
DBG_ERROR(pAdapter,("This should not be called!\n"));
}
#else // !(CARD_REQUEST_ISR == FALSE)
/* @doc EXTERNAL INTERNAL Interupt Interupt_c MiniportISR
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
@func
<f MiniportISR> is the miniport driver's interrupt service routine. This
function runs at a high priority in response to an interrupt. The driver
should do as little work as possible in this function. It should set
<p InterruptRecognized> to TRUE if it recognizes the interrupt as
belonging to its network interface card, or FALSE otherwise. It should
return FALSE as soon as possible if the interrupt is not generated by
its NIC. It should set <f QueueMiniportHandleInterrupt> to TRUE if a
call to <f MiniportHandleInterrupt> at a lower priority is required to
complete the handling of the interrupt.
<f Note>: <f MiniportISR> must not call any support functions in the NDIS
interface library or the transport driver.
@comm
<f MiniportISR> is called in the following cases:<nl>
o The NIC generates an interrupt when there is an outstanding call to
<f MiniportInitialize>.
o The miniport driver supports sharing its interrupt line with another
NIC.
o The miniport driver specifies that this function must be called for
every interrupt.
<f Note>: A deferred processing routine is not queued if the miniport
driver is currently executing <f MiniportHalt> or <f MiniportInitialize>.
*/
void MiniportISR(
OUT PBOOLEAN InterruptRecognized, // @parm
// If the miniport driver is sharing an interrupt line and it detects
// that the interrupt came from its NIC, <f MiniportISR> should set
// this parameter to TRUE.
OUT PBOOLEAN QueueMiniportHandleInterrupt, // @parm
// If the miniport driver is sharing an interrupt line and if
// <f MiniportHandleInterrupt> must be called to complete handling of
// the interrupt, <f MiniportISR> should set this parameter to TRUE.
IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
)
{
DBG_FUNC("MiniportISR")
ULONG InterruptStatus;
// TODO: Get the interrupt status from your card.
if ((InterruptStatus = pAdapter->TODO) == 0)
{
*InterruptRecognized =
*QueueMiniportHandleInterrupt = FALSE;
}
else
{
pAdapter->pCard->InterruptStatus = InterruptStatus;
*InterruptRecognized =
*QueueMiniportHandleInterrupt = TRUE;
}
}
#endif // (CARD_REQUEST_ISR == FALSE)
#endif // defined(CARD_REQUEST_ISR)
/* @doc EXTERNAL INTERNAL Interupt Interupt_c MiniportHandleInterrupt
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
@func
<f MiniportHandleInterrupt> is called by the deferred processing routine
in the NDIS library to process an interrupt.
@comm
During a call to <f MiniportHandleInterrupt>, the miniport driver should
handle all outstanding interrupts and start any new operations.
Interrupts are disabled during a call to <f MiniportHandleInterrupt>.
*/
void MiniportHandleInterrupt(
IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
)
{
DBG_FUNC("MiniportHandleInterrupt")
PBCHANNEL_OBJECT pBChannel;
// A Pointer to one of our <t BCHANNEL_OBJECT>'s.
ULONG BChannelIndex;
// Index into the pBChannelArray.
/*
// Process NIC interrupt.
*/
CardInterruptHandler(pAdapter->pCard);
/*
// Walk through all the links to see if there is any post-proccessing
// that needs to be done.
*/
for (BChannelIndex = 0; BChannelIndex < pAdapter->NumBChannels; ++BChannelIndex)
{
pBChannel = GET_BCHANNEL_FROM_INDEX(pAdapter, BChannelIndex);
if (pBChannel->IsOpen)
{
/*
// Indicate a receive complete if it's needed.
*/
if (pBChannel->NeedReceiveCompleteIndication)
{
pBChannel->NeedReceiveCompleteIndication = FALSE;
/*
// Indicate receive complete to the NDIS wrapper.
*/
DBG_RXC(pAdapter, pBChannel->ObjectID);
NdisMCoReceiveComplete(pAdapter->MiniportAdapterHandle);
}
}
}
/*
// Indicate a status complete if it's needed.
*/
if (pAdapter->NeedStatusCompleteIndication)
{
pAdapter->NeedStatusCompleteIndication = FALSE;
NdisMIndicateStatusComplete(pAdapter->MiniportAdapterHandle);
}
}
/* @doc EXTERNAL INTERNAL Interupt Interupt_c MiniportTimer
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
@func
<f MiniportTimer> is a required function if a Minipor's NIC does not
generate interrupts. Otherwise, one or more <f MiniportTimer> functions
are optional.
The driver of a NIC that does not generate interrupts must have a <f
MiniportTimer> function to poll the state of the NIC. After such a
Miniport's MiniportInitialize function sets up the driver-allocated timer
object with NdisMInitializeTimer, a call to NdisMSetPeriodicTimer causes
the <f MiniportTimer> function associated with the timer object to be run
repeatedly and automatically at the interval specified by
MillisecondsPeriod. Such a polling <f MiniportTimer> function monitors the
state of the NIC to determine when to make indications, when to complete
pending sends, and so forth. In effect, such a polling <f MiniportTimer>
function has the same functionality as the MiniportHandleInterrupt
function in the driver of a NIC that does generate interrupts.
By contrast, calling NdisMSetTimer causes the <f MiniportTimer> function
associated with the timer object to be run once when the given
MillisecondsToDelay expires. Such a <f MiniportTimer> function usually
performs some driver-determined action if a particular operation times
out.
If either type of <f MiniportTimer> function shares resources with other
driver functions, the driver should synchronize access to those resources
with a spin lock.
A Miniport can have more than one <f MiniportTimer> function at the
discretion of the driver writer. Each such <f MiniportTimer> function must
be associated with a driver-allocated and initialized timer object.
A call to NdisMCancelTimer cancels execution of a nonpolling
<f MiniportTimer> function, provided that the interval passed in the
immediately preceding call to NdisMSetTimer has not yet expired. After a
call to NdisMSetPeriodicTimer, a call to NdisMSetTimer or NdisMCancelTimer
with the same timer object disables a polling <f MiniportTimer> function:
either the <f MiniportTimer> function runs once, or it is canceled.
The MiniportHalt function of any driver with a <f MiniportTimer> function
should call NdisMCancelTimer to ensure that the <f MiniportTimer> function
does not attempt to access resources that MiniportHalt has already
released.
By default, <f MiniportTimer> runs at IRQL DISPATCH_LEVEL.
*/
void MiniportTimer(
IN PVOID SystemSpecific1, // @parm
// UNREFERENCED_PARAMETER
IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
IN PVOID SystemSpecific2, // @parm
// UNREFERENCED_PARAMETER
IN PVOID SystemSpecific3 // @parm
// UNREFERENCED_PARAMETER
)
{
DBG_FUNC("MiniportTimer")
// DBG_ENTER(pAdapter);
/*
// If this is a nested callback, just return, and we'll loop back to
// the DoItAgain before leaving the outermost callback.
*/
if (++(pAdapter->NestedEventHandler) > 1)
{
DBG_WARNING(pAdapter,("NestedEventHandler=%d > 1\n",
pAdapter->NestedEventHandler));
return;
}
DoItAgain:
#if defined(SAMPLE_DRIVER)
/*
// This sample driver uses timer to simulate interrupts.
*/
MiniportHandleInterrupt(pAdapter);
#else // SAMPLE_DRIVER
// TODO - Add code here to handle timer interrupt events.
#endif // SAMPLE_DRIVER
/*
// If we got a nested callback, we have to loop back around.
*/
if (--(pAdapter->NestedEventHandler) > 0)
{
goto DoItAgain;
}
else if (pAdapter->NestedEventHandler < 0)
{
DBG_ERROR(pAdapter,("NestedEventHandler=%d < 0\n",
pAdapter->NestedEventHandler));
}
// DBG_LEAVE(pAdapter);
UNREFERENCED_PARAMETER(SystemSpecific1);
UNREFERENCED_PARAMETER(SystemSpecific2);
UNREFERENCED_PARAMETER(SystemSpecific3);
}