Ejemplo n.º 1
0
Archivo: regd.c Proyecto: E-LLP/n900
u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
{
	u32 ctl = NO_CTL;
	struct ath9k_channel *ichan;

	if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) {
		if (IS_CHAN_B(chan))
			ctl = SD_NO_CTL | CTL_11B;
		else if (IS_CHAN_G(chan))
			ctl = SD_NO_CTL | CTL_11G;
		else
			ctl = SD_NO_CTL | CTL_11A;
	} else {
		ichan = ath9k_regd_check_channel(ah, chan);
		if (ichan != NULL) {
			/* FIXME */
			if (IS_CHAN_A(ichan))
				ctl = ichan->conformanceTestLimit[0];
			else if (IS_CHAN_B(ichan))
				ctl = ichan->conformanceTestLimit[1];
			else if (IS_CHAN_G(ichan))
				ctl = ichan->conformanceTestLimit[2];

			if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B)
				ctl = (ctl & ~0xf) | CTL_11G;
		}
	}
	return ctl;
}
Ejemplo n.º 2
0
Archivo: regd.c Proyecto: E-LLP/n900
void ath9k_regd_get_current_country(struct ath_hal *ah,
				    struct ath9k_country_entry *ctry)
{
	u16 rd = ath9k_regd_get_eepromRD(ah);

	ctry->isMultidomain = false;
	if (rd == CTRY_DEFAULT)
		ctry->isMultidomain = true;
	else if (!(rd & COUNTRY_ERD_FLAG))
		ctry->isMultidomain = isWwrSKU(ah);

	ctry->countryCode = ah->ah_countryCode;
	ctry->regDmnEnum = ah->ah_currentRD;
	ctry->regDmn5G = ah->ah_currentRD5G;
	ctry->regDmn2G = ah->ah_currentRD2G;
	ctry->iso[0] = ah->ah_iso[0];
	ctry->iso[1] = ah->ah_iso[1];
	ctry->iso[2] = ah->ah_iso[2];
}
Ejemplo n.º 3
0
/*
 * Return the test group for the specific channel based on
 * the current regulatory setup.
 */
u_int
ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c)
{
	u_int ctl;

	if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz ||
	    (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)))
		ctl = SD_NO_CTL;
	else if (IEEE80211_IS_CHAN_2GHZ(c))
		ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit;
	else
		ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit;
	if (IEEE80211_IS_CHAN_B(c))
		return ctl | CTL_11B;
	if (IEEE80211_IS_CHAN_G(c))
		return ctl | CTL_11G;
	if (IEEE80211_IS_CHAN_108G(c))
		return ctl | CTL_108G;
	if (IEEE80211_IS_CHAN_TURBO(c))
		return ctl | CTL_TURBO;
	if (IEEE80211_IS_CHAN_A(c))
		return ctl | CTL_11A;
	return ctl;
}
Ejemplo n.º 4
0
Archivo: regd.c Proyecto: E-LLP/n900
bool
ath9k_regd_init_channels(struct ath_hal *ah,
			 u32 maxchans,
			 u32 *nchans, u8 *regclassids,
			 u32 maxregids, u32 *nregids, u16 cc,
			 bool enableOutdoor,
			 bool enableExtendedChannels)
{
	u16 maxChan = 7000;
	struct country_code_to_enum_rd *country = NULL;
	struct regDomain rd5GHz, rd2GHz;
	const struct cmode *cm;
	struct ath9k_channel *ichans = &ah->ah_channels[0];
	int next = 0, b;
	u8 ctl;
	int regdmn;
	u16 chanSep;
	unsigned long *modes_avail;
	DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX);

	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n",
		 __func__, cc,
		 enableOutdoor ? "Enable outdoor" : "",
		 enableExtendedChannels ? "Enable ecm" : "");

	if (!ath9k_regd_is_ccode_valid(ah, cc)) {
		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
			"%s: invalid country code %d\n", __func__, cc);
		return false;
	}

	if (!ath9k_regd_is_eeprom_valid(ah)) {
		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
			"%s: invalid EEPROM contents\n", __func__);
		return false;
	}

	ah->ah_countryCode = ath9k_regd_get_default_country(ah);

	if (ah->ah_countryCode == CTRY_DEFAULT) {
		ah->ah_countryCode = cc & COUNTRY_CODE_MASK;
		if ((ah->ah_countryCode == CTRY_DEFAULT) &&
		    (ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)) {
			ah->ah_countryCode = CTRY_UNITED_STATES;
		}
	}

