|
|
/*++
Copyright (c) 1989-1993 Microsoft Corporation
Module Name:
timer.c
Abstract:
This module contains code which implements the timers for netbios.
Environment:
Kernel mode
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
ULONG NbiTickIncrement = 0; ULONG NbiShortTimerDeltaTicks = 0;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,NbiInitializeTimers)
#endif
VOID NbiStartRetransmit( IN PCONNECTION Connection )
/*++
Routine Description:
This routine starts the retransmit timer for the given connection. The connection is inserted on the short list if it isn't on already.
NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
Arguments:
Connection - pointer to the connection.
Return Value:
None.
--*/
{ PDEVICE Device = NbiDevice; NB_DEFINE_LOCK_HANDLE (LockHandle)
//
// Insert us in the queue if we aren't in it.
//
Connection->Retransmit = Device->ShortAbsoluteTime + Connection->CurrentRetransmitTimeout;
if (!Connection->OnShortList) {
CTEAssert (KeGetCurrentIrql() == DISPATCH_LEVEL);
NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
if (!Connection->OnShortList) { Connection->OnShortList = TRUE; InsertTailList (&Device->ShortList, &Connection->ShortList); }
if (!Device->ShortListActive) { NbiStartShortTimer (Device); Device->ShortListActive = TRUE; }
NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); }
} /* NbiStartRetransmit */
VOID NbiStartWatchdog( IN PCONNECTION Connection )
/*++
Routine Description:
This routine starts the watchdog timer for a connection.
NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
Arguments:
Connection - pointer to the connection.
Return Value:
None.
--*/
{ PDEVICE Device = NbiDevice; NB_DEFINE_LOCK_HANDLE (LockHandle);
Connection->Watchdog = Device->LongAbsoluteTime + Connection->WatchdogTimeout;
if (!Connection->OnLongList) {
ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
if (!Connection->OnLongList) { Connection->OnLongList = TRUE; InsertTailList (&Device->LongList, &Connection->LongList); }
NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); }
} /* NbiStartWatchdog */
#if DBG
VOID NbiStopRetransmit( IN PCONNECTION Connection )
/*++
Routine Description:
This routine stops the retransmit timer for a connection.
Arguments:
Connection - pointer to the connection.
Return Value:
None.
--*/
{ Connection->Retransmit = 0;
} /* NbiStopRetransmit */
VOID NbiStopWatchdog( IN PCONNECTION Connection )
/*++
Routine Description:
This routine stops the watchdog timer for a connection.
Arguments:
Connection - pointer to the connection.
Return Value:
None.
--*/
{ Connection->Watchdog = 0;
} /* NbiStopWatchdog */ #endif
VOID NbiExpireRetransmit( IN PCONNECTION Connection )
/*++
Routine Description:
This routine is called when the connection's retransmit timer expires. It is called from NbiShortTimeout.
Arguments:
Connection - Pointer to the connection whose timer has expired.
Return Value:
none.
--*/
{ PDEVICE Device = NbiDevice; BOOLEAN SendFindRoute; NB_DEFINE_LOCK_HANDLE (LockHandle);
NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
if (Connection->State == CONNECTION_STATE_ACTIVE) {
SendFindRoute = FALSE;
++Device->Statistics.ResponseTimerExpirations;
if (!(Connection->NewNetbios) && (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
if (--Connection->Retries == 0) {
//
// Shut down the connection. This will send
// out half the usual number of session end
// frames.
//
NB_DEBUG2 (CONNECTION, ("Wait for ack timeout of active connection %lx\n", Connection));
//
// This free the connection lock.
//
NbiStopConnection( Connection, STATUS_LINK_FAILED NB_LOCK_HANDLE_ARG (LockHandle) );
} else {
//
// Set our current packetize location back to the
// spot of the last ack, and start up again.
//
// Should we send a probe here?
//
Connection->CurrentSend = Connection->UnAckedSend; Connection->RetransmitThisWindow = TRUE; if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) { Connection->CurrentRetransmitTimeout = (Connection->CurrentRetransmitTimeout * 3) / 2; }
NB_DEBUG2 (SEND, ("Connection %lx retransmit timeout\n", Connection));
//
// After half the retries, send a find route unless we
// are already doing one, or the connection is to network
// 0. When this completes we update the local target,
// for whatever good that does.
//
if ((!Connection->FindRouteInProgress) && (Connection->Retries == (Device->KeepAliveCount/2)) && (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
SendFindRoute = TRUE; Connection->FindRouteInProgress = TRUE; NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
}
//
// This releases the lock.
//
NbiPacketizeSend( Connection NB_LOCK_HANDLE_ARG(LockHandle) );
}
} else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) || (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) || (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
if (--Connection->Retries == 0) {
//
// Shut down the connection. This will send
// out half the usual number of session end
// frames.
//
NB_DEBUG2 (CONNECTION, ("Probe timeout of active connection %lx\n", Connection));
//
// This free the connection lock.
//
NbiStopConnection( Connection, STATUS_LINK_FAILED NB_LOCK_HANDLE_ARG (LockHandle) );
} else {
Connection->RetransmitThisWindow = TRUE; if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) { Connection->CurrentRetransmitTimeout = (Connection->CurrentRetransmitTimeout * 3) / 2; }
NbiStartRetransmit (Connection);
//
// After half the retries, send a find route unless we
// are already doing one, or the connection is to network
// 0. When this completes we update the local target,
// for whatever good that does.
//
if ((!Connection->FindRouteInProgress) && (Connection->Retries == (Device->KeepAliveCount/2)) && (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
SendFindRoute = TRUE; Connection->FindRouteInProgress = TRUE; NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
}
//
// Set this so we know to retransmit when the ack
// is received.
//
if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PROBE) { Connection->ResponseTimeout = TRUE; }
//
// This releases the lock.
//
NbiSendDataAck( Connection, NbiAckQuery NB_LOCK_HANDLE_ARG(LockHandle));
}
} else {
NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
}
if (SendFindRoute) {
Connection->FindRouteRequest.Identifier = IDENTIFIER_NB; *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork; RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6); Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_FORCE_RIP;
(*Device->Bind.FindRouteHandler)( &Connection->FindRouteRequest);
}
} else {
NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
}
} /* NbiExpireRetansmit */
VOID NbiExpireWatchdog( IN PCONNECTION Connection )
/*++
Routine Description:
This routine is called when the connection's watchdog timer expires. It is called from NbiLongTimeout.
Arguments:
Connection - Pointer to the connection whose timer has expired.
Return Value:
none.
--*/
{ NB_DEFINE_LOCK_HANDLE (LockHandle);
NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
//
// If we are not idle, then something else is happening
// so the watchdog is unnecessary.
//
if ((Connection->State == CONNECTION_STATE_ACTIVE) && (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE)) {
Connection->Retries = NbiDevice->KeepAliveCount; Connection->SubState = CONNECTION_SUBSTATE_A_W_PROBE; NbiStartRetransmit (Connection);
//
// This releases the lock.
//
NbiSendDataAck( Connection, NbiAckQuery NB_LOCK_HANDLE_ARG(LockHandle));
} else {
NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
}
} /* NbiExpireWatchdog */
VOID NbiShortTimeout( IN CTEEvent * Event, IN PVOID Context )
/*++
Routine Description:
This routine is called at regular intervals to see if any of the short connection timers have expired, and if so to execute their expiration routines.
Arguments:
Event - The event controlling the timer.
Context - Points to our device.
Return Value:
none.
--*/
{ PLIST_ENTRY p, nextp; PDEVICE Device = (PDEVICE)Context; PCONNECTION Connection; BOOLEAN RestartTimer = FALSE; LARGE_INTEGER CurrentTick; LARGE_INTEGER TickDifference; ULONG TickDelta; NB_DEFINE_LOCK_HANDLE (LockHandle);
NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
//
// This prevents anybody from starting the timer while we
// are in this routine (the main reason for this is that it
// makes it easier to determine whether we should restart
// it at the end of this routine).
//
Device->ProcessingShortTimer = TRUE;
//
// Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we
// advance it all the way to 0xf0000000, then reset it to 0x10000000.
// We also run all the lists, decreasing all counters by 0xe0000000.
//
KeQueryTickCount (&CurrentTick);
TickDifference.QuadPart = CurrentTick.QuadPart - Device->ShortTimerStart.QuadPart;
TickDelta = TickDifference.LowPart / NbiShortTimerDeltaTicks; if (TickDelta == 0) { TickDelta = 1; }
Device->ShortAbsoluteTime += TickDelta;
if (Device->ShortAbsoluteTime >= 0xf0000000) {
ULONG Timeout;
Device->ShortAbsoluteTime -= 0xe0000000;
p = Device->ShortList.Flink; while (p != &Device->ShortList) {
Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
Timeout = Connection->Retransmit; if (Timeout) { Connection->Retransmit = Timeout - 0xe0000000; }
p = p->Flink; }
}
p = Device->ShortList.Flink; while (p != &Device->ShortList) {
Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
ASSERT (Connection->OnShortList);
//
// To avoid problems with the refcount being 0, don't
// do this if we are in ADM.
//
if (Connection->State == CONNECTION_STATE_ACTIVE) {
if (Connection->Retransmit && (Device->ShortAbsoluteTime > Connection->Retransmit)) {
Connection->Retransmit = 0; NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
NbiExpireRetransmit (Connection); // no locks held
NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
}
}
if (!Connection->OnShortList) {
//
// The link has been taken out of the list while
// we were processing it. In this (rare) case we
// stop processing the whole list, we'll get it
// next time.
//
break;
}
nextp = p->Flink;
if (Connection->Retransmit == 0) {
Connection->OnShortList = FALSE; RemoveEntryList(p);
//
// Do another check; that way if someone slipped in between
// the check of Connection->Tx and the OnShortList = FALSE and
// therefore exited without inserting, we'll catch that here.
//
if (Connection->Retransmit != 0) { InsertTailList(&Device->ShortList, &Connection->ShortList); Connection->OnShortList = TRUE; }
}
p = nextp;
}
//
// If the list is empty note that, otherwise ShortListActive
// remains TRUE.
//
if (IsListEmpty (&Device->ShortList)) { Device->ShortListActive = FALSE; }
//
// Connection Data Ack timers. This queue is used to indicate
// that a piggyback ack is pending for this connection. We walk
// the queue, for each element we check if the connection has
// been on the queue for enough times through here,
// If so, we take it off and send an ack. Note that
// we have to be very careful how we walk the queue, since
// it may be changing while this is running.
//
for (p = Device->DataAckConnections.Flink; p != &Device->DataAckConnections; p = p->Flink) {
Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
//
// Skip this connection if it is not queued or it is
// too recent to matter. We may skip incorrectly if
// the connection is just being queued, but that is
// OK, we will get it next time.
//
if (!Connection->DataAckPending) { continue; }
++Connection->DataAckTimeouts;
if (Connection->DataAckTimeouts < Device->AckDelayTime) { continue; }
NbiReferenceConnectionSync (Connection, CREF_SHORT_D_ACK);
Device->DataAckQueueChanged = FALSE;
NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
//
// Check the correct connection flag, to ensure that a
// send has not just taken him off the queue.
//
NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
if (Connection->DataAckPending) {
//
// Yes, we were waiting to piggyback an ack, but no send
// has come along. Turn off the flags and send an ack.
// We set PiggybackAckTimeout to TRUE so that we won't try
// to piggyback a response until we get back traffic.
//
Connection->DataAckPending = FALSE; Connection->PiggybackAckTimeout = TRUE; ++Device->Statistics.AckTimerExpirations; ++Device->Statistics.PiggybackAckTimeouts;
//
// This call releases the lock.
//
NbiSendDataAck( Connection, NbiAckResponse NB_LOCK_HANDLE_ARG(LockHandle));
} else {
NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
}
NbiDereferenceConnection (Connection, CREF_SHORT_D_ACK);
NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
//
// If the list has changed, then we need to stop processing
// since p->Flink is not valid.
//
if (Device->DataAckQueueChanged) { break; }
}
if (IsListEmpty (&Device->DataAckConnections)) { Device->DataAckActive = FALSE; }
//
// Update the real counters from the temp ones. We have
// TimerLock here, which is good enough.
//
ADD_TO_LARGE_INTEGER( &Device->Statistics.DataFrameBytesSent, Device->TempFrameBytesSent); Device->Statistics.DataFramesSent += Device->TempFramesSent;
Device->TempFrameBytesSent = 0; Device->TempFramesSent = 0;
ADD_TO_LARGE_INTEGER( &Device->Statistics.DataFrameBytesReceived, Device->TempFrameBytesReceived); Device->Statistics.DataFramesReceived += Device->TempFramesReceived;
Device->TempFrameBytesReceived = 0; Device->TempFramesReceived = 0;
//
// Determine if we have to restart the timer.
//
Device->ProcessingShortTimer = FALSE;
if ((Device->ShortListActive || Device->DataAckActive) && (Device->State != DEVICE_STATE_STOPPING)) {
RestartTimer = TRUE;
}
NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
if (RestartTimer) {
//
// Start up the timer again. Note that because we start the timer
// after doing work (above), the timer values will slip somewhat,
// depending on the load on the protocol. This is entirely acceptable
// and will prevent us from using the timer DPC in two different
// threads of execution.
//
KeQueryTickCount(&Device->ShortTimerStart);
CTEStartTimer( &Device->ShortTimer, SHORT_TIMER_DELTA, NbiShortTimeout, (PVOID)Device);
} else {
NbiDereferenceDevice (Device, DREF_SHORT_TIMER);
}
} /* NbiShortTimeout */
VOID NbiLongTimeout( IN CTEEvent * Event, IN PVOID Context )
/*++
Routine Description:
This routine is called at regular intervals to see if any of the long connection timers have expired, and if so to execute their expiration routines.
Arguments:
Event - The event controlling the timer.
Context - Points to our device.
Return Value:
none.
--*/
{ PDEVICE Device = (PDEVICE)Context; PLIST_ENTRY p, nextp; LIST_ENTRY AdapterStatusList; PREQUEST AdapterStatusRequest; PCONNECTION Connection; PNETBIOS_CACHE CacheName; NB_DEFINE_LOCK_HANDLE (LockHandle) NB_DEFINE_LOCK_HANDLE (LockHandle1)
//
// Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we
// advance it all the way to 0xf0000000, then reset it to 0x10000000.
// We also run all the lists, decreasing all counters by 0xe0000000.
//
NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
if (++Device->LongAbsoluteTime == 0xf0000000) {
ULONG Timeout;
Device->LongAbsoluteTime = 0x10000000;
p = Device->LongList.Flink; while (p != &Device->LongList) {
Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
Timeout = Connection->Watchdog; if (Timeout) { Connection->Watchdog = Timeout - 0xe0000000; }
p = p->Flink; }
}
if ((Device->LongAbsoluteTime % 4) == 0) {
p = Device->LongList.Flink; while (p != &Device->LongList) {
Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
ASSERT (Connection->OnLongList);
//
// To avoid problems with the refcount being 0, don't
// do this if we are in ADM.
//
if (Connection->State == CONNECTION_STATE_ACTIVE) {
if (Connection->Watchdog && (Device->LongAbsoluteTime > Connection->Watchdog)) {
Connection->Watchdog = 0; NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
NbiExpireWatchdog (Connection); // no spinlocks held
NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
}
}
if (!Connection->OnLongList) {
//
// The link has been taken out of the list while
// we were processing it. In this (rare) case we
// stop processing the whole list, we'll get it
// next time.
//
#if DBG
DbgPrint ("NBI: Stop processing LongList, %lx removed\n", Connection); #endif
break;
}
nextp = p->Flink;
if (Connection->Watchdog == 0) {
Connection->OnLongList = FALSE; RemoveEntryList(p);
if (Connection->Watchdog != 0) { InsertTailList(&Device->LongList, &Connection->LongList); Connection->OnLongList = TRUE; }
}
p = nextp;
}
}
//
// Now scan the data ack queue, looking for connections with
// no acks queued that we can get rid of.
//
// Note: The timer spinlock is held here.
//
for (p = Device->DataAckConnections.Flink; p != &Device->DataAckConnections; p = p->Flink) {
Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
if (Connection->DataAckPending) { continue; }
NbiReferenceConnectionSync (Connection, CREF_LONG_D_ACK);
NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1); NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
//
// Have to check again, because the connection might
// just have been stopped, and it also might just have
// had a data ack queued.
//
if (Connection->OnDataAckQueue) {
Connection->OnDataAckQueue = FALSE;
RemoveEntryList (&Connection->DataAckLinkage);
if (Connection->DataAckPending) { InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage); Connection->OnDataAckQueue = TRUE; }
Device->DataAckQueueChanged = TRUE;
}
NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
NbiDereferenceConnection (Connection, CREF_LONG_D_ACK);
NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
//
// Since we have changed the list, we can't tell if p->Flink
// is valid, so break. The effect is that we gradually peel
// connections off the queue.
//
break;
}
NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
//
// Scan for any uncompleted receive IRPs, this may happen if
// the cable is pulled and we don't get any more ReceiveComplete
// indications.
NbiReceiveComplete((USHORT)0);
//
// Check if any adapter status queries are getting old.
//
InitializeListHead (&AdapterStatusList);
NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
p = Device->ActiveAdapterStatus.Flink;
while (p != &Device->ActiveAdapterStatus) {
AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
p = p->Flink;
if (REQUEST_INFORMATION(AdapterStatusRequest) == 1) {
//
// We should resend a certain number of times.
//
RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest)); InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
//
// We are going to abort this request, so dereference
// the cache entry it used.
//
CacheName = (PNETBIOS_CACHE)REQUEST_STATUSPTR(AdapterStatusRequest); if (--CacheName->ReferenceCount == 0) {
NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName)); NbiFreeMemory( CacheName, sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)), MEMORY_CACHE, "Name deleted");
}
} else {
++REQUEST_INFORMATION(AdapterStatusRequest);
}
}
NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p); p = p->Flink;
NB_DEBUG2 (QUERY, ("AdapterStatus %lx got name but no response\n", AdapterStatusRequest));
REQUEST_INFORMATION(AdapterStatusRequest) = 0; REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
NbiCompleteRequest(AdapterStatusRequest); NbiFreeRequest (Device, AdapterStatusRequest);
NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
}
//
// See if a minute has passed and we need to check for empty
// cache entries to age out. We check for 64 seconds to make
// the mod operation faster.
//
#if defined(_PNP_POWER)
NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle); #endif _PNP_POWER
++Device->CacheTimeStamp;
if ((Device->CacheTimeStamp % 64) == 0) {
//
// flush all the entries which have been around for ten minutes
// (LONG_TIMER_DELTA is in milliseconds).
//
FlushOldFromNetbiosCacheTable( Device->NameCache, (600000 / LONG_TIMER_DELTA) );
}
//
// Start up the timer again. Note that because we start the timer
// after doing work (above), the timer values will slip somewhat,
// depending on the load on the protocol. This is entirely acceptable
// and will prevent us from using the timer DPC in two different
// threads of execution.
//
if (Device->State != DEVICE_STATE_STOPPING) {
CTEStartTimer( &Device->LongTimer, LONG_TIMER_DELTA, NbiLongTimeout, (PVOID)Device);
} else { #if defined(_PNP_POWER)
Device->LongTimerRunning = FALSE; #endif _PNP_POWER
NbiDereferenceDevice (Device, DREF_LONG_TIMER); }
#if defined(_PNP_POWER)
NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle); #endif _PNP_POWER
} /* NbiLongTimeout */
VOID NbiStartShortTimer( IN PDEVICE Device )
/*++
Routine Description:
This routine starts the short timer, if it is not already running.
Arguments:
Device - Pointer to our device context.
Return Value:
none.
--*/
{
//
// Start the timer unless it the DPC is already running (in
// which case it will restart the timer itself if needed),
// or some list is active (meaning the timer is already
// queued up).
//
if ((!Device->ProcessingShortTimer) && (!(Device->ShortListActive)) && (!(Device->DataAckActive))) {
NbiReferenceDevice (Device, DREF_SHORT_TIMER);
KeQueryTickCount(&Device->ShortTimerStart);
CTEStartTimer( &Device->ShortTimer, SHORT_TIMER_DELTA, NbiShortTimeout, (PVOID)Device);
}
} /* NbiStartShortTimer */
VOID NbiInitializeTimers( IN PDEVICE Device )
/*++
Routine Description:
This routine initializes the lightweight timer system for the transport provider.
Arguments:
Device - Pointer to our device.
Return Value:
none.
--*/
{
//
// NbiTickIncrement is the number of NT time increments
// which pass between each tick. NbiShortTimerDeltaTicks
// is the number of ticks which should happen in
// SHORT_TIMER_DELTA milliseconds (i.e. between each
// expiration of the short timer).
//
NbiTickIncrement = KeQueryTimeIncrement();
if (NbiTickIncrement > (SHORT_TIMER_DELTA * MILLISECONDS)) { NbiShortTimerDeltaTicks = 1; } else { NbiShortTimerDeltaTicks = (SHORT_TIMER_DELTA * MILLISECONDS) / NbiTickIncrement; }
//
// The AbsoluteTime cycles between 0x10000000 and 0xf0000000.
//
Device->ShortAbsoluteTime = 0x10000000; Device->LongAbsoluteTime = 0x10000000;
CTEInitTimer (&Device->ShortTimer); CTEInitTimer (&Device->LongTimer);
#if !defined(_PNP_POWER)
//
// One reference for the long timer.
//
NbiReferenceDevice (Device, DREF_LONG_TIMER);
CTEStartTimer( &Device->LongTimer, LONG_TIMER_DELTA, NbiLongTimeout, (PVOID)Device);
#endif !_PNP_POWER
Device->TimersInitialized = TRUE; Device->ShortListActive = FALSE; Device->ProcessingShortTimer = FALSE;
InitializeListHead (&Device->ShortList); InitializeListHead (&Device->LongList);
CTEInitLock (&Device->TimerLock.Lock);
} /* NbiInitializeTimers */
|