blob: 5253e8768145a4fb91f950ca922ee1137a4e62ff [file] [log] [blame]
/*
*************************************************************************
* Ralink Tech Inc.
* 5F., No.36, Taiyuan St., Jhubei City,
* Hsinchu County 302,
* Taiwan, R.O.C.
*
* (c) Copyright 2002-2007, Ralink Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
*************************************************************************
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(AsicRfTuningExec);
#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 RTMP_MAC_PCI
BUILD_TIMER_FUNCTION(PsPollWakeExec);
BUILD_TIMER_FUNCTION(RadioOnExec);
#endif // RTMP_MAC_PCI //
#ifdef QOS_DLS_SUPPORT
BUILD_TIMER_FUNCTION(DlsTimeoutAction);
#endif // QOS_DLS_SUPPORT //
#endif // CONFIG_STA_SUPPORT //
#if defined(AP_LED) || defined(STA_LED)
extern void LedCtrlMain(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3);
BUILD_TIMER_FUNCTION(LedCtrlMain);
#endif
#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(!pTask->task_killed)
{
pTimer = NULL;
#ifdef KTHREAD_SUPPORT
RTMP_WAIT_EVENT_INTERRUPTIBLE(pAd, pTask);
#else
RTMP_SEM_EVENT_WAIT(&(pTask->taskSema), status);
#endif
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 OUT PVOID Context)
{
RTMP_OS_TASK *pTask;
PRTMP_ADAPTER pAd;
pTask = (RTMP_OS_TASK *)Context;
pAd = (PRTMP_ADAPTER)pTask->priv;
RtmpOSTaskCustomize(pTask);
RtmpTimerQHandle(pAd);
DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__));
#ifndef KTHREAD_SUPPORT
pTask->taskPID = THREAD_PID_INIT_VALUE;
#endif
/* 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)
{
#ifdef KTHREAD_SUPPORT
WAKE_UP(pTask);
#else
RTMP_SEM_EVENT_UP(&pTask->taskSema);
#endif
}
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);
}
void RtmpTimerQInit(RTMP_ADAPTER *pAd)
{
int i;
RTMP_TIMER_TASK_ENTRY *pQNode, *pEntry;
unsigned long irqFlags;
NdisAllocateSpinLock(&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 <TIMER_QUEUE_SIZE_MAX; i++)
{
pQNode->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 //