upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / staging / rt2860 / 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 BUILD_TIMER_FUNCTION(MlmePeriodicExec);
44 /*BUILD_TIMER_FUNCTION(MlmeRssiReportExec); */
45 BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout);
46 BUILD_TIMER_FUNCTION(APSDPeriodicExec);
47 BUILD_TIMER_FUNCTION(AsicRfTuningExec);
48 #ifdef RTMP_MAC_USB
49 BUILD_TIMER_FUNCTION(BeaconUpdateExec);
50 #endif /* RTMP_MAC_USB // */
51
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 RTMP_MAC_USB
66 BUILD_TIMER_FUNCTION(RtmpUsbStaAsicForceWakeupTimeout);
67 #endif /* RTMP_MAC_USB // */
68
69 #if defined(AP_LED) || defined(STA_LED)
70 extern void LedCtrlMain(void *SystemSpecific1,
71                         void *FunctionContext,
72                         void *SystemSpecific2, void *SystemSpecific3);
73 BUILD_TIMER_FUNCTION(LedCtrlMain);
74 #endif
75
76 #ifdef RTMP_TIMER_TASK_SUPPORT
77 static 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
141 int 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
177 struct 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
214 BOOLEAN 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
248 void 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
270 void 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 // */