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>
21 #include "regd_common.h"
23 static int ath9k_regd_chansort(const void *a
, const void *b
)
25 const struct hal_channel_internal
*ca
= a
;
26 const struct hal_channel_internal
*cb
= b
;
28 return (ca
->channel
== cb
->channel
) ?
29 (ca
->channelFlags
& CHAN_FLAGS
) -
30 (cb
->channelFlags
& CHAN_FLAGS
) : ca
->channel
- cb
->channel
;
34 ath9k_regd_sort(void *a
, u_int32_t n
, u_int32_t size
, ath_hal_cmp_t
*cmp
)
39 for (ai
= aa
+ size
; --n
>= 1; ai
+= size
)
40 for (t
= ai
; t
> aa
; t
-= size
) {
41 u_int8_t
*u
= t
- size
;
48 static u_int16_t
ath9k_regd_get_eepromRD(struct ath_hal
*ah
)
50 return ah
->ah_currentRD
& ~WORLDWIDE_ROAMING_FLAG
;
53 static enum hal_bool
ath9k_regd_is_chan_bm_zero(u_int64_t
*bitmask
)
57 for (i
= 0; i
< BMLEN
; i
++) {
64 static enum hal_bool
ath9k_regd_is_eeprom_valid(struct ath_hal
*ah
)
66 u_int16_t rd
= ath9k_regd_get_eepromRD(ah
);
69 if (rd
& COUNTRY_ERD_FLAG
) {
70 u_int16_t cc
= rd
& ~COUNTRY_ERD_FLAG
;
71 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++)
72 if (allCountries
[i
].countryCode
== cc
)
75 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++)
76 if (regDomainPairs
[i
].regDmnEnum
== rd
)
79 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
80 "%s: invalid regulatory domain/country code 0x%x\n",
85 static enum hal_bool
ath9k_regd_is_fcc_midband_supported(struct ath_hal
90 regcap
= ah
->ah_caps
.halRegCap
;
92 if (regcap
& AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND
)
98 static enum hal_bool
ath9k_regd_is_ccode_valid(struct ath_hal
*ah
,
104 if (cc
== CTRY_DEFAULT
)
106 #ifdef AH_DEBUG_COUNTRY
107 if (cc
== CTRY_DEBUG
)
110 rd
= ath9k_regd_get_eepromRD(ah
);
111 HDPRINTF(ah
, HAL_DBG_REGULATORY
, "%s: EEPROM regdomain 0x%x\n",
114 if (rd
& COUNTRY_ERD_FLAG
) {
116 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
117 "%s: EEPROM setting is country code %u\n",
118 __func__
, rd
& ~COUNTRY_ERD_FLAG
);
119 return cc
== (rd
& ~COUNTRY_ERD_FLAG
);
122 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++) {
123 if (cc
== allCountries
[i
].countryCode
) {
124 #ifdef AH_SUPPORT_11D
125 if ((rd
& WORLD_SKU_MASK
) == WORLD_SKU_PREFIX
)
128 if (allCountries
[i
].regDmnEnum
== rd
||
129 rd
== DEBUG_REG_DMN
|| rd
== NO_ENUMRD
)
137 ath9k_regd_get_wmodes_nreg(struct ath_hal
*ah
,
138 struct country_code_to_enum_rd
*country
,
139 struct regDomain
*rd5GHz
)
143 modesAvail
= ah
->ah_caps
.halWirelessModes
;
145 if ((modesAvail
& ATH9K_MODE_SEL_11G
) && (!country
->allow11g
))
146 modesAvail
&= ~ATH9K_MODE_SEL_11G
;
147 if ((modesAvail
& ATH9K_MODE_SEL_11A
) &&
148 (ath9k_regd_is_chan_bm_zero(rd5GHz
->chan11a
)))
149 modesAvail
&= ~ATH9K_MODE_SEL_11A
;
151 if ((modesAvail
& ATH9K_MODE_SEL_11NG_HT20
)
152 && (!country
->allow11ng20
))
153 modesAvail
&= ~ATH9K_MODE_SEL_11NG_HT20
;
155 if ((modesAvail
& ATH9K_MODE_SEL_11NA_HT20
)
156 && (!country
->allow11na20
))
157 modesAvail
&= ~ATH9K_MODE_SEL_11NA_HT20
;
159 if ((modesAvail
& ATH9K_MODE_SEL_11NG_HT40PLUS
) &&
160 (!country
->allow11ng40
))
161 modesAvail
&= ~ATH9K_MODE_SEL_11NG_HT40PLUS
;
163 if ((modesAvail
& ATH9K_MODE_SEL_11NG_HT40MINUS
) &&
164 (!country
->allow11ng40
))
165 modesAvail
&= ~ATH9K_MODE_SEL_11NG_HT40MINUS
;
167 if ((modesAvail
& ATH9K_MODE_SEL_11NA_HT40PLUS
) &&
168 (!country
->allow11na40
))
169 modesAvail
&= ~ATH9K_MODE_SEL_11NA_HT40PLUS
;
171 if ((modesAvail
& ATH9K_MODE_SEL_11NA_HT40MINUS
) &&
172 (!country
->allow11na40
))
173 modesAvail
&= ~ATH9K_MODE_SEL_11NA_HT40MINUS
;
178 enum hal_bool
ath9k_regd_is_public_safety_sku(struct ath_hal
*ah
)
182 rd
= ath9k_regd_get_eepromRD(ah
);
186 case (CTRY_UNITED_STATES_FCC49
| COUNTRY_ERD_FLAG
):
190 if (ah
->ah_countryCode
== CTRY_UNITED_STATES_FCC49
)
197 static struct country_code_to_enum_rd
*ath9k_regd_find_country(u_int16_t
202 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++) {
203 if (allCountries
[i
].countryCode
== countryCode
)
204 return &allCountries
[i
];
209 static u_int16_t
ath9k_regd_get_default_country(struct ath_hal
*ah
)
214 rd
= ath9k_regd_get_eepromRD(ah
);
215 if (rd
& COUNTRY_ERD_FLAG
) {
216 struct country_code_to_enum_rd
*country
= NULL
;
217 u_int16_t cc
= rd
& ~COUNTRY_ERD_FLAG
;
219 country
= ath9k_regd_find_country(cc
);
224 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++)
225 if (regDomainPairs
[i
].regDmnEnum
== rd
) {
226 if (regDomainPairs
[i
].singleCC
!= 0)
227 return regDomainPairs
[i
].singleCC
;
229 i
= ARRAY_SIZE(regDomainPairs
);
234 static enum hal_bool
ath9k_regd_is_valid_reg_domain(int regDmn
,
235 struct regDomain
*rd
)
239 for (i
= 0; i
< ARRAY_SIZE(regDomains
); i
++) {
240 if (regDomains
[i
].regDmnEnum
== regDmn
) {
242 memcpy(rd
, ®Domains
[i
],
243 sizeof(struct regDomain
));
251 static enum hal_bool
ath9k_regd_is_valid_reg_domainPair(int regDmnPair
)
255 if (regDmnPair
== NO_ENUMRD
)
257 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++) {
258 if (regDomainPairs
[i
].regDmnEnum
== regDmnPair
)
265 ath9k_regd_get_wmode_regdomain(struct ath_hal
*ah
, int regDmn
,
266 u_int16_t channelFlag
, struct regDomain
*rd
)
269 u_int64_t flags
= NO_REQ
;
270 struct reg_dmn_pair_mapping
*regPair
= NULL
;
274 if (regDmn
== CTRY_DEFAULT
) {
276 rdnum
= ath9k_regd_get_eepromRD(ah
);
278 if (!(rdnum
& COUNTRY_ERD_FLAG
)) {
279 if (ath9k_regd_is_valid_reg_domain(rdnum
, NULL
) ||
280 ath9k_regd_is_valid_reg_domainPair(rdnum
)) {
286 if ((regDmn
& MULTI_DOMAIN_MASK
) == 0) {
288 for (i
= 0, found
= 0;
289 (i
< ARRAY_SIZE(regDomainPairs
)) && (!found
); i
++) {
290 if (regDomainPairs
[i
].regDmnEnum
== regDmn
) {
291 regPair
= ®DomainPairs
[i
];
296 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
297 "%s: Failed to find reg domain pair %u\n",
301 if (!(channelFlag
& CHANNEL_2GHZ
)) {
302 regDmn
= regPair
->regDmn5GHz
;
303 flags
= regPair
->flags5GHz
;
305 if (channelFlag
& CHANNEL_2GHZ
) {
306 regDmn
= regPair
->regDmn2GHz
;
307 flags
= regPair
->flags2GHz
;
311 found
= ath9k_regd_is_valid_reg_domain(regDmn
, rd
);
313 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
314 "%s: Failed to find unitary reg domain %u\n",
318 rd
->pscan
&= regPair
->pscanMask
;
319 if (((regOrg
& MULTI_DOMAIN_MASK
) == 0) &&
324 rd
->flags
&= (channelFlag
& CHANNEL_2GHZ
) ?
325 REG_DOMAIN_2GHZ_MASK
: REG_DOMAIN_5GHZ_MASK
;
330 static enum hal_bool
ath9k_regd_is_bit_set(int bit
, u_int64_t
*bitmask
)
332 int byteOffset
, bitnum
;
335 byteOffset
= bit
/ 64;
336 bitnum
= bit
- byteOffset
* 64;
337 val
= ((u_int64_t
) 1) << bitnum
;
338 if (bitmask
[byteOffset
] & val
)
345 ath9k_regd_add_reg_classid(u_int8_t
*regclassids
, u_int maxregids
,
346 u_int
*nregids
, u_int8_t regclassid
)
353 for (i
= 0; i
< maxregids
; i
++) {
354 if (regclassids
[i
] == regclassid
)
356 if (regclassids
[i
] == 0)
363 regclassids
[i
] = regclassid
;
371 ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal
*ah
,
372 enum reg_ext_bitmap bit
)
374 return (ah
->ah_currentRDExt
& (1 << bit
)) ? AH_TRUE
: AH_FALSE
;
377 #ifdef ATH_NF_PER_CHAN
379 static void ath9k_regd_init_rf_buffer(struct hal_channel_internal
*ichans
,
384 for (next
= 0; next
< nchans
; next
++) {
385 for (i
= 0; i
< NUM_NF_READINGS
; i
++) {
386 ichans
[next
].nfCalHist
[i
].currIndex
= 0;
387 ichans
[next
].nfCalHist
[i
].privNF
=
388 AR_PHY_CCA_MAX_GOOD_VALUE
;
389 ichans
[next
].nfCalHist
[i
].invalidNFcount
=
390 AR_PHY_CCA_FILTERWINDOW_LENGTH
;
391 for (j
= 0; j
< HAL_NF_CAL_HIST_MAX
; j
++) {
392 ichans
[next
].nfCalHist
[i
].nfCalBuffer
[j
] =
393 AR_PHY_CCA_MAX_GOOD_VALUE
;
401 ath9k_regd_init_channels(struct ath_hal
*ah
,
402 struct hal_channel
*chans
, u_int maxchans
,
403 u_int
*nchans
, u_int8_t
*regclassids
,
404 u_int maxregids
, u_int
*nregids
, u_int16_t cc
,
405 u_int32_t modeSelect
, enum hal_bool enableOutdoor
,
406 enum hal_bool enableExtendedChannels
)
409 u_int16_t maxChan
= 7000;
410 struct country_code_to_enum_rd
*country
= NULL
;
411 struct regDomain rd5GHz
, rd2GHz
;
412 const struct cmode
*cm
;
413 struct hal_channel_internal
*ichans
= &ah
->ah_channels
[0];
416 int is_quarterchan_cap
, is_halfchan_cap
;
420 HDPRINTF(ah
, HAL_DBG_REGULATORY
, "%s: cc %u mode 0x%x%s%s\n",
421 __func__
, cc
, modeSelect
,
422 enableOutdoor
? " Enable outdoor" : " ",
423 enableExtendedChannels
? " Enable ecm" : "");
425 if (!ath9k_regd_is_ccode_valid(ah
, cc
)) {
427 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
428 "%s: invalid country code %d\n", __func__
, cc
);
432 if (!ath9k_regd_is_eeprom_valid(ah
)) {
434 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
435 "%s: invalid EEPROM contents\n", __func__
);
439 ah
->ah_countryCode
= ath9k_regd_get_default_country(ah
);
441 if (ah
->ah_countryCode
== CTRY_DEFAULT
) {
443 ah
->ah_countryCode
= cc
& COUNTRY_CODE_MASK
;
445 if ((ah
->ah_countryCode
== CTRY_DEFAULT
) &&
446 (ath9k_regd_get_eepromRD(ah
) == CTRY_DEFAULT
)) {
448 ah
->ah_countryCode
= CTRY_UNITED_STATES
;
451 #ifdef AH_SUPPORT_11D
452 if (ah
->ah_countryCode
== CTRY_DEFAULT
) {
453 regdmn
= ath9k_regd_get_eepromRD(ah
);
457 country
= ath9k_regd_find_country(ah
->ah_countryCode
);
459 if (country
== NULL
) {
460 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
461 "Country is NULL!!!!, cc= %d\n",
465 regdmn
= country
->regDmnEnum
;
466 #ifdef AH_SUPPORT_11D
467 if (((ath9k_regd_get_eepromRD(ah
) & WORLD_SKU_MASK
)
469 && (cc
== CTRY_UNITED_STATES
)) {
470 if (!isWwrSKU_NoMidband(ah
)
472 ath9k_regd_is_fcc_midband_supported
480 #ifdef AH_SUPPORT_11D
484 if (!ath9k_regd_get_wmode_regdomain
485 (ah
, regdmn
, ~CHANNEL_2GHZ
, &rd5GHz
)) {
486 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
487 "%s: couldn't find unitary "
488 "5GHz reg domain for country %u\n",
489 __func__
, ah
->ah_countryCode
);
492 if (!ath9k_regd_get_wmode_regdomain
493 (ah
, regdmn
, CHANNEL_2GHZ
, &rd2GHz
)) {
494 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
495 "%s: couldn't find unitary 2GHz "
496 "reg domain for country %u\n",
497 __func__
, ah
->ah_countryCode
);
502 && ((rd5GHz
.regDmnEnum
== FCC1
)
503 || (rd5GHz
.regDmnEnum
== FCC2
))) {
504 if (ath9k_regd_is_fcc_midband_supported(ah
)) {
506 if (!ath9k_regd_get_wmode_regdomain
507 (ah
, FCC3_FCCA
, ~CHANNEL_2GHZ
, &rd5GHz
)) {
508 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
509 "%s: couldn't find unitary 5GHz "
510 "reg domain for country %u\n",
511 __func__
, ah
->ah_countryCode
);
517 if (country
== NULL
) {
518 modesAvail
= ah
->ah_caps
.halWirelessModes
;
521 ath9k_regd_get_wmodes_nreg(ah
, country
, &rd5GHz
);
524 maxChan
= country
->outdoorChanStart
;
529 if (maxchans
> ARRAY_SIZE(ah
->ah_channels
))
530 maxchans
= ARRAY_SIZE(ah
->ah_channels
);
532 is_halfchan_cap
= ah
->ah_caps
.halChanHalfRate
;
533 is_quarterchan_cap
= ah
->ah_caps
.halChanQuarterRate
;
534 for (cm
= modes
; cm
< &modes
[ARRAY_SIZE(modes
)]; cm
++) {
535 u_int16_t c
, c_hi
, c_lo
;
536 u_int64_t
*channelBM
= NULL
;
537 struct regDomain
*rd
= NULL
;
538 struct RegDmnFreqBand
*fband
= NULL
, *freqs
;
539 int8_t low_adj
= 0, hi_adj
= 0;
541 if ((cm
->mode
& modeSelect
) == 0) {
542 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
543 "%s: skip mode 0x%x flags 0x%x\n",
544 __func__
, cm
->mode
, cm
->flags
);
547 if ((cm
->mode
& modesAvail
) == 0) {
548 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
549 "%s: !avail mode 0x%x (0x%x) flags 0x%x\n",
550 __func__
, modesAvail
, cm
->mode
,
554 if (!ath9k_get_channel_edges(ah
, cm
->flags
, &c_lo
, &c_hi
)) {
556 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
557 "%s: channels 0x%x not supported "
559 __func__
, cm
->flags
);
563 case ATH9K_MODE_SEL_11A
:
564 case ATH9K_MODE_SEL_11NA_HT20
:
565 case ATH9K_MODE_SEL_11NA_HT40PLUS
:
566 case ATH9K_MODE_SEL_11NA_HT40MINUS
:
568 channelBM
= rd
->chan11a
;
569 freqs
= ®Dmn5GhzFreq
[0];
570 ctl
= rd
->conformanceTestLimit
;
572 case ATH9K_MODE_SEL_11B
:
574 channelBM
= rd
->chan11b
;
575 freqs
= ®Dmn2GhzFreq
[0];
576 ctl
= rd
->conformanceTestLimit
| CTL_11B
;
578 case ATH9K_MODE_SEL_11G
:
579 case ATH9K_MODE_SEL_11NG_HT20
:
580 case ATH9K_MODE_SEL_11NG_HT40PLUS
:
581 case ATH9K_MODE_SEL_11NG_HT40MINUS
:
583 channelBM
= rd
->chan11g
;
584 freqs
= ®Dmn2Ghz11gFreq
[0];
585 ctl
= rd
->conformanceTestLimit
| CTL_11G
;
588 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
589 "%s: Unkonwn HAL mode 0x%x\n", __func__
,
593 if (ath9k_regd_is_chan_bm_zero(channelBM
))
597 if ((cm
->mode
== ATH9K_MODE_SEL_11NA_HT40PLUS
) ||
598 (cm
->mode
== ATH9K_MODE_SEL_11NG_HT40PLUS
)) {
602 if ((cm
->mode
== ATH9K_MODE_SEL_11NA_HT40MINUS
) ||
603 (cm
->mode
== ATH9K_MODE_SEL_11NG_HT40MINUS
)) {
607 /* XXX: Add a helper here instead */
608 for (b
= 0; b
< 64 * BMLEN
; b
++) {
609 if (ath9k_regd_is_bit_set(b
, channelBM
)) {
613 if (rd5GHz
.regDmnEnum
== MKK1
614 || rd5GHz
.regDmnEnum
== MKK2
) {
619 i
< ARRAY_SIZE(j_bandcheck
);
635 AR_EEPROM_EEREGCAP_EN_KK_U2
)
638 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND
)) {
664 ath9k_regd_add_reg_classid(regclassids
,
670 if (IS_HT40_MODE(cm
->mode
)
671 && (rd
== &rd5GHz
)) {
676 if (fband
->lowChannel
== 5280)
679 if (fband
->lowChannel
== 5170)
682 chanSep
= fband
->channelSep
;
684 for (c
= fband
->lowChannel
+ low_adj
;
685 ((c
<= (fband
->highChannel
+ hi_adj
))
687 (fband
->lowChannel
+ low_adj
)));
689 struct hal_channel_internal icv
;
691 if (!(c_lo
<= c
&& c
<= c_hi
)) {
700 if ((fband
->channelBW
==
705 "%s: Skipping %u half "
711 if ((fband
->channelBW
==
712 CHANNEL_QUARTER_BW
) &&
713 !is_quarterchan_cap
) {
723 if (((c
+ fband
->channelSep
) / 2) >
724 (maxChan
+ HALF_MAXCHANBW
)) {
733 if (next
>= maxchans
) {
737 "channels for channel "
743 usePassScan
& IS_ECM_CHAN
)
744 && !enableExtendedChannels
) {
751 if ((rd
->flags
& NO_HOSTAP
) &&
760 if (IS_HT40_MODE(cm
->mode
) &&
762 (ath9k_regd_get_eeprom_reg_ext_bits
763 (ah
, REG_EXT_FCC_DFS_HT40
))
765 && (rd
->conformanceTestLimit
!=
772 "(en_fcc_dfs_ht40 = "
776 if (IS_HT40_MODE(cm
->mode
) &&
778 (ath9k_regd_get_eeprom_reg_ext_bits
780 REG_EXT_JAPAN_NONDFS_HT40
))
782 && (rd
->conformanceTestLimit
==
787 "channel (en_jap_ht40 "
791 if (IS_HT40_MODE(cm
->mode
) &&
793 (ath9k_regd_get_eeprom_reg_ext_bits
794 (ah
, REG_EXT_JAPAN_DFS_HT40
))
796 && (rd
->conformanceTestLimit
==
800 "Skipping HT40 channel"
801 " (en_jap_dfs_ht40 = "
805 memset(&icv
, 0, sizeof(icv
));
807 icv
.channelFlags
= cm
->flags
;
809 switch (fband
->channelBW
) {
810 case CHANNEL_HALF_BW
:
814 case CHANNEL_QUARTER_BW
:
822 icv
.antennaMax
= fband
->antennaMax
;
823 icv
.regDmnFlags
= rd
->flags
;
824 icv
.conformanceTestLimit
= ctl
;
825 if (fband
->usePassScan
& rd
->pscan
)
831 if (fband
->useDfs
& rd
->dfsMask
)
836 if (rd
->flags
& LIMIT_FRAME_4MS
)
840 if (icv
.privFlags
& CHANNEL_DFS
) {
842 CHANNEL_DISALLOW_ADHOC
;
845 regDmnFlags
& ADHOC_PER_11D
) {
847 CHANNEL_PER_11D_ADHOC
;
850 channelFlags
& CHANNEL_PASSIVE
) {
852 if ((icv
.channel
< 2412)
870 (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN
872 AR_EEPROM_EEREGCAP_EN_KK_U2
874 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND
))
875 && isUNII1OddChan(icv
.channel
)) {
877 icv
.channelFlags
&= ~CHANNEL_PASSIVE
;
879 icv
.privFlags
|= CHANNEL_DISALLOW_ADHOC
;
882 icv
.privFlags
|= CHANNEL_DISALLOW_ADHOC
;
887 mode
& (ATH9K_MODE_SEL_11A
|
888 ATH9K_MODE_SEL_11NA_HT20
890 ATH9K_MODE_SEL_11NA_HT40PLUS
892 ATH9K_MODE_SEL_11NA_HT40MINUS
)) {
896 DISALLOW_ADHOC_11A
)) {
898 CHANNEL_DISALLOW_ADHOC
;
902 memcpy(&ichans
[next
++], &icv
,
904 hal_channel_internal
));
907 if (IS_HT40_MODE(cm
->mode
)
908 && (fband
->lowChannel
== 5280)) {
919 if (next
> ARRAY_SIZE(ah
->ah_channels
)) {
920 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
921 "%s: too many channels %u; truncating to %u\n",
923 (int) ARRAY_SIZE(ah
->ah_channels
));
924 next
= ARRAY_SIZE(ah
->ah_channels
);
926 #ifdef ATH_NF_PER_CHAN
928 ath9k_regd_init_rf_buffer(ichans
, next
);
931 ath9k_regd_sort(ichans
, next
,
932 sizeof(struct hal_channel_internal
),
933 ath9k_regd_chansort
);
936 HDPRINTF(ah
, HAL_DBG_REGULATORY
, "Channel list:\n");
937 for (i
= 0; i
< next
; i
++) {
938 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
939 "chan: %d flags: 0x%x\n",
941 ichans
[i
].channelFlags
);
942 chans
[i
].channel
= ichans
[i
].channel
;
943 chans
[i
].channelFlags
= ichans
[i
].channelFlags
;
944 chans
[i
].privFlags
= ichans
[i
].privFlags
;
945 chans
[i
].maxRegTxPower
= ichans
[i
].maxRegTxPower
;
948 ath9k_hw_get_chip_power_limits(ah
, chans
, next
);
949 for (i
= 0; i
< next
; i
++) {
950 ichans
[i
].maxTxPower
= chans
[i
].maxTxPower
;
951 ichans
[i
].minTxPower
= chans
[i
].minTxPower
;
956 ah
->ah_countryCode
= ah
->ah_countryCode
;
958 ah
->ah_currentRDInUse
= regdmn
;
959 ah
->ah_currentRD5G
= rd5GHz
.regDmnEnum
;
960 ah
->ah_currentRD2G
= rd2GHz
.regDmnEnum
;
961 if (country
== NULL
) {
965 ah
->ah_iso
[0] = country
->isoName
[0];
966 ah
->ah_iso
[1] = country
->isoName
[1];
971 struct hal_channel_internal
*ath9k_regd_check_channel(struct ath_hal
*ah
,
972 const struct hal_channel
*c
)
974 struct hal_channel_internal
*base
, *cc
;
976 int flags
= c
->channelFlags
& CHAN_FLAGS
;
979 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
980 "%s: channel %u/0x%x (0x%x) requested\n", __func__
,
981 c
->channel
, c
->channelFlags
, flags
);
984 if (cc
!= NULL
&& cc
->channel
== c
->channel
&&
985 (cc
->channelFlags
& CHAN_FLAGS
) == flags
) {
986 if ((cc
->privFlags
& CHANNEL_INTERFERENCE
) &&
987 (cc
->privFlags
& CHANNEL_DFS
))
993 base
= ah
->ah_channels
;
996 for (lim
= n
; lim
!= 0; lim
>>= 1) {
998 cc
= &base
[lim
>> 1];
999 d
= c
->channel
- cc
->channel
;
1001 if ((cc
->channelFlags
& CHAN_FLAGS
) == flags
) {
1002 if ((cc
->privFlags
& CHANNEL_INTERFERENCE
)
1003 && (cc
->privFlags
& CHANNEL_DFS
))
1008 d
= flags
- (cc
->channelFlags
& CHAN_FLAGS
);
1010 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
1011 "%s: channel %u/0x%x d %d\n", __func__
,
1012 cc
->channel
, cc
->channelFlags
, d
);
1018 HDPRINTF(ah
, HAL_DBG_REGULATORY
, "%s: no match for %u/0x%x\n",
1019 __func__
, c
->channel
, c
->channelFlags
);
1024 ath9k_regd_get_antenna_allowed(struct ath_hal
*ah
,
1025 struct hal_channel
*chan
)
1027 struct hal_channel_internal
*ichan
= NULL
;
1029 ichan
= ath9k_regd_check_channel(ah
, chan
);
1033 return ichan
->antennaMax
;
1036 u_int
ath9k_regd_get_ctl(struct ath_hal
*ah
, struct hal_channel
*chan
)
1039 struct hal_channel_internal
*ichan
;
1041 if (ah
->ah_countryCode
== CTRY_DEFAULT
&& isWwrSKU(ah
)) {
1042 if (IS_CHAN_B(chan
))
1043 ctl
= SD_NO_CTL
| CTL_11B
;
1044 else if (IS_CHAN_G(chan
))
1045 ctl
= SD_NO_CTL
| CTL_11G
;
1047 ctl
= SD_NO_CTL
| CTL_11A
;
1049 ichan
= ath9k_regd_check_channel(ah
, chan
);
1050 if (ichan
!= NULL
) {
1051 ctl
= ichan
->conformanceTestLimit
;
1053 if (IS_CHAN_PUREG(chan
) && (ctl
& 0xf) == CTL_11B
)
1054 ctl
= (ctl
& ~0xf) | CTL_11G
;
1060 void ath9k_regd_get_current_country(struct ath_hal
*ah
,
1061 struct hal_country_entry
*ctry
)
1063 u_int16_t rd
= ath9k_regd_get_eepromRD(ah
);
1065 ctry
->isMultidomain
= AH_FALSE
;
1066 if (rd
== CTRY_DEFAULT
)
1067 ctry
->isMultidomain
= AH_TRUE
;
1068 else if (!(rd
& COUNTRY_ERD_FLAG
))
1069 ctry
->isMultidomain
= isWwrSKU(ah
);
1071 ctry
->countryCode
= ah
->ah_countryCode
;
1072 ctry
->regDmnEnum
= ah
->ah_currentRD
;
1073 ctry
->regDmn5G
= ah
->ah_currentRD5G
;
1074 ctry
->regDmn2G
= ah
->ah_currentRD2G
;
1075 ctry
->iso
[0] = ah
->ah_iso
[0];
1076 ctry
->iso
[1] = ah
->ah_iso
[1];
1077 ctry
->iso
[2] = ah
->ah_iso
[2];