#ifdef AH_SUPPORT_11D
	if (ah->ah_countryCode == CTRY_DEFAULT) {
		regdmn = ath9k_regd_get_eepromRD(ah);
		country = NULL;
	} else {
#endif
		country = ath9k_regd_find_country(ah->ah_countryCode);
		if (country == NULL) {
			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
				"Country is NULL!!!!, cc= %d\n",
				ah->ah_countryCode);
			return false;
		} else {
			regdmn = country->regDmnEnum;
#ifdef AH_SUPPORT_11D
			if (((ath9k_regd_get_eepromRD(ah) &
			      WORLD_SKU_MASK) == WORLD_SKU_PREFIX) &&
			    (cc == CTRY_UNITED_STATES)) {
				if (!isWwrSKU_NoMidband(ah)
				    && ath9k_regd_is_fcc_midband_supported(ah))
					regdmn = FCC3_FCCA;
				else
					regdmn = FCC1_FCCA;
			}
#endif
		}
#ifdef AH_SUPPORT_11D
	}
#endif
	if (!ath9k_regd_get_wmode_regdomain(ah,
					    regdmn,
					    ~CHANNEL_2GHZ,
					    &rd5GHz)) {
		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
			"%s: couldn't find unitary "
			"5GHz reg domain for country %u\n",
			__func__, ah->ah_countryCode);
		return false;
	}
	if (!ath9k_regd_get_wmode_regdomain(ah,
					    regdmn,
					    CHANNEL_2GHZ,
					    &rd2GHz)) {
		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
			"%s: couldn't find unitary 2GHz "
			"reg domain for country %u\n",
			__func__, ah->ah_countryCode);
		return false;
	}

	if (!isWwrSKU(ah) && ((rd5GHz.regDmnEnum == FCC1) ||
			      (rd5GHz.regDmnEnum == FCC2))) {
		if (ath9k_regd_is_fcc_midband_supported(ah)) {
			if (!ath9k_regd_get_wmode_regdomain(ah,
							    FCC3_FCCA,
							    ~CHANNEL_2GHZ,
							    &rd5GHz)) {
				DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
					"%s: couldn't find unitary 5GHz "
					"reg domain for country %u\n",
					__func__, ah->ah_countryCode);
				return false;
			}
		}
	}

	if (country == NULL) {
		modes_avail = ah->ah_caps.wireless_modes;
	} else {
		ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz, modes_allowed);
		modes_avail = modes_allowed;

		if (!enableOutdoor)
			maxChan = country->outdoorChanStart;
	}

	next = 0;

	if (maxchans > ARRAY_SIZE(ah->ah_channels))
		maxchans = ARRAY_SIZE(ah->ah_channels);

	for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) {
		u16 c, c_hi, c_lo;
		u64 *channelBM = NULL;
		struct regDomain *rd = NULL;
		struct RegDmnFreqBand *fband = NULL, *freqs;
		int8_t low_adj = 0, hi_adj = 0;

		if (!test_bit(cm->mode, modes_avail)) {
			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
				"%s: !avail mode %d flags 0x%x\n",
				__func__, cm->mode, cm->flags);
			continue;
		}
		if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) {
			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
				"%s: channels 0x%x not supported "
				"by hardware\n",
				__func__, cm->flags);
			continue;
		}

		switch (cm->mode) {
		case ATH9K_MODE_11A:
		case ATH9K_MODE_11NA_HT20:
		case ATH9K_MODE_11NA_HT40PLUS:
		case ATH9K_MODE_11NA_HT40MINUS:
			rd = &rd5GHz;
			channelBM = rd->chan11a;
			freqs = &regDmn5GhzFreq[0];
			ctl = rd->conformanceTestLimit;
			break;
		case ATH9K_MODE_11B:
			rd = &rd2GHz;
			channelBM = rd->chan11b;
			freqs = &regDmn2GhzFreq[0];
			ctl = rd->conformanceTestLimit | CTL_11B;
			break;
		case ATH9K_MODE_11G:
		case ATH9K_MODE_11NG_HT20:
		case ATH9K_MODE_11NG_HT40PLUS:
		case ATH9K_MODE_11NG_HT40MINUS:
			rd = &rd2GHz;
			channelBM = rd->chan11g;
			freqs = &regDmn2Ghz11gFreq[0];
			ctl = rd->conformanceTestLimit | CTL_11G;
			break;
		default:
			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
				"%s: Unknown HAL mode 0x%x\n", __func__,
				cm->mode);
			continue;
		}

		if (ath9k_regd_is_chan_bm_zero(channelBM))
			continue;

		if ((cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
		    (cm->mode == ATH9K_MODE_11NG_HT40PLUS)) {
			hi_adj = -20;
		}

		if ((cm->mode == ATH9K_MODE_11NA_HT40MINUS) ||
		    (cm->mode == ATH9K_MODE_11NG_HT40MINUS)) {
			low_adj = 20;
		}

		/* XXX: Add a helper here instead */
		for (b = 0; b < 64 * BMLEN; b++) {
			if (ath9k_regd_is_bit_set(b, channelBM)) {
				fband = &freqs[b];
				if (rd5GHz.regDmnEnum == MKK1
				    || rd5GHz.regDmnEnum == MKK2) {
					if (ath9k_regd_japan_check(ah,
								   b,
								   &rd5GHz))
						continue;
				}

				ath9k_regd_add_reg_classid(regclassids,
							   maxregids,
							   nregids,
							   fband->
							   regClassId);

				if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) {
					chanSep = 40;
					if (fband->lowChannel == 5280)
						low_adj += 20;

					if (fband->lowChannel == 5170)
						continue;
				} else
					chanSep = fband->channelSep;

				for (c = fband->lowChannel + low_adj;
				     ((c <= (fband->highChannel + hi_adj)) &&
				      (c >= (fband->lowChannel + low_adj)));
				     c += chanSep) {
					if (next >= maxchans) {
						DPRINTF(ah->ah_sc,
							ATH_DBG_REGULATORY,
							"%s: too many channels "
							"for channel table\n",
							__func__);
						goto done;
					}
					if (ath9k_regd_add_channel(ah,
						   c, c_lo, c_hi,
						   maxChan, ctl,
						   next,
						   rd5GHz,
						   fband, rd, cm,
						   ichans,
						   enableExtendedChannels))
						next++;
				}
				if (IS_HT40_MODE(cm->mode) &&
				    (fband->lowChannel == 5280)) {
					low_adj -= 20;
				}
			}
		}
	}
