1f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger/****************************************************************************** 2f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * 3f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. 4f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * 5f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * This program is free software; you can redistribute it and/or modify it 6f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * under the terms of version 2 of the GNU General Public License as 7f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * published by the Free Software Foundation. 8f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * 9f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * This program is distributed in the hope that it will be useful, but WITHOUT 10f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * more details. 13f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger * 14f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ******************************************************************************/ 15f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 16f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger/* */ 17f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger/* include files */ 18f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger/* */ 19f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 20f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger#include "odm_precomp.h" 21f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 22f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingerstatic u8 odm_QueryRxPwrPercentage(s8 AntPower) 23f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 24f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if ((AntPower <= -100) || (AntPower >= 20)) 25f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return 0; 26f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (AntPower >= 0) 27f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return 100; 28f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 29f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return 100 + AntPower; 30f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 31f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 32f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingerstatic s32 odm_SignalScaleMapping_92CSeries(struct dm_odm_t *pDM_Odm, s32 CurrSig) 33f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 34f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger s32 RetSig = 0; 35f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 36f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if ((pDM_Odm->SupportInterface == ODM_ITRF_USB) || (pDM_Odm->SupportInterface == ODM_ITRF_SDIO)) { 37f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (CurrSig >= 51 && CurrSig <= 100) 38f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RetSig = 100; 39f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (CurrSig >= 41 && CurrSig <= 50) 40f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RetSig = 80 + ((CurrSig - 40)*2); 41f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (CurrSig >= 31 && CurrSig <= 40) 42f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RetSig = 66 + (CurrSig - 30); 43f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (CurrSig >= 21 && CurrSig <= 30) 44f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RetSig = 54 + (CurrSig - 20); 45f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (CurrSig >= 10 && CurrSig <= 20) 46f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RetSig = 42 + (((CurrSig - 10) * 2) / 3); 47f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (CurrSig >= 5 && CurrSig <= 9) 48f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RetSig = 22 + (((CurrSig - 5) * 3) / 2); 49f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (CurrSig >= 1 && CurrSig <= 4) 50f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RetSig = 6 + (((CurrSig - 1) * 3) / 2); 51f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 52f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RetSig = CurrSig; 53f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 54f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return RetSig; 55f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 56f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 57f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingerstatic s32 odm_SignalScaleMapping(struct dm_odm_t *pDM_Odm, s32 CurrSig) 58f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 59f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return odm_SignalScaleMapping_92CSeries(pDM_Odm, CurrSig); 60f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 61f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 62f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingerstatic u8 63f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingerodm_EVMdbToPercentage( 64f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger s8 Value 65f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ) 66f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 67f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* */ 68f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* -33dB~0dB to 0%~99% */ 69f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* */ 70f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger s8 ret_val; 71f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 72f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ret_val = Value; 73f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 74f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (ret_val >= 0) 75f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ret_val = 0; 76f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (ret_val <= -33) 77f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ret_val = -33; 78f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 79f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ret_val = 0 - ret_val; 80f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ret_val *= 3; 81f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 82f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (ret_val == 99) 83f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ret_val = 100; 84f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 85f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return ret_val; 86f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 87f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 88f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingerstatic void odm_RxPhyStatus92CSeries_Parsing(struct dm_odm_t *pDM_Odm, 89c7fff4e43ced0584bcbcef8a5f93bd9a813aac1bJes Sorensen struct phy_info *pPhyInfo, 90f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 *pPhyStatus, 91f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger struct odm_packet_info *pPktinfo) 92f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 93f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger struct phy_status_rpt *pPhyStaRpt = (struct phy_status_rpt *)pPhyStatus; 94f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 i, Max_spatial_stream; 95f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger s8 rx_pwr[4], rx_pwr_all = 0; 96f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 EVM, PWDB_ALL = 0, PWDB_ALL_BT; 97f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 RSSI, total_rssi = 0; 98f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 isCCKrate = 0; 99f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 rf_rx_num = 0; 100f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 cck_highpwr = 0; 101f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 102f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger isCCKrate = (pPktinfo->Rate <= DESC92C_RATE11M) ? true : false; 103f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = -1; 104f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1; 105f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 106f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (isCCKrate) { 107f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 report; 108f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 cck_agc_rpt; 109f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 110f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK++; 111f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* (1)Hardware does not provide RSSI for CCK */ 112f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ 113f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 114f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger cck_highpwr = pDM_Odm->bCckHighPower; 115f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 116f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ; 117f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 118f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* The RSSI formula should be modified according to the gain table */ 119f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (!cck_highpwr) { 120f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger report = (cck_agc_rpt & 0xc0)>>6; 121f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger switch (report) { 122f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion */ 123f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Note: different RF with the different RNA gain. */ 124f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger case 0x3: 125f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); 126f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger break; 127f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger case 0x2: 128f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); 129f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger break; 130f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger case 0x1: 131f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); 132f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger break; 133f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger case 0x0: 134f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); 135f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger break; 136f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 137f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 138f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger report = (cck_agc_rpt & 0x60)>>5; 139f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger switch (report) { 140f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger case 0x3: 141f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ; 142f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger break; 143f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger case 0x2: 144f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1); 145f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger break; 146f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger case 0x1: 147f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1) ; 148f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger break; 149f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger case 0x0: 150f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1) ; 151f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger break; 152f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 153f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 154f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 155f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); 156f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 157f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Modification for ext-LNA board */ 158f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) { 159f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if ((cck_agc_rpt>>7) == 0) { 160f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL = (PWDB_ALL > 94) ? 100 : (PWDB_ALL+6); 161f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 162f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (PWDB_ALL > 38) 163f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL -= 16; 164f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 165f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL = (PWDB_ALL <= 16) ? (PWDB_ALL>>2) : (PWDB_ALL-12); 166f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 167f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 168f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* CCK modification */ 169f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (PWDB_ALL > 25 && PWDB_ALL <= 60) 170f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL += 6; 171f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { /* Modification for int-LNA board */ 172f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (PWDB_ALL > 99) 173f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL -= 8; 174f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (PWDB_ALL > 50 && PWDB_ALL <= 68) 175f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL += 4; 176f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 177f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxPWDBAll = PWDB_ALL; 178f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; 179f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RecvSignalPower = rx_pwr_all; 180f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* (3) Get Signal Quality (EVM) */ 181f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPktinfo->bPacketMatchBSSID) { 182f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 SQ, SQ_rpt; 183f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 184f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all; 185f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 186f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (SQ_rpt > 64) 187f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger SQ = 0; 188f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if (SQ_rpt < 20) 189f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger SQ = 100; 190f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 191f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger SQ = ((64-SQ_rpt) * 100) / 44; 192f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 193f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->SignalQuality = SQ; 194f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = SQ; 195f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1; 196f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 197f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { /* is OFDM rate */ 198f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++; 199f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 200f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* (1)Get RSSI for HT rate */ 201f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 202f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger for (i = RF_PATH_A; i < RF_PATH_MAX; i++) { 203f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* 2008/01/30 MH we will judge RF RX path now. */ 204f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pDM_Odm->RFPathRxEnable & BIT(i)) 205f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rf_rx_num++; 206f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 207f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F)*2) - 110; 208f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 209f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxPwr[i] = rx_pwr[i]; 210f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 211f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Translate DBM to percentage. */ 212f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); 213f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger total_rssi += RSSI; 214f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 215f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Modification for ext-LNA board */ 216f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) { 217f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if ((pPhyStaRpt->path_agc[i].trsw) == 1) 218f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI = (RSSI > 94) ? 100 : (RSSI+6); 219f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 220f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI = (RSSI <= 16) ? (RSSI>>3) : (RSSI-16); 221f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 222f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if ((RSSI <= 34) && (RSSI >= 4)) 223f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI -= 4; 224f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 225f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 226f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxMIMOSignalStrength[i] = (u8) RSSI; 227f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 228f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Get Rx snr value in DB */ 229f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2); 230f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 231f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 232f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ 233f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f)-110; 234f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 235f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); 236f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger PWDB_ALL_BT = PWDB_ALL; 237f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 238f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxPWDBAll = PWDB_ALL; 239f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; 240f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxPower = rx_pwr_all; 241f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RecvSignalPower = rx_pwr_all; 242f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 243f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* (3)EVM of HT rate */ 244f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPktinfo->Rate >= DESC92C_RATEMCS8 && pPktinfo->Rate <= DESC92C_RATEMCS15) 245f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger Max_spatial_stream = 2; /* both spatial stream make sense */ 246f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 247f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger Max_spatial_stream = 1; /* only spatial stream 1 makes sense */ 248f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 249f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger for (i = 0; i < Max_spatial_stream; i++) { 250f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment */ 251f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* fill most significant bit to "zero" when doing shifting operation which may change a negative */ 252f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. */ 253f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger EVM = odm_EVMdbToPercentage((pPhyStaRpt->stream_rxevm[i])); /* dbm */ 254f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 255f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPktinfo->bPacketMatchBSSID) { 256f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (i == RF_PATH_A) { 257f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Fill value in RFD, Get the first spatial stream only */ 258f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->SignalQuality = (u8)(EVM & 0xff); 259f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 260f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff); 261f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 262f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 263f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 264f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */ 265f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */ 266f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (isCCKrate) { 267f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */ 268f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 269f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (rf_rx_num != 0) 270f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num)); 271f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 272f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 273f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 274f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingervoid odm_Init_RSSIForDM23a(struct dm_odm_t *pDM_Odm) 275f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 276f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 277f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 278f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingerstatic void odm_Process_RSSIForDM(struct dm_odm_t *pDM_Odm, 279c7fff4e43ced0584bcbcef8a5f93bd9a813aac1bJes Sorensen struct phy_info *pPhyInfo, 280f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger struct odm_packet_info *pPktinfo) 281f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 282f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK; 283f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger s32 UndecoratedSmoothedOFDM, RSSI_Ave; 284f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 isCCKrate = 0; 285f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 RSSI_max, RSSI_min, i; 286f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u32 OFDM_pkt = 0; 287f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u32 Weighting = 0; 288f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger struct sta_info *pEntry; 289f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 290f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPktinfo->StationID == 0xFF) 291f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return; 292f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 293f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->StationID]; 2942e8d47e039ec09959800ce559ed6396c4a29351dJes Sorensen if (!pEntry) 295f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return; 296f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if ((!pPktinfo->bPacketMatchBSSID)) 297f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger return; 298f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 299f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger isCCKrate = (pPktinfo->Rate <= DESC92C_RATE11M) ? true : false; 300f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 301f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* Smart Antenna Debug Message------------------*/ 302f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 303f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK; 304f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM; 305f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; 306f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 307f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) { 308f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (!isCCKrate) { /* ofdm rate */ 309f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_B] == 0) { 310f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; 311f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 312f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]) { 313f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; 314f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]; 315f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 316f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]; 317f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; 318f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 319f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if ((RSSI_max - RSSI_min) < 3) 320f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_Ave = RSSI_max; 321f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if ((RSSI_max - RSSI_min) < 6) 322f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_Ave = RSSI_max - 1; 323f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else if ((RSSI_max - RSSI_min) < 10) 324f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_Ave = RSSI_max - 2; 325f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 326f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_Ave = RSSI_max - 3; 327f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 328f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 329f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* 1 Process OFDM RSSI */ 330f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (UndecoratedSmoothedOFDM <= 0) { 331f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* initialize */ 332f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll; 333f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 334f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) { 335f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedOFDM = 336f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + 337f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger (RSSI_Ave)) / (Rx_Smooth_Factor); 338f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1; 339f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 340f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedOFDM = 341f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + 342f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger (RSSI_Ave)) / (Rx_Smooth_Factor); 343f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 344f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 345f061c1b1e3c39790268249c50d593417472ff837Jes Sorensen pEntry->rssi_stat.PacketMap = 346f061c1b1e3c39790268249c50d593417472ff837Jes Sorensen (pEntry->rssi_stat.PacketMap<<1) | BIT(0); 347f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 348f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger RSSI_Ave = pPhyInfo->RxPWDBAll; 349f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 350f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* 1 Process CCK RSSI */ 351f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (UndecoratedSmoothedCCK <= 0) { 352f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* initialize */ 353f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll; 354f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 355f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) { 356f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedCCK = 357f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger (((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + 358f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger (pPhyInfo->RxPWDBAll)) / (Rx_Smooth_Factor); 359f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1; 360f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 361f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedCCK = 362f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger (((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + 363f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger (pPhyInfo->RxPWDBAll)) / (Rx_Smooth_Factor); 364f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 365f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 366f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1; 367f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 368f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 369f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */ 370f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pEntry->rssi_stat.ValidBit >= 64) 371f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pEntry->rssi_stat.ValidBit = 64; 372f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 373f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pEntry->rssi_stat.ValidBit++; 374f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 375f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger for (i = 0; i < pEntry->rssi_stat.ValidBit; i++) 376f061c1b1e3c39790268249c50d593417472ff837Jes Sorensen OFDM_pkt += 377f061c1b1e3c39790268249c50d593417472ff837Jes Sorensen (u8)(pEntry->rssi_stat.PacketMap>>i) & BIT(0); 378f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 379f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pEntry->rssi_stat.ValidBit == 64) { 380f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger Weighting = ((OFDM_pkt<<4) > 64)?64:(OFDM_pkt<<4); 381f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6; 382f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } else { 383f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger if (pEntry->rssi_stat.ValidBit != 0) 384f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedPWDB = (OFDM_pkt*UndecoratedSmoothedOFDM+(pEntry->rssi_stat.ValidBit-OFDM_pkt)*UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit; 385f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger else 386f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger UndecoratedSmoothedPWDB = 0; 387f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 388f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK; 389f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM; 390f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB; 391f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger } 392f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 393f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 394f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger/* Endianness before calling this API */ 395f7c92d2cc2beb3367f244480300eaecdd9502932Larry Fingerstatic void ODM_PhyStatusQuery23a_92CSeries(struct dm_odm_t *pDM_Odm, 396c7fff4e43ced0584bcbcef8a5f93bd9a813aac1bJes Sorensen struct phy_info *pPhyInfo, 397f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 *pPhyStatus, 398f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger struct odm_packet_info *pPktinfo) 399f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 400f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger odm_RxPhyStatus92CSeries_Parsing(pDM_Odm, pPhyInfo, 401f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger pPhyStatus, pPktinfo); 4021a8dcde8d3ecf68924df3a5f6e38379b2b0a5415Jes Sorensen 4031a8dcde8d3ecf68924df3a5f6e38379b2b0a5415Jes Sorensen odm_Process_RSSIForDM(pDM_Odm, pPhyInfo, pPktinfo); 404f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 405f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger 406c7fff4e43ced0584bcbcef8a5f93bd9a813aac1bJes Sorensenvoid ODM_PhyStatusQuery23a(struct dm_odm_t *pDM_Odm, struct phy_info *pPhyInfo, 407f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger u8 *pPhyStatus, struct odm_packet_info *pPktinfo) 408f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger{ 409f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger ODM_PhyStatusQuery23a_92CSeries(pDM_Odm, pPhyInfo, pPhyStatus, pPktinfo); 410f7c92d2cc2beb3367f244480300eaecdd9502932Larry Finger} 411