1/* 2 ************************************************************************* 3 * Ralink Tech Inc. 4 * 5F., No.36, Taiyuan St., Jhubei City, 5 * Hsinchu County 302, 6 * Taiwan, R.O.C. 7 * 8 * (c) Copyright 2002-2007, Ralink Technology, Inc. 9 * 10 * This program is free software; you can redistribute it and/or modify * 11 * it under the terms of the GNU General Public License as published by * 12 * the Free Software Foundation; either version 2 of the License, or * 13 * (at your option) any later version. * 14 * * 15 * This program is distributed in the hope that it will be useful, * 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 * GNU General Public License for more details. * 19 * * 20 * You should have received a copy of the GNU General Public License * 21 * along with this program; if not, write to the * 22 * Free Software Foundation, Inc., * 23 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 24 * * 25 ************************************************************************* 26 27 Module Name: 28 rtmp_timer.c 29 30 Abstract: 31 task for timer handling 32 33 Revision History: 34 Who When What 35 -------- ---------- ---------------------------------------------- 36 Name Date Modification logs 37 Shiang Tu 08-28-2008 init version 38 39*/ 40 41#include "../rt_config.h" 42 43BUILD_TIMER_FUNCTION(MlmePeriodicExec); 44/*BUILD_TIMER_FUNCTION(MlmeRssiReportExec); */ 45BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout); 46BUILD_TIMER_FUNCTION(APSDPeriodicExec); 47BUILD_TIMER_FUNCTION(AsicRfTuningExec); 48#ifdef RTMP_MAC_USB 49BUILD_TIMER_FUNCTION(BeaconUpdateExec); 50#endif /* RTMP_MAC_USB // */ 51 52BUILD_TIMER_FUNCTION(BeaconTimeout); 53BUILD_TIMER_FUNCTION(ScanTimeout); 54BUILD_TIMER_FUNCTION(AuthTimeout); 55BUILD_TIMER_FUNCTION(AssocTimeout); 56BUILD_TIMER_FUNCTION(ReassocTimeout); 57BUILD_TIMER_FUNCTION(DisassocTimeout); 58BUILD_TIMER_FUNCTION(LinkDownExec); 59BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); 60BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); 61#ifdef RTMP_MAC_PCI 62BUILD_TIMER_FUNCTION(PsPollWakeExec); 63BUILD_TIMER_FUNCTION(RadioOnExec); 64#endif /* RTMP_MAC_PCI // */ 65#ifdef RTMP_MAC_USB 66BUILD_TIMER_FUNCTION(RtmpUsbStaAsicForceWakeupTimeout); 67#endif /* RTMP_MAC_USB // */ 68 69#if defined(AP_LED) || defined(STA_LED) 70extern void LedCtrlMain(void *SystemSpecific1, 71 void *FunctionContext, 72 void *SystemSpecific2, void *SystemSpecific3); 73BUILD_TIMER_FUNCTION(LedCtrlMain); 74#endif 75 76#ifdef RTMP_TIMER_TASK_SUPPORT 77static void RtmpTimerQHandle(struct rt_rtmp_adapter *pAd) 78{ 79#ifndef KTHREAD_SUPPORT 80 int status; 81#endif 82 struct rt_ralink_timer *pTimer; 83 struct rt_rtmp_timer_task_entry *pEntry; 84 unsigned long irqFlag; 85 struct rt_rtmp_os_task *pTask; 86 87 pTask = &pAd->timerTask; 88 while (!pTask->task_killed) { 89 pTimer = NULL; 90 91#ifdef KTHREAD_SUPPORT 92 RTMP_WAIT_EVENT_INTERRUPTIBLE(pAd, pTask); 93#else 94 RTMP_SEM_EVENT_WAIT(&(pTask->taskSema), status); 95#endif 96 97 if (pAd->TimerQ.status == RTMP_TASK_STAT_STOPED) 98 break; 99 100 /* event happened. */ 101 while (pAd->TimerQ.pQHead) { 102 RTMP_INT_LOCK(&pAd->TimerQLock, irqFlag); 103 pEntry = pAd->TimerQ.pQHead; 104 if (pEntry) { 105 pTimer = pEntry->pRaTimer; 106 107 /* update pQHead */ 108 pAd->TimerQ.pQHead = pEntry->pNext; 109 if (pEntry == pAd->TimerQ.pQTail) 110 pAd->TimerQ.pQTail = NULL; 111 112 /* return this queue entry to timerQFreeList. */ 113 pEntry->pNext = pAd->TimerQ.pQPollFreeList; 114 pAd->TimerQ.pQPollFreeList = pEntry; 115 } 116 RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlag); 117 118 if (pTimer) { 119 if ((pTimer->handle != NULL) 120 && (!pAd->PM_FlgSuspend)) 121 pTimer->handle(NULL, 122 (void *)pTimer->cookie, 123 NULL, pTimer); 124 if ((pTimer->Repeat) 125 && (pTimer->State == FALSE)) 126 RTMP_OS_Add_Timer(&pTimer->TimerObj, 127 pTimer->TimerValue); 128 } 129 } 130 131#ifndef KTHREAD_SUPPORT 132 if (status != 0) { 133 pAd->TimerQ.status = RTMP_TASK_STAT_STOPED; 134 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); 135 break; 136 } 137#endif 138 } 139} 140 141int RtmpTimerQThread(IN void *Context) 142{ 143 struct rt_rtmp_os_task *pTask; 144 struct rt_rtmp_adapter *pAd; 145 146 pTask = Context; 147 pAd = pTask->priv; 148 149 RtmpOSTaskCustomize(pTask); 150 151 RtmpTimerQHandle(pAd); 152 153 DBGPRINT(RT_DEBUG_TRACE, ("<---%s\n", __func__)); 154#ifndef KTHREAD_SUPPORT 155 pTask->taskPID = THREAD_PID_INIT_VALUE; 156#endif 157 /* notify the exit routine that we're actually exiting now 158 * 159 * complete()/wait_for_completion() is similar to up()/down(), 160 * except that complete() is safe in the case where the structure 161 * is getting deleted in a parallel mode of execution (i.e. just 162 * after the down() -- that's necessary for the thread-shutdown 163 * case. 164 * 165 * complete_and_exit() goes even further than this -- it is safe in 166 * the case that the thread of the caller is going away (not just 167 * the structure) -- this is necessary for the module-remove case. 168 * This is important in preemption kernels, which transfer the flow 169 * of execution immediately upon a complete(). 170 */ 171 RtmpOSTaskNotifyToExit(pTask); 172 173 return 0; 174 175} 176 177struct rt_rtmp_timer_task_entry *RtmpTimerQInsert(struct rt_rtmp_adapter *pAd, 178 struct rt_ralink_timer *pTimer) 179{ 180 struct rt_rtmp_timer_task_entry *pQNode = NULL, *pQTail; 181 unsigned long irqFlags; 182 struct rt_rtmp_os_task *pTask = &pAd->timerTask; 183 184 RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags); 185 if (pAd->TimerQ.status & RTMP_TASK_CAN_DO_INSERT) { 186 if (pAd->TimerQ.pQPollFreeList) { 187 pQNode = pAd->TimerQ.pQPollFreeList; 188 pAd->TimerQ.pQPollFreeList = pQNode->pNext; 189 190 pQNode->pRaTimer = pTimer; 191 pQNode->pNext = NULL; 192 193 pQTail = pAd->TimerQ.pQTail; 194 if (pAd->TimerQ.pQTail != NULL) 195 pQTail->pNext = pQNode; 196 pAd->TimerQ.pQTail = pQNode; 197 if (pAd->TimerQ.pQHead == NULL) 198 pAd->TimerQ.pQHead = pQNode; 199 } 200 } 201 RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags); 202 203 if (pQNode) { 204#ifdef KTHREAD_SUPPORT 205 WAKE_UP(pTask); 206#else 207 RTMP_SEM_EVENT_UP(&pTask->taskSema); 208#endif 209 } 210 211 return pQNode; 212} 213 214BOOLEAN RtmpTimerQRemove(struct rt_rtmp_adapter *pAd, struct rt_ralink_timer *pTimer) 215{ 216 struct rt_rtmp_timer_task_entry *pNode, *pPrev = NULL; 217 unsigned long irqFlags; 218 219 RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags); 220 if (pAd->TimerQ.status >= RTMP_TASK_STAT_INITED) { 221 pNode = pAd->TimerQ.pQHead; 222 while (pNode) { 223 if (pNode->pRaTimer == pTimer) 224 break; 225 pPrev = pNode; 226 pNode = pNode->pNext; 227 } 228 229 /* Now move it to freeList queue. */ 230 if (pNode) { 231 if (pNode == pAd->TimerQ.pQHead) 232 pAd->TimerQ.pQHead = pNode->pNext; 233 if (pNode == pAd->TimerQ.pQTail) 234 pAd->TimerQ.pQTail = pPrev; 235 if (pPrev != NULL) 236 pPrev->pNext = pNode->pNext; 237 238 /* return this queue entry to timerQFreeList. */ 239 pNode->pNext = pAd->TimerQ.pQPollFreeList; 240 pAd->TimerQ.pQPollFreeList = pNode; 241 } 242 } 243 RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags); 244 245 return TRUE; 246} 247 248void RtmpTimerQExit(struct rt_rtmp_adapter *pAd) 249{ 250 struct rt_rtmp_timer_task_entry *pTimerQ; 251 unsigned long irqFlags; 252 253 RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags); 254 while (pAd->TimerQ.pQHead) { 255 pTimerQ = pAd->TimerQ.pQHead; 256 pAd->TimerQ.pQHead = pTimerQ->pNext; 257 /* remove the timeQ */ 258 } 259 pAd->TimerQ.pQPollFreeList = NULL; 260 os_free_mem(pAd, pAd->TimerQ.pTimerQPoll); 261 pAd->TimerQ.pQTail = NULL; 262 pAd->TimerQ.pQHead = NULL; 263#ifndef KTHREAD_SUPPORT 264 pAd->TimerQ.status = RTMP_TASK_STAT_STOPED; 265#endif 266 RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags); 267 268} 269 270void RtmpTimerQInit(struct rt_rtmp_adapter *pAd) 271{ 272 int i; 273 struct rt_rtmp_timer_task_entry *pQNode, *pEntry; 274 unsigned long irqFlags; 275 276 NdisAllocateSpinLock(&pAd->TimerQLock); 277 278 NdisZeroMemory(&pAd->TimerQ, sizeof(pAd->TimerQ)); 279 280 os_alloc_mem(pAd, &pAd->TimerQ.pTimerQPoll, 281 sizeof(struct rt_rtmp_timer_task_entry) * TIMER_QUEUE_SIZE_MAX); 282 if (pAd->TimerQ.pTimerQPoll) { 283 pEntry = NULL; 284 pQNode = (struct rt_rtmp_timer_task_entry *)pAd->TimerQ.pTimerQPoll; 285 NdisZeroMemory(pAd->TimerQ.pTimerQPoll, 286 sizeof(struct rt_rtmp_timer_task_entry) * 287 TIMER_QUEUE_SIZE_MAX); 288 289 RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags); 290 for (i = 0; i < TIMER_QUEUE_SIZE_MAX; i++) { 291 pQNode->pNext = pEntry; 292 pEntry = pQNode; 293 pQNode++; 294 } 295 pAd->TimerQ.pQPollFreeList = pEntry; 296 pAd->TimerQ.pQHead = NULL; 297 pAd->TimerQ.pQTail = NULL; 298 pAd->TimerQ.status = RTMP_TASK_STAT_INITED; 299 RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags); 300 } 301} 302#endif /* RTMP_TIMER_TASK_SUPPORT // */ 303