/*++ 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 */