Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

794 lines
17 KiB

/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
timer.c
Abstract:
NDIS wrapper functions for full mac drivers isr/timer
Author:
Sean Selitrennikoff (SeanSe) 05-Oct-93
Environment:
Kernel mode, FSD
Revision History:
Jameel Hyder (JameelH) Re-organization 01-Jun-95
--*/
#include <precomp.h>
#pragma hdrstop
#include <stdarg.h>
//
// Define the module number for debug code.
//
#define MODULE_NUMBER MODULE_TIMER
VOID
NdisInitializeTimer(
IN OUT PNDIS_TIMER NdisTimer,
IN PNDIS_TIMER_FUNCTION TimerFunction,
IN PVOID FunctionContext
)
/*++
Routine Description:
Sets up an NdisTimer object, initializing the DPC in the timer to
the function and context.
Arguments:
NdisTimer - the timer object.
TimerFunction - Routine to start.
FunctionContext - Context of TimerFunction.
Return Value:
None.
--*/
{
INITIALIZE_TIMER(&(NdisTimer)->Timer);
//
// Initialize our dpc. If Dpc was previously initialized, this will
// reinitialize it.
//
INITIALIZE_DPC(&NdisTimer->Dpc,
(PKDEFERRED_ROUTINE)TimerFunction,
FunctionContext);
SET_PROCESSOR_DPC(&NdisTimer->Dpc,
ndisValidProcessors[ndisCurrentProcessor]);
SET_DPC_IMPORTANCE(&NdisTimer->Dpc);
}
VOID
NdisSetTimer(
IN PNDIS_TIMER NdisTimer,
IN UINT MillisecondsToDelay
)
/*++
Routine Description:
Sets up TimerFunction to fire after MillisecondsToDelay.
Arguments:
NdisTimer - the timer object.
MillisecondsToDelay - Amount of time before TimerFunction is started.
Return Value:
None.
--*/
{
LARGE_INTEGER FireUpTime;
FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsToDelay, -10000);
//
// Set the timer
//
SET_TIMER(&NdisTimer->Timer, FireUpTime, &NdisTimer->Dpc);
}
#undef NdisCancelTimer
VOID
NdisCancelTimer(
IN PNDIS_TIMER Timer,
OUT PBOOLEAN TimerCancelled
)
{
*TimerCancelled = KeCancelTimer(&Timer->Timer);
}
BOOLEAN
ndisIsr(
IN PKINTERRUPT Interrupt,
IN PVOID Context
)
/*++
Routine Description:
Handles ALL Mac interrupts, calling the appropriate Mac ISR and DPC
depending on the context.
Arguments:
Interrupt - Interrupt object for the Mac.
Context - Really a pointer to the interrupt.
Return Value:
None.
--*/
{
//
// Get adapter from context.
//
PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(Context);
BOOLEAN (*InterruptIsr)(PVOID) = (BOOLEAN (*) (PVOID))(NdisInterrupt->MacIsr);
UNREFERENCED_PARAMETER(Interrupt);
//
// Call MacIsr
//
if((*InterruptIsr)(NdisInterrupt->InterruptContext) != FALSE)
{
//
// Queue MacDpc if needed
//
Increment((PLONG)&NdisInterrupt->DpcCount, &Interrupt->DpcCountLock);
if (!(QUEUE_DPC(&NdisInterrupt->InterruptDpc)))
{
//
// If the DPC was already queued, then we have an extra
// reference (we do it this way to ensure that the reference
// is added *before* the DPC is queued).
//
Decrement((PLONG)&NdisInterrupt->DpcCount, &Interrupt->DpcCountLock);
if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0))
{
//
// We need to queue a DPC to set the event because we
// can't do it from the ISR. We know that the interrupt
// DPC won't fire because the refcount is 0, so we reuse it.
//
INITIALIZE_DPC(&NdisInterrupt->InterruptDpc,
ndisLastCountRemovedFunction,
(PVOID)(&NdisInterrupt->DpcsCompletedEvent));
//
// When ndisLastCountRemovedFunction runs it will set
// the event.
//
QUEUE_DPC (&NdisInterrupt->InterruptDpc);
}
}
return TRUE;
}
return FALSE;
}
VOID
ndisDpc(
IN PVOID SystemSpecific1,
IN PVOID InterruptContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3
)
/*++
Routine Description:
Handles ALL Mac interrupt DPCs, calling the appropriate Mac DPC
depending on the context.
Arguments:
Interrupt - Interrupt object for the Mac.
Context - Really a pointer to the Interrupt.
Return Value:
None.
--*/
{
//
// Get adapter from context.
//
PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(InterruptContext);
VOID (*MacDpc)(PVOID) = (VOID (*) (PVOID))(NdisInterrupt->MacDpc);
//
// Call MacDpc
//
(*((PNDIS_DEFERRED_PROCESSING)MacDpc))(SystemSpecific1,
NdisInterrupt->InterruptContext,
SystemSpecific2,
SystemSpecific3);
Decrement((PLONG)&NdisInterrupt->DpcCount, &Interrupt->DpcCountLock);
if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0))
{
SET_EVENT(&NdisInterrupt->DpcsCompletedEvent);
}
}
VOID
NdisInitializeInterrupt(
OUT PNDIS_STATUS Status,
IN OUT PNDIS_INTERRUPT NdisInterrupt,
IN NDIS_HANDLE NdisAdapterHandle,
IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine,
IN PVOID InterruptContext,
IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine,
IN UINT InterruptVector,
IN UINT InterruptLevel,
IN BOOLEAN SharedInterrupt,
IN NDIS_INTERRUPT_MODE InterruptMode
)
/*++
Routine Description:
Initializes the interrupt and sets up the Dpc.
Arguments:
Status - Status of this request.
InterruptDpc - The Dpc object corresponding to DeferredProcessingRoutine.
Interrupt - Points to driver allocated memory that the wrapper fills in
with information about the interrupt handler.
InterruptServiceRoutine - The ISR that is called for this interrupt.
InterruptContext - Value passed to the ISR.
DeferredProcessingRoutine - The DPC queued by the ISR.
InterruptVector - Interrupt number used by the ISR.
InterruptMode - Type of interrupt the adapter generates.
Return Value:
None.
--*/
{
NTSTATUS NtStatus;
PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
ULONG Vector;
ULONG NumberOfElements;
KIRQL Irql;
KAFFINITY InterruptAffinity;
PCM_RESOURCE_LIST Resources;
BOOLEAN Conflict;
BOOLEAN IsAMiniport;
PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)(NdisInterrupt);
IsAMiniport = (AdptrP->DeviceObject == NULL);
//
// First check if any bus access is allowed
//
if (((IsAMiniport ?
Miniport->BusType:
AdptrP->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
((IsAMiniport ?
Miniport->BusNumber:
AdptrP->BusNumber) == (ULONG)-1))
{
*Status = NDIS_STATUS_FAILURE;
return;
}
*Status = NDIS_STATUS_SUCCESS;
//
// First check for resource conflict by expanding current resource list,
// adding in the interrupt, and then re-submitting the resource list.
//
if ((IsAMiniport ?
Miniport->Resources:
AdptrP->Resources) != NULL)
{
NumberOfElements = (IsAMiniport ?
Miniport->Resources->List[0].PartialResourceList.Count + 1 :
AdptrP->Resources->List[0].PartialResourceList.Count + 1);
}
else
{
NumberOfElements = 1;
}
Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
NumberOfElements,
NDIS_TAG_RSRC_LIST);
if (Resources == NULL)
{
*Status = NDIS_STATUS_RESOURCES;
return;
}
if ((IsAMiniport ?
Miniport->Resources :
AdptrP->Resources) != NULL)
{
CopyMemory(Resources,
(IsAMiniport ? Miniport->Resources :AdptrP->Resources),
sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (NumberOfElements - 1));
}
else
{
//
// Setup initial resource info
//
ASSERT(IsAMiniport);
Resources->Count = 1;
Resources->List[0].InterfaceType = Miniport->AdapterType;
Resources->List[0].BusNumber = Miniport->BusNumber;
Resources->List[0].PartialResourceList.Version = 0;
Resources->List[0].PartialResourceList.Revision = 0;
Resources->List[0].PartialResourceList.Count = 0;
}
//
// Setup interrupt
//
Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
CmResourceTypeInterrupt;
Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
SharedInterrupt ? CmResourceShareShared : CmResourceShareDeviceExclusive;
Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
(InterruptMode == NdisInterruptLatched) ?
CM_RESOURCE_INTERRUPT_LATCHED :
CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Level =
InterruptLevel;
Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Vector =
InterruptVector;
Resources->List[0].PartialResourceList.Count++;
//
// Make the call
//
NtStatus = IoReportResourceUsage(NULL,
(IsAMiniport ?
Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver),
NULL,
0,
IsAMiniport ?
Miniport->DeviceObject :
AdptrP->DeviceObject,
Resources,
sizeof(CM_RESOURCE_LIST) +
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * Resources->List[0].PartialResourceList.Count,
TRUE,
&Conflict);
//
// Check for conflict.
//
if ((IsAMiniport ?
Miniport->Resources:
AdptrP->Resources) != NULL)
{
FREE_POOL((IsAMiniport ?
Miniport->Resources:
AdptrP->Resources));
}
if (IsAMiniport)
{
Miniport->Resources = Resources;
}
else
{
AdptrP->Resources = Resources;
}
if (Conflict || (NtStatus != STATUS_SUCCESS))
{
if (Conflict)
{
//
// Log an error
//
PIO_ERROR_LOG_PACKET errorLogEntry;
ULONG i;
ULONG StringSize;
PUCHAR Place;
PWCH baseFileName;
WCHAR Character;
ULONG Value;
baseFileName = ((AdptrP->DeviceObject != NULL) ?
AdptrP->AdapterName.Buffer :
Miniport->MiniportName.Buffer);
//
// Parse out the path name, leaving only the device name.
//
for (i = 0;
i < ((AdptrP->DeviceObject != NULL) ?
AdptrP->AdapterName.Length :
Miniport->MiniportName.Length) / sizeof(WCHAR);
i++)
{
//
// If s points to a directory separator, set baseFileName to
// the character after the separator.
//
if (((AdptrP->DeviceObject != NULL) ?
AdptrP->AdapterName.Buffer[i] :
Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR)
{
baseFileName = ((AdptrP->DeviceObject != NULL) ?
&(AdptrP->AdapterName.Buffer[++i]):
&(Miniport->MiniportName.Buffer[++i]));
}
}
StringSize = ((AdptrP->DeviceObject != NULL) ?
AdptrP->AdapterName.MaximumLength :
Miniport->MiniportName.MaximumLength) -
(((ULONG)baseFileName) -
((AdptrP->DeviceObject != NULL) ?
((ULONG)AdptrP->AdapterName.Buffer) :
((ULONG)Miniport->MiniportName.Buffer)));
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
(IsAMiniport ?
Miniport->DeviceObject :
AdptrP->DeviceObject),
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
StringSize +
6)); // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
if (errorLogEntry != NULL)
{
errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT;
//
// store the time
//
errorLogEntry->MajorFunctionCode = 0;
errorLogEntry->RetryCount = 0;
errorLogEntry->UniqueErrorValue = 0;
errorLogEntry->FinalStatus = 0;
errorLogEntry->SequenceNumber = 0;
errorLogEntry->IoControlCode = 0;
//
// Set string information
//
if (StringSize != 0)
{
errorLogEntry->NumberOfStrings = 1;
errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
CopyMemory(((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
baseFileName,
StringSize);
Place = ((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET) + StringSize;
}
else
{
Place = ((PUCHAR)errorLogEntry) +
sizeof(IO_ERROR_LOG_PACKET);
errorLogEntry->NumberOfStrings = 0;
}
errorLogEntry->NumberOfStrings++;
//
// Put in interrupt level
//
Value = InterruptLevel;
//
// Convert value
//
// I couldn't think of a better way to do this (with some
// loop). If you find one, plz put it in.
//
if (Value > 9)
{
Character = L'0' + (WCHAR)(Value / 10);
memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
Place += sizeof(WCHAR);
Value -= 10;
}
Character = L'0' + (WCHAR)Value;
memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
Place += sizeof(WCHAR);
Character = UNICODE_NULL;
memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
//
// write it out
//
IoWriteErrorLogEntry(errorLogEntry);
}
*Status = NDIS_STATUS_RESOURCE_CONFLICT;
return;
}
*Status = NDIS_STATUS_FAILURE;
return;
}
//
// We must do this stuff first because if we connect the
// interrupt first then an interrupt could occur before
// the MacISR is recorded in the Ndis interrupt structure.
//
if (IsAMiniport)
{
INITIALIZE_SPIN_LOCK(&MiniportInterrupt->DpcCountLock);
Miniport->Interrupt = MiniportInterrupt;
MiniportInterrupt->DpcCount = 0;
MiniportInterrupt->MiniportIdField = NULL;
MiniportInterrupt->Miniport = Miniport;
MiniportInterrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler;
MiniportInterrupt->MiniportDpc = Miniport->HandleInterruptHandler;
MiniportInterrupt->SharedInterrupt = SharedInterrupt;
MiniportInterrupt->IsrRequested = (BOOLEAN)DeferredProcessingRoutine;
CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
}
else
{
NdisInterrupt->MacIsr = InterruptServiceRoutine;
NdisInterrupt->MacDpc = DeferredProcessingRoutine;
NdisInterrupt->InterruptContext = InterruptContext;
INITIALIZE_SPIN_LOCK(&NdisInterrupt->DpcCountLock);
NdisInterrupt->DpcCount = 0;
NdisInterrupt->Removing = FALSE;
}
//
// This is used to tell when all Dpcs are completed after the
// interrupt has been removed.
//
INITIALIZE_EVENT(IsAMiniport ?
&MiniportInterrupt->DpcsCompletedEvent :
&NdisInterrupt->DpcsCompletedEvent);
//
// Initialize our dpc.
//
if (IsAMiniport)
{
INITIALIZE_DPC(&MiniportInterrupt->InterruptDpc,
(Miniport->Flags & fMINIPORT_IS_CO) ?
ndisMCoDpc : ndisMDpc,
MiniportInterrupt);
SET_DPC_IMPORTANCE(&MiniportInterrupt->InterruptDpc);
SET_PROCESSOR_DPC(&MiniportInterrupt->InterruptDpc,
ndisValidProcessors[ndisCurrentProcessor]);
}
else
{
INITIALIZE_DPC(&NdisInterrupt->InterruptDpc,
(PKDEFERRED_ROUTINE) ndisDpc,
NdisInterrupt);
SET_DPC_IMPORTANCE(&NdisInterrupt->InterruptDpc);
SET_PROCESSOR_DPC(&NdisInterrupt->InterruptDpc,
ndisValidProcessors[ndisCurrentProcessor]);
}
//
// Get the system interrupt vector and IRQL.
//
Vector = HalGetInterruptVector((IsAMiniport ?
Miniport->BusType :
AdptrP->BusType), // InterfaceType
(IsAMiniport ?
Miniport->BusNumber :
AdptrP->BusNumber), // BusNumber
(ULONG)InterruptLevel, // BusInterruptLevel
(ULONG)InterruptVector, // BusInterruptVector
&Irql, // Irql
&InterruptAffinity);
if (IsAMiniport)
{
NtStatus = IoConnectInterrupt(
&MiniportInterrupt->InterruptObject,
(PKSERVICE_ROUTINE)ndisMIsr,
MiniportInterrupt,
NULL,
Vector,
Irql,
Irql,
(KINTERRUPT_MODE)InterruptMode,
SharedInterrupt,
InterruptAffinity,
FALSE);
}
else
{
NtStatus = IoConnectInterrupt(
&NdisInterrupt->InterruptObject,
(PKSERVICE_ROUTINE)ndisIsr,
NdisInterrupt,
NULL,
Vector,
Irql,
Irql,
(KINTERRUPT_MODE)InterruptMode,
SharedInterrupt,
InterruptAffinity,
FALSE);
}
if (!NT_SUCCESS(NtStatus))
{
*Status = NDIS_STATUS_FAILURE;
}
}
VOID
NdisRemoveInterrupt(
IN PNDIS_INTERRUPT Interrupt
)
/*++
Routine Description:
Removes the interrupt, will not return until all interrupts and
interrupt dpcs are completed.
Arguments:
Interrupt - Points to driver allocated memory that the wrapper filled
with information about the interrupt handler.
Return Value:
None.
--*/
{
PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
BOOLEAN fIsMiniport;
//
// Determine if this is a miniport's interrupt.
//
fIsMiniport = (BOOLEAN)(MiniportInterrupt->MiniportIdField == NULL);
//
// Mark the interrupt as being removed.
//
if (fIsMiniport)
{
MINIPORT_SET_FLAG(
MiniportInterrupt->Miniport,
fMINIPORT_BEING_REMOVED);
}
else
{
Interrupt->Removing = TRUE;
}
//
// Now we disconnect the interrupt.
// NOTE: they are aligned in both structures
//
IoDisconnectInterrupt(Interrupt->InterruptObject);
//
// Right now we know that any Dpcs that may fire are counted.
// We don't have to guard this with a spin lock because the
// Dpc will set the event it completes first, or we may
// wait for a little while for it to complete.
//
if (fIsMiniport)
{
if (MiniportInterrupt->DpcCount > 0)
{
//
// Now we wait for all dpcs to complete.
//
WAIT_FOR_OBJECT(&MiniportInterrupt->DpcsCompletedEvent, NULL);
RESET_EVENT(&MiniportInterrupt->DpcsCompletedEvent);
}
}
else
{
if (Interrupt->DpcCount > 0)
{
//
// Now we wait for all dpcs to complete.
//
WAIT_FOR_OBJECT(&Interrupt->DpcsCompletedEvent, NULL);
RESET_EVENT(&Interrupt->DpcsCompletedEvent);
}
}
}