2 * Copyright (c) 2008 Atheros Communications Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
22 #include "regd_common.h"
24 static int ath9k_regd_chansort(const void *a, const void *b)
26 const struct ath9k_channel *ca = a;
27 const struct ath9k_channel *cb = b;
29 return (ca->channel == cb->channel) ?
30 (ca->channelFlags & CHAN_FLAGS) -
31 (cb->channelFlags & CHAN_FLAGS) : ca->channel - cb->channel;
35 ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp)
40 for (ai = aa + size; --n >= 1; ai += size)
41 for (t = ai; t > aa; t -= size) {
45 swap_array(u, t, size);
49 static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah)
51 return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG;
54 static bool ath9k_regd_is_chan_bm_zero(u64 *bitmask)
58 for (i = 0; i < BMLEN; i++) {
65 static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah)
67 u16 rd = ath9k_regd_get_eepromRD(ah);
70 if (rd & COUNTRY_ERD_FLAG) {
71 u16 cc = rd & ~COUNTRY_ERD_FLAG;
72 for (i = 0; i < ARRAY_SIZE(allCountries); i++)
73 if (allCountries[i].countryCode == cc)
76 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
77 if (regDomainPairs[i].regDmnEnum == rd)
80 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
81 "invalid regulatory domain/country code 0x%x\n", rd);
85 static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal *ah)
89 regcap = ah->ah_caps.reg_cap;
91 if (regcap & AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND)
97 static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah,
103 if (cc == CTRY_DEFAULT)
105 if (cc == CTRY_DEBUG)
108 rd = ath9k_regd_get_eepromRD(ah);
109 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "EEPROM regdomain 0x%x\n", rd);
111 if (rd & COUNTRY_ERD_FLAG) {
112 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
113 "EEPROM setting is country code %u\n",
114 rd & ~COUNTRY_ERD_FLAG);
115 return cc == (rd & ~COUNTRY_ERD_FLAG);
118 for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
119 if (cc == allCountries[i].countryCode) {
120 #ifdef AH_SUPPORT_11D
121 if ((rd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)
124 if (allCountries[i].regDmnEnum == rd ||
125 rd == DEBUG_REG_DMN || rd == NO_ENUMRD)
133 ath9k_regd_get_wmodes_nreg(struct ath_hal *ah,
134 struct country_code_to_enum_rd *country,
135 struct regDomain *rd5GHz,
136 unsigned long *modes_allowed)
138 bitmap_copy(modes_allowed, ah->ah_caps.wireless_modes, ATH9K_MODE_MAX);
140 if (test_bit(ATH9K_MODE_11G, ah->ah_caps.wireless_modes) &&
141 (!country->allow11g))
142 clear_bit(ATH9K_MODE_11G, modes_allowed);
144 if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes) &&
145 (ath9k_regd_is_chan_bm_zero(rd5GHz->chan11a)))
146 clear_bit(ATH9K_MODE_11A, modes_allowed);
148 if (test_bit(ATH9K_MODE_11NG_HT20, ah->ah_caps.wireless_modes)
149 && (!country->allow11ng20))
150 clear_bit(ATH9K_MODE_11NG_HT20, modes_allowed);
152 if (test_bit(ATH9K_MODE_11NA_HT20, ah->ah_caps.wireless_modes)
153 && (!country->allow11na20))
154 clear_bit(ATH9K_MODE_11NA_HT20, modes_allowed);
156 if (test_bit(ATH9K_MODE_11NG_HT40PLUS, ah->ah_caps.wireless_modes) &&
157 (!country->allow11ng40))
158 clear_bit(ATH9K_MODE_11NG_HT40PLUS, modes_allowed);
160 if (test_bit(ATH9K_MODE_11NG_HT40MINUS, ah->ah_caps.wireless_modes) &&
161 (!country->allow11ng40))
162 clear_bit(ATH9K_MODE_11NG_HT40MINUS, modes_allowed);
164 if (test_bit(ATH9K_MODE_11NA_HT40PLUS, ah->ah_caps.wireless_modes) &&
165 (!country->allow11na40))
166 clear_bit(ATH9K_MODE_11NA_HT40PLUS, modes_allowed);
168 if (test_bit(ATH9K_MODE_11NA_HT40MINUS, ah->ah_caps.wireless_modes) &&
169 (!country->allow11na40))
170 clear_bit(ATH9K_MODE_11NA_HT40MINUS, modes_allowed);
173 bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah)
177 rd = ath9k_regd_get_eepromRD(ah);
181 case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG):
185 if (ah->ah_countryCode == CTRY_UNITED_STATES_FCC49)
192 static struct country_code_to_enum_rd*
193 ath9k_regd_find_country(u16 countryCode)
197 for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
198 if (allCountries[i].countryCode == countryCode)
199 return &allCountries[i];
204 static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
209 rd = ath9k_regd_get_eepromRD(ah);
210 if (rd & COUNTRY_ERD_FLAG) {
211 struct country_code_to_enum_rd *country = NULL;
212 u16 cc = rd & ~COUNTRY_ERD_FLAG;
214 country = ath9k_regd_find_country(cc);
219 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
220 if (regDomainPairs[i].regDmnEnum == rd) {
221 if (regDomainPairs[i].singleCC != 0)
222 return regDomainPairs[i].singleCC;
224 i = ARRAY_SIZE(regDomainPairs);
229 static bool ath9k_regd_is_valid_reg_domain(int regDmn,
230 struct regDomain *rd)
234 for (i = 0; i < ARRAY_SIZE(regDomains); i++) {
235 if (regDomains[i].regDmnEnum == regDmn) {
237 memcpy(rd, ®Domains[i],
238 sizeof(struct regDomain));
246 static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair)
250 if (regDmnPair == NO_ENUMRD)
252 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
253 if (regDomainPairs[i].regDmnEnum == regDmnPair)
260 ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn,
261 u16 channelFlag, struct regDomain *rd)
265 struct reg_dmn_pair_mapping *regPair = NULL;
269 if (regDmn == CTRY_DEFAULT) {
271 rdnum = ath9k_regd_get_eepromRD(ah);
273 if (!(rdnum & COUNTRY_ERD_FLAG)) {
274 if (ath9k_regd_is_valid_reg_domain(rdnum, NULL) ||
275 ath9k_regd_is_valid_reg_domainPair(rdnum)) {
281 if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
282 for (i = 0, found = 0;
283 (i < ARRAY_SIZE(regDomainPairs)) && (!found); i++) {
284 if (regDomainPairs[i].regDmnEnum == regDmn) {
285 regPair = ®DomainPairs[i];
290 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
291 "Failed to find reg domain pair %u\n", regDmn);
294 if (!(channelFlag & CHANNEL_2GHZ)) {
295 regDmn = regPair->regDmn5GHz;
296 flags = regPair->flags5GHz;
298 if (channelFlag & CHANNEL_2GHZ) {
299 regDmn = regPair->regDmn2GHz;
300 flags = regPair->flags2GHz;
304 found = ath9k_regd_is_valid_reg_domain(regDmn, rd);
306 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
307 "Failed to find unitary reg domain %u\n", regDmn);
310 rd->pscan &= regPair->pscanMask;
311 if (((regOrg & MULTI_DOMAIN_MASK) == 0) &&
316 rd->flags &= (channelFlag & CHANNEL_2GHZ) ?
317 REG_DOMAIN_2GHZ_MASK : REG_DOMAIN_5GHZ_MASK;
322 static bool ath9k_regd_is_bit_set(int bit, u64 *bitmask)
324 int byteOffset, bitnum;
327 byteOffset = bit / 64;
328 bitnum = bit - byteOffset * 64;
329 val = ((u64) 1) << bitnum;
330 if (bitmask[byteOffset] & val)
337 ath9k_regd_add_reg_classid(u8 *regclassids, u32 maxregids,
338 u32 *nregids, u8 regclassid)
345 for (i = 0; i < maxregids; i++) {
346 if (regclassids[i] == regclassid)
348 if (regclassids[i] == 0)
355 regclassids[i] = regclassid;
363 ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal *ah,
364 enum reg_ext_bitmap bit)
366 return (ah->ah_currentRDExt & (1 << bit)) ? true : false;
369 #ifdef ATH_NF_PER_CHAN
371 static void ath9k_regd_init_rf_buffer(struct ath9k_channel *ichans,
376 for (next = 0; next < nchans; next++) {
377 for (i = 0; i < NUM_NF_READINGS; i++) {
378 ichans[next].nfCalHist[i].currIndex = 0;
379 ichans[next].nfCalHist[i].privNF =
380 AR_PHY_CCA_MAX_GOOD_VALUE;
381 ichans[next].nfCalHist[i].invalidNFcount =
382 AR_PHY_CCA_FILTERWINDOW_LENGTH;
383 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
384 ichans[next].nfCalHist[i].nfCalBuffer[j] =
385 AR_PHY_CCA_MAX_GOOD_VALUE;
392 static int ath9k_regd_is_chan_present(struct ath_hal *ah,
397 for (i = 0; i < 150; i++) {
398 if (!ah->ah_channels[i].channel)
400 else if (ah->ah_channels[i].channel == c)
408 ath9k_regd_add_channel(struct ath_hal *ah,
415 struct regDomain rd5GHz,
416 struct RegDmnFreqBand *fband,
417 struct regDomain *rd,
418 const struct cmode *cm,
419 struct ath9k_channel *ichans,
420 bool enableExtendedChannels)
422 struct ath9k_channel *chan;
424 u32 channelFlags = 0;
427 if (!(c_lo <= c && c <= c_hi)) {
428 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
429 "c %u out of range [%u..%u]\n",
433 if ((fband->channelBW == CHANNEL_HALF_BW) &&
434 !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) {
435 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
436 "Skipping %u half rate channel\n", c);
440 if ((fband->channelBW == CHANNEL_QUARTER_BW) &&
441 !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) {
442 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
443 "Skipping %u quarter rate channel\n", c);
447 if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) {
448 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
449 "c %u > maxChan %u\n", c, maxChan);
453 if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) {
454 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
455 "Skipping ecm channel\n");
459 if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == NL80211_IFTYPE_AP)) {
460 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
461 "Skipping HOSTAP channel\n");
465 if (IS_HT40_MODE(cm->mode) &&
466 !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_FCC_DFS_HT40)) &&
468 (rd->conformanceTestLimit != MKK)) {
469 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
470 "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n");
474 if (IS_HT40_MODE(cm->mode) &&
475 !(ath9k_regd_get_eeprom_reg_ext_bits(ah,
476 REG_EXT_JAPAN_NONDFS_HT40)) &&
477 !(fband->useDfs) && (rd->conformanceTestLimit == MKK)) {
478 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
479 "Skipping HT40 channel (en_jap_ht40 = 0)\n");
483 if (IS_HT40_MODE(cm->mode) &&
484 !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_JAPAN_DFS_HT40)) &&
486 (rd->conformanceTestLimit == MKK)) {
487 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
488 "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n");
492 /* Calculate channel flags */
494 channelFlags = cm->flags;
496 switch (fband->channelBW) {
497 case CHANNEL_HALF_BW:
498 channelFlags |= CHANNEL_HALF;
500 case CHANNEL_QUARTER_BW:
501 channelFlags |= CHANNEL_QUARTER;
505 if (fband->usePassScan & rd->pscan)
506 channelFlags |= CHANNEL_PASSIVE;
508 channelFlags &= ~CHANNEL_PASSIVE;
509 if (fband->useDfs & rd->dfsMask)
510 privFlags = CHANNEL_DFS;
513 if (rd->flags & LIMIT_FRAME_4MS)
514 privFlags |= CHANNEL_4MS_LIMIT;
515 if (privFlags & CHANNEL_DFS)
516 privFlags |= CHANNEL_DISALLOW_ADHOC;
517 if (rd->flags & ADHOC_PER_11D)
518 privFlags |= CHANNEL_PER_11D_ADHOC;
520 if (channelFlags & CHANNEL_PASSIVE) {
521 if ((c < 2412) || (c > 2462)) {
522 if (rd5GHz.regDmnEnum == MKK1 ||
523 rd5GHz.regDmnEnum == MKK2) {
524 u32 regcap = ah->ah_caps.reg_cap;
526 (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
527 AR_EEPROM_EEREGCAP_EN_KK_U2 |
528 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) &&
530 channelFlags &= ~CHANNEL_PASSIVE;
532 privFlags |= CHANNEL_DISALLOW_ADHOC;
535 privFlags |= CHANNEL_DISALLOW_ADHOC;
540 if ((cm->mode == ATH9K_MODE_11A) ||
541 (cm->mode == ATH9K_MODE_11NA_HT20) ||
542 (cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
543 (cm->mode == ATH9K_MODE_11NA_HT40MINUS)) {
544 if (rd->flags & (ADHOC_NO_11A | DISALLOW_ADHOC_11A))
545 privFlags |= CHANNEL_DISALLOW_ADHOC;
548 /* Fill in channel details */
550 ret = ath9k_regd_is_chan_present(ah, c);
552 chan = &ah->ah_channels[pos];
554 chan->maxRegTxPower = fband->powerDfs;
555 chan->antennaMax = fband->antennaMax;
556 chan->regDmnFlags = rd->flags;
557 chan->maxTxPower = AR5416_MAX_RATE_POWER;
558 chan->minTxPower = AR5416_MAX_RATE_POWER;
559 chan->channelFlags = channelFlags;
560 chan->privFlags = privFlags;
562 chan = &ah->ah_channels[ret];
563 chan->channelFlags |= channelFlags;
564 chan->privFlags |= privFlags;
569 if ((cm->flags & CHANNEL_ALL) == CHANNEL_A)
570 chan->conformanceTestLimit[0] = ctl;
571 else if ((cm->flags & CHANNEL_ALL) == CHANNEL_B)
572 chan->conformanceTestLimit[1] = ctl;
573 else if ((cm->flags & CHANNEL_ALL) == CHANNEL_G)
574 chan->conformanceTestLimit[2] = ctl;
576 return (ret == -1) ? true : false;
579 static bool ath9k_regd_japan_check(struct ath_hal *ah,
581 struct regDomain *rd5GHz)
583 bool skipband = false;
587 for (i = 0; i < ARRAY_SIZE(j_bandcheck); i++) {
588 if (j_bandcheck[i].freqbandbit == b) {
589 regcap = ah->ah_caps.reg_cap;
590 if ((j_bandcheck[i].eepromflagtocheck & regcap) == 0) {
592 } else if ((regcap & AR_EEPROM_EEREGCAP_EN_KK_U2) ||
593 (regcap & AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) {
594 rd5GHz->dfsMask |= DFS_MKK4;
595 rd5GHz->pscan |= PSCAN_MKK3;
601 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
602 "Skipping %d freq band\n", j_bandcheck[i].freqbandbit);
608 ath9k_regd_init_channels(struct ath_hal *ah,
610 u32 *nchans, u8 *regclassids,
611 u32 maxregids, u32 *nregids, u16 cc,
613 bool enableExtendedChannels)
616 struct country_code_to_enum_rd *country = NULL;
617 struct regDomain rd5GHz, rd2GHz;
618 const struct cmode *cm;
619 struct ath9k_channel *ichans = &ah->ah_channels[0];
624 unsigned long *modes_avail;
625 DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX);
627 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "cc %u %s %s\n", cc,
628 enableOutdoor ? "Enable outdoor" : "",
629 enableExtendedChannels ? "Enable ecm" : "");
631 if (!ath9k_regd_is_ccode_valid(ah, cc)) {
632 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
633 "Invalid country code %d\n", cc);
637 if (!ath9k_regd_is_eeprom_valid(ah)) {
638 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
639 "Invalid EEPROM contents\n");
643 ah->ah_countryCode = ath9k_regd_get_default_country(ah);
645 if (ah->ah_countryCode == CTRY_DEFAULT) {
646 ah->ah_countryCode = cc & COUNTRY_CODE_MASK;
647 if ((ah->ah_countryCode == CTRY_DEFAULT) &&
648 (ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)) {
649 ah->ah_countryCode = CTRY_UNITED_STATES;
653 #ifdef AH_SUPPORT_11D
654 if (ah->ah_countryCode == CTRY_DEFAULT) {
655 regdmn = ath9k_regd_get_eepromRD(ah);
659 country = ath9k_regd_find_country(ah->ah_countryCode);
660 if (country == NULL) {
661 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
662 "Country is NULL!!!!, cc= %d\n",
666 regdmn = country->regDmnEnum;
667 #ifdef AH_SUPPORT_11D
668 if (((ath9k_regd_get_eepromRD(ah) &
669 WORLD_SKU_MASK) == WORLD_SKU_PREFIX) &&
670 (cc == CTRY_UNITED_STATES)) {
671 if (!isWwrSKU_NoMidband(ah)
672 && ath9k_regd_is_fcc_midband_supported(ah))
679 #ifdef AH_SUPPORT_11D
682 if (!ath9k_regd_get_wmode_regdomain(ah,
686 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
687 "Couldn't find unitary "
688 "5GHz reg domain for country %u\n",
692 if (!ath9k_regd_get_wmode_regdomain(ah,
696 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
697 "Couldn't find unitary 2GHz "
698 "reg domain for country %u\n",
703 if (!isWwrSKU(ah) && ((rd5GHz.regDmnEnum == FCC1) ||
704 (rd5GHz.regDmnEnum == FCC2))) {
705 if (ath9k_regd_is_fcc_midband_supported(ah)) {
706 if (!ath9k_regd_get_wmode_regdomain(ah,
710 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
711 "Couldn't find unitary 5GHz "
712 "reg domain for country %u\n",
719 if (country == NULL) {
720 modes_avail = ah->ah_caps.wireless_modes;
722 ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz, modes_allowed);
723 modes_avail = modes_allowed;
726 maxChan = country->outdoorChanStart;
731 if (maxchans > ARRAY_SIZE(ah->ah_channels))
732 maxchans = ARRAY_SIZE(ah->ah_channels);
734 for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) {
736 u64 *channelBM = NULL;
737 struct regDomain *rd = NULL;
738 struct RegDmnFreqBand *fband = NULL, *freqs;
739 int8_t low_adj = 0, hi_adj = 0;
741 if (!test_bit(cm->mode, modes_avail)) {
742 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
743 "!avail mode %d flags 0x%x\n",
744 cm->mode, cm->flags);
747 if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) {
748 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
749 "channels 0x%x not supported "
750 "by hardware\n", cm->flags);
756 case ATH9K_MODE_11NA_HT20:
757 case ATH9K_MODE_11NA_HT40PLUS:
758 case ATH9K_MODE_11NA_HT40MINUS:
760 channelBM = rd->chan11a;
761 freqs = ®Dmn5GhzFreq[0];
762 ctl = rd->conformanceTestLimit;
766 channelBM = rd->chan11b;
767 freqs = ®Dmn2GhzFreq[0];
768 ctl = rd->conformanceTestLimit | CTL_11B;
771 case ATH9K_MODE_11NG_HT20:
772 case ATH9K_MODE_11NG_HT40PLUS:
773 case ATH9K_MODE_11NG_HT40MINUS:
775 channelBM = rd->chan11g;
776 freqs = ®Dmn2Ghz11gFreq[0];
777 ctl = rd->conformanceTestLimit | CTL_11G;
780 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
781 "Unknown HAL mode 0x%x\n", cm->mode);
785 if (ath9k_regd_is_chan_bm_zero(channelBM))
788 if ((cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
789 (cm->mode == ATH9K_MODE_11NG_HT40PLUS)) {
793 if ((cm->mode == ATH9K_MODE_11NA_HT40MINUS) ||
794 (cm->mode == ATH9K_MODE_11NG_HT40MINUS)) {
798 /* XXX: Add a helper here instead */
799 for (b = 0; b < 64 * BMLEN; b++) {
800 if (ath9k_regd_is_bit_set(b, channelBM)) {
802 if (rd5GHz.regDmnEnum == MKK1
803 || rd5GHz.regDmnEnum == MKK2) {
804 if (ath9k_regd_japan_check(ah,
810 ath9k_regd_add_reg_classid(regclassids,
816 if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) {
818 if (fband->lowChannel == 5280)
821 if (fband->lowChannel == 5170)
824 chanSep = fband->channelSep;
826 for (c = fband->lowChannel + low_adj;
827 ((c <= (fband->highChannel + hi_adj)) &&
828 (c >= (fband->lowChannel + low_adj)));
830 if (next >= maxchans) {
834 "for channel table\n");
837 if (ath9k_regd_add_channel(ah,
844 enableExtendedChannels))
847 if (IS_HT40_MODE(cm->mode) &&
848 (fband->lowChannel == 5280)) {
858 if (next > ARRAY_SIZE(ah->ah_channels)) {
859 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
860 "too many channels %u; truncating to %u\n",
861 next, (int) ARRAY_SIZE(ah->ah_channels));
862 next = ARRAY_SIZE(ah->ah_channels);
864 #ifdef ATH_NF_PER_CHAN
865 ath9k_regd_init_rf_buffer(ichans, next);
867 ath9k_regd_sort(ichans, next,
868 sizeof(struct ath9k_channel),
869 ath9k_regd_chansort);
873 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Channel list:\n");
874 for (i = 0; i < next; i++) {
875 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
876 "chan: %d flags: 0x%x\n",
877 ah->ah_channels[i].channel,
878 ah->ah_channels[i].channelFlags);
883 ah->ah_countryCode = ah->ah_countryCode;
885 ah->ah_currentRDInUse = regdmn;
886 ah->ah_currentRD5G = rd5GHz.regDmnEnum;
887 ah->ah_currentRD2G = rd2GHz.regDmnEnum;
888 if (country == NULL) {
892 ah->ah_iso[0] = country->isoName[0];
893 ah->ah_iso[1] = country->isoName[1];
899 struct ath9k_channel*
900 ath9k_regd_check_channel(struct ath_hal *ah,
901 const struct ath9k_channel *c)
903 struct ath9k_channel *base, *cc;
905 int flags = c->channelFlags & CHAN_FLAGS;
908 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
909 "channel %u/0x%x (0x%x) requested\n",
910 c->channel, c->channelFlags, flags);
913 if (cc != NULL && cc->channel == c->channel &&
914 (cc->channelFlags & CHAN_FLAGS) == flags) {
915 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
916 (cc->privFlags & CHANNEL_DFS))
922 base = ah->ah_channels;
925 for (lim = n; lim != 0; lim >>= 1) {
927 cc = &base[lim >> 1];
928 d = c->channel - cc->channel;
930 if ((cc->channelFlags & CHAN_FLAGS) == flags) {
931 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
932 (cc->privFlags & CHANNEL_DFS))
937 d = flags - (cc->channelFlags & CHAN_FLAGS);
939 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
940 "channel %u/0x%x d %d\n",
941 cc->channel, cc->channelFlags, d);
947 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "no match for %u/0x%x\n",
948 c->channel, c->channelFlags);
953 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
954 struct ath9k_channel *chan)
956 struct ath9k_channel *ichan = NULL;
958 ichan = ath9k_regd_check_channel(ah, chan);
962 return ichan->antennaMax;
965 u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
968 struct ath9k_channel *ichan;
970 if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) {
972 ctl = SD_NO_CTL | CTL_11B;
973 else if (IS_CHAN_G(chan))
974 ctl = SD_NO_CTL | CTL_11G;
976 ctl = SD_NO_CTL | CTL_11A;
978 ichan = ath9k_regd_check_channel(ah, chan);
981 if (IS_CHAN_A(ichan))
982 ctl = ichan->conformanceTestLimit[0];
983 else if (IS_CHAN_B(ichan))
984 ctl = ichan->conformanceTestLimit[1];
985 else if (IS_CHAN_G(ichan))
986 ctl = ichan->conformanceTestLimit[2];
988 if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B)
989 ctl = (ctl & ~0xf) | CTL_11G;
995 void ath9k_regd_get_current_country(struct ath_hal *ah,
996 struct ath9k_country_entry *ctry)
998 u16 rd = ath9k_regd_get_eepromRD(ah);
1000 ctry->isMultidomain = false;
1001 if (rd == CTRY_DEFAULT)
1002 ctry->isMultidomain = true;
1003 else if (!(rd & COUNTRY_ERD_FLAG))
1004 ctry->isMultidomain = isWwrSKU(ah);
1006 ctry->countryCode = ah->ah_countryCode;
1007 ctry->regDmnEnum = ah->ah_currentRD;
1008 ctry->regDmn5G = ah->ah_currentRD5G;
1009 ctry->regDmn2G = ah->ah_currentRD2G;
1010 ctry->iso[0] = ah->ah_iso[0];
1011 ctry->iso[1] = ah->ah_iso[1];
1012 ctry->iso[2] = ah->ah_iso[2];