/* *************************************************************************** * Ralink Tech Inc. * 4F, No. 2 Technology 5th Rd. * Science-based Industrial Park * Hsin-chu, Taiwan, R.O.C. * * (c) Copyright 2002-2008, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. *************************************************************************** Module Name: rtmp_timer.c Abstract: task for timer handling Revision History: Who When What -------- ---------- ---------------------------------------------- Name Date Modification logs Shiang Tu 08-28-2008 init version */ #include "rt_config.h" BUILD_TIMER_FUNCTION(MlmePeriodicExec); /*BUILD_TIMER_FUNCTION(MlmeRssiReportExec);*/ BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout); BUILD_TIMER_FUNCTION(APSDPeriodicExec); BUILD_TIMER_FUNCTION(EnqueueStartForPSKExec); #ifdef CONFIG_STA_SUPPORT #ifdef ADHOC_WPA2PSK_SUPPORT BUILD_TIMER_FUNCTION(Adhoc_WpaRetryExec); #endif /* ADHOC_WPA2PSK_SUPPORT */ #endif /* CONFIG_STA_SUPPORT */ #ifdef CONFIG_MULTI_CHANNEL BUILD_TIMER_FUNCTION(MCC_ChangeAction); BUILD_TIMER_FUNCTION(ConcurrentP2PConnectTimeout); #endif /* CONFIG_MULTI_CHANNEL */ #ifdef RTMP_MAC_USB BUILD_TIMER_FUNCTION(BeaconUpdateExec); #endif /* RTMP_MAC_USB */ #ifdef CONFIG_AP_SUPPORT extern VOID APDetectOverlappingExec( IN PVOID SystemSpecific1, IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3); BUILD_TIMER_FUNCTION(APDetectOverlappingExec); #ifdef DOT11N_DRAFT3 BUILD_TIMER_FUNCTION(Bss2040CoexistTimeOut); #endif /* DOT11N_DRAFT3 */ BUILD_TIMER_FUNCTION(GREKEYPeriodicExec); BUILD_TIMER_FUNCTION(CMTimerExec); BUILD_TIMER_FUNCTION(WPARetryExec); #ifdef AP_SCAN_SUPPORT BUILD_TIMER_FUNCTION(APScanTimeout); #endif /* AP_SCAN_SUPPORT */ BUILD_TIMER_FUNCTION(APQuickResponeForRateUpExec); #ifdef IDS_SUPPORT BUILD_TIMER_FUNCTION(RTMPIdsPeriodicExec); #endif /* IDS_SUPPORT */ #endif /* CONFIG_AP_SUPPORT */ #ifdef CONFIG_STA_SUPPORT BUILD_TIMER_FUNCTION(BeaconTimeout); BUILD_TIMER_FUNCTION(ScanTimeout); BUILD_TIMER_FUNCTION(AuthTimeout); BUILD_TIMER_FUNCTION(AssocTimeout); BUILD_TIMER_FUNCTION(ReassocTimeout); BUILD_TIMER_FUNCTION(DisassocTimeout); BUILD_TIMER_FUNCTION(LinkDownExec); BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); #ifdef PCIE_PS_SUPPORT BUILD_TIMER_FUNCTION(PsPollWakeExec); BUILD_TIMER_FUNCTION(RadioOnExec); #endif /* PCIE_PS_SUPPORT */ #ifdef QOS_DLS_SUPPORT BUILD_TIMER_FUNCTION(DlsTimeoutAction); #endif /* QOS_DLS_SUPPORT */ #ifdef DOT11Z_TDLS_SUPPORT BUILD_TIMER_FUNCTION(TDLS_TimeoutAction); #endif /* DOT11Z_TDLS_SUPPORT */ #ifdef RTMP_MAC_USB BUILD_TIMER_FUNCTION(RtmpUsbStaAsicForceWakeupTimeout); #endif /* RTMP_MAC_USB */ #endif /* CONFIG_STA_SUPPORT */ #ifdef WSC_INCLUDED BUILD_TIMER_FUNCTION(WscEAPOLTimeOutAction); BUILD_TIMER_FUNCTION(Wsc2MinsTimeOutAction); BUILD_TIMER_FUNCTION(WscUPnPMsgTimeOutAction); BUILD_TIMER_FUNCTION(WscM2DTimeOutAction); BUILD_TIMER_FUNCTION(WscPBCTimeOutAction); BUILD_TIMER_FUNCTION(WscScanTimeOutAction); BUILD_TIMER_FUNCTION(WscProfileRetryTimeout); #ifdef WSC_LED_SUPPORT BUILD_TIMER_FUNCTION(WscLEDTimer); BUILD_TIMER_FUNCTION(WscSkipTurnOffLEDTimer); #endif /* WSC_LED_SUPPORT */ #ifdef CONFIG_AP_SUPPORT BUILD_TIMER_FUNCTION(WscUpdatePortCfgTimeout); #ifdef WSC_V2_SUPPORT BUILD_TIMER_FUNCTION(WscSetupLockTimeout); #endif /* WSC_V2_SUPPORT */ #endif /* CONFIG_AP_SUPPORT */ #ifdef IWSC_SUPPORT BUILD_TIMER_FUNCTION(IWSC_T1TimerAction); BUILD_TIMER_FUNCTION(IWSC_T2TimerAction); BUILD_TIMER_FUNCTION(IWSC_EntryTimerAction); BUILD_TIMER_FUNCTION(IWSC_DevQueryAction); #endif /* IWSC_SUPPORT */ #endif /* WSC_INCLUDED */ #ifdef TXBF_SUPPORT BUILD_TIMER_FUNCTION(eTxBfProbeTimerExec); #endif /* TXBF_SUPPORT */ #ifdef P2P_SUPPORT BUILD_TIMER_FUNCTION(P2PCTWindowTimer); BUILD_TIMER_FUNCTION(P2pSwNoATimeOut); BUILD_TIMER_FUNCTION(P2pPreAbsenTimeOut); BUILD_TIMER_FUNCTION(P2pWscTimeOut); BUILD_TIMER_FUNCTION(P2pReSendTimeOut); BUILD_TIMER_FUNCTION(P2pCliReConnectTimeOut); #endif /* P2P_SUPPORT */ #ifdef RALINK_ATE BUILD_TIMER_FUNCTION(ATEPeriodicExec); #endif /* RALINK_ATE */ #ifdef RTMP_TIMER_TASK_SUPPORT static void RtmpTimerQHandle(RTMP_ADAPTER *pAd) { /*#ifndef KTHREAD_SUPPORT*/ int status; /*#endif*/ RALINK_TIMER_STRUCT *pTimer; RTMP_TIMER_TASK_ENTRY *pEntry; unsigned long irqFlag; RTMP_OS_TASK *pTask; pTask = &pAd->timerTask; while(!RTMP_OS_TASK_IS_KILLED(pTask)) { pTimer = NULL; if (RtmpOSTaskWait(pAd, pTask, &status) == FALSE) { RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); break; } if (pAd->TimerQ.status == RTMP_TASK_STAT_STOPED) break; /* event happened.*/ while(pAd->TimerQ.pQHead) { RTMP_INT_LOCK(&pAd->TimerQLock, irqFlag); pEntry = pAd->TimerQ.pQHead; if (pEntry) { pTimer = pEntry->pRaTimer; /* update pQHead*/ pAd->TimerQ.pQHead = pEntry->pNext; if (pEntry == pAd->TimerQ.pQTail) pAd->TimerQ.pQTail = NULL; /* return this queue entry to timerQFreeList.*/ pEntry->pNext = pAd->TimerQ.pQPollFreeList; pAd->TimerQ.pQPollFreeList = pEntry; } RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlag); if (pTimer) { if ((pTimer->handle != NULL) && (!pAd->PM_FlgSuspend)) pTimer->handle(NULL, (PVOID) pTimer->cookie, NULL, pTimer); if ((pTimer->Repeat) && (pTimer->State == FALSE)) RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue); } } /*#ifndef KTHREAD_SUPPORT*/ if (status != 0) { pAd->TimerQ.status = RTMP_TASK_STAT_STOPED; RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); break; } /*#endif*/ } } INT RtmpTimerQThread( IN ULONG Context) { RTMP_OS_TASK *pTask; PRTMP_ADAPTER pAd = NULL; pTask = (RTMP_OS_TASK *)Context; pAd = (PRTMP_ADAPTER)RTMP_OS_TASK_DATA_GET(pTask); if (pAd == NULL) { DBGPRINT(RT_DEBUG_ERROR,( "%s:: pAd is NULL!\n",__FUNCTION__)); return 0; } RtmpOSTaskCustomize(pTask); RtmpTimerQHandle(pAd); DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); /* notify the exit routine that we're actually exiting now * * complete()/wait_for_completion() is similar to up()/down(), * except that complete() is safe in the case where the structure * is getting deleted in a parallel mode of execution (i.e. just * after the down() -- that's necessary for the thread-shutdown * case. * * complete_and_exit() goes even further than this -- it is safe in * the case that the thread of the caller is going away (not just * the structure) -- this is necessary for the module-remove case. * This is important in preemption kernels, which transfer the flow * of execution immediately upon a complete(). */ RtmpOSTaskNotifyToExit(pTask); return 0; } RTMP_TIMER_TASK_ENTRY *RtmpTimerQInsert( IN RTMP_ADAPTER *pAd, IN RALINK_TIMER_STRUCT *pTimer) { RTMP_TIMER_TASK_ENTRY *pQNode = NULL, *pQTail; unsigned long irqFlags; RTMP_OS_TASK *pTask = &pAd->timerTask; RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags); if (pAd->TimerQ.status & RTMP_TASK_CAN_DO_INSERT) { if(pAd->TimerQ.pQPollFreeList) { pQNode = pAd->TimerQ.pQPollFreeList; pAd->TimerQ.pQPollFreeList = pQNode->pNext; pQNode->pRaTimer = pTimer; pQNode->pNext = NULL; pQTail = pAd->TimerQ.pQTail; if (pAd->TimerQ.pQTail != NULL) pQTail->pNext = pQNode; pAd->TimerQ.pQTail = pQNode; if (pAd->TimerQ.pQHead == NULL) pAd->TimerQ.pQHead = pQNode; } } RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags); if (pQNode) { RTMP_OS_TASK_WAKE_UP(pTask); } return pQNode; } BOOLEAN RtmpTimerQRemove( IN RTMP_ADAPTER *pAd, IN RALINK_TIMER_STRUCT *pTimer) { RTMP_TIMER_TASK_ENTRY *pNode, *pPrev = NULL; unsigned long irqFlags; RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags); if (pAd->TimerQ.status >= RTMP_TASK_STAT_INITED) { pNode = pAd->TimerQ.pQHead; while (pNode) { if (pNode->pRaTimer == pTimer) break; pPrev = pNode; pNode = pNode->pNext; } /* Now move it to freeList queue.*/ if (pNode) { if (pNode == pAd->TimerQ.pQHead) pAd->TimerQ.pQHead = pNode->pNext; if (pNode == pAd->TimerQ.pQTail) pAd->TimerQ.pQTail = pPrev; if (pPrev != NULL) pPrev->pNext = pNode->pNext; /* return this queue entry to timerQFreeList.*/ pNode->pNext = pAd->TimerQ.pQPollFreeList; pAd->TimerQ.pQPollFreeList = pNode; } } RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags); return TRUE; } void RtmpTimerQExit(RTMP_ADAPTER *pAd) { RTMP_TIMER_TASK_ENTRY *pTimerQ; unsigned long irqFlags; RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags); while (pAd->TimerQ.pQHead) { pTimerQ = pAd->TimerQ.pQHead; pAd->TimerQ.pQHead = pTimerQ->pNext; /* remove the timeQ*/ } pAd->TimerQ.pQPollFreeList = NULL; os_free_mem(pAd, pAd->TimerQ.pTimerQPoll); pAd->TimerQ.pQTail = NULL; pAd->TimerQ.pQHead = NULL; /*#ifndef KTHREAD_SUPPORT*/ pAd->TimerQ.status = RTMP_TASK_STAT_STOPED; /*#endif*/ RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags); /* NdisFreeSpinLock(&pAd->TimerQLock); */ } void RtmpTimerQInit(RTMP_ADAPTER *pAd) { int i; RTMP_TIMER_TASK_ENTRY *pQNode, *pEntry; unsigned long irqFlags; NdisAllocateSpinLock(pAd, &pAd->TimerQLock); NdisZeroMemory(&pAd->TimerQ, sizeof(pAd->TimerQ)); os_alloc_mem(pAd, &pAd->TimerQ.pTimerQPoll, sizeof(RTMP_TIMER_TASK_ENTRY) * TIMER_QUEUE_SIZE_MAX); if (pAd->TimerQ.pTimerQPoll) { pEntry = NULL; pQNode = (RTMP_TIMER_TASK_ENTRY *)pAd->TimerQ.pTimerQPoll; NdisZeroMemory(pAd->TimerQ.pTimerQPoll, sizeof(RTMP_TIMER_TASK_ENTRY) * TIMER_QUEUE_SIZE_MAX); RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags); for (i = 0 ;i pNext = pEntry; pEntry = pQNode; pQNode++; } pAd->TimerQ.pQPollFreeList = pEntry; pAd->TimerQ.pQHead = NULL; pAd->TimerQ.pQTail = NULL; pAd->TimerQ.status = RTMP_TASK_STAT_INITED; RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags); } } #endif /* RTMP_TIMER_TASK_SUPPORT */