Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 
 28 /*
 29    All functions in this file must be PCI-depended, or you should out your function
 30         in other files.
 31 
 32 */
 33 #include "../rt_config.h"
 34 
 35 extern RTMP_RF_REGS RF2850RegTable[];
 36 extern UCHAR    NUM_OF_2850_CHNL;
 37 
 38 USHORT RtmpPCI_WriteTxResource(
 39         IN      PRTMP_ADAPTER   pAd,
 40         IN      TX_BLK                  *pTxBlk,
 41         IN      BOOLEAN                 bIsLast,
 42         OUT     USHORT                  *FreeNumber)
 43 {
 44 
 45         UCHAR                   *pDMAHeaderBufVA;
 46         USHORT                  TxIdx, RetTxIdx;
 47         PTXD_STRUC              pTxD;
 48         UINT32                  BufBasePaLow;
 49         PRTMP_TX_RING   pTxRing;
 50         USHORT                  hwHeaderLen;
 51 
 52         //
 53         // get Tx Ring Resource
 54         //
 55         pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
 56         TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
 57         pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
 58         BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
 59 
 60         // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
 61         if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
 62         {
 63                 hwHeaderLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
 64         }
 65         else
 66         {
 67                 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
 68         }
 69         NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
 70 
 71         pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
 72         pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
 73 
 74         //
 75         // build Tx Descriptor
 76         //
 77 
 78         pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
 79         NdisZeroMemory(pTxD, TXD_SIZE);
 80 
 81         pTxD->SDPtr0 = BufBasePaLow;
 82         pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
 83         pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
 84         pTxD->SDLen1 = pTxBlk->SrcBufLen;
 85         pTxD->LastSec0 = 0;
 86         pTxD->LastSec1 = (bIsLast) ? 1 : 0;
 87 
 88         RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
 89 
 90         RetTxIdx = TxIdx;
 91         //
 92         // Update Tx index
 93         //
 94         INC_RING_INDEX(TxIdx, TX_RING_SIZE);
 95         pTxRing->TxCpuIdx = TxIdx;
 96 
 97         *FreeNumber -= 1;
 98 
 99         return RetTxIdx;
100 }
101 
102 
103 USHORT RtmpPCI_WriteSingleTxResource(
104         IN      PRTMP_ADAPTER   pAd,
105         IN      TX_BLK                  *pTxBlk,
106         IN      BOOLEAN                 bIsLast,
107         OUT     USHORT                  *FreeNumber)
108 {
109 
110         UCHAR                   *pDMAHeaderBufVA;
111         USHORT                  TxIdx, RetTxIdx;
112         PTXD_STRUC              pTxD;
113         UINT32                  BufBasePaLow;
114         PRTMP_TX_RING   pTxRing;
115         USHORT                  hwHeaderLen;
116 
117         //
118         // get Tx Ring Resource
119         //
120         pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
121         TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
122         pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
123         BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
124 
125         // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
126         hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
127 
128         NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
129 
130         pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
131         pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
132 
133         //
134         // build Tx Descriptor
135         //
136         pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
137 
138         NdisZeroMemory(pTxD, TXD_SIZE);
139 
140         pTxD->SDPtr0 = BufBasePaLow;
141         pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
142         pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
143         pTxD->SDLen1 = pTxBlk->SrcBufLen;
144         pTxD->LastSec0 = 0;
145         pTxD->LastSec1 = (bIsLast) ? 1 : 0;
146 
147         RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
148 
149         RetTxIdx = TxIdx;
150         //
151         // Update Tx index
152         //
153         INC_RING_INDEX(TxIdx, TX_RING_SIZE);
154         pTxRing->TxCpuIdx = TxIdx;
155 
156         *FreeNumber -= 1;
157 
158         return RetTxIdx;
159 }
160 
161 
162 USHORT RtmpPCI_WriteMultiTxResource(
163         IN      PRTMP_ADAPTER   pAd,
164         IN      TX_BLK                  *pTxBlk,
165         IN      UCHAR                   frameNum,
166         OUT     USHORT                  *FreeNumber)
167 {
168         BOOLEAN bIsLast;
169         UCHAR                   *pDMAHeaderBufVA;
170         USHORT                  TxIdx, RetTxIdx;
171         PTXD_STRUC              pTxD;
172         UINT32                  BufBasePaLow;
173         PRTMP_TX_RING   pTxRing;
174         USHORT                  hwHdrLen;
175         UINT32                  firstDMALen;
176 
177         bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0);
178 
179         //
180         // get Tx Ring Resource
181         //
182         pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
183         TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
184         pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
185         BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
186 
187         if (frameNum == 0)
188         {
189                 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
190                 if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
191                         //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD;
192                         hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
193                 else if (pTxBlk->TxFrameType == TX_RALINK_FRAME)
194                         //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD;
195                         hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD;
196                 else
197                         //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
198                         hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
199 
200                 firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen;
201         }
202         else
203         {
204                 firstDMALen = pTxBlk->MpduHeaderLen;
205         }
206 
207         NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
208 
209         pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
210         pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
211 
212         //
213         // build Tx Descriptor
214         //
215         pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
216 
217         NdisZeroMemory(pTxD, TXD_SIZE);
218 
219         pTxD->SDPtr0 = BufBasePaLow;
220         pTxD->SDLen0 = firstDMALen; // include padding
221         pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
222         pTxD->SDLen1 = pTxBlk->SrcBufLen;
223         pTxD->LastSec0 = 0;
224         pTxD->LastSec1 = (bIsLast) ? 1 : 0;
225 
226         RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
227 
228         RetTxIdx = TxIdx;
229         //
230         // Update Tx index
231         //
232         INC_RING_INDEX(TxIdx, TX_RING_SIZE);
233         pTxRing->TxCpuIdx = TxIdx;
234 
235         *FreeNumber -= 1;
236 
237         return RetTxIdx;
238 
239 }
240 
241 
242 VOID RtmpPCI_FinalWriteTxResource(
243         IN      PRTMP_ADAPTER   pAd,
244         IN      TX_BLK                  *pTxBlk,
245         IN      USHORT                  totalMPDUSize,
246         IN      USHORT                  FirstTxIdx)
247 {
248 
249         PTXWI_STRUC             pTxWI;
250         PRTMP_TX_RING   pTxRing;
251 
252         //
253         // get Tx Ring Resource
254         //
255         pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
256         pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa;
257         pTxWI->MPDUtotalByteCount = totalMPDUSize;
258 }
259 
260 
261 VOID RtmpPCIDataLastTxIdx(
262         IN      PRTMP_ADAPTER   pAd,
263         IN      UCHAR                   QueIdx,
264         IN      USHORT                  LastTxIdx)
265 {
266         PTXD_STRUC              pTxD;
267         PRTMP_TX_RING   pTxRing;
268 
269         //
270         // get Tx Ring Resource
271         //
272         pTxRing = &pAd->TxRing[QueIdx];
273 
274         //
275         // build Tx Descriptor
276         //
277         pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa;
278 
279         pTxD->LastSec1 = 1;
280 }
281 
282 
283 USHORT  RtmpPCI_WriteFragTxResource(
284         IN      PRTMP_ADAPTER   pAd,
285         IN      TX_BLK                  *pTxBlk,
286         IN      UCHAR                   fragNum,
287         OUT     USHORT                  *FreeNumber)
288 {
289         UCHAR                   *pDMAHeaderBufVA;
290         USHORT                  TxIdx, RetTxIdx;
291         PTXD_STRUC              pTxD;
292         UINT32                  BufBasePaLow;
293         PRTMP_TX_RING   pTxRing;
294         USHORT                  hwHeaderLen;
295         UINT32                  firstDMALen;
296 
297         //
298         // Get Tx Ring Resource
299         //
300         pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
301         TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
302         pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
303         BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
304 
305         //
306         // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
307         //
308         hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
309 
310         firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen;
311         NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
312 
313 
314         //
315         // Build Tx Descriptor
316         //
317         pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
318 
319         NdisZeroMemory(pTxD, TXD_SIZE);
320 
321         if (fragNum == pTxBlk->TotalFragNum)
322         {
323                 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
324                 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
325         }
326 
327         pTxD->SDPtr0 = BufBasePaLow;
328         pTxD->SDLen0 = firstDMALen; // include padding
329         pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);
330         pTxD->SDLen1 = pTxBlk->SrcBufLen;
331         pTxD->LastSec0 = 0;
332         pTxD->LastSec1 = 1;
333 
334         RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
335 
336         RetTxIdx = TxIdx;
337         pTxBlk->Priv += pTxBlk->SrcBufLen;
338 
339         //
340         // Update Tx index
341         //
342         INC_RING_INDEX(TxIdx, TX_RING_SIZE);
343         pTxRing->TxCpuIdx = TxIdx;
344 
345         *FreeNumber -= 1;
346 
347         return RetTxIdx;
348 
349 }
350 
351 /*
352         Must be run in Interrupt context
353         This function handle PCI specific TxDesc and cpu index update and kick the packet out.
354  */
355 int RtmpPCIMgmtKickOut(
356         IN RTMP_ADAPTER         *pAd,
357         IN UCHAR                        QueIdx,
358         IN PNDIS_PACKET         pPacket,
359         IN PUCHAR                       pSrcBufVA,
360         IN UINT                         SrcBufLen)
361 {
362         PTXD_STRUC              pTxD;
363         ULONG                   SwIdx = pAd->MgmtRing.TxCpuIdx;
364 
365         pTxD  = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa;
366         if (!pTxD)
367                 return 0;
368 
369         pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket;
370         pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL;
371 
372         RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT);
373         pTxD->LastSec0 = 1;
374         pTxD->LastSec1 = 1;
375         pTxD->DMADONE = 0;
376         pTxD->SDLen1 = 0;
377         pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);;
378         pTxD->SDLen0 = SrcBufLen;
379 
380         pAd->RalinkCounters.KickTxCount++;
381         pAd->RalinkCounters.OneSecTxDoneCount++;
382 
383         // Increase TX_CTX_IDX, but write to register later.
384         INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE);
385 
386         RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX,  pAd->MgmtRing.TxCpuIdx);
387 
388         return 0;
389 }
390 
391 /*
392         ========================================================================
393 
394         Routine Description:
395                 Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
396 
397         Arguments:
398                 pRxD            Pointer to the Rx descriptor
399 
400         Return Value:
401                 NDIS_STATUS_SUCCESS     No err
402                 NDIS_STATUS_FAILURE     Error
403 
404         Note:
405 
406         ========================================================================
407 */
408 NDIS_STATUS RTMPCheckRxError(
409         IN      PRTMP_ADAPTER           pAd,
410         IN      PHEADER_802_11          pHeader,
411         IN      PRXWI_STRUC             pRxWI,
412         IN  PRT28XX_RXD_STRUC   pRxD)
413 {
414         PCIPHER_KEY pWpaKey;
415         INT dBm;
416 
417         // Phy errors & CRC errors
418         if (/*(pRxD->PhyErr) ||*/ (pRxD->Crc))
419         {
420                 // Check RSSI for Noise Hist statistic collection.
421                 dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta;
422                 if (dBm <= -87)
423                         pAd->StaCfg.RPIDensity[0] += 1;
424                 else if (dBm <= -82)
425                         pAd->StaCfg.RPIDensity[1] += 1;
426                 else if (dBm <= -77)
427                         pAd->StaCfg.RPIDensity[2] += 1;
428                 else if (dBm <= -72)
429                         pAd->StaCfg.RPIDensity[3] += 1;
430                 else if (dBm <= -67)
431                         pAd->StaCfg.RPIDensity[4] += 1;
432                 else if (dBm <= -62)
433                         pAd->StaCfg.RPIDensity[5] += 1;
434                 else if (dBm <= -57)
435                         pAd->StaCfg.RPIDensity[6] += 1;
436                 else if (dBm > -57)
437                         pAd->StaCfg.RPIDensity[7] += 1;
438 
439                 return(NDIS_STATUS_FAILURE);
440         }
441 
442         // Add Rx size to channel load counter, we should ignore error counts
443         pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14);
444 
445         // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics
446         if (pHeader != NULL)
447         {
448                 if (pHeader->FC.ToDs)
449                 {
450                         return(NDIS_STATUS_FAILURE);
451                 }
452         }
453 
454         // Drop not U2M frames, cant's drop here because we will drop beacon in this case
455         // I am kind of doubting the U2M bit operation
456         // if (pRxD->U2M == 0)
457         //      return(NDIS_STATUS_FAILURE);
458 
459         // drop decyption fail frame
460         if (pRxD->CipherErr)
461         {
462                 if (pRxD->CipherErr == 2)
463                         {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV ok but MICErr "));}
464                 else if (pRxD->CipherErr == 1)
465                         {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV Err "));}
466                 else if (pRxD->CipherErr == 3)
467                         DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: Key not valid "));
468 
469         if (((pRxD->CipherErr & 1) == 1) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
470             RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
471 
472                 DBGPRINT_RAW(RT_DEBUG_TRACE,(" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n",
473                         pRxD->CipherErr,
474                         pRxD->SDL0,
475                         pRxD->Mcast | pRxD->Bcast,
476                         pRxD->MyBss,
477                         pRxWI->WirelessCliID,
478                         pRxWI->KeyIndex));
479 
480                 //
481                 // MIC Error
482                 //
483                 if (pRxD->CipherErr == 2)
484                 {
485                         pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex];
486 
487             if (pAd->StaCfg.WpaSupplicantUP)
488                 WpaSendMicFailureToWpaSupplicant(pAd,
489                                    (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE);
490             else
491                             RTMPReportMicError(pAd, pWpaKey);
492 
493             if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
494                 RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
495 
496                         DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
497                 }
498 
499                 if (pHeader == NULL)
500                         return(NDIS_STATUS_SUCCESS);
501 
502                 return(NDIS_STATUS_FAILURE);
503         }
504 
505         return(NDIS_STATUS_SUCCESS);
506 }
507 
508 /*
509         ==========================================================================
510         Description:
511                 This routine sends command to firmware and turn our chip to power save mode.
512                 Both RadioOff and .11 power save function needs to call this routine.
513         Input:
514                 Level = GUIRADIO_OFF  : GUI Radio Off mode
515                 Level = DOT11POWERSAVE  : 802.11 power save mode
516                 Level = RTMP_HALT  : When Disable device.
517 
518         ==========================================================================
519  */
520 VOID RT28xxPciAsicRadioOff(
521         IN PRTMP_ADAPTER    pAd,
522         IN UCHAR            Level,
523         IN USHORT           TbttNumToNextWakeUp)
524 {
525         WPDMA_GLO_CFG_STRUC     DmaCfg;
526         UCHAR           i, tempBBP_R3 = 0;
527         BOOLEAN         brc = FALSE, Cancelled;
528     UINT32              TbTTTime = 0;
529         UINT32          PsPollTime = 0, MACValue;
530     ULONG               BeaconPeriodTime;
531     UINT32              RxDmaIdx, RxCpuIdx;
532         DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> TxCpuIdx = %d, TxDmaIdx = %d. RxCpuIdx = %d, RxDmaIdx = %d.\n", pAd->TxRing[0].TxCpuIdx, pAd->TxRing[0].TxDmaIdx, pAd->RxRing.RxCpuIdx, pAd->RxRing.RxDmaIdx));
533 
534     // Check Rx DMA busy status, if more than half is occupied, give up this radio off.
535         RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx);
536         RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx);
537         if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3))
538         {
539                 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d ,  RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
540                 return;
541         }
542         else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
543         {
544                 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2.  RxCpuIdx = %d. RxDmaIdx = %d ,  \n", RxCpuIdx, RxDmaIdx));
545                 return;
546         }
547 
548     // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops.
549         RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
550 
551         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
552         {
553             RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
554             RTMPCancelTimer(&pAd->Mlme.PsPollTimer,     &Cancelled);
555 
556             if (Level == DOT11POWERSAVE)
557                 {
558                         RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
559                         TbTTTime &= 0x1ffff;
560                         // 00. check if need to do sleep in this DTIM period.   If next beacon will arrive within 30ms , ...doesn't necessarily sleep.
561                         // TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms
562                 if  (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0))
563                         {
564                                 DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime));
565                     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
566                                 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
567                                 return;
568                         }
569                         else
570                         {
571                                 PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
572                                 PsPollTime -= 3;
573 
574                     BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
575                                 if (TbttNumToNextWakeUp > 0)
576                                         PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
577 
578                     pAd->Mlme.bPsPollTimerRunning = TRUE;
579                                 RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
580                         }
581                 }
582         }
583 
584     // 0. Disable Tx DMA.
585         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
586         DmaCfg.field.EnableTxDMA = 0;
587         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
588 
589         // 1. Wait DMA not busy
590         i = 0;
591         do
592         {
593                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
594                 if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0))
595                         break;
596                 RTMPusecDelay(20);
597                 i++;
598         }while(i < 50);
599 
600         if (i >= 50)
601         {
602                 DBGPRINT(RT_DEBUG_TRACE, ("DMA keeps busy.  return on RT28xxPciAsicRadioOff ()\n"));
603                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
604                 DmaCfg.field.EnableTxDMA = 1;
605                 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
606                 pAd->CheckDmaBusyCount++;
607                 return;
608         }
609         else
610         {
611                 pAd->CheckDmaBusyCount = 0;
612         }
613 
614     RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
615 
616     // Set to 1R.
617         if (pAd->Antenna.field.RxPath > 1)
618         {
619                 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
620                 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
621         }
622 
623         // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
624         if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
625                 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
626         {
627                 // Must using 40MHz.
628                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
629         }
630         else
631         {
632                 // Must using 20MHz.
633                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
634         }
635 
636         if (Level != RTMP_HALT)
637         {
638                 // Change Interrupt bitmask.
639                 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
640         }
641         else
642         {
643                 NICDisableInterrupt(pAd);
644         }
645 
646     RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
647         // Disable MAC Rx
648         RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
649         MACValue &= 0xf7;
650         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
651 
652         //  2. Send Sleep command
653         RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
654         RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
655         // send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power
656         AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1);
657         //  2-1. Wait command success
658         // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
659         brc = AsicCheckCommanOk(pAd, PowerSafeCID);
660 
661     if (brc == FALSE)
662     {
663         // try again
664         AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x01);   // send POWER-SAVE command to MCU. Timeout unit:40us.
665         //RTMPusecDelay(200);
666         brc = AsicCheckCommanOk(pAd, PowerSafeCID);
667     }
668 
669         //  3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
670         // If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
671         if ((Level == DOT11POWERSAVE) && (brc == TRUE))
672         {
673                 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00);     // lowbyte = 0 means to do power safe, NOT turn off radio.
674                 //  3-1. Wait command success
675                 AsicCheckCommanOk(pAd, PowerRadioOffCID);
676         }
677         else if (brc == TRUE)
678         {
679                 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00);     // lowbyte = 0 means to do power safe, NOT turn off radio.
680                 //  3-1. Wait command success
681                 AsicCheckCommanOk(pAd, PowerRadioOffCID);
682         }
683 
684     // Wait DMA not busy
685         i = 0;
686         do
687         {
688                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
689                 if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
690                         break;
691                 RTMPusecDelay(20);
692                 i++;
693         }while(i < 50);
694 
695         if (i >= 50)
696         {
697                 pAd->CheckDmaBusyCount++;
698                 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy.  on RT28xxPciAsicRadioOff ()\n"));
699         }
700         else
701         {
702                 pAd->CheckDmaBusyCount = 0;
703         }
704 
705         if (Level == DOT11POWERSAVE)
706         {
707                 AUTO_WAKEUP_STRUC       AutoWakeupCfg;
708                 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
709 
710                 // we have decided to SLEEP, so at least do it for a BEACON period.
711                 if (TbttNumToNextWakeUp == 0)
712                         TbttNumToNextWakeUp = 1;
713 
714                 AutoWakeupCfg.word = 0;
715                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
716 
717                 // 1. Set auto wake up timer.
718                 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
719                 AutoWakeupCfg.field.EnableAutoWakeup = 1;
720                 AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
721                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
722         }
723 
724         //  4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
725         if (Level == RTMP_HALT)
726         {
727                 if ((brc == TRUE) && (i < 50))
728                         RTMPPCIeLinkCtrlSetting(pAd, 0);
729         }
730         //  4. Set PCI configuration Space Link Comtrol fields.  Only Radio Off needs to call this function
731         else
732         {
733                 if ((brc == TRUE) && (i < 50))
734                         RTMPPCIeLinkCtrlSetting(pAd, 3);
735         }
736 
737         RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
738 }
739 
740 
741 /*
742         ==========================================================================
743         Description:
744                 This routine sends command to firmware and turn our chip to wake up mode from power save mode.
745                 Both RadioOn and .11 power save function needs to call this routine.
746         Input:
747                 Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On.  Need to restore PCI host value.
748                 Level = other value : normal wake up function.
749 
750         ==========================================================================
751  */
752 BOOLEAN RT28xxPciAsicRadioOn(
753         IN PRTMP_ADAPTER pAd,
754         IN UCHAR     Level)
755 {
756     WPDMA_GLO_CFG_STRUC DmaCfg;
757         BOOLEAN                         Cancelled, brv = TRUE;
758     UINT32                          MACValue;
759 
760         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
761         {
762             pAd->Mlme.bPsPollTimerRunning = FALSE;
763                 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
764                 if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE)
765                 || (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)))
766                 {
767                         DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
768                         // 1. Set PCI Link Control in Configuration Space.
769                         RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
770                         RTMPusecDelay(6000);
771                 }
772         }
773 
774     pAd->bPCIclkOff = FALSE;
775         RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x3a80);
776         // 2. Send wake up command.
777         AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
778 
779         // 2-1. wait command ok.
780         brv = AsicCheckCommanOk(pAd, PowerWakeCID);
781     if (brv)
782     {
783         NICEnableInterrupt(pAd);
784 
785         // 3. Enable Tx DMA.
786         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
787         DmaCfg.field.EnableTxDMA = 1;
788         DmaCfg.field.EnableRxDMA = 1;
789         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
790 
791         // Eable MAC Rx
792         RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
793         MACValue |= 0x8;
794         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
795 
796         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
797         if (Level == GUI_IDLE_POWER_SAVE)
798         {
799                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
800                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
801                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
802                 {
803                         // Must using 40MHz.
804                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
805                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
806                 }
807                 else
808                 {
809                         // Must using 20MHz.
810                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
811                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
812                 }
813         }
814         return TRUE;
815     }
816     else
817         return FALSE;
818 }
819 
820 VOID RT28xxPciStaAsicForceWakeup(
821         IN PRTMP_ADAPTER pAd,
822         IN UCHAR         Level)
823 {
824     AUTO_WAKEUP_STRUC   AutoWakeupCfg;
825 
826     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
827     {
828         DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
829         return;
830     }
831 
832     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
833         RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
834 
835     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
836     {
837         // Support PCIe Advance Power Save
838         if (((Level == FROM_TX) && (pAd->Mlme.bPsPollTimerRunning == TRUE)) ||
839                         (Level == RTMP_HALT))
840         {
841             pAd->Mlme.bPsPollTimerRunning = FALSE;
842                 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
843                 RTMPusecDelay(5000);
844             DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
845         }
846 
847                 AutoWakeupCfg.word = 0;
848                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
849 
850                 // If this is called from Halt. ALWAYS force wakeup!!!
851                 if (Level == RTMP_HALT)
852                 {
853                         RT28xxPciAsicRadioOn(pAd, RTMP_HALT);
854                 }
855                 else
856                 {
857                         if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
858                         {
859                                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
860                                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
861                                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
862                                 {
863                                         // Must using 40MHz.
864                                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
865                                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
866                                 }
867                                 else
868                                 {
869                                         // Must using 20MHz.
870                                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
871                                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
872                                 }
873                         }
874                 }
875     }
876     else
877     {
878         // PCI, 2860-PCIe
879         AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
880                 AutoWakeupCfg.word = 0;
881                 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
882     }
883 
884     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
885     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
886     DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
887 }
888 
889 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
890         IN PRTMP_ADAPTER pAd,
891         IN USHORT TbttNumToNextWakeUp)
892 {
893     if (pAd->StaCfg.bRadio == FALSE)
894         {
895                 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
896                 return;
897         }
898     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
899     {
900         ULONG   Now = 0;
901         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
902         {
903             DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
904             OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
905             return;
906         }
907 
908                 NdisGetSystemUpTime(&Now);
909                 // If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
910                 // Because Some AP can't queuing outgoing frames immediately.
911                 if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
912                 {
913                         DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu :  RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
914                         return;
915                 }
916                 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
917                 {
918                         DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime,  pAd->RalinkCounters.RxCountSinceLastNULL));
919                         return;
920                 }
921 
922         RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
923     }
924     else
925     {
926         AUTO_WAKEUP_STRUC       AutoWakeupCfg;
927         // we have decided to SLEEP, so at least do it for a BEACON period.
928         if (TbttNumToNextWakeUp == 0)
929             TbttNumToNextWakeUp = 1;
930 
931         AutoWakeupCfg.word = 0;
932         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
933         AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
934         AutoWakeupCfg.field.EnableAutoWakeup = 1;
935         AutoWakeupCfg.field.AutoLeadTime = 5;
936         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
937         AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00);   // send POWER-SAVE command to MCU. Timeout 40us.
938         DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
939     }
940     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
941 }
942 
943 VOID PsPollWakeExec(
944         IN PVOID SystemSpecific1,
945         IN PVOID FunctionContext,
946         IN PVOID SystemSpecific2,
947         IN PVOID SystemSpecific3)
948 {
949         RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
950         unsigned long flags;
951 
952     DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
953         RTMP_INT_LOCK(&pAd->irq_lock, flags);
954     if (pAd->Mlme.bPsPollTimerRunning)
955     {
956             RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
957     }
958     pAd->Mlme.bPsPollTimerRunning = FALSE;
959         RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
960 }
961 
962 VOID  RadioOnExec(
963         IN PVOID SystemSpecific1,
964         IN PVOID FunctionContext,
965         IN PVOID SystemSpecific2,
966         IN PVOID SystemSpecific3)
967 {
968         RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
969         WPDMA_GLO_CFG_STRUC     DmaCfg;
970         BOOLEAN                         Cancelled;
971 
972         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
973         {
974                 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
975                 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
976                 return;
977         }
978 
979         if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
980         {
981                 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
982                 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
983                 return;
984         }
985     pAd->Mlme.bPsPollTimerRunning = FALSE;
986         RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
987         if (pAd->StaCfg.bRadio == TRUE)
988         {
989                 pAd->bPCIclkOff = FALSE;
990         RTMPRingCleanUp(pAd, QID_AC_BK);
991                 RTMPRingCleanUp(pAd, QID_AC_BE);
992                 RTMPRingCleanUp(pAd, QID_AC_VI);
993                 RTMPRingCleanUp(pAd, QID_AC_VO);
994                 RTMPRingCleanUp(pAd, QID_HCCA);
995                 RTMPRingCleanUp(pAd, QID_MGMT);
996                 RTMPRingCleanUp(pAd, QID_RX);
997 
998                 // 2. Send wake up command.
999                 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1000                 // 2-1. wait command ok.
1001                 AsicCheckCommanOk(pAd, PowerWakeCID);
1002 
1003                 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1004                 NICEnableInterrupt(pAd);
1005 
1006                 // 3. Enable Tx DMA.
1007                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1008                 DmaCfg.field.EnableTxDMA = 1;
1009                 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1010 
1011                 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1012                 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1013                         && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1014                 {
1015                         // Must using 40MHz.
1016                         AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1017                         AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1018                 }
1019                 else
1020                 {
1021                         // Must using 20MHz.
1022                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1023                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1024                 }
1025 
1026                 // Clear Radio off flag
1027                 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1028 
1029                 // Set LED
1030                 RTMPSetLED(pAd, LED_RADIO_ON);
1031 
1032         if (pAd->StaCfg.Psm == PWR_ACTIVE)
1033         {
1034                 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1035         }
1036         }
1037         else
1038         {
1039                 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1040         }
1041 }
1042 
1043 VOID RT28xxPciMlmeRadioOn(
1044         IN PRTMP_ADAPTER pAd)
1045 {
1046     if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1047                 return;
1048 
1049     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1050 
1051     if ((pAd->OpMode == OPMODE_AP) ||
1052         ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1053     {
1054         NICResetFromError(pAd);
1055 
1056         /*
1057         RTMPRingCleanUp(pAd, QID_AC_BK);
1058         RTMPRingCleanUp(pAd, QID_AC_BE);
1059         RTMPRingCleanUp(pAd, QID_AC_VI);
1060         RTMPRingCleanUp(pAd, QID_AC_VO);
1061         RTMPRingCleanUp(pAd, QID_HCCA);
1062         RTMPRingCleanUp(pAd, QID_MGMT);
1063         RTMPRingCleanUp(pAd, QID_RX);
1064                 */
1065 
1066         // Enable Tx/Rx
1067         RTMPEnableRxTx(pAd);
1068 
1069         // Clear Radio off flag
1070         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1071 
1072             // Set LED
1073             RTMPSetLED(pAd, LED_RADIO_ON);
1074     }
1075 
1076     if ((pAd->OpMode == OPMODE_STA) &&
1077         (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1078     {
1079         BOOLEAN         Cancelled;
1080 
1081         RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1082 
1083         pAd->Mlme.bPsPollTimerRunning = FALSE;
1084         RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1085         RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,     &Cancelled);
1086         RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1087     }
1088 }
1089 
1090 VOID RT28xxPciMlmeRadioOFF(
1091         IN PRTMP_ADAPTER pAd)
1092 {
1093     WPDMA_GLO_CFG_STRUC GloCfg;
1094         UINT32  i;
1095 
1096         if (pAd->StaCfg.bRadio == TRUE)
1097         {
1098                 DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1099                 return;
1100         }
1101 
1102     if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1103         return;
1104 
1105     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1106 
1107         // Set LED
1108         RTMPSetLED(pAd, LED_RADIO_OFF);
1109 
1110     {
1111         BOOLEAN         Cancelled;
1112 
1113         if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1114         {
1115                         RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
1116                         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1117         }
1118 
1119                 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1120         {
1121             BOOLEAN Cancelled;
1122 
1123                         // Always radio on since the NIC needs to set the MCU command (LED_RADIO_OFF).

1124                         if ((pAd->OpMode == OPMODE_STA) && 
1125                              (IDLE_ON(pAd)) && 
1126                              (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))
1127                         {
1128                                 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
1129                         }
1130 
1131             pAd->Mlme.bPsPollTimerRunning = FALSE;
1132             RTMPCancelTimer(&pAd->Mlme.PsPollTimer,     &Cancelled);
1133                 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,     &Cancelled);
1134         }
1135 
1136         // Link down first if any association exists
1137         if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1138             LinkDown(pAd, FALSE);
1139         RTMPusecDelay(10000);
1140         //==========================================
1141         // Clean up old bss table
1142         BssTableInit(&pAd->ScanTab);
1143 
1144                 RTMPRingCleanUp(pAd, QID_AC_BK);
1145         RTMPRingCleanUp(pAd, QID_AC_BE);
1146         RTMPRingCleanUp(pAd, QID_AC_VI);
1147         RTMPRingCleanUp(pAd, QID_AC_VO);
1148         RTMPRingCleanUp(pAd, QID_HCCA);
1149         RTMPRingCleanUp(pAd, QID_MGMT);
1150         RTMPRingCleanUp(pAd, QID_RX);
1151 
1152                 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1153                 {
1154                         RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 500);
1155                         return;
1156                 }
1157     }
1158 
1159         // Set Radio off flag
1160         RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1161 
1162         // Disable Tx/Rx DMA
1163         RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);          // disable DMA
1164         GloCfg.field.EnableTxDMA = 0;
1165         GloCfg.field.EnableRxDMA = 0;
1166         RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);          // abort all TX rings
1167 
1168 
1169         // MAC_SYS_CTRL => value = 0x0 => 40mA
1170         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
1171 
1172         // PWR_PIN_CFG => value = 0x0 => 40mA
1173         RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
1174 
1175         // TX_PIN_CFG => value = 0x0 => 20mA
1176         RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
1177 
1178         if (pAd->CommonCfg.BBPCurrentBW == BW_40)
1179         {
1180                 // Must using 40MHz.
1181                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1182         }
1183         else
1184         {
1185                 // Must using 20MHz.
1186                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1187         }
1188 
1189         // Waiting for DMA idle
1190         i = 0;
1191         do
1192         {
1193                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
1194                 if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
1195                         break;
1196 
1197                 RTMPusecDelay(1000);
1198         }while (i++ < 100);
1199 }
1200 
  This page was automatically generated by the LXR engine.