diff options
Diffstat (limited to 'drivers/net/wireless/ath9k/regd.c')
-rw-r--r-- | drivers/net/wireless/ath9k/regd.c | 1031 |
1 files changed, 0 insertions, 1031 deletions
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c deleted file mode 100644 index 7b0176e3eb40..000000000000 --- a/drivers/net/wireless/ath9k/regd.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * Copyright (c) 2008 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include "core.h" -#include "hw.h" -#include "regd.h" -#include "regd_common.h" - -static int ath9k_regd_chansort(const void *a, const void *b) -{ - const struct ath9k_channel *ca = a; - const struct ath9k_channel *cb = b; - - return (ca->channel == cb->channel) ? - (ca->channelFlags & CHAN_FLAGS) - - (cb->channelFlags & CHAN_FLAGS) : ca->channel - cb->channel; -} - -static void -ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp) -{ - u8 *aa = a; - u8 *ai, *t; - - for (ai = aa + size; --n >= 1; ai += size) - for (t = ai; t > aa; t -= size) { - u8 *u = t - size; - if (cmp(u, t) <= 0) - break; - swap(u, t, size); - } -} - -static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah) -{ - return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG; -} - -static bool ath9k_regd_is_chan_bm_zero(u64 *bitmask) -{ - int i; - - for (i = 0; i < BMLEN; i++) { - if (bitmask[i] != 0) - return false; - } - return true; -} - -static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah) -{ - u16 rd = ath9k_regd_get_eepromRD(ah); - int i; - - if (rd & COUNTRY_ERD_FLAG) { - u16 cc = rd & ~COUNTRY_ERD_FLAG; - for (i = 0; i < ARRAY_SIZE(allCountries); i++) - if (allCountries[i].countryCode == cc) - return true; - } else { - for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) - if (regDomainPairs[i].regDmnEnum == rd) - return true; - } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid regulatory domain/country code 0x%x\n", - __func__, rd); - return false; -} - -static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal *ah) -{ - u32 regcap; - - regcap = ah->ah_caps.halRegCap; - - if (regcap & AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND) - return true; - else - return false; -} - -static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah, - u16 cc) -{ - u16 rd; - int i; - - if (cc == CTRY_DEFAULT) - return true; - if (cc == CTRY_DEBUG) - return true; - - rd = ath9k_regd_get_eepromRD(ah); - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n", - __func__, rd); - - if (rd & COUNTRY_ERD_FLAG) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: EEPROM setting is country code %u\n", - __func__, rd & ~COUNTRY_ERD_FLAG); - return cc == (rd & ~COUNTRY_ERD_FLAG); - } - - for (i = 0; i < ARRAY_SIZE(allCountries); i++) { - if (cc == allCountries[i].countryCode) { -#ifdef AH_SUPPORT_11D - if ((rd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) - return true; -#endif - if (allCountries[i].regDmnEnum == rd || - rd == DEBUG_REG_DMN || rd == NO_ENUMRD) - return true; - } - } - return false; -} - -static u32 -ath9k_regd_get_wmodes_nreg(struct ath_hal *ah, - struct country_code_to_enum_rd *country, - struct regDomain *rd5GHz) -{ - u32 modesAvail; - - modesAvail = ah->ah_caps.halWirelessModes; - - if ((modesAvail & ATH9K_MODE_SEL_11G) && (!country->allow11g)) - modesAvail &= ~ATH9K_MODE_SEL_11G; - if ((modesAvail & ATH9K_MODE_SEL_11A) && - (ath9k_regd_is_chan_bm_zero(rd5GHz->chan11a))) - modesAvail &= ~ATH9K_MODE_SEL_11A; - - if ((modesAvail & ATH9K_MODE_SEL_11NG_HT20) - && (!country->allow11ng20)) - modesAvail &= ~ATH9K_MODE_SEL_11NG_HT20; - - if ((modesAvail & ATH9K_MODE_SEL_11NA_HT20) - && (!country->allow11na20)) - modesAvail &= ~ATH9K_MODE_SEL_11NA_HT20; - - if ((modesAvail & ATH9K_MODE_SEL_11NG_HT40PLUS) && - (!country->allow11ng40)) - modesAvail &= ~ATH9K_MODE_SEL_11NG_HT40PLUS; - - if ((modesAvail & ATH9K_MODE_SEL_11NG_HT40MINUS) && - (!country->allow11ng40)) - modesAvail &= ~ATH9K_MODE_SEL_11NG_HT40MINUS; - - if ((modesAvail & ATH9K_MODE_SEL_11NA_HT40PLUS) && - (!country->allow11na40)) - modesAvail &= ~ATH9K_MODE_SEL_11NA_HT40PLUS; - - if ((modesAvail & ATH9K_MODE_SEL_11NA_HT40MINUS) && - (!country->allow11na40)) - modesAvail &= ~ATH9K_MODE_SEL_11NA_HT40MINUS; - - return modesAvail; -} - -bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah) -{ - u16 rd; - - rd = ath9k_regd_get_eepromRD(ah); - - switch (rd) { - case FCC4_FCCA: - case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG): - return true; - case DEBUG_REG_DMN: - case NO_ENUMRD: - if (ah->ah_countryCode == CTRY_UNITED_STATES_FCC49) - return true; - break; - } - return false; -} - -static struct country_code_to_enum_rd* -ath9k_regd_find_country(u16 countryCode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(allCountries); i++) { - if (allCountries[i].countryCode == countryCode) - return &allCountries[i]; - } - return NULL; -} - -static u16 ath9k_regd_get_default_country(struct ath_hal *ah) -{ - u16 rd; - int i; - - rd = ath9k_regd_get_eepromRD(ah); - if (rd & COUNTRY_ERD_FLAG) { - struct country_code_to_enum_rd *country = NULL; - u16 cc = rd & ~COUNTRY_ERD_FLAG; - - country = ath9k_regd_find_country(cc); - if (country != NULL) - return cc; - } - - for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) - if (regDomainPairs[i].regDmnEnum == rd) { - if (regDomainPairs[i].singleCC != 0) - return regDomainPairs[i].singleCC; - else - i = ARRAY_SIZE(regDomainPairs); - } - return CTRY_DEFAULT; -} - -static bool ath9k_regd_is_valid_reg_domain(int regDmn, - struct regDomain *rd) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(regDomains); i++) { - if (regDomains[i].regDmnEnum == regDmn) { - if (rd != NULL) { - memcpy(rd, ®Domains[i], - sizeof(struct regDomain)); - } - return true; - } - } - return false; -} - -static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair) -{ - int i; - - if (regDmnPair == NO_ENUMRD) - return false; - for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regDmnPair) - return true; - } - return false; -} - -static bool -ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn, - u16 channelFlag, struct regDomain *rd) -{ - int i, found; - u64 flags = NO_REQ; - struct reg_dmn_pair_mapping *regPair = NULL; - int regOrg; - - regOrg = regDmn; - if (regDmn == CTRY_DEFAULT) { - u16 rdnum; - rdnum = ath9k_regd_get_eepromRD(ah); - - if (!(rdnum & COUNTRY_ERD_FLAG)) { - if (ath9k_regd_is_valid_reg_domain(rdnum, NULL) || - ath9k_regd_is_valid_reg_domainPair(rdnum)) { - regDmn = rdnum; - } - } - } - - if ((regDmn & MULTI_DOMAIN_MASK) == 0) { - for (i = 0, found = 0; - (i < ARRAY_SIZE(regDomainPairs)) && (!found); i++) { - if (regDomainPairs[i].regDmnEnum == regDmn) { - regPair = ®DomainPairs[i]; - found = 1; - } - } - if (!found) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Failed to find reg domain pair %u\n", - __func__, regDmn); - return false; - } - if (!(channelFlag & CHANNEL_2GHZ)) { - regDmn = regPair->regDmn5GHz; - flags = regPair->flags5GHz; - } - if (channelFlag & CHANNEL_2GHZ) { - regDmn = regPair->regDmn2GHz; - flags = regPair->flags2GHz; - } - } - - found = ath9k_regd_is_valid_reg_domain(regDmn, rd); - if (!found) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Failed to find unitary reg domain %u\n", - __func__, regDmn); - return false; - } else { - rd->pscan &= regPair->pscanMask; - if (((regOrg & MULTI_DOMAIN_MASK) == 0) && - (flags != NO_REQ)) { - rd->flags = flags; - } - - rd->flags &= (channelFlag & CHANNEL_2GHZ) ? - REG_DOMAIN_2GHZ_MASK : REG_DOMAIN_5GHZ_MASK; - return true; - } -} - -static bool ath9k_regd_is_bit_set(int bit, u64 *bitmask) -{ - int byteOffset, bitnum; - u64 val; - - byteOffset = bit / 64; - bitnum = bit - byteOffset * 64; - val = ((u64) 1) << bitnum; - if (bitmask[byteOffset] & val) - return true; - else - return false; -} - -static void -ath9k_regd_add_reg_classid(u8 *regclassids, u32 maxregids, - u32 *nregids, u8 regclassid) -{ - int i; - - if (regclassid == 0) - return; - - for (i = 0; i < maxregids; i++) { - if (regclassids[i] == regclassid) - return; - if (regclassids[i] == 0) - break; - } - - if (i == maxregids) - return; - else { - regclassids[i] = regclassid; - *nregids += 1; - } - - return; -} - -static bool -ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal *ah, - enum reg_ext_bitmap bit) -{ - return (ah->ah_currentRDExt & (1 << bit)) ? true : false; -} - -#ifdef ATH_NF_PER_CHAN - -static void ath9k_regd_init_rf_buffer(struct ath9k_channel *ichans, - int nchans) -{ - int i, j, next; - - for (next = 0; next < nchans; next++) { - for (i = 0; i < NUM_NF_READINGS; i++) { - ichans[next].nfCalHist[i].currIndex = 0; - ichans[next].nfCalHist[i].privNF = - AR_PHY_CCA_MAX_GOOD_VALUE; - ichans[next].nfCalHist[i].invalidNFcount = - AR_PHY_CCA_FILTERWINDOW_LENGTH; - for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - ichans[next].nfCalHist[i].nfCalBuffer[j] = - AR_PHY_CCA_MAX_GOOD_VALUE; - } - } - } -} -#endif - -static int ath9k_regd_is_chan_present(struct ath_hal *ah, - u16 c) -{ - int i; - - for (i = 0; i < 150; i++) { - if (!ah->ah_channels[i].channel) - return -1; - else if (ah->ah_channels[i].channel == c) - return i; - } - - return -1; -} - -static bool -ath9k_regd_add_channel(struct ath_hal *ah, - u16 c, - u16 c_lo, - u16 c_hi, - u16 maxChan, - u8 ctl, - int pos, - struct regDomain rd5GHz, - struct RegDmnFreqBand *fband, - struct regDomain *rd, - const struct cmode *cm, - struct ath9k_channel *ichans, - bool enableExtendedChannels) -{ - struct ath9k_channel *chan; - int ret; - u32 channelFlags = 0; - u8 privFlags = 0; - - if (!(c_lo <= c && c <= c_hi)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: c %u out of range [%u..%u]\n", - __func__, c, c_lo, c_hi); - return false; - } - if ((fband->channelBW == CHANNEL_HALF_BW) && - !ah->ah_caps.halChanHalfRate) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %u half rate channel\n", - __func__, c); - return false; - } - - if ((fband->channelBW == CHANNEL_QUARTER_BW) && - !ah->ah_caps.halChanQuarterRate) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %u quarter rate channel\n", - __func__, c); - return false; - } - - if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: c %u > maxChan %u\n", - __func__, c, maxChan); - return false; - } - - if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping ecm channel\n"); - return false; - } - - if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping HOSTAP channel\n"); - return false; - } - - if (IS_HT40_MODE(cm->mode) && - !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_FCC_DFS_HT40)) && - (fband->useDfs) && - (rd->conformanceTestLimit != MKK)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n"); - return false; - } - - if (IS_HT40_MODE(cm->mode) && - !(ath9k_regd_get_eeprom_reg_ext_bits(ah, - REG_EXT_JAPAN_NONDFS_HT40)) && - !(fband->useDfs) && (rd->conformanceTestLimit == MKK)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping HT40 channel (en_jap_ht40 = 0)\n"); - return false; - } - - if (IS_HT40_MODE(cm->mode) && - !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_JAPAN_DFS_HT40)) && - (fband->useDfs) && - (rd->conformanceTestLimit == MKK)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n"); - return false; - } - - /* Calculate channel flags */ - - channelFlags = cm->flags; - - switch (fband->channelBW) { - case CHANNEL_HALF_BW: - channelFlags |= CHANNEL_HALF; - break; - case CHANNEL_QUARTER_BW: - channelFlags |= CHANNEL_QUARTER; - break; - } - - if (fband->usePassScan & rd->pscan) - channelFlags |= CHANNEL_PASSIVE; - else - channelFlags &= ~CHANNEL_PASSIVE; - if (fband->useDfs & rd->dfsMask) - privFlags = CHANNEL_DFS; - else - privFlags = 0; - if (rd->flags & LIMIT_FRAME_4MS) - privFlags |= CHANNEL_4MS_LIMIT; - if (privFlags & CHANNEL_DFS) - privFlags |= CHANNEL_DISALLOW_ADHOC; - if (rd->flags & ADHOC_PER_11D) - privFlags |= CHANNEL_PER_11D_ADHOC; - - if (channelFlags & CHANNEL_PASSIVE) { - if ((c < 2412) || (c > 2462)) { - if (rd5GHz.regDmnEnum == MKK1 || - rd5GHz.regDmnEnum == MKK2) { - u32 regcap = ah->ah_caps.halRegCap; - if (!(regcap & - (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) && - isUNII1OddChan(c)) { - channelFlags &= ~CHANNEL_PASSIVE; - } else { - privFlags |= CHANNEL_DISALLOW_ADHOC; - } - } else { - privFlags |= CHANNEL_DISALLOW_ADHOC; - } - } - } - - if (cm->mode & (ATH9K_MODE_SEL_11A | - ATH9K_MODE_SEL_11NA_HT20 | - ATH9K_MODE_SEL_11NA_HT40PLUS | - ATH9K_MODE_SEL_11NA_HT40MINUS)) { - if (rd->flags & (ADHOC_NO_11A | DISALLOW_ADHOC_11A)) - privFlags |= CHANNEL_DISALLOW_ADHOC; - } - - /* Fill in channel details */ - - ret = ath9k_regd_is_chan_present(ah, c); - if (ret == -1) { - chan = &ah->ah_channels[pos]; - chan->channel = c; - chan->maxRegTxPower = fband->powerDfs; - chan->antennaMax = fband->antennaMax; - chan->regDmnFlags = rd->flags; - chan->maxTxPower = AR5416_MAX_RATE_POWER; - chan->minTxPower = AR5416_MAX_RATE_POWER; - chan->channelFlags = channelFlags; - chan->privFlags = privFlags; - } else { - chan = &ah->ah_channels[ret]; - chan->channelFlags |= channelFlags; - chan->privFlags |= privFlags; - } - - /* Set CTLs */ - - if ((cm->flags & CHANNEL_ALL) == CHANNEL_A) - chan->conformanceTestLimit[0] = ctl; - else if ((cm->flags & CHANNEL_ALL) == CHANNEL_B) - chan->conformanceTestLimit[1] = ctl; - else if ((cm->flags & CHANNEL_ALL) == CHANNEL_G) - chan->conformanceTestLimit[2] = ctl; - - return (ret == -1) ? true : false; -} - -static bool ath9k_regd_japan_check(struct ath_hal *ah, - int b, - struct regDomain *rd5GHz) -{ - bool skipband = false; - int i; - u32 regcap; - - for (i = 0; i < ARRAY_SIZE(j_bandcheck); i++) { - if (j_bandcheck[i].freqbandbit == b) { - regcap = ah->ah_caps.halRegCap; - if ((j_bandcheck[i].eepromflagtocheck & regcap) == 0) { - skipband = true; - } else if ((regcap & AR_EEPROM_EEREGCAP_EN_KK_U2) || - (regcap & AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) { - rd5GHz->dfsMask |= DFS_MKK4; - rd5GHz->pscan |= PSCAN_MKK3; - } - break; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %d freq band\n", - __func__, j_bandcheck[i].freqbandbit); - - return skipband; -} - -bool -ath9k_regd_init_channels(struct ath_hal *ah, - u32 maxchans, - u32 *nchans, u8 *regclassids, - u32 maxregids, u32 *nregids, u16 cc, - u32 modeSelect, bool enableOutdoor, - bool enableExtendedChannels) -{ - u32 modesAvail; - u16 maxChan = 7000; - struct country_code_to_enum_rd *country = NULL; - struct regDomain rd5GHz, rd2GHz; - const struct cmode *cm; - struct ath9k_channel *ichans = &ah->ah_channels[0]; - int next = 0, b; - u8 ctl; - int regdmn; - u16 chanSep; - - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u mode 0x%x%s%s\n", - __func__, cc, modeSelect, - enableOutdoor ? " Enable outdoor" : " ", - enableExtendedChannels ? " Enable ecm" : ""); - - if (!ath9k_regd_is_ccode_valid(ah, cc)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid country code %d\n", __func__, cc); - return false; - } - - if (!ath9k_regd_is_eeprom_valid(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid EEPROM contents\n", __func__); - return false; - } - - ah->ah_countryCode = ath9k_regd_get_default_country(ah); - - if (ah->ah_countryCode == CTRY_DEFAULT) { - ah->ah_countryCode = cc & COUNTRY_CODE_MASK; - if ((ah->ah_countryCode == CTRY_DEFAULT) && - (ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)) { - ah->ah_countryCode = CTRY_UNITED_STATES; - } - } - -#ifdef AH_SUPPORT_11D - if (ah->ah_countryCode == CTRY_DEFAULT) { - regdmn = ath9k_regd_get_eepromRD(ah); - country = NULL; - } else { -#endif - country = ath9k_regd_find_country(ah->ah_countryCode); - if (country == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Country is NULL!!!!, cc= %d\n", - ah->ah_countryCode); - return false; - } else { - regdmn = country->regDmnEnum; -#ifdef AH_SUPPORT_11D - if (((ath9k_regd_get_eepromRD(ah) & - WORLD_SKU_MASK) == WORLD_SKU_PREFIX) && - (cc == CTRY_UNITED_STATES)) { - if (!isWwrSKU_NoMidband(ah) - && ath9k_regd_is_fcc_midband_supported(ah)) - regdmn = FCC3_FCCA; - else - regdmn = FCC1_FCCA; - } -#endif - } -#ifdef AH_SUPPORT_11D - } -#endif - if (!ath9k_regd_get_wmode_regdomain(ah, - regdmn, - ~CHANNEL_2GHZ, - &rd5GHz)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary " - "5GHz reg domain for country %u\n", - __func__, ah->ah_countryCode); - return false; - } - if (!ath9k_regd_get_wmode_regdomain(ah, - regdmn, - CHANNEL_2GHZ, - &rd2GHz)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary 2GHz " - "reg domain for country %u\n", - __func__, ah->ah_countryCode); - return false; - } - - if (!isWwrSKU(ah) && ((rd5GHz.regDmnEnum == FCC1) || - (rd5GHz.regDmnEnum == FCC2))) { - if (ath9k_regd_is_fcc_midband_supported(ah)) { - if (!ath9k_regd_get_wmode_regdomain(ah, - FCC3_FCCA, - ~CHANNEL_2GHZ, - &rd5GHz)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary 5GHz " - "reg domain for country %u\n", - __func__, ah->ah_countryCode); - return false; - } - } - } - - if (country == NULL) { - modesAvail = ah->ah_caps.halWirelessModes; - } else { - modesAvail = ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz); - if (!enableOutdoor) - maxChan = country->outdoorChanStart; - } - - next = 0; - - if (maxchans > ARRAY_SIZE(ah->ah_channels)) - maxchans = ARRAY_SIZE(ah->ah_channels); - - for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) { - u16 c, c_hi, c_lo; - u64 *channelBM = NULL; - struct regDomain *rd = NULL; - struct RegDmnFreqBand *fband = NULL, *freqs; - int8_t low_adj = 0, hi_adj = 0; - - if ((cm->mode & modeSelect) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: skip mode 0x%x flags 0x%x\n", - __func__, cm->mode, cm->flags); - continue; - } - if ((cm->mode & modesAvail) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: !avail mode 0x%x (0x%x) flags 0x%x\n", - __func__, modesAvail, cm->mode, - cm->flags); - continue; - } - if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channels 0x%x not supported " - "by hardware\n", - __func__, cm->flags); - continue; - } - - switch (cm->mode) { - case ATH9K_MODE_SEL_11A: - case ATH9K_MODE_SEL_11NA_HT20: - case ATH9K_MODE_SEL_11NA_HT40PLUS: - case ATH9K_MODE_SEL_11NA_HT40MINUS: - rd = &rd5GHz; - channelBM = rd->chan11a; - freqs = ®Dmn5GhzFreq[0]; - ctl = rd->conformanceTestLimit; - break; - case ATH9K_MODE_SEL_11B: - rd = &rd2GHz; - channelBM = rd->chan11b; - freqs = ®Dmn2GhzFreq[0]; - ctl = rd->conformanceTestLimit | CTL_11B; - break; - case ATH9K_MODE_SEL_11G: - case ATH9K_MODE_SEL_11NG_HT20: - case ATH9K_MODE_SEL_11NG_HT40PLUS: - case ATH9K_MODE_SEL_11NG_HT40MINUS: - rd = &rd2GHz; - channelBM = rd->chan11g; - freqs = ®Dmn2Ghz11gFreq[0]; - ctl = rd->conformanceTestLimit | CTL_11G; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Unknown HAL mode 0x%x\n", __func__, - cm->mode); - continue; - } - - if (ath9k_regd_is_chan_bm_zero(channelBM)) - continue; - - if ((cm->mode == ATH9K_MODE_SEL_11NA_HT40PLUS) || - (cm->mode == ATH9K_MODE_SEL_11NG_HT40PLUS)) { - hi_adj = -20; - } - - if ((cm->mode == ATH9K_MODE_SEL_11NA_HT40MINUS) || - (cm->mode == ATH9K_MODE_SEL_11NG_HT40MINUS)) { - low_adj = 20; - } - - /* XXX: Add a helper here instead */ - for (b = 0; b < 64 * BMLEN; b++) { - if (ath9k_regd_is_bit_set(b, channelBM)) { - fband = &freqs[b]; - if (rd5GHz.regDmnEnum == MKK1 - || rd5GHz.regDmnEnum == MKK2) { - if (ath9k_regd_japan_check(ah, - b, - &rd5GHz)) - continue; - } - - ath9k_regd_add_reg_classid(regclassids, - maxregids, - nregids, - fband-> - regClassId); - - if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) { - chanSep = 40; - if (fband->lowChannel == 5280) - low_adj += 20; - - if (fband->lowChannel == 5170) - continue; - } else - chanSep = fband->channelSep; - - for (c = fband->lowChannel + low_adj; - ((c <= (fband->highChannel + hi_adj)) && - (c >= (fband->lowChannel + low_adj))); - c += chanSep) { - if (next >= maxchans) { - DPRINTF(ah->ah_sc, - ATH_DBG_REGULATORY, - "%s: too many channels " - "for channel table\n", - __func__); - goto done; - } - if (ath9k_regd_add_channel(ah, - c, c_lo, c_hi, - maxChan, ctl, - next, - rd5GHz, - fband, rd, cm, - ichans, - enableExtendedChannels)) - next++; - } - if (IS_HT40_MODE(cm->mode) && - (fband->lowChannel == 5280)) { - low_adj -= 20; - } - } - } - } -done: - if (next != 0) { - int i; - - if (next > ARRAY_SIZE(ah->ah_channels)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: too many channels %u; truncating to %u\n", - __func__, next, - (int) ARRAY_SIZE(ah->ah_channels)); - next = ARRAY_SIZE(ah->ah_channels); - } -#ifdef ATH_NF_PER_CHAN - ath9k_regd_init_rf_buffer(ichans, next); -#endif - ath9k_regd_sort(ichans, next, - sizeof(struct ath9k_channel), - ath9k_regd_chansort); - - ah->ah_nchan = next; - - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Channel list:\n"); - for (i = 0; i < next; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "chan: %d flags: 0x%x\n", - ah->ah_channels[i].channel, - ah->ah_channels[i].channelFlags); - } - } - *nchans = next; - - ah->ah_countryCode = ah->ah_countryCode; - - ah->ah_currentRDInUse = regdmn; - ah->ah_currentRD5G = rd5GHz.regDmnEnum; - ah->ah_currentRD2G = rd2GHz.regDmnEnum; - if (country == NULL) { - ah->ah_iso[0] = 0; - ah->ah_iso[1] = 0; - } else { - ah->ah_iso[0] = country->isoName[0]; - ah->ah_iso[1] = country->isoName[1]; - } - - return next != 0; -} - -struct ath9k_channel* -ath9k_regd_check_channel(struct ath_hal *ah, - const struct ath9k_channel *c) -{ - struct ath9k_channel *base, *cc; - - int flags = c->channelFlags & CHAN_FLAGS; - int n, lim; - - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channel %u/0x%x (0x%x) requested\n", __func__, - c->channel, c->channelFlags, flags); - - cc = ah->ah_curchan; - if (cc != NULL && cc->channel == c->channel && - (cc->channelFlags & CHAN_FLAGS) == flags) { - if ((cc->privFlags & CHANNEL_INTERFERENCE) && - (cc->privFlags & CHANNEL_DFS)) - return NULL; - else - return cc; - } - - base = ah->ah_channels; - n = ah->ah_nchan; - - for (lim = n; lim != 0; lim >>= 1) { - int d; - cc = &base[lim >> 1]; - d = c->channel - cc->channel; - if (d == 0) { - if ((cc->channelFlags & CHAN_FLAGS) == flags) { - if ((cc->privFlags & CHANNEL_INTERFERENCE) && - (cc->privFlags & CHANNEL_DFS)) - return NULL; - else - return cc; - } - d = flags - (cc->channelFlags & CHAN_FLAGS); - } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channel %u/0x%x d %d\n", __func__, - cc->channel, cc->channelFlags, d); - if (d > 0) { - base = cc + 1; - lim--; - } - } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n", - __func__, c->channel, c->channelFlags); - return NULL; -} - -u32 -ath9k_regd_get_antenna_allowed(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - struct ath9k_channel *ichan = NULL; - - ichan = ath9k_regd_check_channel(ah, chan); - if (!ichan) - return 0; - - return ichan->antennaMax; -} - -u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan) -{ - u32 ctl = NO_CTL; - struct ath9k_channel *ichan; - - if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) { - if (IS_CHAN_B(chan)) - ctl = SD_NO_CTL | CTL_11B; - else if (IS_CHAN_G(chan)) - ctl = SD_NO_CTL | CTL_11G; - else - ctl = SD_NO_CTL | CTL_11A; - } else { - ichan = ath9k_regd_check_channel(ah, chan); - if (ichan != NULL) { - /* FIXME */ - if (IS_CHAN_A(ichan)) - ctl = ichan->conformanceTestLimit[0]; - else if (IS_CHAN_B(ichan)) - ctl = ichan->conformanceTestLimit[1]; - else if (IS_CHAN_G(ichan)) - ctl = ichan->conformanceTestLimit[2]; - - if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B) - ctl = (ctl & ~0xf) | CTL_11G; - } - } - return ctl; -} - -void ath9k_regd_get_current_country(struct ath_hal *ah, - struct ath9k_country_entry *ctry) -{ - u16 rd = ath9k_regd_get_eepromRD(ah); - - ctry->isMultidomain = false; - if (rd == CTRY_DEFAULT) - ctry->isMultidomain = true; - else if (!(rd & COUNTRY_ERD_FLAG)) - ctry->isMultidomain = isWwrSKU(ah); - - ctry->countryCode = ah->ah_countryCode; - ctry->regDmnEnum = ah->ah_currentRD; - ctry->regDmn5G = ah->ah_currentRD5G; - ctry->regDmn2G = ah->ah_currentRD2G; - ctry->iso[0] = ah->ah_iso[0]; - ctry->iso[1] = ah->ah_iso[1]; - ctry->iso[2] = ah->ah_iso[2]; -} |