done:
	if (next != 0) {
		int i;

		if (next > ARRAY_SIZE(ah->ah_channels)) {
			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
				"%s: too many channels %u; truncating to %u\n",
				__func__, next,
				(int) ARRAY_SIZE(ah->ah_channels));
			next = ARRAY_SIZE(ah->ah_channels);
		}
#ifdef ATH_NF_PER_CHAN
		ath9k_regd_init_rf_buffer(ichans, next);
#endif
		ath9k_regd_sort(ichans, next,
				sizeof(struct ath9k_channel),
				ath9k_regd_chansort);

		ah->ah_nchan = next;

		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Channel list:\n");
		for (i = 0; i < next; i++) {
			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
				"chan: %d flags: 0x%x\n",
				ah->ah_channels[i].channel,
				ah->ah_channels[i].channelFlags);
		}
	}
	*nchans = next;

	ah->ah_countryCode = ah->ah_countryCode;

	ah->ah_currentRDInUse = regdmn;
	ah->ah_currentRD5G = rd5GHz.regDmnEnum;
	ah->ah_currentRD2G = rd2GHz.regDmnEnum;
	if (country == NULL) {
		ah->ah_iso[0] = 0;
		ah->ah_iso[1] = 0;
	} else {
		ah->ah_iso[0] = country->isoName[0];
		ah->ah_iso[1] = country->isoName[1];
	}

	return next != 0;
}