aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath9k/regd.c
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2009-01-22 18:16:48 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:01:20 -0500
commit5f8e077c0adc0dc7cfad64cdc05276e1961a1394 (patch)
treedc918d9eacab12998d8e67f259de32dbbb409e81 /drivers/net/wireless/ath9k/regd.c
parent24ed1da1337b92e3b0a89f2c2b7cd33b9a8fcb62 (diff)
ath9k: simplify regulatory code
Now that cfg80211 has its own regulatory infrastructure we can condense ath9k's regulatory code considerably. We only keep data we need to provide our own regulatory_hint(), reg_notifier() and information necessary for calibration. Atheros hardware supports 12 world regulatory domains, since these are custom we apply them through the the new wiphy_apply_custom_regulatory(). Although we have 12 we can consolidate these into 5 structures based on frequency and apply a different set of flags that differentiate them on a case by case basis through the reg_notifier(). If CRDA is not found our own custom world regulatory domain is applied, this is identical to cfg80211's except we enable passive scan on most frequencies. Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k/regd.c')
-rw-r--r--drivers/net/wireless/ath9k/regd.c1188
1 files changed, 328 insertions, 860 deletions
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c
index 64043e99facf..90f0c982430c 100644
--- a/drivers/net/wireless/ath9k/regd.c
+++ b/drivers/net/wireless/ath9k/regd.c
@@ -21,174 +21,323 @@
21#include "regd.h" 21#include "regd.h"
22#include "regd_common.h" 22#include "regd_common.h"
23 23
24static int ath9k_regd_chansort(const void *a, const void *b) 24/*
25{ 25 * This is a set of common rules used by our world regulatory domains.
26 const struct ath9k_channel *ca = a; 26 * We have 12 world regulatory domains. To save space we consolidate
27 const struct ath9k_channel *cb = b; 27 * the regulatory domains in 5 structures by frequency and change
28 28 * the flags on our reg_notifier() on a case by case basis.
29 return (ca->channel == cb->channel) ? 29 */
30 (ca->channelFlags & CHAN_FLAGS) -
31 (cb->channelFlags & CHAN_FLAGS) : ca->channel - cb->channel;
32}
33 30
34static void 31/* Only these channels all allow active scan on all world regulatory domains */
35ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp) 32#define ATH9K_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
36{ 33
37 u8 *aa = a; 34/* We enable active scan on these a case by case basis by regulatory domain */
38 u8 *ai, *t; 35#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\
39 36 NL80211_RRF_PASSIVE_SCAN)
40 for (ai = aa + size; --n >= 1; ai += size) 37#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\
41 for (t = ai; t > aa; t -= size) { 38 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
42 u8 *u = t - size; 39
43 if (cmp(u, t) <= 0) 40/* We allow IBSS on these on a case by case basis by regulatory domain */
44 break; 41#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 40, 0, 30,\
45 swap_array(u, t, size); 42 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
46 } 43#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 40, 0, 30,\
47} 44 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
45#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 40, 0, 30,\
46 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
47
48#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \
49 ATH9K_2GHZ_CH12_13, \
50 ATH9K_2GHZ_CH14
51
52#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \
53 ATH9K_5GHZ_5470_5850
54/* This one skips what we call "mid band" */
55#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \
56 ATH9K_5GHZ_5725_5850
57
58/* Can be used for:
59 * 0x60, 0x61, 0x62 */
60static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = {
61 .n_reg_rules = 5,
62 .alpha2 = "99",
63 .reg_rules = {
64 ATH9K_2GHZ_ALL,
65 ATH9K_5GHZ_ALL,
66 }
67};
68
69/* Can be used by 0x63 and 0x65 */
70static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = {
71 .n_reg_rules = 4,
72 .alpha2 = "99",
73 .reg_rules = {
74 ATH9K_2GHZ_CH01_11,
75 ATH9K_2GHZ_CH12_13,
76 ATH9K_5GHZ_NO_MIDBAND,
77 }
78};
79
80/* Can be used by 0x64 only */
81static const struct ieee80211_regdomain ath9k_world_regdom_64 = {
82 .n_reg_rules = 3,
83 .alpha2 = "99",
84 .reg_rules = {
85 ATH9K_2GHZ_CH01_11,
86 ATH9K_5GHZ_NO_MIDBAND,
87 }
88};
89
90/* Can be used by 0x66 and 0x69 */
91static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = {
92 .n_reg_rules = 3,
93 .alpha2 = "99",
94 .reg_rules = {
95 ATH9K_2GHZ_CH01_11,
96 ATH9K_5GHZ_ALL,
97 }
98};
99
100/* Can be used by 0x67, 0x6A and 0x68 */
101static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = {
102 .n_reg_rules = 4,
103 .alpha2 = "99",
104 .reg_rules = {
105 ATH9K_2GHZ_CH01_11,
106 ATH9K_2GHZ_CH12_13,
107 ATH9K_5GHZ_ALL,
108 }
109};
48 110
49static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah) 111static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah)
50{ 112{
51 return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG; 113 return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG;
52} 114}
53 115
54static bool ath9k_regd_is_chan_bm_zero(u64 *bitmask) 116u16 ath9k_regd_get_rd(struct ath_hal *ah)
55{ 117{
56 int i; 118 return ath9k_regd_get_eepromRD(ah);
119}
57 120
58 for (i = 0; i < BMLEN; i++) { 121bool ath9k_is_world_regd(struct ath_hal *ah)
59 if (bitmask[i] != 0) 122{
60 return false; 123 return isWwrSKU(ah);
61 }
62 return true;
63} 124}
64 125
65static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah) 126const struct ieee80211_regdomain *ath9k_default_world_regdomain(void)
66{ 127{
67 u16 rd = ath9k_regd_get_eepromRD(ah); 128 /* this is the most restrictive */
68 int i; 129 return &ath9k_world_regdom_64;
130}
69 131
70 if (rd & COUNTRY_ERD_FLAG) { 132const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hal *ah)
71 u16 cc = rd & ~COUNTRY_ERD_FLAG; 133{
72 for (i = 0; i < ARRAY_SIZE(allCountries); i++) 134 switch (ah->regpair->regDmnEnum) {
73 if (allCountries[i].countryCode == cc) 135 case 0x60:
74 return true; 136 case 0x61:
75 } else { 137 case 0x62:
76 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) 138 return &ath9k_world_regdom_60_61_62;
77 if (regDomainPairs[i].regDmnEnum == rd) 139 case 0x63:
78 return true; 140 case 0x65:
141 return &ath9k_world_regdom_63_65;
142 case 0x64:
143 return &ath9k_world_regdom_64;
144 case 0x66:
145 case 0x69:
146 return &ath9k_world_regdom_66_69;
147 case 0x67:
148 case 0x68:
149 case 0x6A:
150 return &ath9k_world_regdom_67_68_6A;
151 default:
152 WARN_ON(1);
153 return ath9k_default_world_regdomain();
79 } 154 }
80 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
81 "invalid regulatory domain/country code 0x%x\n", rd);
82 return false;
83} 155}
84 156
85static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal *ah) 157/* Enable adhoc on 5 GHz if allowed by 11d */
158static void ath9k_reg_apply_5ghz_adhoc_flags(struct wiphy *wiphy,
159 enum reg_set_by setby)
86{ 160{
87 u32 regcap; 161 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
88 162 struct ath_softc *sc = hw->priv;
89 regcap = ah->ah_caps.reg_cap; 163 struct ieee80211_supported_band *sband;
164 const struct ieee80211_reg_rule *reg_rule;
165 struct ieee80211_channel *ch;
166 unsigned int i;
167 u32 bandwidth = 0;
168 int r;
169
170 if (setby != REGDOM_SET_BY_COUNTRY_IE)
171 return;
172 if (!test_bit(ATH9K_MODE_11A,
173 sc->sc_ah->ah_caps.wireless_modes))
174 return;
90 175
91 if (regcap & AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND) 176 sband = wiphy->bands[IEEE80211_BAND_5GHZ];
92 return true; 177 for (i = 0; i < sband->n_channels; i++) {
93 else 178 ch = &sband->channels[i];
94 return false; 179 r = freq_reg_info(wiphy, ch->center_freq,
180 &bandwidth, &reg_rule);
181 if (r)
182 continue;
183 /* If 11d had a rule for this channel ensure we enable adhoc
184 * if it allows us to use it. Note that we would have disabled
185 * it by applying our static world regdomain by default during
186 * probe */
187 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
188 ch->flags &= ~NL80211_RRF_NO_IBSS;
189 }
95} 190}
96 191
97static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah, 192/* Allows active scan scan on Ch 12 and 13 */
98 u16 cc) 193static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
194 enum reg_set_by setby)
99{ 195{
100 u16 rd; 196 struct ieee80211_supported_band *sband;
101 int i; 197 struct ieee80211_channel *ch;
102 198 const struct ieee80211_reg_rule *reg_rule;
103 if (cc == CTRY_DEFAULT) 199 u32 bandwidth = 0;
104 return true; 200 int r;
105 if (cc == CTRY_DEBUG) 201
106 return true; 202 /* Force passive scan on Channels 12-13 */
203 sband = wiphy->bands[IEEE80211_BAND_2GHZ];
204
205 /* If no country IE has been received always enable active scan
206 * on these channels */
207 if (setby != REGDOM_SET_BY_COUNTRY_IE) {
208 ch = &sband->channels[11]; /* CH 12 */
209 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
210 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
211 ch = &sband->channels[12]; /* CH 13 */
212 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
213 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
214 return;
215 }
107 216
108 rd = ath9k_regd_get_eepromRD(ah); 217 /* If a country IE has been recieved check its rule for this
109 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "EEPROM regdomain 0x%x\n", rd); 218 * channel first before enabling active scan. The passive scan
219 * would have been enforced by the initial probe processing on
220 * our custom regulatory domain. */
110 221
111 if (rd & COUNTRY_ERD_FLAG) { 222 ch = &sband->channels[11]; /* CH 12 */
112 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, 223 r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
113 "EEPROM setting is country code %u\n", 224 if (!r) {
114 rd & ~COUNTRY_ERD_FLAG); 225 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
115 return cc == (rd & ~COUNTRY_ERD_FLAG); 226 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
227 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
116 } 228 }
117 229
118 for (i = 0; i < ARRAY_SIZE(allCountries); i++) { 230 ch = &sband->channels[12]; /* CH 13 */
119 if (cc == allCountries[i].countryCode) { 231 r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
120#ifdef AH_SUPPORT_11D 232 if (!r) {
121 if ((rd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) 233 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
122 return true; 234 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
123#endif 235 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
124 if (allCountries[i].regDmnEnum == rd ||
125 rd == DEBUG_REG_DMN || rd == NO_ENUMRD)
126 return true;
127 }
128 } 236 }
129 return false;
130} 237}
131 238
132static void 239/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
133ath9k_regd_get_wmodes_nreg(struct ath_hal *ah, 240void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
134 struct country_code_to_enum_rd *country,
135 struct regDomain *rd5GHz,
136 unsigned long *modes_allowed)
137{ 241{
138 bitmap_copy(modes_allowed, ah->ah_caps.wireless_modes, ATH9K_MODE_MAX); 242 struct ieee80211_supported_band *sband;
243 struct ieee80211_channel *ch;
244 unsigned int i;
139 245
140 if (test_bit(ATH9K_MODE_11G, ah->ah_caps.wireless_modes) && 246 if (!wiphy->bands[IEEE80211_BAND_5GHZ])
141 (!country->allow11g)) 247 return;
142 clear_bit(ATH9K_MODE_11G, modes_allowed);
143 248
144 if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes) && 249 sband = wiphy->bands[IEEE80211_BAND_5GHZ];
145 (ath9k_regd_is_chan_bm_zero(rd5GHz->chan11a)))
146 clear_bit(ATH9K_MODE_11A, modes_allowed);
147 250
148 if (test_bit(ATH9K_MODE_11NG_HT20, ah->ah_caps.wireless_modes) 251 for (i = 0; i < sband->n_channels; i++) {
149 && (!country->allow11ng20)) 252 ch = &sband->channels[i];
150 clear_bit(ATH9K_MODE_11NG_HT20, modes_allowed); 253 if (ch->center_freq < 5260)
254 continue;
255 if (ch->center_freq > 5700)
256 continue;
257 /* We always enable radar detection/DFS on this
258 * frequency range. Additionally we also apply on
259 * this frequency range:
260 * - If STA mode does not yet have DFS supports disable
261 * active scanning
262 * - If adhoc mode does not support DFS yet then
263 * disable adhoc in the frequency.
264 * - If AP mode does not yet support radar detection/DFS
265 * do not allow AP mode
266 */
267 if (!(ch->flags & IEEE80211_CHAN_DISABLED))
268 ch->flags |= IEEE80211_CHAN_RADAR |
269 IEEE80211_CHAN_NO_IBSS |
270 IEEE80211_CHAN_PASSIVE_SCAN;
271 }
272}
151 273
152 if (test_bit(ATH9K_MODE_11NA_HT20, ah->ah_caps.wireless_modes) 274void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
153 && (!country->allow11na20)) 275{
154 clear_bit(ATH9K_MODE_11NA_HT20, modes_allowed); 276 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
277 struct ath_softc *sc = hw->priv;
278 struct ath_hal *ah = sc->sc_ah;
279
280 switch (ah->regpair->regDmnEnum) {
281 case 0x60:
282 case 0x63:
283 case 0x66:
284 case 0x67:
285 ath9k_reg_apply_5ghz_adhoc_flags(wiphy, setby);
286 break;
287 case 0x68:
288 ath9k_reg_apply_5ghz_adhoc_flags(wiphy, setby);
289 ath9k_reg_apply_active_scan_flags(wiphy, setby);
290 break;
291 }
292 return;
293}
155 294
156 if (test_bit(ATH9K_MODE_11NG_HT40PLUS, ah->ah_caps.wireless_modes) && 295int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
157 (!country->allow11ng40)) 296{
158 clear_bit(ATH9K_MODE_11NG_HT40PLUS, modes_allowed); 297 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
298 struct ath_softc *sc = hw->priv;
159 299
160 if (test_bit(ATH9K_MODE_11NG_HT40MINUS, ah->ah_caps.wireless_modes) && 300 /* We always apply this */
161 (!country->allow11ng40)) 301 ath9k_reg_apply_radar_flags(wiphy);
162 clear_bit(ATH9K_MODE_11NG_HT40MINUS, modes_allowed);
163 302
164 if (test_bit(ATH9K_MODE_11NA_HT40PLUS, ah->ah_caps.wireless_modes) && 303 switch (request->initiator) {
165 (!country->allow11na40)) 304 case REGDOM_SET_BY_DRIVER:
166 clear_bit(ATH9K_MODE_11NA_HT40PLUS, modes_allowed); 305 case REGDOM_SET_BY_INIT:
306 case REGDOM_SET_BY_CORE:
307 case REGDOM_SET_BY_USER:
308 break;
309 case REGDOM_SET_BY_COUNTRY_IE:
310 if (ath9k_is_world_regd(sc->sc_ah))
311 ath9k_reg_apply_world_flags(wiphy, request->initiator);
312 break;
313 }
167 314
168 if (test_bit(ATH9K_MODE_11NA_HT40MINUS, ah->ah_caps.wireless_modes) && 315 return 0;
169 (!country->allow11na40))
170 clear_bit(ATH9K_MODE_11NA_HT40MINUS, modes_allowed);
171} 316}
172 317
173bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah) 318bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah)
174{ 319{
175 u16 rd; 320 u16 rd = ath9k_regd_get_eepromRD(ah);
176 321 int i;
177 rd = ath9k_regd_get_eepromRD(ah);
178 322
179 switch (rd) { 323 if (rd & COUNTRY_ERD_FLAG) {
180 case FCC4_FCCA: 324 /* EEPROM value is a country code */
181 case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG): 325 u16 cc = rd & ~COUNTRY_ERD_FLAG;
182 return true; 326 for (i = 0; i < ARRAY_SIZE(allCountries); i++)
183 case DEBUG_REG_DMN: 327 if (allCountries[i].countryCode == cc)
184 case NO_ENUMRD: 328 return true;
185 if (ah->ah_countryCode == CTRY_UNITED_STATES_FCC49) 329 } else {
186 return true; 330 /* EEPROM value is a regpair value */
187 break; 331 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
332 if (regDomainPairs[i].regDmnEnum == rd)
333 return true;
188 } 334 }
335 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
336 "invalid regulatory domain/country code 0x%x\n", rd);
189 return false; 337 return false;
190} 338}
191 339
340/* EEPROM country code to regpair mapping */
192static struct country_code_to_enum_rd* 341static struct country_code_to_enum_rd*
193ath9k_regd_find_country(u16 countryCode) 342ath9k_regd_find_country(u16 countryCode)
194{ 343{
@@ -201,10 +350,23 @@ ath9k_regd_find_country(u16 countryCode)
201 return NULL; 350 return NULL;
202} 351}
203 352
353/* EEPROM rd code to regpair mapping */
354static struct country_code_to_enum_rd*
355ath9k_regd_find_country_by_rd(int regdmn)
356{
357 int i;
358
359 for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
360 if (allCountries[i].regDmnEnum == regdmn)
361 return &allCountries[i];
362 }
363 return NULL;
364}
365
366/* Returns the map of the EEPROM set RD to a country code */
204static u16 ath9k_regd_get_default_country(struct ath_hal *ah) 367static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
205{ 368{
206 u16 rd; 369 u16 rd;
207 int i;
208 370
209 rd = ath9k_regd_get_eepromRD(ah); 371 rd = ath9k_regd_get_eepromRD(ah);
210 if (rd & COUNTRY_ERD_FLAG) { 372 if (rd & COUNTRY_ERD_FLAG) {
@@ -216,798 +378,104 @@ static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
216 return cc; 378 return cc;
217 } 379 }
218 380
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;
223 else
224 i = ARRAY_SIZE(regDomainPairs);
225 }
226 return CTRY_DEFAULT; 381 return CTRY_DEFAULT;
227} 382}
228 383
229static bool ath9k_regd_is_valid_reg_domain(int regDmn, 384static struct reg_dmn_pair_mapping*
230 struct regDomain *rd) 385ath9k_get_regpair(int regdmn)
231{
232 int i;
233
234 for (i = 0; i < ARRAY_SIZE(regDomains); i++) {
235 if (regDomains[i].regDmnEnum == regDmn) {
236 if (rd != NULL) {
237 memcpy(rd, &regDomains[i],
238 sizeof(struct regDomain));
239 }
240 return true;
241 }
242 }
243 return false;
244}
245
246static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair)
247{ 386{
248 int i; 387 int i;
249 388
250 if (regDmnPair == NO_ENUMRD) 389 if (regdmn == NO_ENUMRD)
251 return false; 390 return NULL;
252 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { 391 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
253 if (regDomainPairs[i].regDmnEnum == regDmnPair) 392 if (regDomainPairs[i].regDmnEnum == regdmn)
254 return true; 393 return &regDomainPairs[i];
255 } 394 }
256 return false; 395 return NULL;
257}
258
259static bool
260ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn,
261 u16 channelFlag, struct regDomain *rd)
262{
263 int i, found;
264 u64 flags = NO_REQ;
265 struct reg_dmn_pair_mapping *regPair = NULL;
266 int regOrg;
267
268 regOrg = regDmn;
269 if (regDmn == CTRY_DEFAULT) {
270 u16 rdnum;
271 rdnum = ath9k_regd_get_eepromRD(ah);
272
273 if (!(rdnum & COUNTRY_ERD_FLAG)) {
274 if (ath9k_regd_is_valid_reg_domain(rdnum, NULL) ||
275 ath9k_regd_is_valid_reg_domainPair(rdnum)) {
276 regDmn = rdnum;
277 }
278 }
279 }
280
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 = &regDomainPairs[i];
286 found = 1;
287 }
288 }
289 if (!found) {
290 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
291 "Failed to find reg domain pair %u\n", regDmn);
292 return false;
293 }
294 if (!(channelFlag & CHANNEL_2GHZ)) {
295 regDmn = regPair->regDmn5GHz;
296 flags = regPair->flags5GHz;
297 }
298 if (channelFlag & CHANNEL_2GHZ) {
299 regDmn = regPair->regDmn2GHz;
300 flags = regPair->flags2GHz;
301 }
302 }
303
304 found = ath9k_regd_is_valid_reg_domain(regDmn, rd);
305 if (!found) {
306 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
307 "Failed to find unitary reg domain %u\n", regDmn);
308 return false;
309 } else {
310 rd->pscan &= regPair->pscanMask;
311 if (((regOrg & MULTI_DOMAIN_MASK) == 0) &&
312 (flags != NO_REQ)) {
313 rd->flags = flags;
314 }
315
316 rd->flags &= (channelFlag & CHANNEL_2GHZ) ?
317 REG_DOMAIN_2GHZ_MASK : REG_DOMAIN_5GHZ_MASK;
318 return true;
319 }
320}
321
322static bool ath9k_regd_is_bit_set(int bit, u64 *bitmask)
323{
324 int byteOffset, bitnum;
325 u64 val;
326
327 byteOffset = bit / 64;
328 bitnum = bit - byteOffset * 64;
329 val = ((u64) 1) << bitnum;
330 if (bitmask[byteOffset] & val)
331 return true;
332 else
333 return false;
334}
335
336static void
337ath9k_regd_add_reg_classid(u8 *regclassids, u32 maxregids,
338 u32 *nregids, u8 regclassid)
339{
340 int i;
341
342 if (regclassid == 0)
343 return;
344
345 for (i = 0; i < maxregids; i++) {
346 if (regclassids[i] == regclassid)
347 return;
348 if (regclassids[i] == 0)
349 break;
350 }
351
352 if (i == maxregids)
353 return;
354 else {
355 regclassids[i] = regclassid;
356 *nregids += 1;
357 }
358
359 return;
360}
361
362static bool
363ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal *ah,
364 enum reg_ext_bitmap bit)
365{
366 return (ah->ah_currentRDExt & (1 << bit)) ? true : false;
367}
368
369#ifdef ATH_NF_PER_CHAN
370
371static void ath9k_regd_init_rf_buffer(struct ath9k_channel *ichans,
372 int nchans)
373{
374 int i, j, next;
375
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;
386 }
387 }
388 }
389}
390#endif
391
392static int ath9k_regd_is_chan_present(struct ath_hal *ah,
393 u16 c)
394{
395 int i;
396
397 for (i = 0; i < 150; i++) {
398 if (!ah->ah_channels[i].channel)
399 return -1;
400 else if (ah->ah_channels[i].channel == c)
401 return i;
402 }
403
404 return -1;
405}
406
407static bool
408ath9k_regd_add_channel(struct ath_hal *ah,
409 u16 c,
410 u16 c_lo,
411 u16 c_hi,
412 u16 maxChan,
413 u8 ctl,
414 int pos,
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)
421{
422 struct ath9k_channel *chan;
423 int ret;
424 u32 channelFlags = 0;
425 u8 privFlags = 0;
426
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",
430 c, c_lo, c_hi);
431 return false;
432 }
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);
437 return false;
438 }
439
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);
444 return false;
445 }
446
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);
450 return false;
451 }
452
453 if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) {
454 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
455 "Skipping ecm channel\n");
456 return false;
457 }
458
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");
462 return false;
463 }
464
465 if (IS_HT40_MODE(cm->mode) &&
466 !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_FCC_DFS_HT40)) &&
467 (fband->useDfs) &&
468 (rd->conformanceTestLimit != MKK)) {
469 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
470 "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n");
471 return false;
472 }
473
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");
480 return false;
481 }
482
483 if (IS_HT40_MODE(cm->mode) &&
484 !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_JAPAN_DFS_HT40)) &&
485 (fband->useDfs) &&
486 (rd->conformanceTestLimit == MKK)) {
487 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
488 "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n");
489 return false;
490 }
491
492 /* Calculate channel flags */
493
494 channelFlags = cm->flags;
495
496 switch (fband->channelBW) {
497 case CHANNEL_HALF_BW:
498 channelFlags |= CHANNEL_HALF;
499 break;
500 case CHANNEL_QUARTER_BW:
501 channelFlags |= CHANNEL_QUARTER;
502 break;
503 }
504
505 if (fband->usePassScan & rd->pscan)
506 channelFlags |= CHANNEL_PASSIVE;
507 else
508 channelFlags &= ~CHANNEL_PASSIVE;
509 if (fband->useDfs & rd->dfsMask)
510 privFlags = CHANNEL_DFS;
511 else
512 privFlags = 0;
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;
519
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;
525 if (!(regcap &
526 (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
527 AR_EEPROM_EEREGCAP_EN_KK_U2 |
528 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) &&
529 isUNII1OddChan(c)) {
530 channelFlags &= ~CHANNEL_PASSIVE;
531 } else {
532 privFlags |= CHANNEL_DISALLOW_ADHOC;
533 }
534 } else {
535 privFlags |= CHANNEL_DISALLOW_ADHOC;
536 }
537 }
538 }
539
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;
546 }
547
548 /* Fill in channel details */
549
550 ret = ath9k_regd_is_chan_present(ah, c);
551 if (ret == -1) {
552 chan = &ah->ah_channels[pos];
553 chan->channel = c;
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;
561 } else {
562 chan = &ah->ah_channels[ret];
563 chan->channelFlags |= channelFlags;
564 chan->privFlags |= privFlags;
565 }
566
567 /* Set CTLs */
568
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;
575
576 return (ret == -1) ? true : false;
577}
578
579static bool ath9k_regd_japan_check(struct ath_hal *ah,
580 int b,
581 struct regDomain *rd5GHz)
582{
583 bool skipband = false;
584 int i;
585 u32 regcap;
586
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) {
591 skipband = true;
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;
596 }
597 break;
598 }
599 }
600
601 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
602 "Skipping %d freq band\n", j_bandcheck[i].freqbandbit);
603
604 return skipband;
605} 396}
606 397
607bool 398int ath9k_regd_init(struct ath_hal *ah)
608ath9k_regd_init_channels(struct ath_hal *ah,
609 u32 maxchans,
610 u32 *nchans, u8 *regclassids,
611 u32 maxregids, u32 *nregids, u16 cc,
612 bool enableOutdoor,
613 bool enableExtendedChannels)
614{ 399{
615 u16 maxChan = 7000;
616 struct country_code_to_enum_rd *country = NULL; 400 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];
620 int next = 0, b;
621 u8 ctl;
622 int regdmn; 401 int regdmn;
623 u16 chanSep;
624 unsigned long *modes_avail;
625 DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX);
626
627 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "cc %u %s %s\n", cc,
628 enableOutdoor ? "Enable outdoor" : "",
629 enableExtendedChannels ? "Enable ecm" : "");
630
631 if (!ath9k_regd_is_ccode_valid(ah, cc)) {
632 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
633 "Invalid country code %d\n", cc);
634 return false;
635 }
636 402
637 if (!ath9k_regd_is_eeprom_valid(ah)) { 403 if (!ath9k_regd_is_eeprom_valid(ah)) {
638 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, 404 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
639 "Invalid EEPROM contents\n"); 405 "Invalid EEPROM contents\n");
640 return false; 406 return -EINVAL;
641 } 407 }
642 408
643 ah->ah_countryCode = ath9k_regd_get_default_country(ah); 409 ah->ah_countryCode = ath9k_regd_get_default_country(ah);
644 410
645 if (ah->ah_countryCode == CTRY_DEFAULT) { 411 if (ah->ah_countryCode == CTRY_DEFAULT &&
646 ah->ah_countryCode = cc & COUNTRY_CODE_MASK; 412 ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)
647 if ((ah->ah_countryCode == CTRY_DEFAULT) && 413 ah->ah_countryCode = CTRY_UNITED_STATES;
648 (ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)) {
649 ah->ah_countryCode = CTRY_UNITED_STATES;
650 }
651 }
652 414
653#ifdef AH_SUPPORT_11D
654 if (ah->ah_countryCode == CTRY_DEFAULT) { 415 if (ah->ah_countryCode == CTRY_DEFAULT) {
655 regdmn = ath9k_regd_get_eepromRD(ah); 416 regdmn = ath9k_regd_get_eepromRD(ah);
656 country = NULL; 417 country = NULL;
657 } else { 418 } else {
658#endif
659 country = ath9k_regd_find_country(ah->ah_countryCode); 419 country = ath9k_regd_find_country(ah->ah_countryCode);
660 if (country == NULL) { 420 if (country == NULL) {
661 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, 421 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
662 "Country is NULL!!!!, cc= %d\n", 422 "Country is NULL!!!!, cc= %d\n",
663 ah->ah_countryCode); 423 ah->ah_countryCode);
664 return false; 424 return -EINVAL;
665 } else { 425 } else
666 regdmn = country->regDmnEnum; 426 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))
673 regdmn = FCC3_FCCA;
674 else
675 regdmn = FCC1_FCCA;
676 }
677#endif
678 }
679#ifdef AH_SUPPORT_11D
680 }
681#endif
682 if (!ath9k_regd_get_wmode_regdomain(ah,
683 regdmn,
684 ~CHANNEL_2GHZ,
685 &rd5GHz)) {
686 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
687 "Couldn't find unitary "
688 "5GHz reg domain for country %u\n",
689 ah->ah_countryCode);
690 return false;
691 }
692 if (!ath9k_regd_get_wmode_regdomain(ah,
693 regdmn,
694 CHANNEL_2GHZ,
695 &rd2GHz)) {
696 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
697 "Couldn't find unitary 2GHz "
698 "reg domain for country %u\n",
699 ah->ah_countryCode);
700 return false;
701 } 427 }
702 428
703 if (!isWwrSKU(ah) && ((rd5GHz.regDmnEnum == FCC1) || 429 ah->ah_currentRDInUse = regdmn;
704 (rd5GHz.regDmnEnum == FCC2))) { 430 ah->regpair = ath9k_get_regpair(regdmn);
705 if (ath9k_regd_is_fcc_midband_supported(ah)) {
706 if (!ath9k_regd_get_wmode_regdomain(ah,
707 FCC3_FCCA,
708 ~CHANNEL_2GHZ,
709 &rd5GHz)) {
710 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
711 "Couldn't find unitary 5GHz "
712 "reg domain for country %u\n",
713 ah->ah_countryCode);
714 return false;
715 }
716 }
717 }
718
719 if (country == NULL) {
720 modes_avail = ah->ah_caps.wireless_modes;
721 } else {
722 ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz, modes_allowed);
723 modes_avail = modes_allowed;
724
725 if (!enableOutdoor)
726 maxChan = country->outdoorChanStart;
727 }
728
729 next = 0;
730
731 if (maxchans > ARRAY_SIZE(ah->ah_channels))
732 maxchans = ARRAY_SIZE(ah->ah_channels);
733
734 for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) {
735 u16 c, c_hi, c_lo;
736 u64 *channelBM = NULL;
737 struct regDomain *rd = NULL;
738 struct RegDmnFreqBand *fband = NULL, *freqs;
739 int8_t low_adj = 0, hi_adj = 0;
740
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);
745 continue;
746 }
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);
751 continue;
752 }
753
754 switch (cm->mode) {
755 case ATH9K_MODE_11A:
756 case ATH9K_MODE_11NA_HT20:
757 case ATH9K_MODE_11NA_HT40PLUS:
758 case ATH9K_MODE_11NA_HT40MINUS:
759 rd = &rd5GHz;
760 channelBM = rd->chan11a;
761 freqs = &regDmn5GhzFreq[0];
762 ctl = rd->conformanceTestLimit;
763 break;
764 case ATH9K_MODE_11B:
765 rd = &rd2GHz;
766 channelBM = rd->chan11b;
767 freqs = &regDmn2GhzFreq[0];
768 ctl = rd->conformanceTestLimit | CTL_11B;
769 break;
770 case ATH9K_MODE_11G:
771 case ATH9K_MODE_11NG_HT20:
772 case ATH9K_MODE_11NG_HT40PLUS:
773 case ATH9K_MODE_11NG_HT40MINUS:
774 rd = &rd2GHz;
775 channelBM = rd->chan11g;
776 freqs = &regDmn2Ghz11gFreq[0];
777 ctl = rd->conformanceTestLimit | CTL_11G;
778 break;
779 default:
780 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
781 "Unknown HAL mode 0x%x\n", cm->mode);
782 continue;
783 }
784
785 if (ath9k_regd_is_chan_bm_zero(channelBM))
786 continue;
787
788 if ((cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
789 (cm->mode == ATH9K_MODE_11NG_HT40PLUS)) {
790 hi_adj = -20;
791 }
792
793 if ((cm->mode == ATH9K_MODE_11NA_HT40MINUS) ||
794 (cm->mode == ATH9K_MODE_11NG_HT40MINUS)) {
795 low_adj = 20;
796 }
797
798 /* XXX: Add a helper here instead */
799 for (b = 0; b < 64 * BMLEN; b++) {
800 if (ath9k_regd_is_bit_set(b, channelBM)) {
801 fband = &freqs[b];
802 if (rd5GHz.regDmnEnum == MKK1
803 || rd5GHz.regDmnEnum == MKK2) {
804 if (ath9k_regd_japan_check(ah,
805 b,
806 &rd5GHz))
807 continue;
808 }
809
810 ath9k_regd_add_reg_classid(regclassids,
811 maxregids,
812 nregids,
813 fband->
814 regClassId);
815
816 if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) {
817 chanSep = 40;
818 if (fband->lowChannel == 5280)
819 low_adj += 20;
820
821 if (fband->lowChannel == 5170)
822 continue;
823 } else
824 chanSep = fband->channelSep;
825
826 for (c = fband->lowChannel + low_adj;
827 ((c <= (fband->highChannel + hi_adj)) &&
828 (c >= (fband->lowChannel + low_adj)));
829 c += chanSep) {
830 if (next >= maxchans) {
831 DPRINTF(ah->ah_sc,
832 ATH_DBG_REGULATORY,
833 "too many channels "
834 "for channel table\n");
835 goto done;
836 }
837 if (ath9k_regd_add_channel(ah,
838 c, c_lo, c_hi,
839 maxChan, ctl,
840 next,
841 rd5GHz,
842 fband, rd, cm,
843 ichans,
844 enableExtendedChannels))
845 next++;
846 }
847 if (IS_HT40_MODE(cm->mode) &&
848 (fband->lowChannel == 5280)) {
849 low_adj -= 20;
850 }
851 }
852 }
853 }
854done:
855 if (next != 0) {
856 int i;
857 431
858 if (next > ARRAY_SIZE(ah->ah_channels)) { 432 if (!ah->regpair) {
859 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, 433 DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
860 "too many channels %u; truncating to %u\n", 434 "No regulatory domain pair found, cannot continue\n");
861 next, (int) ARRAY_SIZE(ah->ah_channels)); 435 return -EINVAL;
862 next = ARRAY_SIZE(ah->ah_channels);
863 }
864#ifdef ATH_NF_PER_CHAN
865 ath9k_regd_init_rf_buffer(ichans, next);
866#endif
867 ath9k_regd_sort(ichans, next,
868 sizeof(struct ath9k_channel),
869 ath9k_regd_chansort);
870
871 ah->ah_nchan = next;
872
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);
879 }
880 } 436 }
881 *nchans = next;
882 437
883 ah->ah_countryCode = ah->ah_countryCode; 438 if (!country)
439 country = ath9k_regd_find_country_by_rd(regdmn);
884 440
885 ah->ah_currentRDInUse = regdmn; 441 if (country) {
886 ah->ah_currentRD5G = rd5GHz.regDmnEnum; 442 ah->alpha2[0] = country->isoName[0];
887 ah->ah_currentRD2G = rd2GHz.regDmnEnum; 443 ah->alpha2[1] = country->isoName[1];
888 if (country == NULL) {
889 ah->ah_iso[0] = 0;
890 ah->ah_iso[1] = 0;
891 } else { 444 } else {
892 ah->ah_iso[0] = country->isoName[0]; 445 ah->alpha2[0] = '0';
893 ah->ah_iso[1] = country->isoName[1]; 446 ah->alpha2[1] = '0';
894 } 447 }
895 448
896 return next != 0;
897}
898
899struct ath9k_channel*
900ath9k_regd_check_channel(struct ath_hal *ah,
901 const struct ath9k_channel *c)
902{
903 struct ath9k_channel *base, *cc;
904
905 int flags = c->channelFlags & CHAN_FLAGS;
906 int n, lim;
907
908 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, 449 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
909 "channel %u/0x%x (0x%x) requested\n", 450 "Country alpha2 being used: %c%c\n",
910 c->channel, c->channelFlags, flags); 451 "Regpair detected: 0x%0x\n",
911 452 ah->alpha2[0], ah->alpha2[1],
912 cc = ah->ah_curchan; 453 ah->regpair->regDmnEnum);
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))
917 return NULL;
918 else
919 return cc;
920 }
921 454
922 base = ah->ah_channels; 455 return 0;
923 n = ah->ah_nchan;
924
925 for (lim = n; lim != 0; lim >>= 1) {
926 int d;
927 cc = &base[lim >> 1];
928 d = c->channel - cc->channel;
929 if (d == 0) {
930 if ((cc->channelFlags & CHAN_FLAGS) == flags) {
931 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
932 (cc->privFlags & CHANNEL_DFS))
933 return NULL;
934 else
935 return cc;
936 }
937 d = flags - (cc->channelFlags & CHAN_FLAGS);
938 }
939 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
940 "channel %u/0x%x d %d\n",
941 cc->channel, cc->channelFlags, d);
942 if (d > 0) {
943 base = cc + 1;
944 lim--;
945 }
946 }
947 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "no match for %u/0x%x\n",
948 c->channel, c->channelFlags);
949 return NULL;
950}
951
952u32
953ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
954 struct ath9k_channel *chan)
955{
956 struct ath9k_channel *ichan = NULL;
957
958 ichan = ath9k_regd_check_channel(ah, chan);
959 if (!ichan)
960 return 0;
961
962 return ichan->antennaMax;
963} 456}
964 457
965u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan) 458u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
966{ 459{
967 u32 ctl = NO_CTL; 460 u32 ctl = NO_CTL;
968 struct ath9k_channel *ichan;
969 461
970 if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) { 462 if (!ah->regpair ||
463 (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah))) {
971 if (IS_CHAN_B(chan)) 464 if (IS_CHAN_B(chan))
972 ctl = SD_NO_CTL | CTL_11B; 465 ctl = SD_NO_CTL | CTL_11B;
973 else if (IS_CHAN_G(chan)) 466 else if (IS_CHAN_G(chan))
974 ctl = SD_NO_CTL | CTL_11G; 467 ctl = SD_NO_CTL | CTL_11G;
975 else 468 else
976 ctl = SD_NO_CTL | CTL_11A; 469 ctl = SD_NO_CTL | CTL_11A;
977 } else { 470 return ctl;
978 ichan = ath9k_regd_check_channel(ah, chan);
979 if (ichan != NULL) {
980 /* FIXME */
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];
987
988 if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B)
989 ctl = (ctl & ~0xf) | CTL_11G;
990 }
991 } 471 }
992 return ctl;
993}
994 472
995void ath9k_regd_get_current_country(struct ath_hal *ah, 473 if (IS_CHAN_B(chan))
996 struct ath9k_country_entry *ctry) 474 ctl = ah->regpair->reg_2ghz_ctl | CTL_11B;
997{ 475 else if (IS_CHAN_G(chan))
998 u16 rd = ath9k_regd_get_eepromRD(ah); 476 ctl = ah->regpair->reg_5ghz_ctl | CTL_11G;
477 else
478 ctl = ah->regpair->reg_5ghz_ctl | CTL_11A;
999 479
1000 ctry->isMultidomain = false; 480 return ctl;
1001 if (rd == CTRY_DEFAULT)
1002 ctry->isMultidomain = true;
1003 else if (!(rd & COUNTRY_ERD_FLAG))
1004 ctry->isMultidomain = isWwrSKU(ah);
1005
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];
1013} 481}