📄 ar5211_reset.c
字号:
upperPower = pPowerInfo[upperIndex].twicePwr54; break; } } twicePower = ar5211GetInterpolatedValue(chan->channel, lowerChannel, upperChannel, lowerPower, upperPower, 0); /* Reduce power by band edge restrictions */ twicePower = AH_MIN(twicePower, twiceMaxEdgePower); /* * If turbo is set, reduce power to keep power * consumption under 2 Watts. Note that we always do * this unless specially configured. Then we limit * power only for non-AP operation. */ if (IS_CHAN_TURBO(chan) && ahp->ah_eeversion >= AR_EEPROM_VER3_1#ifdef AH_ENABLE_AP_SUPPORT && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP#endif ) { twicePower = AH_MIN(twicePower, ahp->ah_turbo2WMaxPower5); } /* Reduce power by max regulatory domain allowed restrictions */ pRatesPower[i] = AH_MIN(twicePower, twiceMaxRDPower - twiceAntennaReduction); /* Use 6 Mb power level for transmit power scaling reduction */ /* We don't want to reduce higher rates if its not needed */ if (i == 0) { scaledPower = pRatesPower[0] - (tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2); if (scaledPower < 1) scaledPower = 1; } pRatesPower[i] = AH_MIN(pRatesPower[i], scaledPower); } /* Record txPower at Rate 6 for info gathering */ ahp->ah_tx6PowerInHalfDbm = pRatesPower[0];#ifdef AH_DEBUG HALDEBUG(ah, "%s: final output power setting %d MHz:\n", __func__, chan->channel); HALDEBUG(ah, "6 Mb %d dBm, MaxRD: %d dBm, MaxEdge %d dBm\n", scaledPower / 2, twiceMaxRDPower / 2, twiceMaxEdgePower / 2); HALDEBUG(ah, "TPC Scale %d dBm - Ant Red %d dBm\n", tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2, twiceAntennaReduction / 2); if (IS_CHAN_TURBO(chan) && ahp->ah_eeversion >= AR_EEPROM_VER3_1) HALDEBUG(ah, "Max Turbo %d dBm\n", ahp->ah_turbo2WMaxPower5); HALDEBUG(ah, " %2d | %2d | %2d | %2d | %2d | %2d | %2d | %2d dBm\n", pRatesPower[0] / 2, pRatesPower[1] / 2, pRatesPower[2] / 2, pRatesPower[3] / 2, pRatesPower[4] / 2, pRatesPower[5] / 2, pRatesPower[6] / 2, pRatesPower[7] / 2);#endif /* AH_DEBUG */ /* Write the power table into the hardware */ OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ((paPreDEnable & 1)<< 30) | ((pRatesPower[3] & mask) << 24) | ((paPreDEnable & 1)<< 22) | ((pRatesPower[2] & mask) << 16) | ((paPreDEnable & 1)<< 14) | ((pRatesPower[1] & mask) << 8) | ((paPreDEnable & 1)<< 6 ) | (pRatesPower[0] & mask)); OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, ((paPreDEnable & 1)<< 30) | ((pRatesPower[7] & mask) << 24) | ((paPreDEnable & 1)<< 22) | ((pRatesPower[6] & mask) << 16) | ((paPreDEnable & 1)<< 14) | ((pRatesPower[5] & mask) << 8) | ((paPreDEnable & 1)<< 6 ) | (pRatesPower[4] & mask)); /* set max power to the power value at rate 6 */ ar5211SetTxPowerLimit(ah, pRatesPower[0]); AH_PRIVATE(ah)->ah_maxPowerLevel = pRatesPower[0];}/* * Get or interpolate the pcdac value from the calibrated data */u_int16_tar5211GetScaledPower(u_int16_t channel, u_int16_t pcdacValue, PCDACS_EEPROM *pSrcStruct){ u_int16_t powerValue; u_int16_t lFreq, rFreq; /* left and right frequency values */ u_int16_t llPcdac, ulPcdac; /* lower and upper left pcdac values */ u_int16_t lrPcdac, urPcdac; /* lower and upper right pcdac values */ u_int16_t lPwr, uPwr; /* lower and upper temp pwr values */ u_int16_t lScaledPwr, rScaledPwr; /* left and right scaled power */ if (ar5211FindValueInList(channel, pcdacValue, pSrcStruct, &powerValue)) /* value was copied from srcStruct */ return powerValue; ar5211GetLowerUpperValues(channel, pSrcStruct->pChannelList, pSrcStruct->numChannels, &lFreq, &rFreq); ar5211GetLowerUpperPcdacs(pcdacValue, lFreq, pSrcStruct, &llPcdac, &ulPcdac); ar5211GetLowerUpperPcdacs(pcdacValue, rFreq, pSrcStruct, &lrPcdac, &urPcdac); /* get the power index for the pcdac value */ ar5211FindValueInList(lFreq, llPcdac, pSrcStruct, &lPwr); ar5211FindValueInList(lFreq, ulPcdac, pSrcStruct, &uPwr); lScaledPwr = ar5211GetInterpolatedValue(pcdacValue, llPcdac, ulPcdac, lPwr, uPwr, 0); ar5211FindValueInList(rFreq, lrPcdac, pSrcStruct, &lPwr); ar5211FindValueInList(rFreq, urPcdac, pSrcStruct, &uPwr); rScaledPwr = ar5211GetInterpolatedValue(pcdacValue, lrPcdac, urPcdac, lPwr, uPwr, 0); return ar5211GetInterpolatedValue(channel, lFreq, rFreq, lScaledPwr, rScaledPwr, 0);}/* * Find the value from the calibrated source data struct */HAL_BOOLar5211FindValueInList(u_int16_t channel, u_int16_t pcdacValue, PCDACS_EEPROM *pSrcStruct, u_int16_t *powerValue){ DATA_PER_CHANNEL *pChannelData; u_int16_t *pPcdac; u_int16_t i, j; pChannelData = pSrcStruct->pDataPerChannel; for (i = 0; i < pSrcStruct->numChannels; i++ ) { if (pChannelData->channelValue == channel) { pPcdac = pChannelData->PcdacValues; for (j = 0; j < pChannelData->numPcdacValues; j++ ) { if (*pPcdac == pcdacValue) { *powerValue = pChannelData->PwrValues[j]; return AH_TRUE; } pPcdac++; } } pChannelData++; } return AH_FALSE;}/* * Returns interpolated or the scaled up interpolated value */u_int16_tar5211GetInterpolatedValue(u_int16_t target, u_int16_t srcLeft, u_int16_t srcRight, u_int16_t targetLeft, u_int16_t targetRight, HAL_BOOL scaleUp){ u_int16_t rv; int16_t lRatio; u_int16_t scaleValue = EEP_SCALE; /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */ if ((targetLeft * targetRight) == 0) return 0; if (scaleUp) scaleValue = 1; if (srcRight != srcLeft) { /* * Note the ratio always need to be scaled, * since it will be a fraction. */ lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft); if (lRatio < 0) { /* Return as Left target if value would be negative */ rv = targetLeft * (scaleUp ? EEP_SCALE : 1); } else if (lRatio > EEP_SCALE) { /* Return as Right target if Ratio is greater than 100% (SCALE) */ rv = targetRight * (scaleUp ? EEP_SCALE : 1); } else { rv = (lRatio * targetRight + (EEP_SCALE - lRatio) * targetLeft) / scaleValue; } } else { rv = targetLeft; if (scaleUp) rv *= EEP_SCALE; } return rv;}/* * Look for value being within 0.1 of the search values * however, NDIS can't do float calculations, so multiply everything * up by EEP_SCALE so can do integer arithmatic * * INPUT value -value to search for * INPUT pList -ptr to the list to search * INPUT listSize -number of entries in list * OUTPUT pLowerValue -return the lower value * OUTPUT pUpperValue -return the upper value */voidar5211GetLowerUpperValues(u_int16_t value, u_int16_t *pList, u_int16_t listSize, u_int16_t *pLowerValue, u_int16_t *pUpperValue){ u_int16_t listEndValue = *(pList + listSize - 1); u_int32_t target = value * EEP_SCALE; int i; /* * See if value is lower than the first value in the list * if so return first value */ if (target < (u_int32_t)(*pList * EEP_SCALE - EEP_DELTA)) { *pLowerValue = *pList; *pUpperValue = *pList; return; } /* * See if value is greater than last value in list * if so return last value */ if (target > (u_int32_t)(listEndValue * EEP_SCALE + EEP_DELTA)) { *pLowerValue = listEndValue; *pUpperValue = listEndValue; return; } /* look for value being near or between 2 values in list */ for (i = 0; i < listSize; i++) { /* * If value is close to the current value of the list * then target is not between values, it is one of the values */ if (abs(pList[i] * EEP_SCALE - (int32_t) target) < EEP_DELTA) { *pLowerValue = pList[i]; *pUpperValue = pList[i]; return; } /* * Look for value being between current value and next value * if so return these 2 values */ if (target < (u_int32_t)(pList[i + 1] * EEP_SCALE - EEP_DELTA)) { *pLowerValue = pList[i]; *pUpperValue = pList[i + 1]; return; } }}/* * Get the upper and lower pcdac given the channel and the pcdac * used in the search */voidar5211GetLowerUpperPcdacs(u_int16_t pcdac, u_int16_t channel, PCDACS_EEPROM *pSrcStruct, u_int16_t *pLowerPcdac, u_int16_t *pUpperPcdac){ DATA_PER_CHANNEL *pChannelData; int i; /* Find the channel information */ pChannelData = pSrcStruct->pDataPerChannel; for (i = 0; i < pSrcStruct->numChannels; i++) { if (pChannelData->channelValue == channel) break; pChannelData++; } ar5211GetLowerUpperValues(pcdac, pChannelData->PcdacValues, pChannelData->numPcdacValues, pLowerPcdac, pUpperPcdac);}#define DYN_ADJ_UP_MARGIN 15#define DYN_ADJ_LO_MARGIN 20static const GAIN_OPTIMIZATION_LADDER gainLadder = { 9, /* numStepsInLadder */ 4, /* defaultStepNum */ { { {4, 1, 1, 1}, 6, "FG8"}, { {4, 0, 1, 1}, 4, "FG7"}, { {3, 1, 1, 1}, 3, "FG6"}, { {4, 0, 0, 1}, 1, "FG5"}, { {4, 1, 1, 0}, 0, "FG4"}, /* noJack */ { {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */ { {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */ { {4, 0, 0, 0}, -4, "FG1"}, /* noJack */ { {2, 1, 1, 0}, -6, "FG0"} /* clip2 */ }};/* * Initialize the gain structure to good values */voidar5211InitializeGainValues(struct ath_hal *ah){ struct ath_hal_5211 *ahp = AH5211(ah); GAIN_VALUES *gv = &ahp->ah_gainValues; /* initialize gain optimization values */ gv->currStepNum = gainLadder.defaultStepNum; gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum]; gv->active = AH_TRUE; gv->loTrig = 20; gv->hiTrig = 35;}static HAL_BOOLar5211InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv){ HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; u_int32_t gStep, g; u_int32_t L1, L2, L3, L4; if (IS_CHAN_CCK(chan)) { gStep = 0x18; L1 = 0; L2 = gStep + 4; L3 = 0x40; L4 = L3 + 50; gv->loTrig = L1; gv->hiTrig = L4+5; } else { gStep = 0x3f; L1 = 0; L2 = 50; L3 = L1; L4 = L3 + 50; gv->loTrig = L1 + DYN_ADJ_LO_MARGIN; gv->hiTrig = L4 - DYN_ADJ_UP_MARGIN; } g = gv->currGain; return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4));}/* * Enable the probe gain check on the next packet */static voidar5211RequestRfgain(struct ath_hal *ah){ struct ath_hal_5211 *ahp = AH5211(ah); /* Enable the gain readback probe */ OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE, SM(ahp->ah_tx6PowerInHalfDbm, AR_PHY_PAPD_PROBE_POWERTX) | AR_PHY_PAPD_PROBE_NEXT_TX); ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED;}/* * Exported call to check for a recent gain reading and return * the current state of the thermal calibration gain engine. */HAL_RFGAINar5211GetRfgain(struct ath_hal *ah){ struct ath_hal_5211 *ahp = AH5211(ah); GAIN_VALUES *gv = &ahp->ah_gainValues; u_int32_t rddata; if (!gv->active) return HAL_RFGAIN_INACTIVE; if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) { /* Caller had asked to setup a new reading. Check it. */ rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE); if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) { /* bit got cleared, we have a new reading. */ gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S; /* inactive by default */ ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; if (!ar5211InvalidGainReadback(ah, gv) && ar5211IsGainAdjustNeeded(ah, gv) && ar5211AdjustGain(ah, gv) > 0) { /* * Change needed. Copy ladder info * into eeprom info. */ ar5211SetRfgain(ah, gv); ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE; } } } return ahp->ah_rfgainState;}/* * Check to see if our readback gain level sits within the linear * region of our current variable attenuation window */static HAL_BOOLar5211IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv){ return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);}/* * Move the rabbit ears in the correct direction. */static int32_t ar5211AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv){ /* return > 0 for valid adjustments. */ if (!gv->active) return -1; gv->currStep = &gainLadder.optStep[gv->currStepNum]; if (gv->currGain >= gv->hiTrig) { if (gv->currStepNum == 0) { HALDEBUG(ah, "%s: Max gain limit.\n", __func__); return -1; } HALDEBUG(ah, "%s: Adding gain: currG=%d [%s] --> ", __func__, gv->currGain, gv->currStep->stepName); gv->targetGain = gv->currGain; while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) { gv->targetGain -= 2 * (gainLadder.optStep[--(gv->currStepNum)].stepGain - gv->currStep->stepGain); gv->currStep = &gainLadder.optStep[gv->currStepNum]; } HALDEBUG(ah, "targG=%d [%s]\n", gv->targetGain, gv->currStep->stepName); return 1; } if (gv->currGain <= gv->loTrig) { if (gv->currStepNum == gainLadder.numStepsInLadder-1) { HALDEBUG(ah, "%s: Min gain limit.\n", __func__); return -2; } HALDEBUG(ah, "%s: Deducting gain: currG=%d [%s] --> ", __func__, gv->currGain, gv->currStep->stepName); gv->targetGain = gv->currGain; while (gv->targetGain <= gv->loTrig && gv->currStepNum < (gainLadder.numStepsInLadder - 1)) { gv->targetGain -= 2 * (gainLadder.optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain); gv->currStep = &gainLadder.optStep[gv->currStepNum]; } HALDEBUG(ah, "targG=%d [%s]\n", gv->targetGain, gv->currStep->stepName); return 2; } return 0; /* caller didn't call needAdjGain first */}/* * Adjust the 5GHz EEPROM information with the desired calibration values. */static voidar5211SetRfgain(struct ath_hal *ah, const GAIN_VALUES *gv){ struct ath_hal_5211 *ahp = AH5211(ah); if (!gv->active) return; ahp->ah_cornerCal.clip = gv->currStep->paramVal[0]; /* bb_tx_clip */ ahp->ah_cornerCal.pd90 = gv->currStep->paramVal[1]; /* rf_pwd_90 */ ahp->ah_cornerCal.pd84 = gv->currStep->paramVal[2]; /* rf_pwd_84 */ ahp->ah_cornerCal.gSel = gv->currStep->paramVal[3]; /* rf_rfgainsel */}voidar5211SetPCUConfig(struct ath_hal *ah){ u_int32_t val; val = OS_REG_READ(ah, AR_STA_ID1) & 0xffff; switch (AH_PRIVATE(ah)->ah_opmode) { case HAL_M_HOSTAP: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP | AR_STA_ID1_RTS_USE_DEF); break; case HAL_M_IBSS: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC | AR_STA_ID1_DESC_ANTENNA); break; case HAL_M_STA: case HAL_M_MONITOR: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_DEFAULT_ANTENNA); break; }}#endif /* AH_SUPPORT_AR5211 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -