#include "opt_ah.h"
#include "ah.h"
#include <sys/param.h>
#include <net80211/_ieee80211.h>
#include <net80211/ieee80211_regdomain.h>
#include "ah_internal.h"
#include "ah_eeprom_v3.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int ath_hal_debug = 0;
HAL_CTRY_CODE cc = CTRY_DEFAULT;
HAL_REG_DOMAIN rd = 169;
HAL_BOOL Amode = 1;
HAL_BOOL Bmode = 1;
HAL_BOOL Gmode = 1;
HAL_BOOL HT20mode = 1;
HAL_BOOL HT40mode = 1;
HAL_BOOL turbo5Disable = AH_FALSE;
HAL_BOOL turbo2Disable = AH_FALSE;
u_int16_t _numCtls = 8;
u_int16_t _ctl[32] =
{ 0x10, 0x13, 0x40, 0x30, 0x11, 0x31, 0x12, 0x32 };
RD_EDGES_POWER _rdEdgesPower[NUM_EDGES*NUM_CTLS] = {
{ 5180, 28, 0 },
{ 5240, 60, 0 },
{ 5260, 36, 0 },
{ 5320, 27, 0 },
{ 5745, 36, 0 },
{ 5765, 36, 0 },
{ 5805, 36, 0 },
{ 5825, 36, 0 },
{ 5210, 28, 0 },
{ 5250, 28, 0 },
{ 5290, 30, 0 },
{ 5760, 36, 0 },
{ 5800, 36, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 5170, 60, 0 },
{ 5230, 60, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 5180, 33, 0 },
{ 5320, 33, 0 },
{ 5500, 34, 0 },
{ 5700, 34, 0 },
{ 5745, 35, 0 },
{ 5765, 35, 0 },
{ 5785, 35, 0 },
{ 5825, 35, 0 },
{ 2412, 36, 0 },
{ 2417, 36, 0 },
{ 2422, 36, 0 },
{ 2432, 36, 0 },
{ 2442, 36, 0 },
{ 2457, 36, 0 },
{ 2467, 36, 0 },
{ 2472, 36, 0 },
{ 2412, 36, 0 },
{ 2417, 36, 0 },
{ 2422, 36, 0 },
{ 2432, 36, 0 },
{ 2442, 36, 0 },
{ 2457, 36, 0 },
{ 2467, 36, 0 },
{ 2472, 36, 0 },
{ 2412, 36, 0 },
{ 2417, 36, 0 },
{ 2422, 36, 0 },
{ 2432, 36, 0 },
{ 2442, 36, 0 },
{ 2457, 36, 0 },
{ 2467, 36, 0 },
{ 2472, 36, 0 },
{ 2412, 28, 0 },
{ 2417, 28, 0 },
{ 2422, 28, 0 },
{ 2432, 28, 0 },
{ 2442, 28, 0 },
{ 2457, 28, 0 },
{ 2467, 28, 0 },
{ 2472, 28, 0 },
};
u_int16_t turbo2WMaxPower5 = 32;
u_int16_t turbo2WMaxPower2;
int8_t antennaGainMax[2] = { 0, 0 };
int eeversion = AR_EEPROM_VER3_1;
TRGT_POWER_ALL_MODES tpow = {
8, {
{ 22, 24, 28, 32, 5180 },
{ 22, 24, 28, 32, 5200 },
{ 22, 24, 28, 32, 5320 },
{ 26, 30, 34, 34, 5500 },
{ 26, 30, 34, 34, 5700 },
{ 20, 30, 34, 36, 5745 },
{ 20, 30, 34, 36, 5825 },
{ 20, 30, 34, 36, 5850 },
},
2, {
{ 23, 27, 31, 34, 2412 },
{ 23, 27, 31, 34, 2447 },
},
2, {
{ 36, 36, 36, 36, 2412 },
{ 36, 36, 36, 36, 2484 },
}
};
#define numTargetPwr_11a tpow.numTargetPwr_11a
#define trgtPwr_11a tpow.trgtPwr_11a
#define numTargetPwr_11g tpow.numTargetPwr_11g
#define trgtPwr_11g tpow.trgtPwr_11g
#define numTargetPwr_11b tpow.numTargetPwr_11b
#define trgtPwr_11b tpow.trgtPwr_11b
static HAL_BOOL
getChannelEdges(struct ath_hal *ah, u_int16_t flags, u_int16_t *low, u_int16_t *high)
{
struct ath_hal_private *ahp = AH_PRIVATE(ah);
HAL_CAPABILITIES *pCap = &ahp->ah_caps;
if (flags & IEEE80211_CHAN_5GHZ) {
*low = pCap->halLow5GhzChan;
*high = pCap->halHigh5GhzChan;
return AH_TRUE;
}
if (flags & IEEE80211_CHAN_2GHZ) {
*low = pCap->halLow2GhzChan;
*high = pCap->halHigh2GhzChan;
return AH_TRUE;
}
return AH_FALSE;
}
static u_int
getWirelessModes(struct ath_hal *ah)
{
u_int mode = 0;
if (Amode) {
mode = HAL_MODE_11A;
if (!turbo5Disable)
mode |= HAL_MODE_TURBO;
}
if (Bmode)
mode |= HAL_MODE_11B;
if (Gmode) {
mode |= HAL_MODE_11G;
if (!turbo2Disable)
mode |= HAL_MODE_108G;
}
if (HT20mode)
mode |= HAL_MODE_11NG_HT20|HAL_MODE_11NA_HT20;
if (HT40mode)
mode |= HAL_MODE_11NG_HT40PLUS|HAL_MODE_11NA_HT40PLUS
| HAL_MODE_11NG_HT40MINUS|HAL_MODE_11NA_HT40MINUS
;
return mode;
}
enum EnumRd {
NO_ENUMRD = 0x00,
NULL1_WORLD = 0x03,
NULL1_ETSIB = 0x07,
NULL1_ETSIC = 0x08,
FCC1_FCCA = 0x10,
FCC1_WORLD = 0x11,
FCC4_FCCA = 0x12,
FCC2_FCCA = 0x20,
FCC2_WORLD = 0x21,
FCC2_ETSIC = 0x22,
FRANCE_RES = 0x31,
FCC3_FCCA = 0x3A,
FCC3_WORLD = 0x3B,
ETSI1_WORLD = 0x37,
ETSI3_ETSIA = 0x32,
ETSI2_WORLD = 0x35,
ETSI3_WORLD = 0x36,
ETSI4_WORLD = 0x30,
ETSI4_ETSIC = 0x38,
ETSI5_WORLD = 0x39,
ETSI6_WORLD = 0x34,
ETSI_RESERVED = 0x33,
MKK1_MKKA = 0x40,
MKK1_MKKB = 0x41,
APL4_WORLD = 0x42,
MKK2_MKKA = 0x43,
APL_RESERVED = 0x44,
APL2_WORLD = 0x45,
APL2_APLC = 0x46,
APL3_WORLD = 0x47,
MKK1_FCCA = 0x48,
APL2_APLD = 0x49,
MKK1_MKKA1 = 0x4A,
MKK1_MKKA2 = 0x4B,
MKK1_MKKC = 0x4C,
APL3_FCCA = 0x50,
APL1_WORLD = 0x52,
APL1_FCCA = 0x53,
APL1_APLA = 0x54,
APL1_ETSIC = 0x55,
APL2_ETSIC = 0x56,
APL5_WORLD = 0x58,
APL6_WORLD = 0x5B,
APL7_FCCA = 0x5C,
APL8_WORLD = 0x5D,
APL9_WORLD = 0x5E,
WOR0_WORLD = 0x60,
WOR1_WORLD = 0x61,
WOR2_WORLD = 0x62,
WOR3_WORLD = 0x63,
WOR4_WORLD = 0x64,
WOR5_ETSIC = 0x65,
WOR01_WORLD = 0x66,
WOR02_WORLD = 0x67,
EU1_WORLD = 0x68,
WOR9_WORLD = 0x69,
WORA_WORLD = 0x6A,
MKK3_MKKB = 0x80,
MKK3_MKKA2 = 0x81,
MKK3_MKKC = 0x82,
MKK4_MKKB = 0x83,
MKK4_MKKA2 = 0x84,
MKK4_MKKC = 0x85,
MKK5_MKKB = 0x86,
MKK5_MKKA2 = 0x87,
MKK5_MKKC = 0x88,
MKK6_MKKB = 0x89,
MKK6_MKKA2 = 0x8A,
MKK6_MKKC = 0x8B,
MKK7_MKKB = 0x8C,
MKK7_MKKA2 = 0x8D,
MKK7_MKKC = 0x8E,
MKK8_MKKB = 0x8F,
MKK8_MKKA2 = 0x90,
MKK8_MKKC = 0x91,
MKK3_MKKA = 0xF0,
MKK3_MKKA1 = 0xF1,
MKK3_FCCA = 0xF2,
MKK4_MKKA = 0xF3,
MKK4_MKKA1 = 0xF4,
MKK4_FCCA = 0xF5,
MKK9_MKKA = 0xF6,
MKK10_MKKA = 0xF7,
APL1 = 0x0150,
APL2 = 0x0250,
APL3 = 0x0350,
APL4 = 0x0450,
APL5 = 0x0550,
APL6 = 0x0650,
APL8 = 0x0850,
APL9 = 0x0950,
ETSI1 = 0x0130,
ETSI2 = 0x0230,
ETSI3 = 0x0330,
ETSI4 = 0x0430,
ETSI5 = 0x0530,
ETSI6 = 0x0630,
ETSIA = 0x0A30,
ETSIB = 0x0B30,
ETSIC = 0x0C30,
FCC1 = 0x0110,
FCC2 = 0x0120,
FCC3 = 0x0160,
FCC4 = 0x0165,
FCCA = 0x0A10,
APLD = 0x0D50,
MKK1 = 0x0140,
MKK2 = 0x0240,
MKK3 = 0x0340,
MKK4 = 0x0440,
MKK5 = 0x0540,
MKK6 = 0x0640,
MKK7 = 0x0740,
MKK8 = 0x0840,
MKK9 = 0x0940,
MKK10 = 0x0B40,
MKKA = 0x0A40,
MKKC = 0x0A50,
NULL1 = 0x0198,
WORLD = 0x0199,
DEBUG_REG_DMN = 0x01ff,
};
#define DEF_REGDMN FCC1_FCCA
static struct {
const char *name;
HAL_REG_DOMAIN rd;
} domains[] = {
#define D(_x) { #_x, _x }
D(NO_ENUMRD),
D(NULL1_WORLD),
D(NULL1_ETSIB),
D(NULL1_ETSIC),
D(FCC1_FCCA),
D(FCC1_WORLD),
D(FCC4_FCCA),
D(FCC2_FCCA),
D(FCC2_WORLD),
D(FCC2_ETSIC),
D(FRANCE_RES),
D(FCC3_FCCA),
D(FCC3_WORLD),
D(ETSI1_WORLD),
D(ETSI3_ETSIA),
D(ETSI2_WORLD),
D(ETSI3_WORLD),
D(ETSI4_WORLD),
D(ETSI4_ETSIC),
D(ETSI5_WORLD),
D(ETSI6_WORLD),
D(ETSI_RESERVED),
D(MKK1_MKKA),
D(MKK1_MKKB),
D(APL4_WORLD),
D(MKK2_MKKA),
D(APL_RESERVED),
D(APL2_WORLD),
D(APL2_APLC),
D(APL3_WORLD),
D(MKK1_FCCA),
D(APL2_APLD),
D(MKK1_MKKA1),
D(MKK1_MKKA2),
D(MKK1_MKKC),
D(APL3_FCCA),
D(APL1_WORLD),
D(APL1_FCCA),
D(APL1_APLA),
D(APL1_ETSIC),
D(APL2_ETSIC),
D(APL5_WORLD),
D(APL6_WORLD),
D(APL7_FCCA),
D(APL8_WORLD),
D(APL9_WORLD),
D(WOR0_WORLD),
D(WOR1_WORLD),
D(WOR2_WORLD),
D(WOR3_WORLD),
D(WOR4_WORLD),
D(WOR5_ETSIC),
D(WOR01_WORLD),
D(WOR02_WORLD),
D(EU1_WORLD),
D(WOR9_WORLD),
D(WORA_WORLD),
D(MKK3_MKKB),
D(MKK3_MKKA2),
D(MKK3_MKKC),
D(MKK4_MKKB),
D(MKK4_MKKA2),
D(MKK4_MKKC),
D(MKK5_MKKB),
D(MKK5_MKKA2),
D(MKK5_MKKC),
D(MKK6_MKKB),
D(MKK6_MKKA2),
D(MKK6_MKKC),
D(MKK7_MKKB),
D(MKK7_MKKA2),
D(MKK7_MKKC),
D(MKK8_MKKB),
D(MKK8_MKKA2),
D(MKK8_MKKC),
D(MKK3_MKKA),
D(MKK3_MKKA1),
D(MKK3_FCCA),
D(MKK4_MKKA),
D(MKK4_MKKA1),
D(MKK4_FCCA),
D(MKK9_MKKA),
D(MKK10_MKKA),
D(APL1),
D(APL2),
D(APL3),
D(APL4),
D(APL5),
D(APL6),
D(APL8),
D(APL9),
D(ETSI1),
D(ETSI2),
D(ETSI3),
D(ETSI4),
D(ETSI5),
D(ETSI6),
D(ETSIA),
D(ETSIB),
D(ETSIC),
D(FCC1),
D(FCC2),
D(FCC3),
D(FCC4),
D(FCCA),
D(APLD),
D(MKK1),
D(MKK2),
D(MKK3),
D(MKK4),
D(MKK5),
D(MKK6),
D(MKK7),
D(MKK8),
D(MKK9),
D(MKK10),
D(MKKA),
D(MKKC),
D(NULL1),
D(WORLD),
D(DEBUG_REG_DMN),
#undef D
};
static HAL_BOOL
rdlookup(const char *name, HAL_REG_DOMAIN *rd)
{
int i;
for (i = 0; i < nitems(domains); i++)
if (strcasecmp(domains[i].name, name) == 0) {
*rd = domains[i].rd;
return AH_TRUE;
}
return AH_FALSE;
}
static const char *
getrdname(HAL_REG_DOMAIN rd)
{
int i;
for (i = 0; i < nitems(domains); i++)
if (domains[i].rd == rd)
return domains[i].name;
return NULL;
}
static void
rdlist()
{
int i;
printf("\nRegulatory domains:\n\n");
for (i = 0; i < nitems(domains); i++)
printf("%-15s%s", domains[i].name,
((i+1)%5) == 0 ? "\n" : "");
printf("\n");
}
typedef struct {
HAL_CTRY_CODE countryCode;
HAL_REG_DOMAIN regDmnEnum;
const char* isoName;
const char* name;
} COUNTRY_CODE_TO_ENUM_RD;
static COUNTRY_CODE_TO_ENUM_RD allCountries[] = {
{CTRY_DEBUG, NO_ENUMRD, "DB", "DEBUG" },
{CTRY_DEFAULT, DEF_REGDMN, "NA", "NO_COUNTRY_SET" },
{CTRY_ALBANIA, NULL1_WORLD, "AL", "ALBANIA" },
{CTRY_ALGERIA, NULL1_WORLD, "DZ", "ALGERIA" },
{CTRY_ARGENTINA, APL3_WORLD, "AR", "ARGENTINA" },
{CTRY_ARMENIA, ETSI4_WORLD, "AM", "ARMENIA" },
{CTRY_AUSTRALIA, FCC2_WORLD, "AU", "AUSTRALIA" },
{CTRY_AUSTRIA, ETSI1_WORLD, "AT", "AUSTRIA" },
{CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ", "AZERBAIJAN" },
{CTRY_BAHRAIN, APL6_WORLD, "BH", "BAHRAIN" },
{CTRY_BELARUS, NULL1_WORLD, "BY", "BELARUS" },
{CTRY_BELGIUM, ETSI1_WORLD, "BE", "BELGIUM" },
{CTRY_BELIZE, APL1_ETSIC, "BZ", "BELIZE" },
{CTRY_BOLIVIA, APL1_ETSIC, "BO", "BOLVIA" },
{CTRY_BRAZIL, FCC3_WORLD, "BR", "BRAZIL" },
{CTRY_BRUNEI_DARUSSALAM,APL1_WORLD,"BN", "BRUNEI DARUSSALAM" },
{CTRY_BULGARIA, ETSI6_WORLD, "BG", "BULGARIA" },
{CTRY_CANADA, FCC2_FCCA, "CA", "CANADA" },
{CTRY_CHILE, APL6_WORLD, "CL", "CHILE" },
{CTRY_CHINA, APL1_WORLD, "CN", "CHINA" },
{CTRY_COLOMBIA, FCC1_FCCA, "CO", "COLOMBIA" },
{CTRY_COSTA_RICA, NULL1_WORLD, "CR", "COSTA RICA" },
{CTRY_CROATIA, ETSI3_WORLD, "HR", "CROATIA" },
{CTRY_CYPRUS, ETSI1_WORLD, "CY", "CYPRUS" },
{CTRY_CZECH, ETSI3_WORLD, "CZ", "CZECH REPUBLIC" },
{CTRY_DENMARK, ETSI1_WORLD, "DK", "DENMARK" },
{CTRY_DOMINICAN_REPUBLIC,FCC1_FCCA,"DO", "DOMINICAN REPUBLIC" },
{CTRY_ECUADOR, NULL1_WORLD, "EC", "ECUADOR" },
{CTRY_EGYPT, ETSI3_WORLD, "EG", "EGYPT" },
{CTRY_EL_SALVADOR, NULL1_WORLD, "SV", "EL SALVADOR" },
{CTRY_ESTONIA, ETSI1_WORLD, "EE", "ESTONIA" },
{CTRY_FINLAND, ETSI1_WORLD, "FI", "FINLAND" },
{CTRY_FRANCE, ETSI3_WORLD, "FR", "FRANCE" },
{CTRY_FRANCE2, ETSI3_WORLD, "F2", "FRANCE_RES" },
{CTRY_GEORGIA, ETSI4_WORLD, "GE", "GEORGIA" },
{CTRY_GERMANY, ETSI1_WORLD, "DE", "GERMANY" },
{CTRY_GREECE, ETSI1_WORLD, "GR", "GREECE" },
{CTRY_GUATEMALA, FCC1_FCCA, "GT", "GUATEMALA" },
{CTRY_HONDURAS, NULL1_WORLD, "HN", "HONDURAS" },
{CTRY_HONG_KONG, FCC2_WORLD, "HK", "HONG KONG" },
{CTRY_HUNGARY, ETSI1_WORLD, "HU", "HUNGARY" },
{CTRY_ICELAND, ETSI1_WORLD, "IS", "ICELAND" },
{CTRY_INDIA, APL6_WORLD, "IN", "INDIA" },
{CTRY_INDONESIA, APL1_WORLD, "ID", "INDONESIA" },
{CTRY_IRAN, APL1_WORLD, "IR", "IRAN" },
{CTRY_IRELAND, ETSI1_WORLD, "IE", "IRELAND" },
{CTRY_ISRAEL, NULL1_WORLD, "IL", "ISRAEL" },
{CTRY_ITALY, ETSI1_WORLD, "IT", "ITALY" },
{CTRY_JAPAN, MKK1_MKKA, "JP", "JAPAN" },
{CTRY_JAPAN1, MKK1_MKKB, "JP", "JAPAN1" },
{CTRY_JAPAN2, MKK1_FCCA, "JP", "JAPAN2" },
{CTRY_JAPAN3, MKK2_MKKA, "JP", "JAPAN3" },
{CTRY_JAPAN4, MKK1_MKKA1, "JP", "JAPAN4" },
{CTRY_JAPAN5, MKK1_MKKA2, "JP", "JAPAN5" },
{CTRY_JAPAN6, MKK1_MKKC, "JP", "JAPAN6" },
{CTRY_JAPAN7, MKK3_MKKB, "JP", "JAPAN7" },
{CTRY_JAPAN8, MKK3_MKKA2, "JP", "JAPAN8" },
{CTRY_JAPAN9, MKK3_MKKC, "JP", "JAPAN9" },
{CTRY_JAPAN10, MKK4_MKKB, "JP", "JAPAN10" },
{CTRY_JAPAN11, MKK4_MKKA2, "JP", "JAPAN11" },
{CTRY_JAPAN12, MKK4_MKKC, "JP", "JAPAN12" },
{CTRY_JAPAN13, MKK5_MKKB, "JP", "JAPAN13" },
{CTRY_JAPAN14, MKK5_MKKA2, "JP", "JAPAN14" },
{CTRY_JAPAN15, MKK5_MKKC, "JP", "JAPAN15" },
{CTRY_JAPAN16, MKK6_MKKB, "JP", "JAPAN16" },
{CTRY_JAPAN17, MKK6_MKKA2, "JP", "JAPAN17" },
{CTRY_JAPAN18, MKK6_MKKC, "JP", "JAPAN18" },
{CTRY_JAPAN19, MKK7_MKKB, "JP", "JAPAN19" },
{CTRY_JAPAN20, MKK7_MKKA2, "JP", "JAPAN20" },
{CTRY_JAPAN21, MKK7_MKKC, "JP", "JAPAN21" },
{CTRY_JAPAN22, MKK8_MKKB, "JP", "JAPAN22" },
{CTRY_JAPAN23, MKK8_MKKA2, "JP", "JAPAN23" },
{CTRY_JAPAN24, MKK8_MKKC, "JP", "JAPAN24" },
{CTRY_JORDAN, APL4_WORLD, "JO", "JORDAN" },
{CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ", "KAZAKHSTAN" },
{CTRY_KOREA_NORTH, APL2_WORLD, "KP", "NORTH KOREA" },
{CTRY_KOREA_ROC, APL2_WORLD, "KR", "KOREA REPUBLIC" },
{CTRY_KOREA_ROC2, APL2_WORLD, "K2", "KOREA REPUBLIC2" },
{CTRY_KOREA_ROC3, APL9_WORLD, "K3", "KOREA REPUBLIC3" },
{CTRY_KUWAIT, NULL1_WORLD, "KW", "KUWAIT" },
{CTRY_LATVIA, ETSI1_WORLD, "LV", "LATVIA" },
{CTRY_LEBANON, NULL1_WORLD, "LB", "LEBANON" },
{CTRY_LIECHTENSTEIN,ETSI1_WORLD, "LI", "LIECHTENSTEIN" },
{CTRY_LITHUANIA, ETSI1_WORLD, "LT", "LITHUANIA" },
{CTRY_LUXEMBOURG, ETSI1_WORLD, "LU", "LUXEMBOURG" },
{CTRY_MACAU, FCC2_WORLD, "MO", "MACAU" },
{CTRY_MACEDONIA, NULL1_WORLD, "MK", "MACEDONIA" },
{CTRY_MALAYSIA, APL8_WORLD, "MY", "MALAYSIA" },
{CTRY_MALTA, ETSI1_WORLD, "MT", "MALTA" },
{CTRY_MEXICO, FCC1_FCCA, "MX", "MEXICO" },
{CTRY_MONACO, ETSI4_WORLD, "MC", "MONACO" },
{CTRY_MOROCCO, NULL1_WORLD, "MA", "MOROCCO" },
{CTRY_NETHERLANDS, ETSI1_WORLD, "NL", "NETHERLANDS" },
{CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ", "NEW ZEALAND" },
{CTRY_NORWAY, ETSI1_WORLD, "NO", "NORWAY" },
{CTRY_OMAN, APL6_WORLD, "OM", "OMAN" },
{CTRY_PAKISTAN, NULL1_WORLD, "PK", "PAKISTAN" },
{CTRY_PANAMA, FCC1_FCCA, "PA", "PANAMA" },
{CTRY_PERU, APL1_WORLD, "PE", "PERU" },
{CTRY_PHILIPPINES, APL1_WORLD, "PH", "PHILIPPINES" },
{CTRY_POLAND, ETSI1_WORLD, "PL", "POLAND" },
{CTRY_PORTUGAL, ETSI1_WORLD, "PT", "PORTUGAL" },
{CTRY_PUERTO_RICO, FCC1_FCCA, "PR", "PUERTO RICO" },
{CTRY_QATAR, NULL1_WORLD, "QA", "QATAR" },
{CTRY_ROMANIA, NULL1_WORLD, "RO", "ROMANIA" },
{CTRY_RUSSIA, NULL1_WORLD, "RU", "RUSSIA" },
{CTRY_SAUDI_ARABIA,NULL1_WORLD, "SA", "SAUDI ARABIA" },
{CTRY_SINGAPORE, APL6_WORLD, "SG", "SINGAPORE" },
{CTRY_SLOVAKIA, ETSI1_WORLD, "SK", "SLOVAK REPUBLIC" },
{CTRY_SLOVENIA, ETSI1_WORLD, "SI", "SLOVENIA" },
{CTRY_SOUTH_AFRICA,FCC3_WORLD, "ZA", "SOUTH AFRICA" },
{CTRY_SPAIN, ETSI1_WORLD, "ES", "SPAIN" },
{CTRY_SWEDEN, ETSI1_WORLD, "SE", "SWEDEN" },
{CTRY_SWITZERLAND, ETSI1_WORLD, "CH", "SWITZERLAND" },
{CTRY_SYRIA, NULL1_WORLD, "SY", "SYRIA" },
{CTRY_TAIWAN, APL3_FCCA, "TW", "TAIWAN" },
{CTRY_THAILAND, NULL1_WORLD, "TH", "THAILAND" },
{CTRY_TRINIDAD_Y_TOBAGO,ETSI4_WORLD,"TT", "TRINIDAD & TOBAGO" },
{CTRY_TUNISIA, ETSI3_WORLD, "TN", "TUNISIA" },
{CTRY_TURKEY, ETSI3_WORLD, "TR", "TURKEY" },
{CTRY_UKRAINE, NULL1_WORLD, "UA", "UKRAINE" },
{CTRY_UAE, NULL1_WORLD, "AE", "UNITED ARAB EMIRATES" },
{CTRY_UNITED_KINGDOM, ETSI1_WORLD,"GB", "UNITED KINGDOM" },
{CTRY_UNITED_STATES, FCC1_FCCA, "US", "UNITED STATES" },
{CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS", "UNITED STATES (PUBLIC SAFETY)" },
{CTRY_URUGUAY, APL2_WORLD, "UY", "URUGUAY" },
{CTRY_UZBEKISTAN, FCC3_FCCA, "UZ", "UZBEKISTAN" },
{CTRY_VENEZUELA, APL2_ETSIC, "VE", "VENEZUELA" },
{CTRY_VIET_NAM, NULL1_WORLD, "VN", "VIET NAM" },
{CTRY_YEMEN, NULL1_WORLD, "YE", "YEMEN" },
{CTRY_ZIMBABWE, NULL1_WORLD, "ZW", "ZIMBABWE" }
};
static HAL_BOOL
cclookup(const char *name, HAL_REG_DOMAIN *rd, HAL_CTRY_CODE *cc)
{
int i;
for (i = 0; i < nitems(allCountries); i++)
if (strcasecmp(allCountries[i].isoName, name) == 0 ||
strcasecmp(allCountries[i].name, name) == 0) {
*rd = allCountries[i].regDmnEnum;
*cc = allCountries[i].countryCode;
return AH_TRUE;
}
return AH_FALSE;
}
static const char *
getccname(HAL_CTRY_CODE cc)
{
int i;
for (i = 0; i < nitems(allCountries); i++)
if (allCountries[i].countryCode == cc)
return allCountries[i].name;
return NULL;
}
static const char *
getccisoname(HAL_CTRY_CODE cc)
{
int i;
for (i = 0; i < nitems(allCountries); i++)
if (allCountries[i].countryCode == cc)
return allCountries[i].isoName;
return NULL;
}
static void
cclist()
{
int i;
printf("\nCountry codes:\n");
for (i = 0; i < nitems(allCountries); i++)
printf("%2s %-15.15s%s",
allCountries[i].isoName,
allCountries[i].name,
((i+1)%4) == 0 ? "\n" : " ");
printf("\n");
}
static HAL_BOOL
setRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan,
int16_t tpcScaleReduction, int16_t powerLimit,
int16_t *pMinPower, int16_t *pMaxPower);
static void
calctxpower(struct ath_hal *ah,
int nchan, const struct ieee80211_channel *chans,
int16_t tpcScaleReduction, int16_t powerLimit, int16_t *txpow)
{
int16_t minpow;
int i;
for (i = 0; i < nchan; i++)
if (!setRateTable(ah, &chans[i],
tpcScaleReduction, powerLimit, &minpow, &txpow[i])) {
printf("unable to set rate table\n");
exit(-1);
}
}
int n = 1;
const char *sep = "";
int dopassive = 0;
int showchannels = 0;
int isdfs = 0;
int is4ms = 0;
static int
anychan(const struct ieee80211_channel *chans, int nc, int flag)
{
int i;
for (i = 0; i < nc; i++)
if ((chans[i].ic_flags & flag) != 0)
return 1;
return 0;
}
static __inline int
mapgsm(u_int freq, u_int flags)
{
freq *= 10;
if (flags & IEEE80211_CHAN_QUARTER)
freq += 5;
else if (flags & IEEE80211_CHAN_HALF)
freq += 10;
else
freq += 20;
return (freq - 24220) / 5;
}
static __inline int
mappsb(u_int freq, u_int flags)
{
return ((freq * 10) + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
}
int
ath_hal_mhz2ieee(struct ath_hal *ah, u_int freq, u_int flags)
{
if (flags & IEEE80211_CHAN_2GHZ) {
if (freq == 2484)
return 14;
if (freq < 2484)
return ((int)freq - 2407) / 5;
else
return 15 + ((freq - 2512) / 20);
} else if (flags & IEEE80211_CHAN_5GHZ) {
if (IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq))
return mappsb(freq, flags);
else if ((flags & IEEE80211_CHAN_A) && (freq <= 5000))
return (freq - 4000) / 5;
else
return (freq - 5000) / 5;
} else {
if (freq == 2484)
return 14;
if (freq < 2484)
return ((int)freq - 2407) / 5;
if (freq < 5000) {
if (IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq))
return mappsb(freq, flags);
else if (freq > 4900)
return (freq - 4000) / 5;
else
return 15 + ((freq - 2512) / 20);
}
return (freq - 5000) / 5;
}
}
#define IEEE80211_IS_CHAN_4MS(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_4MSXMIT) != 0)
static void
dumpchannels(struct ath_hal *ah, int nc,
const struct ieee80211_channel *chans, int16_t *txpow)
{
int i;
for (i = 0; i < nc; i++) {
const struct ieee80211_channel *c = &chans[i];
int type;
if (showchannels)
printf("%s%3d", sep,
ath_hal_mhz2ieee(ah, c->ic_freq, c->ic_flags));
else
printf("%s%u", sep, c->ic_freq);
if (IEEE80211_IS_CHAN_HALF(c))
type = 'H';
else if (IEEE80211_IS_CHAN_QUARTER(c))
type = 'Q';
else if (IEEE80211_IS_CHAN_TURBO(c))
type = 'T';
else if (IEEE80211_IS_CHAN_HT(c))
type = 'N';
else if (IEEE80211_IS_CHAN_A(c))
type = 'A';
else if (IEEE80211_IS_CHAN_108G(c))
type = 'T';
else if (IEEE80211_IS_CHAN_G(c))
type = 'G';
else
type = 'B';
if (dopassive && IEEE80211_IS_CHAN_PASSIVE(c))
type = tolower(type);
if (isdfs && is4ms)
printf("%c%c%c %d.%d", type,
IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ',
IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ',
txpow[i]/2, (txpow[i]%2)*5);
else if (isdfs)
printf("%c%c %d.%d", type,
IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ',
txpow[i]/2, (txpow[i]%2)*5);
else if (is4ms)
printf("%c%c %d.%d", type,
IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ',
txpow[i]/2, (txpow[i]%2)*5);
else
printf("%c %d.%d", type, txpow[i]/2, (txpow[i]%2)*5);
if ((n++ % (showchannels ? 7 : 6)) == 0)
sep = "\n";
else
sep = " ";
}
}
static void
intersect(struct ieee80211_channel *dst, int16_t *dtxpow, int *nd,
const struct ieee80211_channel *src, int16_t *stxpow, int ns)
{
int i = 0, j, k, l;
while (i < *nd) {
for (j = 0; j < ns && dst[i].ic_freq != src[j].ic_freq; j++)
;
if (j < ns && dtxpow[i] == stxpow[j]) {
for (k = i+1, l = i; k < *nd; k++, l++)
dst[l] = dst[k];
(*nd)--;
} else
i++;
}
}
static void
usage(const char *progname)
{
printf("usage: %s [-acdefoilpr4ABGT] [-m opmode] [cc | rd]\n", progname);
exit(-1);
}
static HAL_BOOL
getChipPowerLimits(struct ath_hal *ah, struct ieee80211_channel *chan)
{
}
static HAL_BOOL
eepromRead(struct ath_hal *ah, u_int off, u_int16_t *data)
{
switch (off) {
case AR_EEPROM_VERSION:
*data = eeversion;
return AH_TRUE;
case AR_EEPROM_REG_CAPABILITIES_OFFSET:
*data = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A;
return AH_TRUE;
case AR_EEPROM_REG_CAPABILITIES_OFFSET_PRE4_0:
*data = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0;
return AH_TRUE;
}
return AH_FALSE;
}
HAL_STATUS
getCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
uint32_t capability, uint32_t *result)
{
const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
switch (type) {
case HAL_CAP_REG_DMN:
*result = AH_PRIVATE(ah)->ah_currentRD;
return HAL_OK;
default:
return HAL_EINVAL;
}
}
#define HAL_MODE_HT20 \
(HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20)
#define HAL_MODE_HT40 \
(HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \
HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS)
#define HAL_MODE_HT (HAL_MODE_HT20 | HAL_MODE_HT40)
int
main(int argc, char *argv[])
{
static const u_int16_t tpcScaleReductionTable[5] =
{ 0, 3, 6, 9, MAX_RATE_POWER };
struct ath_hal_private ahp;
struct ieee80211_channel achans[IEEE80211_CHAN_MAX];
int16_t atxpow[IEEE80211_CHAN_MAX];
struct ieee80211_channel bchans[IEEE80211_CHAN_MAX];
int16_t btxpow[IEEE80211_CHAN_MAX];
struct ieee80211_channel gchans[IEEE80211_CHAN_MAX];
int16_t gtxpow[IEEE80211_CHAN_MAX];
struct ieee80211_channel tchans[IEEE80211_CHAN_MAX];
int16_t ttxpow[IEEE80211_CHAN_MAX];
struct ieee80211_channel tgchans[IEEE80211_CHAN_MAX];
int16_t tgtxpow[IEEE80211_CHAN_MAX];
struct ieee80211_channel nchans[IEEE80211_CHAN_MAX];
int16_t ntxpow[IEEE80211_CHAN_MAX];
int i, na, nb, ng, nt, ntg, nn;
HAL_BOOL showall = AH_FALSE;
HAL_BOOL extendedChanMode = AH_TRUE;
int modes = 0;
int16_t tpcReduction, powerLimit;
int showdfs = 0;
int show4ms = 0;
memset(&ahp, 0, sizeof(ahp));
ahp.ah_getChannelEdges = getChannelEdges;
ahp.ah_getWirelessModes = getWirelessModes;
ahp.ah_eepromRead = eepromRead;
ahp.ah_getChipPowerLimits = getChipPowerLimits;
ahp.ah_caps.halWirelessModes = HAL_MODE_ALL;
ahp.ah_caps.halLow5GhzChan = 4920;
ahp.ah_caps.halHigh5GhzChan = 6100;
ahp.ah_caps.halLow2GhzChan = 2312;
ahp.ah_caps.halHigh2GhzChan = 2732;
ahp.ah_caps.halChanHalfRate = AH_TRUE;
ahp.ah_caps.halChanQuarterRate = AH_TRUE;
ahp.h.ah_getCapability = getCapability;
ahp.ah_opmode = HAL_M_STA;
tpcReduction = tpcScaleReductionTable[0];
powerLimit = MAX_RATE_POWER;
while ((i = getopt(argc, argv, "acdeflm:pr4ABGhHNT")) != -1)
switch (i) {
case 'a':
showall = AH_TRUE;
break;
case 'c':
showchannels = AH_TRUE;
break;
case 'd':
ath_hal_debug = HAL_DEBUG_ANY;
break;
case 'e':
extendedChanMode = AH_FALSE;
break;
case 'f':
showchannels = AH_FALSE;
break;
case 'l':
cclist();
rdlist();
exit(0);
case 'm':
if (strncasecmp(optarg, "sta", 2) == 0)
ahp.ah_opmode = HAL_M_STA;
else if (strncasecmp(optarg, "ibss", 2) == 0)
ahp.ah_opmode = HAL_M_IBSS;
else if (strncasecmp(optarg, "adhoc", 2) == 0)
ahp.ah_opmode = HAL_M_IBSS;
else if (strncasecmp(optarg, "ap", 2) == 0)
ahp.ah_opmode = HAL_M_HOSTAP;
else if (strncasecmp(optarg, "hostap", 2) == 0)
ahp.ah_opmode = HAL_M_HOSTAP;
else if (strncasecmp(optarg, "monitor", 2) == 0)
ahp.ah_opmode = HAL_M_MONITOR;
else
usage(argv[0]);
break;
case 'p':
dopassive = 1;
break;
case 'A':
modes |= HAL_MODE_11A;
break;
case 'B':
modes |= HAL_MODE_11B;
break;
case 'G':
modes |= HAL_MODE_11G;
break;
case 'h':
modes |= HAL_MODE_HT20;
break;
case 'H':
modes |= HAL_MODE_HT40;
break;
case 'N':
modes |= HAL_MODE_HT;
break;
case 'T':
modes |= HAL_MODE_TURBO | HAL_MODE_108G;
break;
case 'r':
showdfs = 1;
break;
case '4':
show4ms = 1;
break;
default:
usage(argv[0]);
}
switch (argc - optind) {
case 0:
if (!cclookup("US", &rd, &cc)) {
printf("%s: unknown country code\n", "US");
exit(-1);
}
break;
case 1:
if (!cclookup(argv[optind], &rd, &cc)) {
if (!rdlookup(argv[optind], &rd)) {
const char* rdname;
rd = strtoul(argv[optind], NULL, 0);
rdname = getrdname(rd);
if (rdname == NULL) {
printf("%s: unknown country/regulatory "
"domain code\n", argv[optind]);
exit(-1);
}
}
cc = CTRY_DEFAULT;
}
break;
default:
if (!rdlookup(argv[optind], &rd)) {
const char* rdname;
rd = strtoul(argv[optind], NULL, 0);
rdname = getrdname(rd);
if (rdname == NULL) {
printf("%s: unknown country/regulatory "
"domain code\n", argv[optind]);
exit(-1);
}
}
if (!cclookup(argv[optind+1], &rd, &cc))
cc = strtoul(argv[optind+1], NULL, 0);
break;
}
if (cc != CTRY_DEFAULT)
printf("\n%s (%s, 0x%x, %u) %s (0x%x, %u)\n",
getccname(cc), getccisoname(cc), cc, cc,
getrdname(rd), rd, rd);
else
printf("\n%s (0x%x, %u)\n",
getrdname(rd), rd, rd);
if (modes == 0) {
modes = HAL_MODE_11A | HAL_MODE_11B |
HAL_MODE_11G | HAL_MODE_TURBO | HAL_MODE_108G;
}
na = nb = ng = nt = ntg = nn = 0;
if (modes & HAL_MODE_11G) {
ahp.ah_currentRD = rd;
if (ath_hal_getchannels(&ahp.h, gchans, IEEE80211_CHAN_MAX, &ng,
HAL_MODE_11G, cc, rd, extendedChanMode) == HAL_OK) {
calctxpower(&ahp.h, ng, gchans, tpcReduction, powerLimit, gtxpow);
if (showdfs)
isdfs |= anychan(gchans, ng, IEEE80211_CHAN_DFS);
if (show4ms)
is4ms |= anychan(gchans, ng, IEEE80211_CHAN_4MSXMIT);
}
}
if (modes & HAL_MODE_11B) {
ahp.ah_currentRD = rd;
if (ath_hal_getchannels(&ahp.h, bchans, IEEE80211_CHAN_MAX, &nb,
HAL_MODE_11B, cc, rd, extendedChanMode) == HAL_OK) {
calctxpower(&ahp.h, nb, bchans, tpcReduction, powerLimit, btxpow);
if (showdfs)
isdfs |= anychan(bchans, nb, IEEE80211_CHAN_DFS);
if (show4ms)
is4ms |= anychan(bchans, nb, IEEE80211_CHAN_4MSXMIT);
}
}
if (modes & HAL_MODE_11A) {
ahp.ah_currentRD = rd;
if (ath_hal_getchannels(&ahp.h, achans, IEEE80211_CHAN_MAX, &na,
HAL_MODE_11A, cc, rd, extendedChanMode) == HAL_OK) {
calctxpower(&ahp.h, na, achans, tpcReduction, powerLimit, atxpow);
if (showdfs)
isdfs |= anychan(achans, na, IEEE80211_CHAN_DFS);
if (show4ms)
is4ms |= anychan(achans, na, IEEE80211_CHAN_4MSXMIT);
}
}
if (modes & HAL_MODE_TURBO) {
ahp.ah_currentRD = rd;
if (ath_hal_getchannels(&ahp.h, tchans, IEEE80211_CHAN_MAX, &nt,
HAL_MODE_TURBO, cc, rd, extendedChanMode) == HAL_OK) {
calctxpower(&ahp.h, nt, tchans, tpcReduction, powerLimit, ttxpow);
if (showdfs)
isdfs |= anychan(tchans, nt, IEEE80211_CHAN_DFS);
if (show4ms)
is4ms |= anychan(tchans, nt, IEEE80211_CHAN_4MSXMIT);
}
}
if (modes & HAL_MODE_108G) {
ahp.ah_currentRD = rd;
if (ath_hal_getchannels(&ahp.h, tgchans, IEEE80211_CHAN_MAX, &ntg,
HAL_MODE_108G, cc, rd, extendedChanMode) == HAL_OK) {
calctxpower(&ahp.h, ntg, tgchans, tpcReduction, powerLimit, tgtxpow);
if (showdfs)
isdfs |= anychan(tgchans, ntg, IEEE80211_CHAN_DFS);
if (show4ms)
is4ms |= anychan(tgchans, ntg, IEEE80211_CHAN_4MSXMIT);
}
}
if (modes & HAL_MODE_HT) {
ahp.ah_currentRD = rd;
if (ath_hal_getchannels(&ahp.h, nchans, IEEE80211_CHAN_MAX, &nn,
modes & HAL_MODE_HT, cc, rd, extendedChanMode) == HAL_OK) {
calctxpower(&ahp.h, nn, nchans, tpcReduction, powerLimit, ntxpow);
if (showdfs)
isdfs |= anychan(nchans, nn, IEEE80211_CHAN_DFS);
if (show4ms)
is4ms |= anychan(nchans, nn, IEEE80211_CHAN_4MSXMIT);
}
}
if (!showall) {
#define CHECKMODES(_modes, _m) ((_modes & (_m)) == (_m))
if (CHECKMODES(modes, HAL_MODE_11B|HAL_MODE_11G)) {
intersect(bchans, btxpow, &nb, gchans, gtxpow, ng);
}
if (CHECKMODES(modes, HAL_MODE_11A|HAL_MODE_TURBO)) {
intersect(tchans, ttxpow, &nt, achans, atxpow, na);
}
if (CHECKMODES(modes, HAL_MODE_11G|HAL_MODE_108G)) {
intersect(tgchans, tgtxpow, &ntg, gchans, gtxpow, ng);
}
if (CHECKMODES(modes, HAL_MODE_11G|HAL_MODE_HT)) {
intersect(gchans, gtxpow, &ng, nchans, ntxpow, nn);
}
if (CHECKMODES(modes, HAL_MODE_11A|HAL_MODE_HT)) {
intersect(achans, atxpow, &na, nchans, ntxpow, nn);
}
#undef CHECKMODES
}
if (modes & HAL_MODE_11G)
dumpchannels(&ahp.h, ng, gchans, gtxpow);
if (modes & HAL_MODE_11B)
dumpchannels(&ahp.h, nb, bchans, btxpow);
if (modes & HAL_MODE_11A)
dumpchannels(&ahp.h, na, achans, atxpow);
if (modes & HAL_MODE_108G)
dumpchannels(&ahp.h, ntg, tgchans, tgtxpow);
if (modes & HAL_MODE_TURBO)
dumpchannels(&ahp.h, nt, tchans, ttxpow);
if (modes & HAL_MODE_HT)
dumpchannels(&ahp.h, nn, nchans, ntxpow);
printf("\n");
return (0);
}
static void
ar5212GetLowerUpperValues(u_int16_t v, u_int16_t *lp, u_int16_t listSize,
u_int16_t *vlo, u_int16_t *vhi)
{
u_int32_t target = v * EEP_SCALE;
u_int16_t *ep = lp+listSize;
if (target < (u_int32_t)(lp[0] * EEP_SCALE - EEP_DELTA)) {
*vlo = *vhi = lp[0];
return;
}
if (target > (u_int32_t)(ep[-1] * EEP_SCALE + EEP_DELTA)) {
*vlo = *vhi = ep[-1];
return;
}
for (; lp < ep; lp++) {
if (abs(lp[0] * EEP_SCALE - target) < EEP_DELTA) {
*vlo = *vhi = lp[0];
return;
}
if (target < (u_int32_t)(lp[1] * EEP_SCALE - EEP_DELTA)) {
*vlo = lp[0];
*vhi = lp[1];
return;
}
}
}
static u_int16_t
ar5212GetMaxEdgePower(u_int16_t channel, RD_EDGES_POWER *pRdEdgesPower)
{
u_int16_t tempChannelList[NUM_EDGES];
u_int16_t clo, chi, twiceMaxEdgePower;
int i, numEdges;
for (i = 0; i < NUM_EDGES; i++) {
if (pRdEdgesPower[i].rdEdge == 0)
break;
tempChannelList[i] = pRdEdgesPower[i].rdEdge;
}
numEdges = i;
ar5212GetLowerUpperValues(channel, tempChannelList,
numEdges, &clo, &chi);
for (i = 0; i < numEdges && clo != tempChannelList[i]; i++)
;
HALASSERT(i != numEdges);
if ((clo == chi && clo == channel) || (pRdEdgesPower[i].flag)) {
twiceMaxEdgePower = pRdEdgesPower[i].twice_rdEdgePower;
HALASSERT(twiceMaxEdgePower > 0);
} else
twiceMaxEdgePower = MAX_RATE_POWER;
return twiceMaxEdgePower;
}
static u_int16_t
interpolate(u_int16_t target, u_int16_t srcLeft, u_int16_t srcRight,
u_int16_t targetLeft, u_int16_t targetRight)
{
u_int16_t rv;
int16_t lRatio;
if ((targetLeft * targetRight) == 0)
return 0;
if (srcRight != srcLeft) {
lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft);
if (lRatio < 0) {
rv = targetLeft;
} else if (lRatio > EEP_SCALE) {
rv = targetRight;
} else {
rv = (lRatio * targetRight + (EEP_SCALE - lRatio) *
targetLeft) / EEP_SCALE;
}
} else {
rv = targetLeft;
}
return rv;
}
static void
ar5212GetTargetPowers(struct ath_hal *ah, const struct ieee80211_channel *chan,
TRGT_POWER_INFO *powInfo,
u_int16_t numChannels, TRGT_POWER_INFO *pNewPower)
{
u_int16_t tempChannelList[NUM_TEST_FREQUENCIES];
u_int16_t clo, chi, ixlo, ixhi;
int i;
for (i = 0; i < numChannels; i++)
tempChannelList[i] = powInfo[i].testChannel;
ar5212GetLowerUpperValues(chan->ic_freq, tempChannelList,
numChannels, &clo, &chi);
ixlo = ixhi = 0;
for (i = 0; i < numChannels; i++) {
if (clo == tempChannelList[i]) {
ixlo = i;
}
if (chi == tempChannelList[i]) {
ixhi = i;
break;
}
}
pNewPower->twicePwr6_24 = interpolate(chan->ic_freq, clo, chi,
powInfo[ixlo].twicePwr6_24, powInfo[ixhi].twicePwr6_24);
pNewPower->twicePwr36 = interpolate(chan->ic_freq, clo, chi,
powInfo[ixlo].twicePwr36, powInfo[ixhi].twicePwr36);
pNewPower->twicePwr48 = interpolate(chan->ic_freq, clo, chi,
powInfo[ixlo].twicePwr48, powInfo[ixhi].twicePwr48);
pNewPower->twicePwr54 = interpolate(chan->ic_freq, clo, chi,
powInfo[ixlo].twicePwr54, powInfo[ixhi].twicePwr54);
}
static RD_EDGES_POWER*
findEdgePower(struct ath_hal *ah, u_int ctl)
{
int i;
for (i = 0; i < _numCtls; i++)
if (_ctl[i] == ctl)
return &_rdEdgesPower[i * NUM_EDGES];
return AH_NULL;
}
static HAL_BOOL
setRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan,
int16_t tpcScaleReduction, int16_t powerLimit,
int16_t *pMinPower, int16_t *pMaxPower)
{
u_int16_t ratesArray[16];
u_int16_t *rpow = ratesArray;
u_int16_t twiceMaxRDPower, twiceMaxEdgePower, twiceMaxEdgePowerCck;
int8_t twiceAntennaGain, twiceAntennaReduction;
TRGT_POWER_INFO targetPowerOfdm, targetPowerCck;
RD_EDGES_POWER *rep;
int16_t scaledPower;
u_int8_t cfgCtl;
twiceMaxRDPower = chan->ic_maxregpower * 2;
*pMaxPower = -MAX_RATE_POWER;
*pMinPower = MAX_RATE_POWER;
cfgCtl = ath_hal_getctl(ah, chan);
rep = findEdgePower(ah, cfgCtl);
if (rep != AH_NULL)
twiceMaxEdgePower = ar5212GetMaxEdgePower(chan->ic_freq, rep);
else
twiceMaxEdgePower = MAX_RATE_POWER;
if (IEEE80211_IS_CHAN_G(chan)) {
cfgCtl = (cfgCtl & 0xFC) | 0x01;
rep = findEdgePower(ah, cfgCtl);
if (rep != AH_NULL)
twiceMaxEdgePowerCck = ar5212GetMaxEdgePower(chan->ic_freq, rep);
else
twiceMaxEdgePowerCck = MAX_RATE_POWER;
} else {
twiceMaxEdgePowerCck = twiceMaxEdgePower;
}
if (IEEE80211_IS_CHAN_5GHZ(chan)) {
twiceAntennaGain = antennaGainMax[0];
} else {
twiceAntennaGain = antennaGainMax[1];
}
twiceAntennaReduction =
ath_hal_getantennareduction(ah, chan, twiceAntennaGain);
if (IEEE80211_IS_CHAN_OFDM(chan)) {
if (IEEE80211_IS_CHAN_G(chan)) {
ar5212GetTargetPowers(ah, chan, trgtPwr_11g,
numTargetPwr_11g, &targetPowerOfdm);
} else {
ar5212GetTargetPowers(ah, chan, trgtPwr_11a,
numTargetPwr_11a, &targetPowerOfdm);
}
scaledPower = AH_MIN(twiceMaxEdgePower,
twiceMaxRDPower - twiceAntennaReduction);
if (IEEE80211_IS_CHAN_TURBO(chan)
#ifdef AH_ENABLE_AP_SUPPORT
&& AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP
#endif
) {
if (eeversion >= AR_EEPROM_VER3_1)
scaledPower = AH_MIN(scaledPower,
turbo2WMaxPower5);
if (eeversion >= AR_EEPROM_VER4_0 &&
IEEE80211_IS_CHAN_2GHZ(chan))
scaledPower = AH_MIN(scaledPower,
turbo2WMaxPower2);
}
scaledPower -= (tpcScaleReduction * 2);
scaledPower = (scaledPower < 0) ? 0 : scaledPower;
scaledPower = AH_MIN(scaledPower, powerLimit);
scaledPower = AH_MIN(scaledPower, targetPowerOfdm.twicePwr6_24);
rpow[0] = rpow[1] = rpow[2] = rpow[3] = rpow[4] = scaledPower;
rpow[5] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr36);
rpow[6] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr48);
rpow[7] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr54);
#ifdef notyet
if (eeversion >= AR_EEPROM_VER4_0) {
rpow[15] = AH_MIN(scaledPower, IS_CHAN_2GHZ(chan) ?
xrTargetPower2 : xrTargetPower5);
} else {
rpow[15] = rpow[0];
}
#else
rpow[15] = rpow[0];
#endif
*pMinPower = rpow[7];
*pMaxPower = rpow[0];
#if 0
ahp->ah_ofdmTxPower = rpow[0];
#endif
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: MaxRD: %d TurboMax: %d MaxCTL: %d "
"TPC_Reduction %d\n", __func__,
twiceMaxRDPower, turbo2WMaxPower5,
twiceMaxEdgePower, tpcScaleReduction * 2);
}
if (IEEE80211_IS_CHAN_CCK(chan)) {
ar5212GetTargetPowers(ah, chan, trgtPwr_11b,
numTargetPwr_11b, &targetPowerCck);
scaledPower = AH_MIN(twiceMaxEdgePowerCck,
twiceMaxRDPower - twiceAntennaReduction);
scaledPower -= (tpcScaleReduction * 2);
scaledPower = (scaledPower < 0) ? 0 : scaledPower;
scaledPower = AH_MIN(scaledPower, powerLimit);
rpow[8] = (scaledPower < 1) ? 1 : scaledPower;
rpow[8] = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24);
rpow[9] = AH_MIN(scaledPower, targetPowerCck.twicePwr36);
rpow[10] = rpow[9];
rpow[11] = AH_MIN(scaledPower, targetPowerCck.twicePwr48);
rpow[12] = rpow[11];
rpow[13] = AH_MIN(scaledPower, targetPowerCck.twicePwr54);
rpow[14] = rpow[13];
if (rpow[13] < *pMinPower)
*pMinPower = rpow[13];
if (rpow[9] > *pMaxPower)
*pMaxPower = rpow[9];
}
#if 0
ahp->ah_tx6PowerInHalfDbm = *pMaxPower;
#endif
return AH_TRUE;
}
void*
ath_hal_malloc(size_t size)
{
return calloc(1, size);
}
void
ath_hal_free(void* p)
{
return free(p);
}
void
ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap)
{
vprintf(fmt, ap);
}
void
ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
ath_hal_vprintf(ah, fmt, ap);
va_end(ap);
}
void
DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
{
__va_list ap;
va_start(ap, fmt);
ath_hal_vprintf(ah, fmt, ap);
va_end(ap);
}