ALSA: hda - Add position_fix quirk for Biostar mobo
[pandora-kernel.git] / drivers / staging / rtl8192su / ieee80211 / rtl819x_TSProc.c
1 #include "ieee80211.h"
2 #include <linux/etherdevice.h>
3 #include "rtl819x_TS.h"
4
5 void TsSetupTimeOut(unsigned long data)
6 {
7         // Not implement yet
8         // This is used for WMMSA and ACM , that would send ADDTSReq frame.
9 }
10
11 void TsInactTimeout(unsigned long data)
12 {
13         // Not implement yet
14         // This is used for WMMSA and ACM.
15         // This function would be call when TS is no Tx/Rx for some period of time.
16 }
17
18 /********************************************************************************************************************
19  *function:  I still not understand this function, so wait for further implementation
20  *   input:  unsigned long       data           //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer
21  *  return:  NULL
22  *  notice:
23 ********************************************************************************************************************/
24 #if 1
25 void RxPktPendingTimeout(unsigned long data)
26 {
27         PRX_TS_RECORD   pRxTs = (PRX_TS_RECORD)data;
28         struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]);
29
30         PRX_REORDER_ENTRY       pReorderEntry = NULL;
31
32         //u32 flags = 0;
33         unsigned long flags = 0;
34         struct ieee80211_rxb *stats_IndicateArray[REORDER_WIN_SIZE];
35         u8 index = 0;
36         bool bPktInBuf = false;
37
38
39         spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
40         //PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK);
41         IEEE80211_DEBUG(IEEE80211_DL_REORDER,"==================>%s()\n",__FUNCTION__);
42         if(pRxTs->RxTimeoutIndicateSeq != 0xffff)
43         {
44                 // Indicate the pending packets sequentially according to SeqNum until meet the gap.
45                 while(!list_empty(&pRxTs->RxPendingPktList))
46                 {
47                         pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTs->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
48                         if(index == 0)
49                                 pRxTs->RxIndicateSeq = pReorderEntry->SeqNum;
50
51                         if( SN_LESS(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq) ||
52                                 SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq)   )
53                         {
54                                 list_del_init(&pReorderEntry->List);
55
56                                 if(SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq))
57                                         pRxTs->RxIndicateSeq = (pRxTs->RxIndicateSeq + 1) % 4096;
58
59                                 IEEE80211_DEBUG(IEEE80211_DL_REORDER,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum);
60                                 stats_IndicateArray[index] = pReorderEntry->prxb;
61                                 index++;
62
63                                 list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List);
64                         }
65                         else
66                         {
67                                 bPktInBuf = true;
68                                 break;
69                         }
70                 }
71         }
72
73         if(index>0)
74         {
75                 // Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now.
76                 pRxTs->RxTimeoutIndicateSeq = 0xffff;
77
78                 // Indicate packets
79                 if(index > REORDER_WIN_SIZE){
80                         IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorer buffer full!! \n");
81                         spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
82                         return;
83                 }
84                 ieee80211_indicate_packets(ieee, stats_IndicateArray, index);
85                  bPktInBuf = false;
86
87         }
88
89         if(bPktInBuf && (pRxTs->RxTimeoutIndicateSeq==0xffff))
90         {
91                 pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq;
92                 mod_timer(&pRxTs->RxPktPendingTimer,  jiffies + MSECS(ieee->pHTInfo->RxReorderPendingTime));
93         }
94         spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
95         //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK);
96 }
97 #endif
98
99 /********************************************************************************************************************
100  *function:  Add BA timer function
101  *   input:  unsigned long       data           //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer
102  *  return:  NULL
103  *  notice:
104 ********************************************************************************************************************/
105 void TsAddBaProcess(unsigned long data)
106 {
107         PTX_TS_RECORD   pTxTs = (PTX_TS_RECORD)data;
108         u8 num = pTxTs->num;
109         struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]);
110
111         TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
112         IEEE80211_DEBUG(IEEE80211_DL_BA, "TsAddBaProcess(): ADDBA Req is started!! \n");
113 }
114
115
116 void ResetTsCommonInfo(PTS_COMMON_INFO  pTsCommonInfo)
117 {
118         memset(pTsCommonInfo->Addr, 0, 6);
119         memset(&pTsCommonInfo->TSpec, 0, sizeof(TSPEC_BODY));
120         memset(&pTsCommonInfo->TClass, 0, sizeof(QOS_TCLAS)*TCLAS_NUM);
121         pTsCommonInfo->TClasProc = 0;
122         pTsCommonInfo->TClasNum = 0;
123 }
124
125 void ResetTxTsEntry(PTX_TS_RECORD pTS)
126 {
127         ResetTsCommonInfo(&pTS->TsCommonInfo);
128         pTS->TxCurSeq = 0;
129         pTS->bAddBaReqInProgress = false;
130         pTS->bAddBaReqDelayed = false;
131         pTS->bUsingBa = false;
132         ResetBaEntry(&pTS->TxAdmittedBARecord); //For BA Originator
133         ResetBaEntry(&pTS->TxPendingBARecord);
134 }
135
136 void ResetRxTsEntry(PRX_TS_RECORD pTS)
137 {
138         ResetTsCommonInfo(&pTS->TsCommonInfo);
139         pTS->RxIndicateSeq = 0xffff; // This indicate the RxIndicateSeq is not used now!!
140         pTS->RxTimeoutIndicateSeq = 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!!
141         ResetBaEntry(&pTS->RxAdmittedBARecord);   // For BA Recepient
142 }
143
144 void TSInitialize(struct ieee80211_device *ieee)
145 {
146         PTX_TS_RECORD           pTxTS  = ieee->TxTsRecord;
147         PRX_TS_RECORD           pRxTS  = ieee->RxTsRecord;
148         PRX_REORDER_ENTRY       pRxReorderEntry = ieee->RxReorderEntry;
149         u8                              count = 0;
150         IEEE80211_DEBUG(IEEE80211_DL_TS, "==========>%s()\n", __FUNCTION__);
151         // Initialize Tx TS related info.
152         INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List);
153         INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List);
154         INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List);
155
156         for(count = 0; count < TOTAL_TS_NUM; count++)
157         {
158                 //
159                 pTxTS->num = count;
160                 // The timers for the operation of Traffic Stream and Block Ack.
161                 // DLS related timer will be add here in the future!!
162                 init_timer(&pTxTS->TsCommonInfo.SetupTimer);
163                 pTxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pTxTS;
164                 pTxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut;
165
166                 init_timer(&pTxTS->TsCommonInfo.InactTimer);
167                 pTxTS->TsCommonInfo.InactTimer.data = (unsigned long)pTxTS;
168                 pTxTS->TsCommonInfo.InactTimer.function = TsInactTimeout;
169
170                 init_timer(&pTxTS->TsAddBaTimer);
171                 pTxTS->TsAddBaTimer.data = (unsigned long)pTxTS;
172                 pTxTS->TsAddBaTimer.function = TsAddBaProcess;
173
174                 init_timer(&pTxTS->TxPendingBARecord.Timer);
175                 pTxTS->TxPendingBARecord.Timer.data = (unsigned long)pTxTS;
176                 pTxTS->TxPendingBARecord.Timer.function = BaSetupTimeOut;
177
178                 init_timer(&pTxTS->TxAdmittedBARecord.Timer);
179                 pTxTS->TxAdmittedBARecord.Timer.data = (unsigned long)pTxTS;
180                 pTxTS->TxAdmittedBARecord.Timer.function = TxBaInactTimeout;
181
182                 ResetTxTsEntry(pTxTS);
183                 list_add_tail(&pTxTS->TsCommonInfo.List, &ieee->Tx_TS_Unused_List);
184                 pTxTS++;
185         }
186
187         // Initialize Rx TS related info.
188         INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List);
189         INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List);
190         INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List);
191         for(count = 0; count < TOTAL_TS_NUM; count++)
192         {
193                 pRxTS->num = count;
194                 INIT_LIST_HEAD(&pRxTS->RxPendingPktList);
195
196                 init_timer(&pRxTS->TsCommonInfo.SetupTimer);
197                 pRxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pRxTS;
198                 pRxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut;
199
200                 init_timer(&pRxTS->TsCommonInfo.InactTimer);
201                 pRxTS->TsCommonInfo.InactTimer.data = (unsigned long)pRxTS;
202                 pRxTS->TsCommonInfo.InactTimer.function = TsInactTimeout;
203
204                 init_timer(&pRxTS->RxAdmittedBARecord.Timer);
205                 pRxTS->RxAdmittedBARecord.Timer.data = (unsigned long)pRxTS;
206                 pRxTS->RxAdmittedBARecord.Timer.function = RxBaInactTimeout;
207
208                 init_timer(&pRxTS->RxPktPendingTimer);
209                 pRxTS->RxPktPendingTimer.data = (unsigned long)pRxTS;
210                 pRxTS->RxPktPendingTimer.function = RxPktPendingTimeout;
211
212                 ResetRxTsEntry(pRxTS);
213                 list_add_tail(&pRxTS->TsCommonInfo.List, &ieee->Rx_TS_Unused_List);
214                 pRxTS++;
215         }
216         // Initialize unused Rx Reorder List.
217         INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
218 //#ifdef TO_DO_LIST
219         for(count = 0; count < REORDER_ENTRY_NUM; count++)
220         {
221                 list_add_tail( &pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
222                 if(count == (REORDER_ENTRY_NUM-1))
223                         break;
224                 pRxReorderEntry = &ieee->RxReorderEntry[count+1];
225         }
226 //#endif
227
228 }
229
230 void AdmitTS(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, u32 InactTime)
231 {
232         del_timer_sync(&pTsCommonInfo->SetupTimer);
233         del_timer_sync(&pTsCommonInfo->InactTimer);
234
235         if(InactTime!=0)
236                 mod_timer(&pTsCommonInfo->InactTimer, jiffies + MSECS(InactTime));
237 }
238
239
240 PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8*  Addr, u8 TID, TR_SELECT TxRxSelect)
241 {
242         //DIRECTION_VALUE       dir;
243         u8      dir;
244         bool                            search_dir[4] = {0, 0, 0, 0};
245         struct list_head*               psearch_list; //FIXME
246         PTS_COMMON_INFO pRet = NULL;
247         if(ieee->iw_mode == IW_MODE_MASTER) //ap mode
248         {
249                 if(TxRxSelect == TX_DIR)
250                 {
251                         search_dir[DIR_DOWN] = true;
252                         search_dir[DIR_BI_DIR]= true;
253                 }
254                 else
255                 {
256                         search_dir[DIR_UP]      = true;
257                         search_dir[DIR_BI_DIR]= true;
258                 }
259         }
260         else if(ieee->iw_mode == IW_MODE_ADHOC)
261         {
262                 if(TxRxSelect == TX_DIR)
263                         search_dir[DIR_UP]      = true;
264                 else
265                         search_dir[DIR_DOWN] = true;
266         }
267         else
268         {
269                 if(TxRxSelect == TX_DIR)
270                 {
271                         search_dir[DIR_UP]      = true;
272                         search_dir[DIR_BI_DIR]= true;
273                         search_dir[DIR_DIRECT]= true;
274                 }
275                 else
276                 {
277                         search_dir[DIR_DOWN] = true;
278                         search_dir[DIR_BI_DIR]= true;
279                         search_dir[DIR_DIRECT]= true;
280                 }
281         }
282
283         if(TxRxSelect == TX_DIR)
284                 psearch_list = &ieee->Tx_TS_Admit_List;
285         else
286                 psearch_list = &ieee->Rx_TS_Admit_List;
287
288         //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
289         for(dir = 0; dir <= DIR_BI_DIR; dir++)
290         {
291                 if(search_dir[dir] ==false )
292                         continue;
293                 list_for_each_entry(pRet, psearch_list, List){
294         //              IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
295                         if (memcmp(pRet->Addr, Addr, 6) == 0)
296                                 if (pRet->TSpec.f.TSInfo.field.ucTSID == TID)
297                                         if(pRet->TSpec.f.TSInfo.field.ucDirection == dir)
298                                         {
299         //                                      printk("Bingo! got it\n");
300                                                 break;
301                                         }
302
303                 }
304                 if(&pRet->List  != psearch_list)
305                         break;
306         }
307
308         if(&pRet->List  != psearch_list){
309                 return pRet ;
310         }
311         else
312                 return NULL;
313 }
314
315 void MakeTSEntry(
316                 PTS_COMMON_INFO pTsCommonInfo,
317                 u8*             Addr,
318                 PTSPEC_BODY     pTSPEC,
319                 PQOS_TCLAS      pTCLAS,
320                 u8              TCLAS_Num,
321                 u8              TCLAS_Proc
322         )
323 {
324         u8      count;
325
326         if(pTsCommonInfo == NULL)
327                 return;
328
329         memcpy(pTsCommonInfo->Addr, Addr, 6);
330
331         if(pTSPEC != NULL)
332                 memcpy((u8*)(&(pTsCommonInfo->TSpec)), (u8*)pTSPEC, sizeof(TSPEC_BODY));
333
334         for(count = 0; count < TCLAS_Num; count++)
335                 memcpy((u8*)(&(pTsCommonInfo->TClass[count])), (u8*)pTCLAS, sizeof(QOS_TCLAS));
336
337         pTsCommonInfo->TClasProc = TCLAS_Proc;
338         pTsCommonInfo->TClasNum = TCLAS_Num;
339 }
340
341
342 bool GetTs(
343         struct ieee80211_device*        ieee,
344         PTS_COMMON_INFO                 *ppTS,
345         u8*                             Addr,
346         u8                              TID,
347         TR_SELECT                       TxRxSelect,  //Rx:1, Tx:0
348         bool                            bAddNewTs
349         )
350 {
351         u8      UP = 0;
352         //
353         // We do not build any TS for Broadcast or Multicast stream.
354         // So reject these kinds of search here.
355         //
356         if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr))
357         {
358                 IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
359                 return false;
360         }
361
362         if (ieee->current_network.qos_data.supported == 0)
363                 UP = 0;
364         else
365         {
366                 // In WMM case: we use 4 TID only
367                 if (!IsACValid(TID))
368                 {
369                         IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __FUNCTION__, TID);
370                         return false;
371                 }
372
373                 switch(TID)
374                 {
375                 case 0:
376                 case 3:
377                         UP = 0;
378                         break;
379
380                 case 1:
381                 case 2:
382                         UP = 2;
383                         break;
384
385                 case 4:
386                 case 5:
387                         UP = 5;
388                         break;
389
390                 case 6:
391                 case 7:
392                         UP = 7;
393                         break;
394                 }
395         }
396
397         *ppTS = SearchAdmitTRStream(
398                         ieee,
399                         Addr,
400                         UP,
401                         TxRxSelect);
402         if(*ppTS != NULL)
403         {
404                 return true;
405         }
406         else
407         {
408                 if(bAddNewTs == false)
409                 {
410                         IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP);
411                         return false;
412                 }
413                 else
414                 {
415                         //
416                         // Create a new Traffic stream for current Tx/Rx
417                         // This is for EDCA and WMM to add a new TS.
418                         // For HCCA or WMMSA, TS cannot be addmit without negotiation.
419                         //
420                         TSPEC_BODY      TSpec;
421                         PQOS_TSINFO             pTSInfo = &TSpec.f.TSInfo;
422                         struct list_head*       pUnusedList =
423                                                                 (TxRxSelect == TX_DIR)?
424                                                                 (&ieee->Tx_TS_Unused_List):
425                                                                 (&ieee->Rx_TS_Unused_List);
426
427                         struct list_head*       pAddmitList =
428                                                                 (TxRxSelect == TX_DIR)?
429                                                                 (&ieee->Tx_TS_Admit_List):
430                                                                 (&ieee->Rx_TS_Admit_List);
431
432                         DIRECTION_VALUE         Dir =           (ieee->iw_mode == IW_MODE_MASTER)?
433                                                                 ((TxRxSelect==TX_DIR)?DIR_DOWN:DIR_UP):
434                                                                 ((TxRxSelect==TX_DIR)?DIR_UP:DIR_DOWN);
435                         IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n");
436                         if(!list_empty(pUnusedList))
437                         {
438                                 (*ppTS) = list_entry(pUnusedList->next, TS_COMMON_INFO, List);
439                                 list_del_init(&(*ppTS)->List);
440                                 if(TxRxSelect==TX_DIR)
441                                 {
442                                         PTX_TS_RECORD tmp = container_of(*ppTS, TX_TS_RECORD, TsCommonInfo);
443                                         ResetTxTsEntry(tmp);
444                                 }
445                                 else{
446                                         PRX_TS_RECORD tmp = container_of(*ppTS, RX_TS_RECORD, TsCommonInfo);
447                                         ResetRxTsEntry(tmp);
448                                 }
449
450                                 IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
451                                 // Prepare TS Info releated field
452                                 pTSInfo->field.ucTrafficType = 0;                       // Traffic type: WMM is reserved in this field
453                                 pTSInfo->field.ucTSID = UP;                     // TSID
454                                 pTSInfo->field.ucDirection = Dir;                       // Direction: if there is DirectLink, this need additional consideration.
455                                 pTSInfo->field.ucAccessPolicy = 1;              // Access policy
456                                 pTSInfo->field.ucAggregation = 0;               // Aggregation
457                                 pTSInfo->field.ucPSB = 0;                               // Aggregation
458                                 pTSInfo->field.ucUP = UP;                               // User priority
459                                 pTSInfo->field.ucTSInfoAckPolicy = 0;           // Ack policy
460                                 pTSInfo->field.ucSchedule = 0;                  // Schedule
461
462                                 MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
463                                 AdmitTS(ieee, *ppTS, 0);
464                                 list_add_tail(&((*ppTS)->List), pAddmitList);
465                                 // if there is DirectLink, we need to do additional operation here!!
466
467                                 return true;
468                         }
469                         else
470                         {
471                                 IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __FUNCTION__);
472                                 return false;
473                         }
474                 }
475         }
476 }
477
478 void RemoveTsEntry(
479         struct ieee80211_device*        ieee,
480         PTS_COMMON_INFO                 pTs,
481         TR_SELECT                       TxRxSelect
482         )
483 {
484         //u32 flags = 0;
485         unsigned long flags = 0;
486         del_timer_sync(&pTs->SetupTimer);
487         del_timer_sync(&pTs->InactTimer);
488         TsInitDelBA(ieee, pTs, TxRxSelect);
489
490         if(TxRxSelect == RX_DIR)
491         {
492 //#ifdef TO_DO_LIST
493                 PRX_REORDER_ENTRY       pRxReorderEntry;
494                 PRX_TS_RECORD           pRxTS = (PRX_TS_RECORD)pTs;
495                 if(timer_pending(&pRxTS->RxPktPendingTimer))
496                         del_timer_sync(&pRxTS->RxPktPendingTimer);
497
498                 while(!list_empty(&pRxTS->RxPendingPktList))
499                 {
500                 //      PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK);
501                         spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
502                         //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
503                         pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
504                         list_del_init(&pRxReorderEntry->List);
505                         {
506                                 int i = 0;
507                                 struct ieee80211_rxb * prxb = pRxReorderEntry->prxb;
508                                 if (unlikely(!prxb))
509                                 {
510                                         spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
511                                         return;
512                                 }
513                                 for(i =0; i < prxb->nr_subframes; i++) {
514                                         dev_kfree_skb(prxb->subframes[i]);
515                                 }
516                                 kfree(prxb);
517                                 prxb = NULL;
518                         }
519                         list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
520                         //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK);
521                         spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
522                 }
523
524 //#endif
525         }
526         else
527         {
528                 PTX_TS_RECORD pTxTS = (PTX_TS_RECORD)pTs;
529                 del_timer_sync(&pTxTS->TsAddBaTimer);
530         }
531 }
532
533 void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr)
534 {
535         PTS_COMMON_INFO pTS, pTmpTS;
536         printk("===========>RemovePeerTS,%pM\n", Addr);
537 #if 1
538         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
539         {
540                 if (memcmp(pTS->Addr, Addr, 6) == 0)
541                 {
542                         RemoveTsEntry(ieee, pTS, TX_DIR);
543                         list_del_init(&pTS->List);
544                         list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
545                 }
546         }
547
548         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List)
549         {
550                 if (memcmp(pTS->Addr, Addr, 6) == 0)
551                 {
552                         printk("====>remove Tx_TS_admin_list\n");
553                         RemoveTsEntry(ieee, pTS, TX_DIR);
554                         list_del_init(&pTS->List);
555                         list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
556                 }
557         }
558
559         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List)
560         {
561                 if (memcmp(pTS->Addr, Addr, 6) == 0)
562                 {
563                         RemoveTsEntry(ieee, pTS, RX_DIR);
564                         list_del_init(&pTS->List);
565                         list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
566                 }
567         }
568
569         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List)
570         {
571                 if (memcmp(pTS->Addr, Addr, 6) == 0)
572                 {
573                         RemoveTsEntry(ieee, pTS, RX_DIR);
574                         list_del_init(&pTS->List);
575                         list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
576                 }
577         }
578 #endif
579 }
580
581 void RemoveAllTS(struct ieee80211_device* ieee)
582 {
583         PTS_COMMON_INFO pTS, pTmpTS;
584 #if 1
585         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
586         {
587                 RemoveTsEntry(ieee, pTS, TX_DIR);
588                 list_del_init(&pTS->List);
589                 list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
590         }
591
592         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List)
593         {
594                 RemoveTsEntry(ieee, pTS, TX_DIR);
595                 list_del_init(&pTS->List);
596                 list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
597         }
598
599         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List)
600         {
601                 RemoveTsEntry(ieee, pTS, RX_DIR);
602                 list_del_init(&pTS->List);
603                 list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
604         }
605
606         list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List)
607         {
608                 RemoveTsEntry(ieee, pTS, RX_DIR);
609                 list_del_init(&pTS->List);
610                 list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
611         }
612 #endif
613 }
614
615 void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD   pTxTS)
616 {
617         if(pTxTS->bAddBaReqInProgress == false)
618         {
619                 pTxTS->bAddBaReqInProgress = true;
620 #if 1
621                 if(pTxTS->bAddBaReqDelayed)
622                 {
623                         IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
624                         mod_timer(&pTxTS->TsAddBaTimer, jiffies + MSECS(TS_ADDBA_DELAY));
625                 }
626                 else
627                 {
628                         IEEE80211_DEBUG(IEEE80211_DL_BA,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
629                         mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); //set 10 ticks
630                 }
631 #endif
632         }
633         else
634                 IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __FUNCTION__);
635 }