2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3 * Copyright (c) 2005-2006 Atheros Communications, Inc.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 #include <net80211/_ieee80211.h>
25 #include <net80211/ieee80211_regdomain.h>
27 #include "ah_internal.h"
28 #include "ah_eeprom.h"
31 #include "ah_regdomain.h"
34 * XXX this code needs a audit+review
37 /* used throughout this file... */
38 #define N(a) (sizeof (a) / sizeof (a[0]))
40 #define HAL_MODE_11A_TURBO HAL_MODE_108A
41 #define HAL_MODE_11G_TURBO HAL_MODE_108G
44 * Mask to check whether a domain is a multidomain or a single domain
46 #define MULTI_DOMAIN_MASK 0xFF00
49 * Enumerated Regulatory Domain Information 8 bit values indicate that
50 * the regdomain is really a pair of unitary regdomains. 12 bit values
51 * are the real unitary regdomains and are the only ones which have the
52 * frequency bitmasks and flags set.
54 #include "ah_regdomain/ah_rd_regenum.h"
56 #define WORLD_SKU_MASK 0x00F0
57 #define WORLD_SKU_PREFIX 0x0060
60 * THE following table is the mapping of regdomain pairs specified by
61 * an 8 bit regdomain value to the individual unitary reg domains
63 #include "ah_regdomain/ah_rd_regmap.h"
66 * The following tables are the master list for all different freqeuncy
67 * bands with the complete matrix of all possible flags and settings
68 * for each band if it is used in ANY reg domain.
71 #define COUNTRY_ERD_FLAG 0x8000
72 #define WORLDWIDE_ROAMING_FLAG 0x4000
75 * This table maps country ISO codes from net80211 into regulatory
76 * domains which the ath regulatory domain code understands.
78 #include "ah_regdomain/ah_rd_ctry.h"
81 * The frequency band collections are a set of frequency ranges
82 * with shared properties - max tx power, max antenna gain, channel width,
83 * channel spacing, DFS requirements and passive scanning requirements.
85 * These are represented as entries in a frequency band bitmask.
86 * Each regulatory domain entry in ah_regdomain_domains.h uses one
87 * or more frequency band entries for each of the channel modes
88 * supported (11bg, 11a, half, quarter, turbo, etc.)
91 #include "ah_regdomain/ah_rd_freqbands.h"
94 * This is the main regulatory database. It defines the supported
95 * set of features and requirements for each of the defined regulatory
96 * zones. It uses combinations of frequency ranges - represented in
97 * a bitmask - to determine the requirements and limitations needed.
99 #include "ah_regdomain/ah_rd_domains.h"
101 static const struct cmode modes[] = {
102 { HAL_MODE_TURBO, IEEE80211_CHAN_ST },
103 { HAL_MODE_11A, IEEE80211_CHAN_A },
104 { HAL_MODE_11B, IEEE80211_CHAN_B },
105 { HAL_MODE_11G, IEEE80211_CHAN_G },
106 { HAL_MODE_11G_TURBO, IEEE80211_CHAN_108G },
107 { HAL_MODE_11A_TURBO, IEEE80211_CHAN_108A },
108 { HAL_MODE_11A_QUARTER_RATE,
109 IEEE80211_CHAN_A | IEEE80211_CHAN_QUARTER },
110 { HAL_MODE_11A_HALF_RATE,
111 IEEE80211_CHAN_A | IEEE80211_CHAN_HALF },
112 { HAL_MODE_11G_QUARTER_RATE,
113 IEEE80211_CHAN_G | IEEE80211_CHAN_QUARTER },
114 { HAL_MODE_11G_HALF_RATE,
115 IEEE80211_CHAN_G | IEEE80211_CHAN_HALF },
116 { HAL_MODE_11NG_HT20, IEEE80211_CHAN_G | IEEE80211_CHAN_HT20 },
117 { HAL_MODE_11NG_HT40PLUS,
118 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U },
119 { HAL_MODE_11NG_HT40MINUS,
120 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D },
121 { HAL_MODE_11NA_HT20, IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 },
122 { HAL_MODE_11NA_HT40PLUS,
123 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U },
124 { HAL_MODE_11NA_HT40MINUS,
125 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D },
128 static void ath_hal_update_dfsdomain(struct ath_hal *ah);
130 static OS_INLINE uint16_t
131 getEepromRD(struct ath_hal *ah)
133 return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG;
137 * Test to see if the bitmask array is all zeros
140 isChanBitMaskZero(const uint64_t *bitmask)
143 #error "add more cases"
149 return (bitmask[0] == 0);
153 * Return whether or not the regulatory domain/country in EEPROM
157 isEepromValid(struct ath_hal *ah)
159 uint16_t rd = getEepromRD(ah);
162 if (rd & COUNTRY_ERD_FLAG) {
163 uint16_t cc = rd &~ COUNTRY_ERD_FLAG;
164 for (i = 0; i < N(allCountries); i++)
165 if (allCountries[i].countryCode == cc)
168 for (i = 0; i < N(regDomainPairs); i++)
169 if (regDomainPairs[i].regDmnEnum == rd)
173 if (rd == FCC_UBNT) {
177 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
178 "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd);
183 * Find the pointer to the country element in the country table
184 * corresponding to the country code
186 static COUNTRY_CODE_TO_ENUM_RD*
187 findCountry(HAL_CTRY_CODE countryCode)
191 for (i = 0; i < N(allCountries); i++) {
192 if (allCountries[i].countryCode == countryCode)
193 return &allCountries[i];
199 findRegDmn(int regDmn)
203 for (i = 0; i < N(regDomains); i++) {
204 if (regDomains[i].regDmnEnum == regDmn)
205 return ®Domains[i];
210 static REG_DMN_PAIR_MAPPING *
211 findRegDmnPair(int regDmnPair)
215 if (regDmnPair != NO_ENUMRD) {
216 for (i = 0; i < N(regDomainPairs); i++) {
217 if (regDomainPairs[i].regDmnEnum == regDmnPair)
218 return ®DomainPairs[i];
225 * Calculate a default country based on the EEPROM setting.
228 getDefaultCountry(struct ath_hal *ah)
230 REG_DMN_PAIR_MAPPING *regpair;
233 rd = getEepromRD(ah);
234 if (rd & COUNTRY_ERD_FLAG) {
235 COUNTRY_CODE_TO_ENUM_RD *country;
236 uint16_t cc = rd & ~COUNTRY_ERD_FLAG;
237 country = findCountry(cc);
238 if (country != AH_NULL)
242 * Check reg domains that have only one country
244 regpair = findRegDmnPair(rd);
245 return (regpair != AH_NULL) ? regpair->singleCC : CTRY_DEFAULT;
249 IS_BIT_SET(int bit, const uint64_t bitmask[])
251 int byteOffset, bitnum;
255 bitnum = bit - byteOffset*64;
256 val = ((uint64_t) 1) << bitnum;
257 return (bitmask[byteOffset] & val) != 0;
261 getregstate(struct ath_hal *ah, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
262 COUNTRY_CODE_TO_ENUM_RD **pcountry,
263 REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
265 COUNTRY_CODE_TO_ENUM_RD *country;
266 REG_DOMAIN *rd5GHz, *rd2GHz;
268 if (cc == CTRY_DEFAULT && regDmn == SKU_NONE) {
270 * Validate the EEPROM setting and setup defaults
272 if (!isEepromValid(ah)) {
274 * Don't return any channels if the EEPROM has an
275 * invalid regulatory domain/country code setting.
277 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
278 "%s: invalid EEPROM contents\n",__func__);
282 cc = getDefaultCountry(ah);
283 country = findCountry(cc);
284 if (country == AH_NULL) {
285 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
286 "NULL Country!, cc %d\n", cc);
289 regDmn = country->regDmnEnum;
290 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: EEPROM cc %u rd 0x%x\n",
291 __func__, cc, regDmn);
293 if (country->countryCode == CTRY_DEFAULT) {
295 * Check EEPROM; SKU may be for a country, single
296 * domain, or multiple domains (WWR).
298 uint16_t rdnum = getEepromRD(ah);
299 if ((rdnum & COUNTRY_ERD_FLAG) == 0 &&
300 (findRegDmn(rdnum) != AH_NULL ||
301 findRegDmnPair(rdnum) != AH_NULL)) {
303 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
304 "%s: EEPROM rd 0x%x\n", __func__, rdnum);
308 country = findCountry(cc);
309 if (country == AH_NULL) {
310 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
311 "unknown country, cc %d\n", cc);
314 if (regDmn == SKU_NONE)
315 regDmn = country->regDmnEnum;
316 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u rd 0x%x\n",
317 __func__, cc, regDmn);
321 * Setup per-band state.
323 if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
324 REG_DMN_PAIR_MAPPING *regpair = findRegDmnPair(regDmn);
325 if (regpair == AH_NULL) {
326 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
327 "%s: no reg domain pair %u for country %u\n",
328 __func__, regDmn, country->countryCode);
331 rd5GHz = findRegDmn(regpair->regDmn5GHz);
332 if (rd5GHz == AH_NULL) {
333 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
334 "%s: no 5GHz reg domain %u for country %u\n",
335 __func__, regpair->regDmn5GHz, country->countryCode);
338 rd2GHz = findRegDmn(regpair->regDmn2GHz);
339 if (rd2GHz == AH_NULL) {
340 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
341 "%s: no 2GHz reg domain %u for country %u\n",
342 __func__, regpair->regDmn2GHz, country->countryCode);
346 rd5GHz = rd2GHz = findRegDmn(regDmn);
347 if (rd2GHz == AH_NULL) {
348 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
349 "%s: no unitary reg domain %u for country %u\n",
350 __func__, regDmn, country->countryCode);
354 if (pcountry != AH_NULL)
362 * Construct the channel list for the specified regulatory config.
365 getchannels(struct ath_hal *ah,
366 struct ieee80211_channel chans[], u_int maxchans, int *nchans,
367 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
368 HAL_BOOL enableExtendedChannels,
369 COUNTRY_CODE_TO_ENUM_RD **pcountry,
370 REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
372 #define CHANNEL_HALF_BW 10
373 #define CHANNEL_QUARTER_BW 5
374 #define HAL_MODE_11A_ALL \
375 (HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \
376 HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE)
377 REG_DOMAIN *rd5GHz, *rd2GHz;
379 const struct cmode *cm;
380 struct ieee80211_channel *ic;
384 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n",
385 __func__, cc, regDmn, modeSelect,
386 enableExtendedChannels ? " ecm" : "");
388 status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz);
389 if (status != HAL_OK)
392 /* get modes that HW is capable of */
393 modesAvail = ath_hal_getWirelessModes(ah);
394 /* optimize work below if no 11a channels */
395 if (isChanBitMaskZero(rd5GHz->chan11a) &&
396 (modesAvail & HAL_MODE_11A_ALL)) {
397 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
398 "%s: disallow all 11a\n", __func__);
399 modesAvail &= ~HAL_MODE_11A_ALL;
404 for (cm = modes; cm < &modes[N(modes)]; cm++) {
405 uint16_t c, c_hi, c_lo;
406 uint64_t *channelBM = AH_NULL;
407 REG_DMN_FREQ_BAND *fband = AH_NULL,*freqs;
408 int low_adj, hi_adj, channelSep, lastc;
413 if ((cm->mode & modeSelect) == 0) {
414 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
415 "%s: skip mode 0x%x flags 0x%x\n",
416 __func__, cm->mode, cm->flags);
419 if ((cm->mode & modesAvail) == 0) {
420 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
421 "%s: !avail mode 0x%x (0x%x) flags 0x%x\n",
422 __func__, modesAvail, cm->mode, cm->flags);
425 if (!ath_hal_getChannelEdges(ah, cm->flags, &c_lo, &c_hi)) {
426 /* channel not supported by hardware, skip it */
427 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
428 "%s: channels 0x%x not supported by hardware\n",
434 case HAL_MODE_11A_TURBO:
435 rdflags = rd5GHz->flags;
436 dfsMask = rd5GHz->dfsMask;
437 pscan = rd5GHz->pscan;
438 if (cm->mode == HAL_MODE_TURBO)
439 channelBM = rd5GHz->chan11a_turbo;
441 channelBM = rd5GHz->chan11a_dyn_turbo;
442 freqs = ®Dmn5GhzTurboFreq[0];
444 case HAL_MODE_11G_TURBO:
445 rdflags = rd2GHz->flags;
446 dfsMask = rd2GHz->dfsMask;
447 pscan = rd2GHz->pscan;
448 channelBM = rd2GHz->chan11g_turbo;
449 freqs = ®Dmn2Ghz11gTurboFreq[0];
452 case HAL_MODE_11A_HALF_RATE:
453 case HAL_MODE_11A_QUARTER_RATE:
454 case HAL_MODE_11NA_HT20:
455 case HAL_MODE_11NA_HT40PLUS:
456 case HAL_MODE_11NA_HT40MINUS:
457 rdflags = rd5GHz->flags;
458 dfsMask = rd5GHz->dfsMask;
459 pscan = rd5GHz->pscan;
460 if (cm->mode == HAL_MODE_11A_HALF_RATE)
461 channelBM = rd5GHz->chan11a_half;
462 else if (cm->mode == HAL_MODE_11A_QUARTER_RATE)
463 channelBM = rd5GHz->chan11a_quarter;
465 channelBM = rd5GHz->chan11a;
466 freqs = ®Dmn5GhzFreq[0];
470 case HAL_MODE_11G_HALF_RATE:
471 case HAL_MODE_11G_QUARTER_RATE:
472 case HAL_MODE_11NG_HT20:
473 case HAL_MODE_11NG_HT40PLUS:
474 case HAL_MODE_11NG_HT40MINUS:
475 rdflags = rd2GHz->flags;
476 dfsMask = rd2GHz->dfsMask;
477 pscan = rd2GHz->pscan;
478 if (cm->mode == HAL_MODE_11G_HALF_RATE)
479 channelBM = rd2GHz->chan11g_half;
480 else if (cm->mode == HAL_MODE_11G_QUARTER_RATE)
481 channelBM = rd2GHz->chan11g_quarter;
482 else if (cm->mode == HAL_MODE_11B)
483 channelBM = rd2GHz->chan11b;
485 channelBM = rd2GHz->chan11g;
486 if (cm->mode == HAL_MODE_11B)
487 freqs = ®Dmn2GhzFreq[0];
489 freqs = ®Dmn2Ghz11gFreq[0];
492 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
493 "%s: Unknown HAL mode 0x%x\n", __func__, cm->mode);
496 if (isChanBitMaskZero(channelBM))
499 * Setup special handling for HT40 channels; e.g.
500 * 5G HT40 channels require 40Mhz channel separation.
502 hi_adj = (cm->mode == HAL_MODE_11NA_HT40PLUS ||
503 cm->mode == HAL_MODE_11NG_HT40PLUS) ? -20 : 0;
504 low_adj = (cm->mode == HAL_MODE_11NA_HT40MINUS ||
505 cm->mode == HAL_MODE_11NG_HT40MINUS) ? 20 : 0;
506 channelSep = (cm->mode == HAL_MODE_11NA_HT40PLUS ||
507 cm->mode == HAL_MODE_11NA_HT40MINUS) ? 40 : 0;
509 for (b = 0; b < 64*BMLEN; b++) {
510 if (!IS_BIT_SET(b, channelBM))
515 for (c = fband->lowChannel + low_adj;
516 c <= fband->highChannel + hi_adj;
517 c += fband->channelSep) {
518 if (!(c_lo <= c && c <= c_hi)) {
519 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
520 "%s: c %u out of range [%u..%u]\n",
521 __func__, c, c_lo, c_hi);
524 if (next >= maxchans){
525 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
526 "%s: too many channels for channel table\n",
530 if ((fband->usePassScan & IS_ECM_CHAN) &&
531 !enableExtendedChannels) {
532 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
533 "skip ecm channel\n");
537 if ((fband->useDfs & dfsMask) &&
538 (cm->flags & IEEE80211_CHAN_HT40)) {
539 /* NB: DFS and HT40 don't mix */
540 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
541 "skip HT40 chan, DFS required\n");
546 * Make sure that channel separation
547 * meets the requirement.
549 if (lastc && channelSep &&
550 (c-lastc) < channelSep)
554 OS_MEMZERO(ic, sizeof(*ic));
556 ic->ic_flags = cm->flags;
557 ic->ic_maxregpower = fband->powerDfs;
558 ath_hal_getpowerlimits(ah, ic);
559 ic->ic_maxantgain = fband->antennaMax;
560 if (fband->usePassScan & pscan)
561 ic->ic_flags |= IEEE80211_CHAN_PASSIVE;
562 if (fband->useDfs & dfsMask)
563 ic->ic_flags |= IEEE80211_CHAN_DFS;
564 if (IEEE80211_IS_CHAN_5GHZ(ic) &&
565 (rdflags & DISALLOW_ADHOC_11A))
566 ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
567 if (IEEE80211_IS_CHAN_TURBO(ic) &&
568 (rdflags & DISALLOW_ADHOC_11A_TURB))
569 ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
570 if (rdflags & NO_HOSTAP)
571 ic->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
572 if (rdflags & LIMIT_FRAME_4MS)
573 ic->ic_flags |= IEEE80211_CHAN_4MSXMIT;
574 if (rdflags & NEED_NFC)
575 ic->ic_flags |= CHANNEL_NFCREQUIRED;
583 /* NB: pcountry set above by getregstate */
584 if (prd2GHz != AH_NULL)
586 if (prd5GHz != AH_NULL)
589 #undef HAL_MODE_11A_ALL
590 #undef CHANNEL_HALF_BW
591 #undef CHANNEL_QUARTER_BW
595 * Retrieve a channel list without affecting runtime state.
598 ath_hal_getchannels(struct ath_hal *ah,
599 struct ieee80211_channel chans[], u_int maxchans, int *nchans,
600 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
601 HAL_BOOL enableExtendedChannels)
603 return getchannels(ah, chans, maxchans, nchans, modeSelect,
604 cc, regDmn, enableExtendedChannels, AH_NULL, AH_NULL, AH_NULL);
608 * Handle frequency mapping from 900Mhz range to 2.4GHz range
609 * for GSM radios. This is done when we need the h/w frequency
610 * and the channel is marked IEEE80211_CHAN_GSM.
613 ath_hal_mapgsm(int sku, int freq)
617 if (sku == SKU_GZ901)
621 if (sku == SKU_XC900M)
623 HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
624 "%s: cannot map freq %u unknown gsm sku %u\n",
625 __func__, freq, sku);
630 * Setup the internal/private channel state given a table of
631 * net80211 channels. We collapse entries for the same frequency
632 * and record the frequency for doing noise floor processing
633 * where we don't have net80211 channel context.
636 assignPrivateChannels(struct ath_hal *ah,
637 struct ieee80211_channel chans[], int nchans, int sku)
639 HAL_CHANNEL_INTERNAL *ic;
640 int i, j, next, freq;
643 for (i = 0; i < nchans; i++) {
644 struct ieee80211_channel *c = &chans[i];
645 for (j = i-1; j >= 0; j--)
646 if (chans[j].ic_freq == c->ic_freq) {
647 c->ic_devdata = chans[j].ic_devdata;
651 /* new entry, assign a private channel entry */
652 if (next >= N(AH_PRIVATE(ah)->ah_channels)) {
653 HALDEBUG(ah, HAL_DEBUG_ANY,
654 "%s: too many channels, max %zu\n",
655 __func__, N(AH_PRIVATE(ah)->ah_channels));
659 * Handle frequency mapping for 900MHz devices.
660 * The hardware uses 2.4GHz frequencies that are
661 * down-converted. The 802.11 layer uses the
664 freq = IEEE80211_IS_CHAN_GSM(c) ?
665 ath_hal_mapgsm(sku, c->ic_freq) : c->ic_freq;
667 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
668 "%s: private[%3u] %u/0x%x -> channel %u\n",
669 __func__, next, c->ic_freq, c->ic_flags, freq);
671 ic = &AH_PRIVATE(ah)->ah_channels[next];
673 * NB: This clears privFlags which means ancillary
674 * code like ANI and IQ calibration will be
675 * restarted and re-setup any per-channel state.
677 OS_MEMZERO(ic, sizeof(*ic));
679 c->ic_devdata = next;
683 AH_PRIVATE(ah)->ah_nchan = next;
684 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: %u public, %u private channels\n",
685 __func__, nchans, next);
690 * Setup the channel list based on the information in the EEPROM.
693 ath_hal_init_channels(struct ath_hal *ah,
694 struct ieee80211_channel chans[], u_int maxchans, int *nchans,
695 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
696 HAL_BOOL enableExtendedChannels)
698 COUNTRY_CODE_TO_ENUM_RD *country;
699 REG_DOMAIN *rd5GHz, *rd2GHz;
702 status = getchannels(ah, chans, maxchans, nchans, modeSelect,
703 cc, regDmn, enableExtendedChannels, &country, &rd2GHz, &rd5GHz);
704 if (status == HAL_OK &&
705 assignPrivateChannels(ah, chans, *nchans, AH_PRIVATE(ah)->ah_currentRD)) {
706 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
707 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
709 ah->ah_countryCode = country->countryCode;
710 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
711 __func__, ah->ah_countryCode);
713 /* Update current DFS domain */
714 ath_hal_update_dfsdomain(ah);
722 * Set the channel list.
725 ath_hal_set_channels(struct ath_hal *ah,
726 struct ieee80211_channel chans[], int nchans,
727 HAL_CTRY_CODE cc, HAL_REG_DOMAIN rd)
729 COUNTRY_CODE_TO_ENUM_RD *country;
730 REG_DOMAIN *rd5GHz, *rd2GHz;
739 * Map 900MHz sku's. The frequencies will be mapped
740 * according to the sku to compensate for the down-converter.
741 * We use the FCC for these sku's as the mapped channel
742 * list is known compatible (will need to change if/when
743 * vendors do different mapping in different locales).
745 status = getregstate(ah, CTRY_DEFAULT, SKU_FCC,
746 &country, &rd2GHz, &rd5GHz);
749 status = getregstate(ah, cc, rd,
750 &country, &rd2GHz, &rd5GHz);
751 rd = AH_PRIVATE(ah)->ah_currentRD;
754 if (status == HAL_OK && assignPrivateChannels(ah, chans, nchans, rd)) {
755 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
756 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
758 ah->ah_countryCode = country->countryCode;
759 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
760 __func__, ah->ah_countryCode);
764 if (status == HAL_OK) {
765 /* Update current DFS domain */
766 (void) ath_hal_update_dfsdomain(ah);
773 * Return the internal channel corresponding to a public channel.
774 * NB: normally this routine is inline'd (see ah_internal.h)
776 HAL_CHANNEL_INTERNAL *
777 ath_hal_checkchannel(struct ath_hal *ah, const struct ieee80211_channel *c)
779 HAL_CHANNEL_INTERNAL *cc = &AH_PRIVATE(ah)->ah_channels[c->ic_devdata];
781 if (c->ic_devdata < AH_PRIVATE(ah)->ah_nchan &&
782 (c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c)))
784 if (c->ic_devdata >= AH_PRIVATE(ah)->ah_nchan) {
785 HALDEBUG(ah, HAL_DEBUG_ANY,
786 "%s: bad mapping, devdata %u nchans %u\n",
787 __func__, c->ic_devdata, AH_PRIVATE(ah)->ah_nchan);
788 HALASSERT(c->ic_devdata < AH_PRIVATE(ah)->ah_nchan);
790 HALDEBUG(ah, HAL_DEBUG_ANY,
791 "%s: no match for %u/0x%x devdata %u channel %u\n",
792 __func__, c->ic_freq, c->ic_flags, c->ic_devdata,
794 HALASSERT(c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c));
798 #endif /* AH_DEBUG */
800 #define isWwrSKU(_ah) \
801 ((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \
802 getEepromRD(_ah) == WORLD)
805 * Return the test group for the specific channel based on
806 * the current regulatory setup.
809 ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c)
813 if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz ||
814 (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)))
816 else if (IEEE80211_IS_CHAN_2GHZ(c))
817 ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit;
819 ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit;
820 if (IEEE80211_IS_CHAN_B(c))
821 return ctl | CTL_11B;
822 if (IEEE80211_IS_CHAN_G(c))
823 return ctl | CTL_11G;
824 if (IEEE80211_IS_CHAN_108G(c))
825 return ctl | CTL_108G;
826 if (IEEE80211_IS_CHAN_TURBO(c))
827 return ctl | CTL_TURBO;
828 if (IEEE80211_IS_CHAN_A(c))
829 return ctl | CTL_11A;
835 * Update the current dfsDomain setting based on the given
838 * Since FreeBSD/net80211 allows the channel set to change
839 * after the card has been setup (via ath_hal_init_channels())
840 * this function method is needed to update ah_dfsDomain.
843 ath_hal_update_dfsdomain(struct ath_hal *ah)
845 const REG_DOMAIN *rd5GHz = AH_PRIVATE(ah)->ah_rd5GHz;
846 HAL_DFS_DOMAIN dfsDomain = HAL_DFS_UNINIT_DOMAIN;
848 if (rd5GHz->dfsMask & DFS_FCC3)
849 dfsDomain = HAL_DFS_FCC_DOMAIN;
850 if (rd5GHz->dfsMask & DFS_ETSI)
851 dfsDomain = HAL_DFS_ETSI_DOMAIN;
852 if (rd5GHz->dfsMask & DFS_MKK4)
853 dfsDomain = HAL_DFS_MKK4_DOMAIN;
854 AH_PRIVATE(ah)->ah_dfsDomain = dfsDomain;
855 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s ah_dfsDomain: %d\n",
856 __func__, AH_PRIVATE(ah)->ah_dfsDomain);
861 * Return the max allowed antenna gain and apply any regulatory
862 * domain specific changes.
864 * NOTE: a negative reduction is possible in RD's that only
865 * measure radiated power (e.g., ETSI) which would increase
866 * that actual conducted output power (though never beyond
867 * the calibrated target power).
870 ath_hal_getantennareduction(struct ath_hal *ah,
871 const struct ieee80211_channel *chan, u_int twiceGain)
873 int8_t antennaMax = twiceGain - chan->ic_maxantgain*2;
874 return (antennaMax < 0) ? 0 : antennaMax;