/* §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ (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 reports the state of the network interface card. @comm The NDIS library calls 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 . 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. : 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 returns FALSE if the NIC is working properly. 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 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 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 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 is called. */ void MiniportDisableInterrupt( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance. ) { DBG_FUNC("MiniportDisableInterrupt") DBG_ERROR(pAdapter,("This should not be called!\n")); } /* @doc EXTERNAL INTERNAL Interupt Interupt_c MiniportEnableInterrupt §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func 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 is called. */ void MiniportEnableInterrupt( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the 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 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

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 to TRUE if a call to at a lower priority is required to complete the handling of the interrupt. : must not call any support functions in the NDIS interface library or the transport driver. @comm is called in the following cases: o The NIC generates an interrupt when there is an outstanding call to . 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. : A deferred processing routine is not queued if the miniport driver is currently executing or . */ 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, should set // this parameter to TRUE. OUT PBOOLEAN QueueMiniportHandleInterrupt, // @parm // If the miniport driver is sharing an interrupt line and if // must be called to complete handling of // the interrupt, should set this parameter to TRUE. IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the 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 is called by the deferred processing routine in the NDIS library to process an interrupt. @comm During a call to , the miniport driver should handle all outstanding interrupts and start any new operations. Interrupts are disabled during a call to . */ void MiniportHandleInterrupt( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance. ) { DBG_FUNC("MiniportHandleInterrupt") PBCHANNEL_OBJECT pBChannel; // A Pointer to one of our '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 is a required function if a Minipor's NIC does not generate interrupts. Otherwise, one or more functions are optional. The driver of a NIC that does not generate interrupts must have a 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 function associated with the timer object to be run repeatedly and automatically at the interval specified by MillisecondsPeriod. Such a polling 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 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 function associated with the timer object to be run once when the given MillisecondsToDelay expires. Such a function usually performs some driver-determined action if a particular operation times out. If either type of 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 function at the discretion of the driver writer. Each such function must be associated with a driver-allocated and initialized timer object. A call to NdisMCancelTimer cancels execution of a nonpolling 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 function: either the function runs once, or it is canceled. The MiniportHalt function of any driver with a function should call NdisMCancelTimer to ensure that the function does not attempt to access resources that MiniportHalt has already released. By default, runs at IRQL DISPATCH_LEVEL. */ void MiniportTimer( IN PVOID SystemSpecific1, // @parm // UNREFERENCED_PARAMETER IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the 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); }