regd.c revision 8a57cef6afbd3163c64efedaa20cbfab2c46b9cd
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2008 Atheros Communications Inc.
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "core.h"
#include "hw.h"
#include "regd.h"
#include "regd_common.h"
static int
ath9k_regd_chansort(const void *a, const void *b)
{
const struct ath9k_channel *ca = a;
const struct ath9k_channel *cb = b;
}
static void
{
if (cmp(u, t) <= 0)
break;
}
}
static uint16_t
{
}
static boolean_t
{
int i;
for (i = 0; i < BMLEN; i++) {
if (bitmask[i] != 0)
return (B_FALSE);
}
return (B_TRUE);
}
static boolean_t
{
int i;
if (rd & COUNTRY_ERD_FLAG) {
for (i = 0; i < ARRAY_SIZE(allCountries); i++)
return (B_TRUE);
} else {
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
return (B_TRUE);
}
return (B_FALSE);
}
static boolean_t
{
return (B_TRUE);
else
return (B_FALSE);
}
static boolean_t
{
int i;
if (cc == CTRY_DEFAULT)
return (B_TRUE);
if (cc == CTRY_DEBUG)
return (B_TRUE);
if (rd & COUNTRY_ERD_FLAG) {
"%s: EEPROM setting is country code %u\n",
}
for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
#ifdef ARN_SUPPORT_11D
return (B_TRUE);
#endif
return (B_TRUE);
}
}
return (B_FALSE);
}
static void
struct country_code_to_enum_rd *country,
{
(!country->allow11ng20))
(!country->allow11na20))
(!country->allow11ng40))
(!country->allow11ng40))
(!country->allow11na40))
(!country->allow11na40))
}
{
switch (rd) {
case FCC4_FCCA:
case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG):
return (B_TRUE);
case DEBUG_REG_DMN:
case NO_ENUMRD:
return (B_TRUE);
break;
}
return (B_FALSE);
}
static struct country_code_to_enum_rd *
{
int i;
for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
return (&allCountries[i]);
}
return (NULL);
}
static uint16_t
{
int i;
if (rd & COUNTRY_ERD_FLAG) {
return (cc);
}
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
if (regDomainPairs[i].singleCC != 0)
return (regDomainPairs[i].singleCC);
else
i = ARRAY_SIZE(regDomainPairs);
}
return (CTRY_DEFAULT);
}
static boolean_t
{
int i;
for (i = 0; i < ARRAY_SIZE(regDomains); i++) {
sizeof (struct regDomain));
}
return (B_TRUE);
}
}
return (B_FALSE);
}
static boolean_t
{
int i;
if (regDmnPair == NO_ENUMRD)
return (B_FALSE);
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
return (B_TRUE);
}
return (B_FALSE);
}
static boolean_t
{
int i, found;
int regOrg;
if (regDmn == CTRY_DEFAULT) {
if (!(rdnum & COUNTRY_ERD_FLAG)) {
}
}
}
if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
for (i = 0, found = 0;
regPair = ®DomainPairs[i];
found = 1;
}
}
if (!found) {
"%s: Failed to find reg domain pair %u\n",
return (B_FALSE);
}
if (!(channelFlag & CHANNEL_2GHZ)) {
}
if (channelFlag & CHANNEL_2GHZ) {
}
}
if (!found) {
"%s: Failed to find unitary reg domain %u\n",
return (B_FALSE);
} else {
if (((regOrg & MULTI_DOMAIN_MASK) == 0) &&
}
return (B_TRUE);
}
}
static boolean_t
{
int byteOffset, bitnum;
return (B_TRUE);
else
return (B_FALSE);
}
static void
{
int i;
if (regclassid == 0)
return;
for (i = 0; i < maxregids; i++) {
if (regclassids[i] == regclassid)
return;
if (regclassids[i] == 0)
break;
}
if (i == maxregids)
return;
else {
regclassids[i] = regclassid;
*nregids += 1;
}
}
static boolean_t
enum reg_ext_bitmap bit)
{
}
#ifdef ARN_NF_PER_CHAN
static void
{
int i, j, next;
for (i = 0; i < NUM_NF_READINGS; i++) {
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
}
}
}
}
#endif
static int
{
int i;
for (i = 0; i < 150; i++) {
return (-1);
return (i);
}
return (-1);
}
/* ARGSUSED */
static boolean_t
uint16_t c,
int pos,
struct RegDmnFreqBand *fband,
struct ath9k_channel *ichans,
{
struct ath9k_channel *chan;
int ret;
uint32_t channelFlags = 0;
"%s: c %u out of range [%u..%u]\n",
return (B_FALSE);
}
"%s: Skipping %u half rate channel\n",
__func__, c));
return (B_FALSE);
}
"%s: Skipping %u quarter rate channel\n",
__func__, c));
return (B_FALSE);
}
"%s: c %u > maxChan %u\n",
return (B_FALSE);
}
"Skipping ecm channel\n"));
return (B_FALSE);
}
"Skipping HOSTAP channel\n"));
return (B_FALSE);
}
"Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n"));
return (B_FALSE);
}
"Skipping HT40 channel (en_jap_ht40 = 0)\n"));
return (B_FALSE);
}
"Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n"));
return (B_FALSE);
}
/* Calculate channel flags */
case CHANNEL_HALF_BW:
break;
case CHANNEL_QUARTER_BW:
break;
}
else
else
privFlags = 0;
if (privFlags & CHANNEL_DFS)
if (channelFlags & CHANNEL_PASSIVE) {
if ((c < 2412) || (c > 2462)) {
if (!(regcap &
isUNII1OddChan(c)) {
} else {
}
} else {
}
}
}
}
/* Fill in channel details */
if (ret == -1) {
} else {
}
/* Set CTLs */
}
static boolean_t
{
int i;
for (i = 0; i < ARRAY_SIZE(j_bandcheck); i++) {
if (j_bandcheck[i].freqbandbit == b) {
} else if ((regcap & AR_EEPROM_EEREGCAP_EN_KK_U2) ||
}
break;
}
}
"%s: Skipping %d freq band\n",
return (skipband);
}
{
int next = 0, b;
int regdmn;
"cc %u %s %s\n",
cc,
"invalid country code %d\n", cc));
return (B_FALSE);
}
if (!ath9k_regd_is_eeprom_valid(ah)) {
"invalid EEPROM contents\n"));
return (B_FALSE);
}
}
}
#ifdef ARN_SUPPORT_11D
} else {
#endif
"arn: ath9k_regd_init_channels(): "
"Country is NULL!!!!, cc= %d\n",
ah->ah_countryCode));
return (B_FALSE);
} else {
#ifdef ARN_SUPPORT_11D
if (((ath9k_regd_get_eepromRD(ah) &
WORLD_SKU_MASK) == WORLD_SKU_PREFIX) &&
(cc == CTRY_UNITED_STATES)) {
if (!isWwrSKU_NoMidband(ah) &&
else
}
#endif
}
#ifdef ARN_SUPPORT_11D
}
#endif
~CHANNEL_2GHZ, &rd5GHz)) {
"couldn't find unitary "
"5GHz reg domain for country %u\n",
ah->ah_countryCode));
return (B_FALSE);
}
CHANNEL_2GHZ, &rd2GHz)) {
"couldn't find unitary 2GHz "
"reg domain for country %u\n",
ah->ah_countryCode));
return (B_FALSE);
}
"arn: ath9k_regd_init_channels(): "
"couldn't find unitary 5GHz "
"reg domain for country %u\n",
ah->ah_countryCode));
return (B_FALSE);
}
}
}
} else {
if (!enableOutdoor)
}
next = 0;
"%s: !avail mode %d flags 0x%x\n",
continue;
}
"arn: ath9k_regd_init_channels(): "
"channels 0x%x not supported "
continue;
}
case ATH9K_MODE_11A:
case ATH9K_MODE_11NA_HT20:
case ATH9K_MODE_11NA_HT40PLUS:
freqs = ®Dmn5GhzFreq[0];
break;
case ATH9K_MODE_11B:
freqs = ®Dmn2GhzFreq[0];
break;
case ATH9K_MODE_11G:
case ATH9K_MODE_11NG_HT20:
case ATH9K_MODE_11NG_HT40PLUS:
freqs = ®Dmn2Ghz11gFreq[0];
break;
default:
"arn: ath9k_regd_init_channels(): "
continue;
}
continue;
hi_adj = -20;
}
low_adj = 20;
}
/* XXX: Add a helper here instead */
for (b = 0; b < 64 * BMLEN; b++) {
if (ath9k_regd_is_bit_set(b, channelBM)) {
if (ath9k_regd_japan_check(ah,
b, &rd5GHz))
continue;
}
fband->regClassId);
chanSep = 40;
low_adj += 20;
continue;
} else
c += chanSep) {
"too many channels "
"for channel table\n"));
goto done;
}
if (ath9k_regd_add_channel(ah,
next,
next++;
}
low_adj -= 20;
}
}
}
}
done:
if (next != 0) {
int i;
"arn: ath9k_regd_init_channels(): "
"too many channels %u; truncating to %u\n",
}
#ifdef ARN_NF_PER_CHAN
#endif
"Channel list:\n"));
for (i = 0; i < next; i++) {
"chan: %d flags: 0x%x\n",
}
}
} else {
}
return (next != 0);
}
struct ath9k_channel *
{
int n, lim;
"%s: channel %u/0x%x (0x%x) requested\n", __func__,
return (NULL);
else
return (cc);
}
int d;
if (d == 0) {
return (NULL);
else
return (cc);
}
}
"%s: channel %u/0x%x d %d\n", __func__,
if (d > 0) {
lim--;
}
}
"%s: no match for %u/0x%x\n",
return (NULL);
}
{
if (!ichan)
return (0);
return (ichan->antennaMax);
}
{
struct ath9k_channel *ichan;
else
} else {
/* FIXME */
}
}
return (ctl);
}
void
struct ath9k_country_entry *ctry)
{
if (rd == CTRY_DEFAULT)
else if (!(rd & COUNTRY_ERD_FLAG))
}