- supported.conf: Added sparse_keymap (eeepc_laptop depends on it)
[linux-flexiantxendom0-3.2.10.git] / drivers / staging / rt3090 / common / rtmp_timer.c
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
43
44 BUILD_TIMER_FUNCTION(MlmePeriodicExec);
45 //BUILD_TIMER_FUNCTION(MlmeRssiReportExec);
46 BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout);
47 BUILD_TIMER_FUNCTION(APSDPeriodicExec);
48 BUILD_TIMER_FUNCTION(AsicRfTuningExec);
49
50
51 #ifdef CONFIG_STA_SUPPORT
52 BUILD_TIMER_FUNCTION(BeaconTimeout);
53 BUILD_TIMER_FUNCTION(ScanTimeout);
54 BUILD_TIMER_FUNCTION(AuthTimeout);
55 BUILD_TIMER_FUNCTION(AssocTimeout);
56 BUILD_TIMER_FUNCTION(ReassocTimeout);
57 BUILD_TIMER_FUNCTION(DisassocTimeout);
58 BUILD_TIMER_FUNCTION(LinkDownExec);
59 BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec);
60 BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc);
61 #ifdef RTMP_MAC_PCI
62 BUILD_TIMER_FUNCTION(PsPollWakeExec);
63 BUILD_TIMER_FUNCTION(RadioOnExec);
64 #endif // RTMP_MAC_PCI //
65 #ifdef QOS_DLS_SUPPORT
66 BUILD_TIMER_FUNCTION(DlsTimeoutAction);
67 #endif // QOS_DLS_SUPPORT //
68
69
70 #endif // CONFIG_STA_SUPPORT //
71
72
73
74 #if defined(AP_LED) || defined(STA_LED)
75 extern void LedCtrlMain(
76         IN PVOID SystemSpecific1,
77         IN PVOID FunctionContext,
78         IN PVOID SystemSpecific2,
79         IN PVOID SystemSpecific3);
80 BUILD_TIMER_FUNCTION(LedCtrlMain);
81 #endif
82
83
84 #ifdef RTMP_TIMER_TASK_SUPPORT
85 static void RtmpTimerQHandle(RTMP_ADAPTER *pAd)
86 {
87 #ifndef KTHREAD_SUPPORT
88         int status;
89 #endif
90         RALINK_TIMER_STRUCT     *pTimer;
91         RTMP_TIMER_TASK_ENTRY   *pEntry;
92         unsigned long   irqFlag;
93         RTMP_OS_TASK *pTask;
94
95
96         pTask = &pAd->timerTask;
97         while(!pTask->task_killed)
98         {
99                 pTimer = NULL;
100
101 #ifdef KTHREAD_SUPPORT
102                 RTMP_WAIT_EVENT_INTERRUPTIBLE(pAd, pTask);
103 #else
104                 RTMP_SEM_EVENT_WAIT(&(pTask->taskSema), status);
105 #endif
106
107                 if (pAd->TimerQ.status == RTMP_TASK_STAT_STOPED)
108                         break;
109
110                 // event happened.
111                 while(pAd->TimerQ.pQHead)
112                 {
113                         RTMP_INT_LOCK(&pAd->TimerQLock, irqFlag);
114                         pEntry = pAd->TimerQ.pQHead;
115                         if (pEntry)
116                         {
117                                 pTimer = pEntry->pRaTimer;
118
119                                 // update pQHead
120                                 pAd->TimerQ.pQHead = pEntry->pNext;
121                                 if (pEntry == pAd->TimerQ.pQTail)
122                                         pAd->TimerQ.pQTail = NULL;
123
124                                 // return this queue entry to timerQFreeList.
125                                 pEntry->pNext = pAd->TimerQ.pQPollFreeList;
126                                 pAd->TimerQ.pQPollFreeList = pEntry;
127                         }
128                         RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlag);
129
130                         if (pTimer)
131                         {
132                                 if ((pTimer->handle != NULL) && (!pAd->PM_FlgSuspend))
133                                         pTimer->handle(NULL, (PVOID) pTimer->cookie, NULL, pTimer);
134                                 if ((pTimer->Repeat) && (pTimer->State == FALSE))
135                                         RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue);
136                         }
137                 }
138
139 #ifndef KTHREAD_SUPPORT
140                 if (status != 0)
141                 {
142                         pAd->TimerQ.status = RTMP_TASK_STAT_STOPED;
143                         RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
144                         break;
145                 }
146 #endif
147         }
148 }
149
150
151 INT RtmpTimerQThread(
152         IN OUT PVOID Context)
153 {
154         RTMP_OS_TASK    *pTask;
155         PRTMP_ADAPTER   pAd;
156
157
158         pTask = (RTMP_OS_TASK *)Context;
159         pAd = (PRTMP_ADAPTER)pTask->priv;
160
161         RtmpOSTaskCustomize(pTask);
162
163         RtmpTimerQHandle(pAd);
164
165         DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__));
166 #ifndef KTHREAD_SUPPORT
167         pTask->taskPID = THREAD_PID_INIT_VALUE;
168 #endif
169         /* notify the exit routine that we're actually exiting now
170          *
171          * complete()/wait_for_completion() is similar to up()/down(),
172          * except that complete() is safe in the case where the structure
173          * is getting deleted in a parallel mode of execution (i.e. just
174          * after the down() -- that's necessary for the thread-shutdown
175          * case.
176          *
177          * complete_and_exit() goes even further than this -- it is safe in
178          * the case that the thread of the caller is going away (not just
179          * the structure) -- this is necessary for the module-remove case.
180          * This is important in preemption kernels, which transfer the flow
181          * of execution immediately upon a complete().
182          */
183         RtmpOSTaskNotifyToExit(pTask);
184
185         return 0;
186
187 }
188
189
190 RTMP_TIMER_TASK_ENTRY *RtmpTimerQInsert(
191         IN RTMP_ADAPTER *pAd,
192         IN RALINK_TIMER_STRUCT *pTimer)
193 {
194         RTMP_TIMER_TASK_ENTRY *pQNode = NULL, *pQTail;
195         unsigned long irqFlags;
196         RTMP_OS_TASK    *pTask = &pAd->timerTask;
197
198         RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags);
199         if (pAd->TimerQ.status & RTMP_TASK_CAN_DO_INSERT)
200         {
201                 if(pAd->TimerQ.pQPollFreeList)
202                 {
203                         pQNode = pAd->TimerQ.pQPollFreeList;
204                         pAd->TimerQ.pQPollFreeList = pQNode->pNext;
205
206                         pQNode->pRaTimer = pTimer;
207                         pQNode->pNext = NULL;
208
209                         pQTail = pAd->TimerQ.pQTail;
210                         if (pAd->TimerQ.pQTail != NULL)
211                                 pQTail->pNext = pQNode;
212                         pAd->TimerQ.pQTail = pQNode;
213                         if (pAd->TimerQ.pQHead == NULL)
214                                 pAd->TimerQ.pQHead = pQNode;
215                 }
216         }
217         RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags);
218
219         if (pQNode)
220         {
221 #ifdef KTHREAD_SUPPORT
222                 WAKE_UP(pTask);
223 #else
224                 RTMP_SEM_EVENT_UP(&pTask->taskSema);
225 #endif
226         }
227
228         return pQNode;
229 }
230
231
232 BOOLEAN RtmpTimerQRemove(
233         IN RTMP_ADAPTER *pAd,
234         IN RALINK_TIMER_STRUCT *pTimer)
235 {
236         RTMP_TIMER_TASK_ENTRY *pNode, *pPrev = NULL;
237         unsigned long irqFlags;
238
239         RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags);
240         if (pAd->TimerQ.status >= RTMP_TASK_STAT_INITED)
241         {
242                 pNode = pAd->TimerQ.pQHead;
243                 while (pNode)
244                 {
245                         if (pNode->pRaTimer == pTimer)
246                                 break;
247                         pPrev = pNode;
248                         pNode = pNode->pNext;
249                 }
250
251                 // Now move it to freeList queue.
252                 if (pNode)
253                 {
254                         if (pNode == pAd->TimerQ.pQHead)
255                                 pAd->TimerQ.pQHead = pNode->pNext;
256                         if (pNode == pAd->TimerQ.pQTail)
257                                 pAd->TimerQ.pQTail = pPrev;
258                         if (pPrev != NULL)
259                                 pPrev->pNext = pNode->pNext;
260
261                         // return this queue entry to timerQFreeList.
262                         pNode->pNext = pAd->TimerQ.pQPollFreeList;
263                         pAd->TimerQ.pQPollFreeList = pNode;
264                 }
265         }
266         RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags);
267
268         return TRUE;
269 }
270
271
272 void RtmpTimerQExit(RTMP_ADAPTER *pAd)
273 {
274         RTMP_TIMER_TASK_ENTRY *pTimerQ;
275         unsigned long irqFlags;
276
277         RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags);
278         while (pAd->TimerQ.pQHead)
279         {
280                 pTimerQ = pAd->TimerQ.pQHead;
281                 pAd->TimerQ.pQHead = pTimerQ->pNext;
282                 // remove the timeQ
283         }
284         pAd->TimerQ.pQPollFreeList = NULL;
285         os_free_mem(pAd, pAd->TimerQ.pTimerQPoll);
286         pAd->TimerQ.pQTail = NULL;
287         pAd->TimerQ.pQHead = NULL;
288 #ifndef KTHREAD_SUPPORT
289         pAd->TimerQ.status = RTMP_TASK_STAT_STOPED;
290 #endif
291         RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags);
292
293 }
294
295
296 void RtmpTimerQInit(RTMP_ADAPTER *pAd)
297 {
298         int     i;
299         RTMP_TIMER_TASK_ENTRY *pQNode, *pEntry;
300         unsigned long irqFlags;
301
302         NdisAllocateSpinLock(&pAd->TimerQLock);
303
304         NdisZeroMemory(&pAd->TimerQ, sizeof(pAd->TimerQ));
305
306         os_alloc_mem(pAd, &pAd->TimerQ.pTimerQPoll, sizeof(RTMP_TIMER_TASK_ENTRY) * TIMER_QUEUE_SIZE_MAX);
307         if (pAd->TimerQ.pTimerQPoll)
308         {
309                 pEntry = NULL;
310                 pQNode = (RTMP_TIMER_TASK_ENTRY *)pAd->TimerQ.pTimerQPoll;
311                 NdisZeroMemory(pAd->TimerQ.pTimerQPoll, sizeof(RTMP_TIMER_TASK_ENTRY) * TIMER_QUEUE_SIZE_MAX);
312
313                 RTMP_INT_LOCK(&pAd->TimerQLock, irqFlags);
314                 for (i = 0 ;i <TIMER_QUEUE_SIZE_MAX; i++)
315                 {
316                         pQNode->pNext = pEntry;
317                         pEntry = pQNode;
318                         pQNode++;
319                 }
320                 pAd->TimerQ.pQPollFreeList = pEntry;
321                 pAd->TimerQ.pQHead = NULL;
322                 pAd->TimerQ.pQTail = NULL;
323                 pAd->TimerQ.status = RTMP_TASK_STAT_INITED;
324                 RTMP_INT_UNLOCK(&pAd->TimerQLock, irqFlags);
325         }
326 }
327 #endif // RTMP_TIMER_TASK_SUPPORT //