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.
19 #include "regd_common.h"
21 static int ath9k_regd_chansort(const void *a
, const void *b
)
23 const struct hal_channel_internal
*ca
= a
;
24 const struct hal_channel_internal
*cb
= b
;
26 return (ca
->channel
== cb
->channel
) ?
27 (ca
->channelFlags
& CHAN_FLAGS
) -
28 (cb
->channelFlags
& CHAN_FLAGS
) : ca
->channel
- cb
->channel
;
32 ath9k_regd_sort(void *a
, u_int32_t n
, u_int32_t size
, ath_hal_cmp_t
*cmp
)
37 for (ai
= aa
+ size
; --n
>= 1; ai
+= size
)
38 for (t
= ai
; t
> aa
; t
-= size
) {
39 u_int8_t
*u
= t
- size
;
46 static u_int16_t
ath9k_regd_get_eepromRD(struct ath_hal
*ah
)
48 return ah
->ah_currentRD
& ~WORLDWIDE_ROAMING_FLAG
;
51 static enum hal_bool
ath9k_regd_is_chan_bm_zero(u_int64_t
*bitmask
)
55 for (i
= 0; i
< BMLEN
; i
++) {
62 static enum hal_bool
ath9k_regd_is_eeprom_valid(struct ath_hal
*ah
)
64 u_int16_t rd
= ath9k_regd_get_eepromRD(ah
);
67 if (rd
& COUNTRY_ERD_FLAG
) {
68 u_int16_t cc
= rd
& ~COUNTRY_ERD_FLAG
;
69 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++)
70 if (allCountries
[i
].countryCode
== cc
)
73 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++)
74 if (regDomainPairs
[i
].regDmnEnum
== rd
)
77 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
78 "%s: invalid regulatory domain/country code 0x%x\n",
83 static enum hal_bool
ath9k_regd_is_fcc_midband_supported(struct ath_hal
88 regcap
= ah
->ah_caps
.halRegCap
;
90 if (regcap
& AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND
)
96 static enum hal_bool
ath9k_regd_is_ccode_valid(struct ath_hal
*ah
,
102 if (cc
== CTRY_DEFAULT
)
104 #ifdef AH_DEBUG_COUNTRY
105 if (cc
== CTRY_DEBUG
)
108 rd
= ath9k_regd_get_eepromRD(ah
);
109 HDPRINTF(ah
, HAL_DBG_REGULATORY
, "%s: EEPROM regdomain 0x%x\n",
112 if (rd
& COUNTRY_ERD_FLAG
) {
114 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
115 "%s: EEPROM setting is country code %u\n",
116 __func__
, rd
& ~COUNTRY_ERD_FLAG
);
117 return cc
== (rd
& ~COUNTRY_ERD_FLAG
);
120 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++) {
121 if (cc
== allCountries
[i
].countryCode
) {
122 #ifdef AH_SUPPORT_11D
123 if ((rd
& WORLD_SKU_MASK
) == WORLD_SKU_PREFIX
)
126 if (allCountries
[i
].regDmnEnum
== rd
||
127 rd
== DEBUG_REG_DMN
|| rd
== NO_ENUMRD
)
135 ath9k_regd_get_wmodes_nreg(struct ath_hal
*ah
,
136 struct country_code_to_enum_rd
*country
,
137 struct regDomain
*rd5GHz
)
141 modesAvail
= ah
->ah_caps
.halWirelessModes
;
143 if ((modesAvail
& ATH9K_MODE_SEL_11G
) && (!country
->allow11g
))
144 modesAvail
&= ~ATH9K_MODE_SEL_11G
;
145 if ((modesAvail
& ATH9K_MODE_SEL_11A
) &&
146 (ath9k_regd_is_chan_bm_zero(rd5GHz
->chan11a
)))
147 modesAvail
&= ~ATH9K_MODE_SEL_11A
;
149 if ((modesAvail
& ATH9K_MODE_SEL_11NG_HT20
)
150 && (!country
->allow11ng20
))
151 modesAvail
&= ~ATH9K_MODE_SEL_11NG_HT20
;
153 if ((modesAvail
& ATH9K_MODE_SEL_11NA_HT20
)
154 && (!country
->allow11na20
))
155 modesAvail
&= ~ATH9K_MODE_SEL_11NA_HT20
;
157 if ((modesAvail
& ATH9K_MODE_SEL_11NG_HT40PLUS
) &&
158 (!country
->allow11ng40
))
159 modesAvail
&= ~ATH9K_MODE_SEL_11NG_HT40PLUS
;
161 if ((modesAvail
& ATH9K_MODE_SEL_11NG_HT40MINUS
) &&
162 (!country
->allow11ng40
))
163 modesAvail
&= ~ATH9K_MODE_SEL_11NG_HT40MINUS
;
165 if ((modesAvail
& ATH9K_MODE_SEL_11NA_HT40PLUS
) &&
166 (!country
->allow11na40
))
167 modesAvail
&= ~ATH9K_MODE_SEL_11NA_HT40PLUS
;
169 if ((modesAvail
& ATH9K_MODE_SEL_11NA_HT40MINUS
) &&
170 (!country
->allow11na40
))
171 modesAvail
&= ~ATH9K_MODE_SEL_11NA_HT40MINUS
;
176 enum hal_bool
ath9k_regd_is_public_safety_sku(struct ath_hal
*ah
)
180 rd
= ath9k_regd_get_eepromRD(ah
);
184 case (CTRY_UNITED_STATES_FCC49
| COUNTRY_ERD_FLAG
):
188 if (ah
->ah_countryCode
== CTRY_UNITED_STATES_FCC49
)
195 static struct country_code_to_enum_rd
*ath9k_regd_find_country(u_int16_t
200 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++) {
201 if (allCountries
[i
].countryCode
== countryCode
)
202 return &allCountries
[i
];
207 static u_int16_t
ath9k_regd_get_default_country(struct ath_hal
*ah
)
212 rd
= ath9k_regd_get_eepromRD(ah
);
213 if (rd
& COUNTRY_ERD_FLAG
) {
214 struct country_code_to_enum_rd
*country
= NULL
;
215 u_int16_t cc
= rd
& ~COUNTRY_ERD_FLAG
;
217 country
= ath9k_regd_find_country(cc
);
222 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++)
223 if (regDomainPairs
[i
].regDmnEnum
== rd
) {
224 if (regDomainPairs
[i
].singleCC
!= 0)
225 return regDomainPairs
[i
].singleCC
;
227 i
= ARRAY_SIZE(regDomainPairs
);
232 static enum hal_bool
ath9k_regd_is_valid_reg_domain(int regDmn
,
233 struct regDomain
*rd
)
237 for (i
= 0; i
< ARRAY_SIZE(regDomains
); i
++) {
238 if (regDomains
[i
].regDmnEnum
== regDmn
) {
240 memcpy(rd
, ®Domains
[i
],
241 sizeof(struct regDomain
));
249 static enum hal_bool
ath9k_regd_is_valid_reg_domainPair(int regDmnPair
)
253 if (regDmnPair
== NO_ENUMRD
)
255 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++) {
256 if (regDomainPairs
[i
].regDmnEnum
== regDmnPair
)
263 ath9k_regd_get_wmode_regdomain(struct ath_hal
*ah
, int regDmn
,
264 u_int16_t channelFlag
, struct regDomain
*rd
)
267 u_int64_t flags
= NO_REQ
;
268 struct reg_dmn_pair_mapping
*regPair
= NULL
;
272 if (regDmn
== CTRY_DEFAULT
) {
274 rdnum
= ath9k_regd_get_eepromRD(ah
);
276 if (!(rdnum
& COUNTRY_ERD_FLAG
)) {
277 if (ath9k_regd_is_valid_reg_domain(rdnum
, NULL
) ||
278 ath9k_regd_is_valid_reg_domainPair(rdnum
)) {
284 if ((regDmn
& MULTI_DOMAIN_MASK
) == 0) {
286 for (i
= 0, found
= 0;
287 (i
< ARRAY_SIZE(regDomainPairs
)) && (!found
); i
++) {
288 if (regDomainPairs
[i
].regDmnEnum
== regDmn
) {
289 regPair
= ®DomainPairs
[i
];
294 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
295 "%s: Failed to find reg domain pair %u\n",
299 if (!(channelFlag
& CHANNEL_2GHZ
)) {
300 regDmn
= regPair
->regDmn5GHz
;
301 flags
= regPair
->flags5GHz
;
303 if (channelFlag
& CHANNEL_2GHZ
) {
304 regDmn
= regPair
->regDmn2GHz
;
305 flags
= regPair
->flags2GHz
;
309 found
= ath9k_regd_is_valid_reg_domain(regDmn
, rd
);
311 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
312 "%s: Failed to find unitary reg domain %u\n",
316 rd
->pscan
&= regPair
->pscanMask
;
317 if (((regOrg
& MULTI_DOMAIN_MASK
) == 0) &&
322 rd
->flags
&= (channelFlag
& CHANNEL_2GHZ
) ?
323 REG_DOMAIN_2GHZ_MASK
: REG_DOMAIN_5GHZ_MASK
;
328 static enum hal_bool
ath9k_regd_is_bit_set(int bit
, u_int64_t
*bitmask
)
330 int byteOffset
, bitnum
;
333 byteOffset
= bit
/ 64;
334 bitnum
= bit
- byteOffset
* 64;
335 val
= ((u_int64_t
) 1) << bitnum
;
336 if (bitmask
[byteOffset
] & val
)
343 ath9k_regd_add_reg_classid(u_int8_t
*regclassids
, u_int maxregids
,
344 u_int
*nregids
, u_int8_t regclassid
)
351 for (i
= 0; i
< maxregids
; i
++) {
352 if (regclassids
[i
] == regclassid
)
354 if (regclassids
[i
] == 0)
361 regclassids
[i
] = regclassid
;
369 ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal
*ah
,
370 enum reg_ext_bitmap bit
)
372 return (ah
->ah_currentRDExt
& (1 << bit
)) ? AH_TRUE
: AH_FALSE
;
375 #ifdef ATH_NF_PER_CHAN
377 static void ath9k_regd_init_rf_buffer(struct hal_channel_internal
*ichans
,
382 for (next
= 0; next
< nchans
; next
++) {
383 for (i
= 0; i
< NUM_NF_READINGS
; i
++) {
384 ichans
[next
].nfCalHist
[i
].currIndex
= 0;
385 ichans
[next
].nfCalHist
[i
].privNF
=
386 AR_PHY_CCA_MAX_GOOD_VALUE
;
387 ichans
[next
].nfCalHist
[i
].invalidNFcount
=
388 AR_PHY_CCA_FILTERWINDOW_LENGTH
;
389 for (j
= 0; j
< HAL_NF_CAL_HIST_MAX
; j
++) {
390 ichans
[next
].nfCalHist
[i
].nfCalBuffer
[j
] =
391 AR_PHY_CCA_MAX_GOOD_VALUE
;
399 ath9k_regd_init_channels(struct ath_hal
*ah
,
400 struct hal_channel
*chans
, u_int maxchans
,
401 u_int
*nchans
, u_int8_t
*regclassids
,
402 u_int maxregids
, u_int
*nregids
, u_int16_t cc
,
403 u_int32_t modeSelect
, enum hal_bool enableOutdoor
,
404 enum hal_bool enableExtendedChannels
)
407 u_int16_t maxChan
= 7000;
408 struct country_code_to_enum_rd
*country
= NULL
;
409 struct regDomain rd5GHz
, rd2GHz
;
410 const struct cmode
*cm
;
411 struct hal_channel_internal
*ichans
= &ah
->ah_channels
[0];
414 int is_quarterchan_cap
, is_halfchan_cap
;
418 HDPRINTF(ah
, HAL_DBG_REGULATORY
, "%s: cc %u mode 0x%x%s%s\n",
419 __func__
, cc
, modeSelect
,
420 enableOutdoor
? " Enable outdoor" : " ",
421 enableExtendedChannels
? " Enable ecm" : "");
423 if (!ath9k_regd_is_ccode_valid(ah
, cc
)) {
425 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
426 "%s: invalid country code %d\n", __func__
, cc
);
430 if (!ath9k_regd_is_eeprom_valid(ah
)) {
432 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
433 "%s: invalid EEPROM contents\n", __func__
);
437 ah
->ah_countryCode
= ath9k_regd_get_default_country(ah
);
439 if (ah
->ah_countryCode
== CTRY_DEFAULT
) {
441 ah
->ah_countryCode
= cc
& COUNTRY_CODE_MASK
;
443 if ((ah
->ah_countryCode
== CTRY_DEFAULT
) &&
444 (ath9k_regd_get_eepromRD(ah
) == CTRY_DEFAULT
)) {
446 ah
->ah_countryCode
= CTRY_UNITED_STATES
;
449 #ifdef AH_SUPPORT_11D
450 if (ah
->ah_countryCode
== CTRY_DEFAULT
) {
451 regdmn
= ath9k_regd_get_eepromRD(ah
);
455 country
= ath9k_regd_find_country(ah
->ah_countryCode
);
457 if (country
== NULL
) {
458 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
459 "Country is NULL!!!!, cc= %d\n",
463 regdmn
= country
->regDmnEnum
;
464 #ifdef AH_SUPPORT_11D
465 if (((ath9k_regd_get_eepromRD(ah
) & WORLD_SKU_MASK
)
467 && (cc
== CTRY_UNITED_STATES
)) {
468 if (!isWwrSKU_NoMidband(ah
)
470 ath9k_regd_is_fcc_midband_supported
478 #ifdef AH_SUPPORT_11D
482 if (!ath9k_regd_get_wmode_regdomain
483 (ah
, regdmn
, ~CHANNEL_2GHZ
, &rd5GHz
)) {
484 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
485 "%s: couldn't find unitary "
486 "5GHz reg domain for country %u\n",
487 __func__
, ah
->ah_countryCode
);
490 if (!ath9k_regd_get_wmode_regdomain
491 (ah
, regdmn
, CHANNEL_2GHZ
, &rd2GHz
)) {
492 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
493 "%s: couldn't find unitary 2GHz "
494 "reg domain for country %u\n",
495 __func__
, ah
->ah_countryCode
);
500 && ((rd5GHz
.regDmnEnum
== FCC1
)
501 || (rd5GHz
.regDmnEnum
== FCC2
))) {
502 if (ath9k_regd_is_fcc_midband_supported(ah
)) {
504 if (!ath9k_regd_get_wmode_regdomain
505 (ah
, FCC3_FCCA
, ~CHANNEL_2GHZ
, &rd5GHz
)) {
506 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
507 "%s: couldn't find unitary 5GHz "
508 "reg domain for country %u\n",
509 __func__
, ah
->ah_countryCode
);
515 if (country
== NULL
) {
516 modesAvail
= ah
->ah_caps
.halWirelessModes
;
519 ath9k_regd_get_wmodes_nreg(ah
, country
, &rd5GHz
);
522 maxChan
= country
->outdoorChanStart
;
527 if (maxchans
> ARRAY_SIZE(ah
->ah_channels
))
528 maxchans
= ARRAY_SIZE(ah
->ah_channels
);
530 is_halfchan_cap
= ah
->ah_caps
.halChanHalfRate
;
531 is_quarterchan_cap
= ah
->ah_caps
.halChanQuarterRate
;
532 for (cm
= modes
; cm
< &modes
[ARRAY_SIZE(modes
)]; cm
++) {
533 u_int16_t c
, c_hi
, c_lo
;
534 u_int64_t
*channelBM
= NULL
;
535 struct regDomain
*rd
= NULL
;
536 struct RegDmnFreqBand
*fband
= NULL
, *freqs
;
537 int8_t low_adj
= 0, hi_adj
= 0;
539 if ((cm
->mode
& modeSelect
) == 0) {
540 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
541 "%s: skip mode 0x%x flags 0x%x\n",
542 __func__
, cm
->mode
, cm
->flags
);
545 if ((cm
->mode
& modesAvail
) == 0) {
546 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
547 "%s: !avail mode 0x%x (0x%x) flags 0x%x\n",
548 __func__
, modesAvail
, cm
->mode
,
552 if (!ath9k_get_channel_edges(ah
, cm
->flags
, &c_lo
, &c_hi
)) {
554 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
555 "%s: channels 0x%x not supported "
557 __func__
, cm
->flags
);
561 case ATH9K_MODE_SEL_11A
:
562 case ATH9K_MODE_SEL_11NA_HT20
:
563 case ATH9K_MODE_SEL_11NA_HT40PLUS
:
564 case ATH9K_MODE_SEL_11NA_HT40MINUS
:
566 channelBM
= rd
->chan11a
;
567 freqs
= ®Dmn5GhzFreq
[0];
568 ctl
= rd
->conformanceTestLimit
;
570 case ATH9K_MODE_SEL_11B
:
572 channelBM
= rd
->chan11b
;
573 freqs
= ®Dmn2GhzFreq
[0];
574 ctl
= rd
->conformanceTestLimit
| CTL_11B
;
576 case ATH9K_MODE_SEL_11G
:
577 case ATH9K_MODE_SEL_11NG_HT20
:
578 case ATH9K_MODE_SEL_11NG_HT40PLUS
:
579 case ATH9K_MODE_SEL_11NG_HT40MINUS
:
581 channelBM
= rd
->chan11g
;
582 freqs
= ®Dmn2Ghz11gFreq
[0];
583 ctl
= rd
->conformanceTestLimit
| CTL_11G
;
586 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
587 "%s: Unkonwn HAL mode 0x%x\n", __func__
,
591 if (ath9k_regd_is_chan_bm_zero(channelBM
))
595 if ((cm
->mode
== ATH9K_MODE_SEL_11NA_HT40PLUS
) ||
596 (cm
->mode
== ATH9K_MODE_SEL_11NG_HT40PLUS
)) {
600 if ((cm
->mode
== ATH9K_MODE_SEL_11NA_HT40MINUS
) ||
601 (cm
->mode
== ATH9K_MODE_SEL_11NG_HT40MINUS
)) {
605 /* XXX: Add a helper here instead */
606 for (b
= 0; b
< 64 * BMLEN
; b
++) {
607 if (ath9k_regd_is_bit_set(b
, channelBM
)) {
611 if (rd5GHz
.regDmnEnum
== MKK1
612 || rd5GHz
.regDmnEnum
== MKK2
) {
617 i
< ARRAY_SIZE(j_bandcheck
);
633 AR_EEPROM_EEREGCAP_EN_KK_U2
)
636 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND
)) {
662 ath9k_regd_add_reg_classid(regclassids
,
668 if (IS_HT40_MODE(cm
->mode
)
669 && (rd
== &rd5GHz
)) {
674 if (fband
->lowChannel
== 5280)
677 if (fband
->lowChannel
== 5170)
680 chanSep
= fband
->channelSep
;
682 for (c
= fband
->lowChannel
+ low_adj
;
683 ((c
<= (fband
->highChannel
+ hi_adj
))
685 (fband
->lowChannel
+ low_adj
)));
687 struct hal_channel_internal icv
;
689 if (!(c_lo
<= c
&& c
<= c_hi
)) {
698 if ((fband
->channelBW
==
703 "%s: Skipping %u half "
709 if ((fband
->channelBW
==
710 CHANNEL_QUARTER_BW
) &&
711 !is_quarterchan_cap
) {
721 if (((c
+ fband
->channelSep
) / 2) >
722 (maxChan
+ HALF_MAXCHANBW
)) {
731 if (next
>= maxchans
) {
735 "channels for channel "
741 usePassScan
& IS_ECM_CHAN
)
742 && !enableExtendedChannels
) {
749 if ((rd
->flags
& NO_HOSTAP
) &&
758 if (IS_HT40_MODE(cm
->mode
) &&
760 (ath9k_regd_get_eeprom_reg_ext_bits
761 (ah
, REG_EXT_FCC_DFS_HT40
))
763 && (rd
->conformanceTestLimit
!=
770 "(en_fcc_dfs_ht40 = "
774 if (IS_HT40_MODE(cm
->mode
) &&
776 (ath9k_regd_get_eeprom_reg_ext_bits
778 REG_EXT_JAPAN_NONDFS_HT40
))
780 && (rd
->conformanceTestLimit
==
785 "channel (en_jap_ht40 "
789 if (IS_HT40_MODE(cm
->mode
) &&
791 (ath9k_regd_get_eeprom_reg_ext_bits
792 (ah
, REG_EXT_JAPAN_DFS_HT40
))
794 && (rd
->conformanceTestLimit
==
798 "Skipping HT40 channel"
799 " (en_jap_dfs_ht40 = "
803 memset(&icv
, 0, sizeof(icv
));
805 icv
.channelFlags
= cm
->flags
;
807 switch (fband
->channelBW
) {
808 case CHANNEL_HALF_BW
:
812 case CHANNEL_QUARTER_BW
:
820 icv
.antennaMax
= fband
->antennaMax
;
821 icv
.regDmnFlags
= rd
->flags
;
822 icv
.conformanceTestLimit
= ctl
;
823 if (fband
->usePassScan
& rd
->pscan
)
829 if (fband
->useDfs
& rd
->dfsMask
)
834 if (rd
->flags
& LIMIT_FRAME_4MS
)
838 if (icv
.privFlags
& CHANNEL_DFS
) {
840 CHANNEL_DISALLOW_ADHOC
;
843 regDmnFlags
& ADHOC_PER_11D
) {
845 CHANNEL_PER_11D_ADHOC
;
848 channelFlags
& CHANNEL_PASSIVE
) {
850 if ((icv
.channel
< 2412)
868 (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN
870 AR_EEPROM_EEREGCAP_EN_KK_U2
872 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND
))
873 && isUNII1OddChan(icv
.channel
)) {
875 icv
.channelFlags
&= ~CHANNEL_PASSIVE
;
877 icv
.privFlags
|= CHANNEL_DISALLOW_ADHOC
;
880 icv
.privFlags
|= CHANNEL_DISALLOW_ADHOC
;
885 mode
& (ATH9K_MODE_SEL_11A
|
886 ATH9K_MODE_SEL_11NA_HT20
888 ATH9K_MODE_SEL_11NA_HT40PLUS
890 ATH9K_MODE_SEL_11NA_HT40MINUS
)) {
894 DISALLOW_ADHOC_11A
)) {
896 CHANNEL_DISALLOW_ADHOC
;
900 memcpy(&ichans
[next
++], &icv
,
902 hal_channel_internal
));
905 if (IS_HT40_MODE(cm
->mode
)
906 && (fband
->lowChannel
== 5280)) {
917 if (next
> ARRAY_SIZE(ah
->ah_channels
)) {
918 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
919 "%s: too many channels %u; truncating to %u\n",
921 (int) ARRAY_SIZE(ah
->ah_channels
));
922 next
= ARRAY_SIZE(ah
->ah_channels
);
924 #ifdef ATH_NF_PER_CHAN
926 ath9k_regd_init_rf_buffer(ichans
, next
);
929 ath9k_regd_sort(ichans
, next
,
930 sizeof(struct hal_channel_internal
),
931 ath9k_regd_chansort
);
934 HDPRINTF(ah
, HAL_DBG_REGULATORY
, "Channel list:\n");
935 for (i
= 0; i
< next
; i
++) {
936 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
937 "chan: %d flags: 0x%x\n",
939 ichans
[i
].channelFlags
);
940 chans
[i
].channel
= ichans
[i
].channel
;
941 chans
[i
].channelFlags
= ichans
[i
].channelFlags
;
942 chans
[i
].privFlags
= ichans
[i
].privFlags
;
943 chans
[i
].maxRegTxPower
= ichans
[i
].maxRegTxPower
;
946 ath9k_hw_get_chip_power_limits(ah
, chans
, next
);
947 for (i
= 0; i
< next
; i
++) {
948 ichans
[i
].maxTxPower
= chans
[i
].maxTxPower
;
949 ichans
[i
].minTxPower
= chans
[i
].minTxPower
;
954 ah
->ah_countryCode
= ah
->ah_countryCode
;
956 ah
->ah_currentRDInUse
= regdmn
;
957 ah
->ah_currentRD5G
= rd5GHz
.regDmnEnum
;
958 ah
->ah_currentRD2G
= rd2GHz
.regDmnEnum
;
959 if (country
== NULL
) {
963 ah
->ah_iso
[0] = country
->isoName
[0];
964 ah
->ah_iso
[1] = country
->isoName
[1];
969 struct hal_channel_internal
*ath9k_regd_check_channel(struct ath_hal
*ah
,
970 const struct hal_channel
*c
)
972 struct hal_channel_internal
*base
, *cc
;
974 int flags
= c
->channelFlags
& CHAN_FLAGS
;
977 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
978 "%s: channel %u/0x%x (0x%x) requested\n", __func__
,
979 c
->channel
, c
->channelFlags
, flags
);
982 if (cc
!= NULL
&& cc
->channel
== c
->channel
&&
983 (cc
->channelFlags
& CHAN_FLAGS
) == flags
) {
984 if ((cc
->privFlags
& CHANNEL_INTERFERENCE
) &&
985 (cc
->privFlags
& CHANNEL_DFS
))
991 base
= ah
->ah_channels
;
994 for (lim
= n
; lim
!= 0; lim
>>= 1) {
996 cc
= &base
[lim
>> 1];
997 d
= c
->channel
- cc
->channel
;
999 if ((cc
->channelFlags
& CHAN_FLAGS
) == flags
) {
1000 if ((cc
->privFlags
& CHANNEL_INTERFERENCE
)
1001 && (cc
->privFlags
& CHANNEL_DFS
))
1006 d
= flags
- (cc
->channelFlags
& CHAN_FLAGS
);
1008 HDPRINTF(ah
, HAL_DBG_REGULATORY
,
1009 "%s: channel %u/0x%x d %d\n", __func__
,
1010 cc
->channel
, cc
->channelFlags
, d
);
1016 HDPRINTF(ah
, HAL_DBG_REGULATORY
, "%s: no match for %u/0x%x\n",
1017 __func__
, c
->channel
, c
->channelFlags
);
1022 ath9k_regd_get_antenna_allowed(struct ath_hal
*ah
,
1023 struct hal_channel
*chan
)
1025 struct hal_channel_internal
*ichan
= NULL
;
1027 ichan
= ath9k_regd_check_channel(ah
, chan
);
1031 return ichan
->antennaMax
;
1034 u_int
ath9k_regd_get_ctl(struct ath_hal
*ah
, struct hal_channel
*chan
)
1037 struct hal_channel_internal
*ichan
;
1039 if (ah
->ah_countryCode
== CTRY_DEFAULT
&& isWwrSKU(ah
)) {
1040 if (IS_CHAN_B(chan
))
1041 ctl
= SD_NO_CTL
| CTL_11B
;
1042 else if (IS_CHAN_G(chan
))
1043 ctl
= SD_NO_CTL
| CTL_11G
;
1045 ctl
= SD_NO_CTL
| CTL_11A
;
1047 ichan
= ath9k_regd_check_channel(ah
, chan
);
1048 if (ichan
!= NULL
) {
1049 ctl
= ichan
->conformanceTestLimit
;
1051 if (IS_CHAN_PUREG(chan
) && (ctl
& 0xf) == CTL_11B
)
1052 ctl
= (ctl
& ~0xf) | CTL_11G
;
1058 void ath9k_regd_get_current_country(struct ath_hal
*ah
,
1059 struct hal_country_entry
*ctry
)
1061 u_int16_t rd
= ath9k_regd_get_eepromRD(ah
);
1063 ctry
->isMultidomain
= AH_FALSE
;
1064 if (rd
== CTRY_DEFAULT
)
1065 ctry
->isMultidomain
= AH_TRUE
;
1066 else if (!(rd
& COUNTRY_ERD_FLAG
))
1067 ctry
->isMultidomain
= isWwrSKU(ah
);
1069 ctry
->countryCode
= ah
->ah_countryCode
;
1070 ctry
->regDmnEnum
= ah
->ah_currentRD
;
1071 ctry
->regDmn5G
= ah
->ah_currentRD5G
;
1072 ctry
->regDmn2G
= ah
->ah_currentRD2G
;
1073 ctry
->iso
[0] = ah
->ah_iso
[0];
1074 ctry
->iso
[1] = ah
->ah_iso
[1];
1075 ctry
->iso
[2] = ah
->ah_iso
[2];