--- /dev/null
+--- a/tools/ath_info.c
++++ b/tools/ath_info.c
+@@ -16,78 +16,8 @@
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+-/* So here is how it works:
+- *
+- * First compile...
+- *
+- * gcc ath_info.c -o ath_info
+- *
+- * then find card's physical address
+- *
+- * lspci -v
+- *
+- * 02:02.0 Ethernet controller: Atheros Communications, Inc. AR5212 802.11abg NIC (rev 01)
+- * Subsystem: Fujitsu Limited. Unknown device 1234
+- * Flags: bus master, medium devsel, latency 168, IRQ 23
+- * Memory at c2000000 (32-bit, non-prefetchable) [size=64K]
+- * Capabilities: [44] Power Management version 2
+- *
+- * address here is 0xc2000000
+- *
+- * load madwifi-ng or madwifi-old if not already loaded (be sure the
+- * interface is down!)
+- *
+- * modprobe ath_pci
+- *
+- * OR
+- *
+- * call:
+- * setpci -s 02:02.0 command=0x41f cache_line_size=0x10
+- *
+- * to enable access to the PCI device.
+- *
+- * and we run the thing...
+- *
+- * ./ath_info 0xc2000000
+- *
+- * In order to change the regdomain to 0, call:
+- *
+- * ./ath_info -w 0xc2000000 regdomain 0
+- *
+- * to change any PCI ID value, say:
+- *
+- * ./ath_info -w 0xc2000000 <name> X
+- *
+- * with <name> ::= pci_dev_id | pci_vendor_id | pci_class |
+- * pci_subsys_dev_id | pci_subsys_vendor_id
+- *
+- * With newer chipsets (>= AR5004x, i.e. MAC >= AR5213), Atheros introduced
+- * write protection on the EEPROM. On a GIGABYTE GN-WI01HT you can set GPIO 4
+- * to low to be able to write the EEPROM. This depends highly on the PCB layout,
+- * so there may be different GPIO used.
+- * This program currently sets GPIO 4 to low for a MAC >= AR5213, but you can
+- * override this with the -g option:
+- *
+- * ./ath_info -g 5:0 -w 0xc2000000 regdomain X
+- *
+- * would set GPIO 5 to low (and wouldn't touch GPIO 4). -g can be given several times.
+- *
+- * The write function is currently not tested with 5210 devices.
+- *
+- * Use at your own risk, entering a false device address will have really
+- * nasty results!
+- *
+- * Writing wrong values to the PCI id fields may prevent the driver from
+- * detecting the card!
+- *
+- * Transmitting on illegal frequencies may violate state laws. Stick to the local
+- * regulations!
+- *
+- * DISCLAIMER:
+- * The authors are in no case responsible for damaged hardware or violation of
+- * local laws by operating modified hardware.
+- *
+- */
++/* Try accepting 64-bit device address even with 32-bit userspace */
++#define _FILE_OFFSET_BITS 64
+
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -130,109 +60,103 @@
+ */
+ #define AR5K_GPIODI 0x401c
+
+-/*
+- * Common silicon revision/version values
+- */
+-enum ath5k_srev_type {
+- AR5K_VERSION_VER,
+- AR5K_VERSION_REV,
+- AR5K_VERSION_RAD,
+-};
+-
+ struct ath5k_srev_name {
+ const char *sr_name;
+- enum ath5k_srev_type sr_type;
+- u_int sr_val;
++ u_int8_t sr_val;
+ };
+
+-#define AR5K_SREV_UNKNOWN 0xffff
+-
+ /* Known MAC revision numbers */
+-#define AR5K_SREV_VER_AR5210 0x00
+-#define AR5K_SREV_VER_AR5311 0x10
+-#define AR5K_SREV_VER_AR5311A 0x20
+-#define AR5K_SREV_VER_AR5311B 0x30
+-#define AR5K_SREV_VER_AR5211 0x40
+-#define AR5K_SREV_VER_AR5212 0x50
+-#define AR5K_SREV_VER_AR5213 0x55
+-#define AR5K_SREV_VER_AR5213A 0x59
+-#define AR5K_SREV_VER_AR2424 0xa0
+-#define AR5K_SREV_VER_AR5424 0xa3
+-#define AR5K_SREV_VER_AR5413 0xa4
+-#define AR5K_SREV_VER_AR5414 0xa5
+-#define AR5K_SREV_VER_AR5416 0xc0
+-#define AR5K_SREV_VER_AR5418 0xca
+-#define AR5K_SREV_VER_AR2425 0xe0
+-
+-/* Known PHY revision nymbers */
+-#define AR5K_SREV_RAD_5110 0x00
+-#define AR5K_SREV_RAD_5111 0x10
+-#define AR5K_SREV_RAD_5111A 0x15
+-#define AR5K_SREV_RAD_2111 0x20
+-#define AR5K_SREV_RAD_5112 0x30
+-#define AR5K_SREV_RAD_5112A 0x35
+-#define AR5K_SREV_RAD_2112 0x40
+-#define AR5K_SREV_RAD_2112A 0x45
+-#define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */
+-#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424/5424 */
+-#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */
+-
+-static const struct ath5k_srev_name ath5k_srev_names[] = {
+- {"5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210},
+- {"5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311},
+- {"5311A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A},
+- {"5311B", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B},
+- {"5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211},
+- {"5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212},
+- {"5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213},
+- {"5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A},
+- {"2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424},
+- {"5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424},
+- {"5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413},
+- {"5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414},
+- {"5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416},
+- {"5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418},
+- {"2425", AR5K_VERSION_VER, AR5K_SREV_VER_AR2425},
+- {"xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN},
+- {"5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110},
+- {"5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111},
+- {"2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111},
+- {"5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112},
+- {"5112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A},
+- {"2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112},
+- {"2112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A},
+- {"SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1},
+- {"SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2},
+- {"5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133},
+- {"xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN},
++#define AR5K_SREV_MAC_AR5210 0x00
++#define AR5K_SREV_MAC_AR5311 0x10
++#define AR5K_SREV_MAC_AR5311A 0x20
++#define AR5K_SREV_MAC_AR5311B 0x30
++#define AR5K_SREV_MAC_AR5211 0x40
++#define AR5K_SREV_MAC_AR5212 0x50
++#define AR5K_SREV_MAC_AR5213 0x55
++#define AR5K_SREV_MAC_AR5213A 0x59
++#define AR5K_SREV_MAC_AR5513 0x61
++#define AR5K_SREV_MAC_AR2413 0x78
++#define AR5K_SREV_MAC_AR2414 0x79
++#define AR5K_SREV_MAC_AR2424 0xa0
++#define AR5K_SREV_MAC_AR5424 0xa3
++#define AR5K_SREV_MAC_AR5413 0xa4
++#define AR5K_SREV_MAC_AR5414 0xa5
++#define AR5K_SREV_MAC_AR5416 0xc0
++#define AR5K_SREV_MAC_AR5418 0xca
++#define AR5K_SREV_MAC_AR2425 0xe2
++
++/* Known PHY revision numbers */
++#define AR5K_SREV_PHY_5110 0x00
++#define AR5K_SREV_PHY_5111 0x10
++#define AR5K_SREV_PHY_5111A 0x15
++#define AR5K_SREV_PHY_2111 0x20
++#define AR5K_SREV_PHY_5112 0x30
++#define AR5K_SREV_PHY_5112A 0x35
++#define AR5K_SREV_PHY_2112 0x40
++#define AR5K_SREV_PHY_2112A 0x45
++#define AR5K_SREV_PHY_SC0 0x56 /* Found on 2413/2414 */
++#define AR5K_SREV_PHY_SC1 0x63 /* Found on 5413/5414 */
++#define AR5K_SREV_PHY_SC2 0xa2 /* Found on 2424/5424 */
++#define AR5K_SREV_PHY_5133 0xc0 /* MIMO found on 5418 */
++
++static const struct ath5k_srev_name ath5k_mac_names[] = {
++ {"5210", AR5K_SREV_MAC_AR5210},
++ {"5311", AR5K_SREV_MAC_AR5311},
++ {"5311A", AR5K_SREV_MAC_AR5311A},
++ {"5311B", AR5K_SREV_MAC_AR5311B},
++ {"5211", AR5K_SREV_MAC_AR5211},
++ {"5212", AR5K_SREV_MAC_AR5212},
++ {"5213", AR5K_SREV_MAC_AR5213},
++ {"5213A", AR5K_SREV_MAC_AR5213A},
++ {"2413", AR5K_SREV_MAC_AR2413},
++ {"2414", AR5K_SREV_MAC_AR2414},
++ {"2424", AR5K_SREV_MAC_AR2424},
++ {"5424", AR5K_SREV_MAC_AR5424},
++ {"5413", AR5K_SREV_MAC_AR5413},
++ {"5414", AR5K_SREV_MAC_AR5414},
++ {"5416", AR5K_SREV_MAC_AR5416},
++ {"5418", AR5K_SREV_MAC_AR5418},
++ {"2425", AR5K_SREV_MAC_AR2425},
++};
++
++static const struct ath5k_srev_name ath5k_phy_names[] = {
++ {"5110", AR5K_SREV_PHY_5110},
++ {"5111", AR5K_SREV_PHY_5111},
++ {"2111", AR5K_SREV_PHY_2111},
++ {"5112", AR5K_SREV_PHY_5112},
++ {"5112A", AR5K_SREV_PHY_5112A},
++ {"2112", AR5K_SREV_PHY_2112},
++ {"2112A", AR5K_SREV_PHY_2112A},
++ {"SChip", AR5K_SREV_PHY_SC0},
++ {"SChip", AR5K_SREV_PHY_SC1},
++ {"SChip", AR5K_SREV_PHY_SC2},
++ {"5133", AR5K_SREV_PHY_5133},
+ };
+
+ /*
+ * Silicon revision register
+ */
+ #define AR5K_SREV 0x4020 /* Register Address */
+-#define AR5K_SREV_REV 0x0000000f /* Mask for revision */
+-#define AR5K_SREV_REV_S 0
+-#define AR5K_SREV_VER 0x000000ff /* Mask for version */
+-#define AR5K_SREV_VER_S 4
++#define AR5K_SREV_VER 0x000000f0 /* Mask for version */
++#define AR5K_SREV_REV 0x000000ff /* Mask for revision */
+
+ /*
+ * PHY chip revision register
+ */
+-#define AR5K_PHY_CHIP_ID 0x9818
++#define AR5K_PHY_CHIP_ID 0x9818
+
+ /*
+ * PHY register
+ */
+-#define AR5K_PHY_BASE 0x9800
+-#define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2))
++#define AR5K_PHY_BASE 0x9800
++#define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2))
+ #define AR5K_PHY_SHIFT_2GHZ 0x00004007
+ #define AR5K_PHY_SHIFT_5GHZ 0x00000007
+
+ #define AR5K_RESET_CTL 0x4000 /* Register Address */
+ #define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */
+ #define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset -5210 only */
+-#define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset (5211/5212) */
++#define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset (5211/5212) */
+ #define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband?) -5210 only */
+ #define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset -5210 only */
+ #define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */
+@@ -253,7 +177,7 @@
+ #define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* not on 5210 */
+
+ #define AR5K_PCICFG 0x4010 /* Register Address */
+-#define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */
++#define AR5K_PCICFG_EEAE 0x00000001 /* EEPROM access enable [5210] */
+ #define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */
+ #define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */
+ #define AR5K_PCICFG_EESIZE_S 3
+@@ -264,26 +188,118 @@
+
+ #define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status (5210) */
+
+-#define AR5K_EEPROM_BASE 0x6000
++#define AR5K_EEPROM_BASE 0x6000
+
+-#define AR5K_EEPROM_MAGIC 0x003d /* Offset for EEPROM Magic number */
++/*
++ * Common AR5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
++ */
++#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */
+ #define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */
+ #define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */
+ #define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */
+ #define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */
+
++#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */
++#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */
++#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */
++#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */
++#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008
++#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */
++#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020
++#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */
++#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080
++#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */
++#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200
++#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */
++#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800
++#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */
++#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
++#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */
++#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
++#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
++#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
++#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
++#define AR5K_EEPROM_INFO_CKSUM 0xffff
++#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n))
++
++#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */
++#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */
++#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2GHz (AR5211_rfregs) */
++#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */
++#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
++#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
++#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_3 0x4003
++#define AR5K_EEPROM_VERSION_4_4 0x4004
++#define AR5K_EEPROM_VERSION_4_5 0x4005
++#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */
++#define AR5K_EEPROM_VERSION_4_7 0x3007
++
++#define AR5K_EEPROM_MODE_11A 0
++#define AR5K_EEPROM_MODE_11B 1
++#define AR5K_EEPROM_MODE_11G 2
++
++#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */
++#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
++#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
++#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
++#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2GHz (?) */
++#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */
++#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7)
++#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5GHz (?) */
++#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */
++
++/* Misc values available since EEPROM 4.0 */
++#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4)
++#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff)
++#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1)
++#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1)
++#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3)
++#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5)
++#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff)
++#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1)
++
++#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c
++#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2
++#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002
++#define AR5K_EEPROM_RFKILL_POLARITY_S 1
++
++/* Newer EEPROMs are using a different offset */
++#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
++ (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
++
++#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
++#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff))
++#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff))
++
++/* calibration settings */
++#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
++#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
++#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
++#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */
++#define AR5K_EEPROM_CHANNELS_5GHZ(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* List of calibrated 5GHz chans */
++#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0055, 0x0000)
++#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0065, 0x0010)
++#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0069, 0x0014)
++
++/* [3.1 - 3.3] */
++#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec
++#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed
++
+ /*
+ * EEPROM data register
+ */
+ #define AR5K_EEPROM_DATA_5211 0x6004
+ #define AR5K_EEPROM_DATA_5210 0x6800
+-#define AR5K_EEPROM_DATA (mac_version == AR5K_SREV_VER_AR5210 ? \
++#define AR5K_EEPROM_DATA (mac_version == AR5K_SREV_MAC_AR5210 ? \
+ AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
+
+ /*
+ * EEPROM command register
+ */
+-#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */
++#define AR5K_EEPROM_CMD 0x6008 /* Register Address */
+ #define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */
+ #define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */
+ #define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */
+@@ -291,43 +307,163 @@
+ /*
+ * EEPROM status register
+ */
+-#define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */
+-#define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */
+-#define AR5K_EEPROM_STATUS (mac_version == AR5K_SREV_VER_AR5210 ? \
++#define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */
++#define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */
++#define AR5K_EEPROM_STATUS (mac_version == AR5K_SREV_MAC_AR5210 ? \
+ AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
+ #define AR5K_EEPROM_STAT_RDERR 0x00000001 /* EEPROM read failed */
+ #define AR5K_EEPROM_STAT_RDDONE 0x00000002 /* EEPROM read successful */
+ #define AR5K_EEPROM_STAT_WRERR 0x00000004 /* EEPROM write failed */
+ #define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */
+
+-#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* Offset for EEPROM regulatory domain */
+-#define AR5K_EEPROM_INFO_BASE 0x00c0 /* Offset for EEPROM header */
+-#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
+-#define AR5K_EEPROM_INFO_CKSUM 0xffff
+-#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n))
+-#define AR5K_EEPROM_MODE_11A 0
+-#define AR5K_EEPROM_MODE_11B 1
+-#define AR5K_EEPROM_MODE_11G 2
++/*
++ * EEPROM config register (?)
++ */
++#define AR5K_EEPROM_CFG 0x6010
+
+-#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1)
++/* Some EEPROM defines */
++#define AR5K_EEPROM_EEP_SCALE 100
++#define AR5K_EEPROM_EEP_DELTA 10
++#define AR5K_EEPROM_N_MODES 3
++#define AR5K_EEPROM_N_5GHZ_CHAN 10
++#define AR5K_EEPROM_N_2GHZ_CHAN 3
++#define AR5K_EEPROM_MAX_CHAN 10
++#define AR5K_EEPROM_N_PCDAC 11
++#define AR5K_EEPROM_N_TEST_FREQ 8
++#define AR5K_EEPROM_N_EDGES 8
++#define AR5K_EEPROM_N_INTERCEPTS 11
++#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
++#define AR5K_EEPROM_PCDAC_M 0x3f
++#define AR5K_EEPROM_PCDAC_START 1
++#define AR5K_EEPROM_PCDAC_STOP 63
++#define AR5K_EEPROM_PCDAC_STEP 1
++#define AR5K_EEPROM_NON_EDGE_M 0x40
++#define AR5K_EEPROM_CHANNEL_POWER 8
++#define AR5K_EEPROM_N_OBDB 4
++#define AR5K_EEPROM_OBDB_DIS 0xffff
++#define AR5K_EEPROM_CHANNEL_DIS 0xff
++#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10)
++#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32)
++#define AR5K_EEPROM_MAX_CTLS 32
++#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4
++#define AR5K_EEPROM_N_XPD0_POINTS 4
++#define AR5K_EEPROM_N_XPD3_POINTS 3
++#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35
++#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55
++#define AR5K_EEPROM_POWER_M 0x3f
++#define AR5K_EEPROM_POWER_MIN 0
++#define AR5K_EEPROM_POWER_MAX 3150
++#define AR5K_EEPROM_POWER_STEP 50
++#define AR5K_EEPROM_POWER_TABLE_SIZE 64
++#define AR5K_EEPROM_N_POWER_LOC_11B 4
++#define AR5K_EEPROM_N_POWER_LOC_11G 6
++#define AR5K_EEPROM_I_GAIN 10
++#define AR5K_EEPROM_CCK_OFDM_DELTA 15
++#define AR5K_EEPROM_N_IQ_CAL 2
++
++enum ath5k_ant_setting {
++ AR5K_ANT_VARIABLE = 0, /* variable by programming */
++ AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */
++ AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */
++ AR5K_ANT_MAX = 3,
++};
+
+-#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */
+-#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) /* Device has a support */
+-#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) /* Device has b support */
+-#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) /* Device has g support */
+-#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */
+-#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */
+-#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7)
+-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */
+-#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */
++/* Per channel calibration data, used for power table setup */
++struct ath5k_chan_pcal_info {
++ u_int16_t freq; /* Frequency */
++ /* Power levels in dBm * 4 units */
++ int16_t pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
++ int16_t pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
++ /* PCDAC tables in dBm * 2 units */
++ u_int16_t pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
++ u_int16_t pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
++ /* Max available power */
++ u_int16_t max_pwr;
++};
+
+-/* Misc values available since EEPROM 4.0 */
+-#define AR5K_EEPROM_MISC0 0x00c4
+-#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff)
+-#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3)
+-#define AR5K_EEPROM_MISC1 0x00c5
+-#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff)
+-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1)
++/* Per rate calibration data for each mode, used for power table setup */
++struct ath5k_rate_pcal_info {
++ u_int16_t freq; /* Frequency */
++ /* Power level for 6-24Mbit/s rates */
++ u_int16_t target_power_6to24;
++ /* Power level for 36Mbit rate */
++ u_int16_t target_power_36;
++ /* Power level for 48Mbit rate */
++ u_int16_t target_power_48;
++ /* Power level for 54Mbit rate */
++ u_int16_t target_power_54;
++};
++
++/* EEPROM calibration data */
++struct ath5k_eeprom_info {
++
++ /* Header information */
++ u_int16_t ee_magic;
++ u_int16_t ee_protect;
++ u_int16_t ee_regdomain;
++ u_int16_t ee_version;
++ u_int16_t ee_header;
++ u_int16_t ee_ant_gain;
++ u_int16_t ee_misc0;
++ u_int16_t ee_misc1;
++ u_int16_t ee_cck_ofdm_gain_delta;
++ u_int16_t ee_cck_ofdm_power_delta;
++ u_int16_t ee_scaled_cck_delta;
++
++ /* Used for tx thermal adjustment (eeprom_init, rfregs) */
++ u_int16_t ee_tx_clip;
++ u_int16_t ee_pwd_84;
++ u_int16_t ee_pwd_90;
++ u_int16_t ee_gain_select;
++
++ /* RF Calibration settings (reset, rfregs) */
++ u_int16_t ee_i_cal[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_q_cal[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_fixed_bias[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_turbo_max_power[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_xr_power[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_switch_settling[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
++ u_int16_t ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
++ u_int16_t ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
++ u_int16_t ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_thr_62[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_xlna_gain[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_xpd[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_x_gain[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_i_gain[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
++
++ /* Power calibration data */
++ u_int16_t ee_false_detect[AR5K_EEPROM_N_MODES];
++ u_int16_t ee_cal_piers_a;
++ struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
++ u_int16_t ee_cal_piers_b;
++ struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN];
++ u_int16_t ee_cal_piers_g;
++ struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN];
++ /* Per rate target power levels */
++ u_int16_t ee_rate_target_pwr_num_a;
++ struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
++ u_int16_t ee_rate_target_pwr_num_b;
++ struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN];
++ u_int16_t ee_rate_target_pwr_num_g;
++ struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN];
++
++ /* Conformance test limits (Unused) */
++ u_int16_t ee_ctls;
++ u_int16_t ee_ctl[AR5K_EEPROM_MAX_CTLS];
++
++ /* Noise Floor Calibration settings */
++ int16_t ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
++ int8_t ee_adc_desired_size[AR5K_EEPROM_N_MODES];
++ int8_t ee_pga_desired_size[AR5K_EEPROM_N_MODES];
++
++ u_int32_t ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
++};
+
+ /*
+ * Read data by masking
+@@ -350,7 +486,6 @@
+ (*((volatile u_int32_t *)(mem + (_reg))) = (_val))
+ #endif
+
+-
+ #define AR5K_REG_ENABLE_BITS(_reg, _flags) \
+ AR5K_REG_WRITE(_reg, AR5K_REG_READ(_reg) | (_flags))
+
+@@ -359,7 +494,12 @@
+
+ #define AR5K_TUNE_REGISTER_TIMEOUT 20000
+
+-/* names for eeprom fields */
++#define AR5K_EEPROM_READ(_o, _v) do { \
++ if ((ret = ath5k_hw_eeprom_read(mem, (_o), &(_v), mac_version)) != 0) \
++ return (ret); \
++} while (0)
++
++/* Names for EEPROM fields */
+ struct eeprom_entry {
+ const char *name;
+ int addr;
+@@ -375,8 +515,6 @@
+ {"regdomain", AR5K_EEPROM_REG_DOMAIN},
+ };
+
+-static const int eeprom_addr_len = sizeof(eeprom_addr) / sizeof(eeprom_addr[0]);
+-
+ static int force_write = 0;
+ static int verbose = 0;
+
+@@ -398,8 +536,8 @@
+ /*
+ * Get the PHY Chip revision
+ */
+-static u_int16_t
+-ath5k_hw_radio_revision(u_int16_t mac_version, void *mem, u_int8_t chip)
++static u_int16_t ath5k_hw_radio_revision(u_int16_t mac_version, void *mem,
++ u_int8_t chip)
+ {
+ int i;
+ u_int32_t srev;
+@@ -427,7 +565,7 @@
+ for (i = 0; i < 8; i++)
+ AR5K_REG_WRITE(AR5K_PHY(0x20), 0x00010000);
+
+- if (mac_version == AR5K_SREV_VER_AR5210) {
++ if (mac_version == AR5K_SREV_MAC_AR5210) {
+ srev = AR5K_REG_READ(AR5K_PHY(256) >> 28) & 0xf;
+
+ ret = (u_int16_t)ath5k_hw_bitswap(srev, 4) + 1;
+@@ -447,9 +585,8 @@
+ /*
+ * Write to EEPROM
+ */
+-static int
+-ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data,
+- u_int8_t mac_version)
++static int ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data,
++ u_int8_t mac_version)
+ {
+ u_int32_t status, timeout;
+
+@@ -457,7 +594,7 @@
+ * Initialize EEPROM access
+ */
+
+- if (mac_version == AR5K_SREV_VER_AR5210) {
++ if (mac_version == AR5K_SREV_MAC_AR5210) {
+
+ AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE);
+
+@@ -466,7 +603,7 @@
+
+ } else {
+ /* not 5210 */
+- /* reset eeprom access */
++ /* reset EEPROM access */
+ AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_RESET);
+ usleep(5);
+
+@@ -484,7 +621,7 @@
+ status = AR5K_REG_READ(AR5K_EEPROM_STATUS);
+ if (status & AR5K_EEPROM_STAT_WRDONE) {
+ if (status & AR5K_EEPROM_STAT_WRERR) {
+- err("eeprom write access to 0x%04x failed",
++ err("EEPROM write access to 0x%04x failed",
+ offset);
+ return 1;
+ }
+@@ -499,16 +636,15 @@
+ /*
+ * Read from EEPROM
+ */
+-static int
+-ath5k_hw_eeprom_read(void *mem, u_int32_t offset, u_int16_t *data,
+- u_int8_t mac_version)
++static int ath5k_hw_eeprom_read(void *mem, u_int32_t offset, u_int16_t *data,
++ u_int8_t mac_version)
+ {
+ u_int32_t status, timeout;
+
+ /*
+ * Initialize EEPROM access
+ */
+- if (mac_version == AR5K_SREV_VER_AR5210) {
++ if (mac_version == AR5K_SREV_MAC_AR5210) {
+ AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE);
+ (void)AR5K_REG_READ(AR5K_EEPROM_BASE + (4 * offset));
+ } else {
+@@ -531,50 +667,701 @@
+ return 1;
+ }
+
+-static const char *ath5k_hw_get_part_name(enum ath5k_srev_type type,
+- u_int32_t val)
++/*
++ * Translate binary channel representation in EEPROM to frequency
++ */
++static u_int16_t ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee,
++ u_int16_t bin, unsigned int mode)
+ {
+- const char *name = "xxxxx";
+- int i;
++ u_int16_t val;
+
+- for (i = 0; i < ARRAY_SIZE(ath5k_srev_names); i++) {
+- if (ath5k_srev_names[i].sr_type != type ||
+- ath5k_srev_names[i].sr_val == AR5K_SREV_UNKNOWN)
+- continue;
+- if ((val & 0xff) < ath5k_srev_names[i + 1].sr_val) {
+- name = ath5k_srev_names[i].sr_name;
++ if (bin == AR5K_EEPROM_CHANNEL_DIS)
++ return bin;
++
++ if (mode == AR5K_EEPROM_MODE_11A) {
++ if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
++ val = (5 * bin) + 4800;
++ else
++ val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
++ (bin * 10) + 5100;
++ } else {
++ if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
++ val = bin + 2300;
++ else
++ val = bin + 2400;
++ }
++
++ return val;
++}
++
++/*
++ * Read antenna info from EEPROM
++ */
++static int ath5k_eeprom_read_ants(void *mem, u_int8_t mac_version,
++ struct ath5k_eeprom_info *ee,
++ u_int32_t *offset, unsigned int mode)
++{
++ u_int32_t o = *offset;
++ u_int16_t val;
++ int ret, i = 0;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_switch_settling[mode] = (val >> 8) & 0x7f;
++ ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f;
++ ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;
++ ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;
++ ee->ee_ant_control[mode][i++] = val & 0x3f;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f;
++ ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f;
++ ee->ee_ant_control[mode][i] = (val << 2) & 0x3f;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3;
++ ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f;
++ ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f;
++ ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;
++ ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;
++ ee->ee_ant_control[mode][i++] = val & 0x3f;
++
++ /* Get antenna modes */
++ ee->ee_antenna[mode][0] =
++ (ee->ee_ant_control[mode][0] << 4) | 0x1;
++ ee->ee_antenna[mode][AR5K_ANT_FIXED_A] =
++ ee->ee_ant_control[mode][1] |
++ (ee->ee_ant_control[mode][2] << 6) |
++ (ee->ee_ant_control[mode][3] << 12) |
++ (ee->ee_ant_control[mode][4] << 18) |
++ (ee->ee_ant_control[mode][5] << 24);
++ ee->ee_antenna[mode][AR5K_ANT_FIXED_B] =
++ ee->ee_ant_control[mode][6] |
++ (ee->ee_ant_control[mode][7] << 6) |
++ (ee->ee_ant_control[mode][8] << 12) |
++ (ee->ee_ant_control[mode][9] << 18) |
++ (ee->ee_ant_control[mode][10] << 24);
++
++ /* return new offset */
++ *offset = o;
++
++ return 0;
++}
++
++/*
++ * Read supported modes from EEPROM
++ */
++static int ath5k_eeprom_read_modes(void *mem, u_int8_t mac_version,
++ struct ath5k_eeprom_info *ee,
++ u_int32_t *offset, unsigned int mode)
++{
++ u_int32_t o = *offset;
++ u_int16_t val;
++ int ret;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;
++ ee->ee_thr_62[mode] = val & 0xff;
++
++ if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2)
++ ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff;
++ ee->ee_tx_frm2xpa_enable[mode] = val & 0xff;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff;
++
++ if ((val & 0xff) & 0x80)
++ ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
++ else
++ ee->ee_noise_floor_thr[mode] = val & 0xff;
++
++ if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2)
++ ee->ee_noise_floor_thr[mode] =
++ mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_xlna_gain[mode] = (val >> 5) & 0xff;
++ ee->ee_x_gain[mode] = (val >> 1) & 0xf;
++ ee->ee_xpd[mode] = val & 0x1;
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
++ ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
++
++ if (mode == AR5K_EEPROM_MODE_11A)
++ ee->ee_xr_power[mode] = val & 0x3f;
++ else {
++ ee->ee_ob[mode][0] = val & 0x7;
++ ee->ee_db[mode][0] = (val >> 3) & 0x7;
++ }
++ }
++
++ if (ee->ee_version < AR5K_EEPROM_VERSION_3_4) {
++ ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
++ ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
++ } else {
++ ee->ee_i_gain[mode] = (val >> 13) & 0x7;
++
++ AR5K_EEPROM_READ(o++, val);
++ ee->ee_i_gain[mode] |= (val << 3) & 0x38;
++
++ if (mode == AR5K_EEPROM_MODE_11G)
++ ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
++ }
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0 &&
++ mode == AR5K_EEPROM_MODE_11A) {
++ ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
++ ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
++ }
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_6 &&
++ mode == AR5K_EEPROM_MODE_11G)
++ ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
++
++ /* return new offset */
++ *offset = o;
++
++ return 0;
++}
++
++/*
++ * Read per channel calibration info from EEPROM
++ * This doesn't work on 2112+ chips (EEPROM versions >= 4.6),
++ * I only tested it on 5213 + 5112. This is still work in progress...
++ *
++ * This info is used to calibrate the baseband power table. Imagine
++ * that for each channel there is a power curve that's hw specific
++ * (depends on amplifier) and we try to "correct" this curve using offests
++ * we pass on to phy chip (baseband -> before amplifier) so that it can
++ * use acurate power values when setting tx power (takes amplifier's performance
++ * on each channel into account).
++ *
++ * EEPROM provides us with the offsets for some pre-calibrated channels
++ * and we have to scale (to create the full table for these channels) and
++ * interpolate (in order to create the table for any channel).
++ */
++static int ath5k_eeprom_read_pcal_info(void *mem, u_int8_t mac_version,
++ struct ath5k_eeprom_info *ee,
++ u_int32_t *offset, unsigned int mode)
++{
++ u_int32_t o = *offset;
++ unsigned int i, c;
++ int ret;
++ u_int16_t val;
++ struct ath5k_chan_pcal_info *chan_pcal_info;
++ u_int16_t cal_piers;
++
++ switch (mode) {
++ case AR5K_EEPROM_MODE_11A:
++ chan_pcal_info = ee->ee_pwr_cal_a;
++ cal_piers = ee->ee_cal_piers_a;
++ break;
++ case AR5K_EEPROM_MODE_11B:
++ chan_pcal_info = ee->ee_pwr_cal_b;
++ cal_piers = ee->ee_cal_piers_b;
++ break;
++ case AR5K_EEPROM_MODE_11G:
++ chan_pcal_info = ee->ee_pwr_cal_g;
++ cal_piers = ee->ee_cal_piers_g;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ for (i = 0; i < cal_piers; i++) {
++ /* Power values in dBm * 4 */
++ for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++ AR5K_EEPROM_READ(o++, val);
++ chan_pcal_info[i].pwr_x0[c] = (val & 0xff);
++ chan_pcal_info[i].pwr_x0[++c] = ((val >> 8) & 0xff);
++ }
++
++ /* PCDAC steps (dBm * 2) */
++ AR5K_EEPROM_READ(o++, val);
++ chan_pcal_info[i].pcdac_x0[1] = (val & 0x1f);
++ chan_pcal_info[i].pcdac_x0[2] = ((val >> 5) & 0x1f);
++ chan_pcal_info[i].pcdac_x0[3] = ((val >> 10) & 0x1f);
++
++ /* No idea what these power levels are for (4 xpds ?)
++ I got zeroes on my card and the EEPROM info
++ dumps we found on the net also have weird values */
++ AR5K_EEPROM_READ(o++, val);
++ chan_pcal_info[i].pwr_x3[0] = (val & 0xff);
++ chan_pcal_info[i].pwr_x3[1] = ((val >> 8) & 0xff);
++
++ AR5K_EEPROM_READ(o++, val);
++ chan_pcal_info[i].pwr_x3[2] = (val & 0xff);
++ /* It's weird but they put it here, that's the
++ PCDAC starting step */
++ chan_pcal_info[i].pcdac_x0[0] = ((val >> 8) & 0xff);
++
++ /* Static values seen on EEPROM info dumps */
++ chan_pcal_info[i].pcdac_x3[0] = 20;
++ chan_pcal_info[i].pcdac_x3[1] = 35;
++ chan_pcal_info[i].pcdac_x3[2] = 63;
++
++ /* Last xpd0 power level is also channel maximum */
++ chan_pcal_info[i].max_pwr = chan_pcal_info[i].pwr_x0[3];
++
++ /* Recreate pcdac_x0 table for this channel using pcdac steps */
++ chan_pcal_info[i].pcdac_x0[1] += chan_pcal_info[i].pcdac_x0[0];
++ chan_pcal_info[i].pcdac_x0[2] += chan_pcal_info[i].pcdac_x0[1];
++ chan_pcal_info[i].pcdac_x0[3] += chan_pcal_info[i].pcdac_x0[2];
++ }
++
++ /* return new offset */
++ (*offset) = o;
++
++ return 0;
++}
++
++/*
++ * Read per rate target power (this is the maximum tx power
++ * supported by the card). This info is used when setting
++ * tx power, no matter the channel.
++ *
++ * This also works for v5 EEPROMs.
++ */
++static int ath5k_eeprom_read_target_rate_pwr_info(void *mem,
++ u_int8_t mac_version,
++ struct ath5k_eeprom_info *ee,
++ u_int32_t *offset,
++ unsigned int mode)
++{
++ u_int32_t o = *offset;
++ u_int16_t val;
++ struct ath5k_rate_pcal_info *rate_pcal_info;
++ u_int16_t *rate_target_pwr_num;
++ int ret, i;
++
++ switch (mode) {
++ case AR5K_EEPROM_MODE_11A:
++ rate_pcal_info = ee->ee_rate_tpwr_a;
++ ee->ee_rate_target_pwr_num_a = AR5K_EEPROM_N_5GHZ_CHAN;
++ rate_target_pwr_num = &ee->ee_rate_target_pwr_num_a;
++ break;
++ case AR5K_EEPROM_MODE_11B:
++ rate_pcal_info = ee->ee_rate_tpwr_b;
++ ee->ee_rate_target_pwr_num_b = 2; /* 3rd is g mode'ss 1st */
++ rate_target_pwr_num = &ee->ee_rate_target_pwr_num_b;
++ break;
++ case AR5K_EEPROM_MODE_11G:
++ rate_pcal_info = ee->ee_rate_tpwr_g;
++ ee->ee_rate_target_pwr_num_g = AR5K_EEPROM_N_2GHZ_CHAN;
++ rate_target_pwr_num = &ee->ee_rate_target_pwr_num_g;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ /* Different freq mask for older eeproms (<= v3.2) */
++ if(ee->ee_version <= 0x3002){
++ for (i = 0; i < (*rate_target_pwr_num); i++) {
++ AR5K_EEPROM_READ(o++, val);
++ rate_pcal_info[i].freq =
++ ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
++
++ rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
++ rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
++
++ AR5K_EEPROM_READ(o++, val);
++
++ if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
++ val == 0) {
++ (*rate_target_pwr_num) = i;
++ break;
++ }
++
++ rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
++ rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
++ rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
++ }
++ } else {
++ for (i = 0; i < (*rate_target_pwr_num); i++) {
++ AR5K_EEPROM_READ(o++, val);
++ rate_pcal_info[i].freq =
++ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++
++ rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
++ rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
++
++ AR5K_EEPROM_READ(o++, val);
++
++ if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
++ val == 0) {
++ (*rate_target_pwr_num) = i;
++ break;
++ }
++
++ rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
++ rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
++ rate_pcal_info[i].target_power_54 = (val & 0x3f);
++ }
++ }
++ /* return new offset */
++ (*offset) = o;
++
++ return 0;
++}
++
++/*
++ * Initialize EEPROM & capabilities data
++ */
++static int ath5k_eeprom_init(void *mem, u_int8_t mac_version,
++ struct ath5k_eeprom_info *ee)
++{
++ unsigned int mode, i;
++ int ret;
++ u_int32_t offset;
++ u_int16_t val;
++
++ /* Initial TX thermal adjustment values */
++ ee->ee_tx_clip = 4;
++ ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
++ ee->ee_gain_select = 1;
++
++ /*
++ * Read values from EEPROM and store them in the capability structure
++ */
++ AR5K_EEPROM_READ(AR5K_EEPROM_MAGIC, ee->ee_magic);
++ AR5K_EEPROM_READ(AR5K_EEPROM_PROTECT, ee->ee_protect);
++ AR5K_EEPROM_READ(AR5K_EEPROM_REG_DOMAIN, ee->ee_regdomain);
++ AR5K_EEPROM_READ(AR5K_EEPROM_VERSION, ee->ee_version);
++ AR5K_EEPROM_READ(AR5K_EEPROM_HDR, ee->ee_header);
++
++ /* Return if we have an old EEPROM */
++ if (ee->ee_version < AR5K_EEPROM_VERSION_3_0)
++ return 0;
++
++#ifdef notyet
++ /*
++ * Validate the checksum of the EEPROM date. There are some
++ * devices with invalid EEPROMs.
++ */
++ for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
++ AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
++ cksum ^= val;
++ }
++ if (cksum != AR5K_EEPROM_INFO_CKSUM) {
++ AR5K_PRINTF("Invalid EEPROM checksum 0x%04x\n", cksum);
++ return -EIO;
++ }
++#endif
++
++ AR5K_EEPROM_READ(AR5K_EEPROM_ANT_GAIN(ee->ee_version), ee->ee_ant_gain);
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++ AR5K_EEPROM_READ(AR5K_EEPROM_MISC0, ee->ee_misc0);
++ AR5K_EEPROM_READ(AR5K_EEPROM_MISC1, ee->ee_misc1);
++ }
++
++ if (ee->ee_version < AR5K_EEPROM_VERSION_3_3) {
++ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
++ ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
++ ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
++
++ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
++ ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
++ ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
++ }
++
++ /*
++ * Get conformance test limit values
++ */
++ offset = AR5K_EEPROM_CTL(ee->ee_version);
++ ee->ee_ctls = 0;
++
++ for (i = 0; i < AR5K_EEPROM_N_CTLS(ee->ee_version); i++) {
++ AR5K_EEPROM_READ(offset++, val);
++
++ if (((val >> 8) & 0xff) == 0)
++ break;
++
++ ee->ee_ctl[i] = (val >> 8) & 0xff;
++ ee->ee_ctls++;
++
++ if ((val & 0xff) == 0)
+ break;
++
++ ee->ee_ctl[i + 1] = val & 0xff;
++ ee->ee_ctls++;
++ }
++
++ /*
++ * Get values for 802.11a (5GHz)
++ */
++ mode = AR5K_EEPROM_MODE_11A;
++
++ ee->ee_turbo_max_power[mode] =
++ AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
++
++ offset = AR5K_EEPROM_MODES_11A(ee->ee_version);
++
++ ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_adc_desired_size[mode] = (int8_t)((val >> 8) & 0xff);
++ ee->ee_ob[mode][3] = (val >> 5) & 0x7;
++ ee->ee_db[mode][3] = (val >> 2) & 0x7;
++ ee->ee_ob[mode][2] = (val << 1) & 0x7;
++
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_ob[mode][2] |= (val >> 15) & 0x1;
++ ee->ee_db[mode][2] = (val >> 12) & 0x7;
++ ee->ee_ob[mode][1] = (val >> 9) & 0x7;
++ ee->ee_db[mode][1] = (val >> 6) & 0x7;
++ ee->ee_ob[mode][0] = (val >> 3) & 0x7;
++ ee->ee_db[mode][0] = val & 0x7;
++
++ ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1) {
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_margin_tx_rx[mode] = val & 0x3f;
++ }
++
++ /*
++ * Get values for 802.11b (2.4GHz)
++ */
++ mode = AR5K_EEPROM_MODE_11B;
++ offset = AR5K_EEPROM_MODES_11B(ee->ee_version);
++
++ ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_adc_desired_size[mode] = (int8_t)((val >> 8) & 0xff);
++ ee->ee_ob[mode][1] = (val >> 4) & 0x7;
++ ee->ee_db[mode][1] = val & 0x7;
++
++ ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++ AR5K_EEPROM_READ(offset++, val);
++
++ ee->ee_cal_piers_b = 0;
++
++ ee->ee_pwr_cal_b[0].freq =
++ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++ if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
++ ee->ee_cal_piers_b++;
++
++ ee->ee_pwr_cal_b[1].freq =
++ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++ if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
++ ee->ee_cal_piers_b++;
++
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_pwr_cal_b[2].freq =
++ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++ if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
++ ee->ee_cal_piers_b++;
++ }
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1)
++ ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
++
++ /*
++ * Get values for 802.11g (2.4GHz)
++ */
++ mode = AR5K_EEPROM_MODE_11G;
++ offset = AR5K_EEPROM_MODES_11G(ee->ee_version);
++
++ ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_adc_desired_size[mode] = (signed short int)((val >> 8) & 0xff);
++ ee->ee_ob[mode][1] = (val >> 4) & 0x7;
++ ee->ee_db[mode][1] = val & 0x7;
++
++ ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++ AR5K_EEPROM_READ(offset++, val);
++
++ ee->ee_cal_piers_g = 0;
++
++ ee->ee_pwr_cal_g[0].freq =
++ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++ if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
++ ee->ee_cal_piers_g++;
++
++ ee->ee_pwr_cal_g[1].freq =
++ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++ if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
++ ee->ee_cal_piers_g++;
++
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_turbo_max_power[mode] = val & 0x7f;
++ ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
++
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_pwr_cal_g[2].freq =
++ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++ if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
++ ee->ee_cal_piers_g++;
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1)
++ ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
++
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
++ ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
++
++ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_2) {
++ AR5K_EEPROM_READ(offset++, val);
++ ee->ee_cck_ofdm_gain_delta = val & 0xff;
+ }
+ }
+
+- return (name);
++ /*
++ * Read 5GHz EEPROM channels
++ */
++ offset = AR5K_EEPROM_CHANNELS_5GHZ(ee->ee_version);
++ ee->ee_cal_piers_a = 0;
++ for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {
++ AR5K_EEPROM_READ(offset++, val);
++
++ if ((val & 0xff) == 0)
++ break;
++
++ ee->ee_pwr_cal_a[i].freq =
++ ath5k_eeprom_bin2freq(ee, val & 0xff, AR5K_EEPROM_MODE_11A);
++ ee->ee_cal_piers_a++;
++
++ if (((val >> 8) & 0xff) == 0)
++ break;
++
++ ee->ee_pwr_cal_a[++i].freq =
++ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, AR5K_EEPROM_MODE_11A);
++ ee->ee_cal_piers_a++;
++
++ }
++
++ /*
++ * Read power calibration info
++ */
++ mode = AR5K_EEPROM_MODE_11A;
++ ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ mode = AR5K_EEPROM_MODE_11B;
++ ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ mode = AR5K_EEPROM_MODE_11G;
++ ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++
++ /*
++ * Read per rate target power info
++ */
++ offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
++ mode = AR5K_EEPROM_MODE_11A;
++ ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
++ mode = AR5K_EEPROM_MODE_11B;
++ ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
++ mode = AR5K_EEPROM_MODE_11G;
++ ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static const char *ath5k_hw_get_mac_name(u_int8_t val)
++{
++ static char name[16];
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(ath5k_mac_names); i++) {
++ if (val <= ath5k_mac_names[i].sr_val)
++ break;
++ }
++
++ if (val == ath5k_mac_names[i].sr_val)
++ return ath5k_mac_names[i].sr_name;
++
++ snprintf(name, sizeof(name), "%s+", ath5k_mac_names[i - 1].sr_name);
++ return name;
++}
++
++static const char *ath5k_hw_get_phy_name(u_int8_t val)
++{
++ const char *name = "?????";
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(ath5k_phy_names); i++) {
++ if (val < ath5k_phy_names[i + 1].sr_val) {
++ name = ath5k_phy_names[i].sr_name;
++ break;
++ }
++ }
++
++ return name;
+ }
+
+ /* returns -1 on unknown name */
+ static int eeprom_name2addr(const char *name)
+ {
+- int i;
++ unsigned int i;
++
+ if (!name || !name[0])
+ return -1;
+- for (i = 0; i < eeprom_addr_len; i++)
++ for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+ if (!strcmp(name, eeprom_addr[i].name))
+ return eeprom_addr[i].addr;
+ return -1;
+-} /* eeprom_name2addr */
++}
+
+ /* returns "<unknown>" on unknown address */
+ static const char *eeprom_addr2name(int addr)
+ {
+- int i;
+- for (i = 0; i < eeprom_addr_len; i++)
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+ if (eeprom_addr[i].addr == addr)
+ return eeprom_addr[i].name;
+ return "<unknown>";
+-} /* eeprom_addr2name */
++}
+
+-static int
+-do_write_pairs(int anr, int argc, char **argv, unsigned char *mem,
+- int mac_version)
++static int do_write_pairs(int anr, int argc, char **argv, unsigned char *mem,
++ int mac_version)
+ {
+ #define MAX_NR_WRITES 16
+ struct {
+@@ -635,7 +1422,7 @@
+ }
+ anr++;
+ i++;
+- } /* while (anr < (argc-1)) */
++ }
+
+ if (!(wr_ops_len = i)) {
+ err("no (addr,val) pairs given");
+@@ -702,20 +1489,22 @@
+ }
+
+ return errors ? 11 : 0;
+-} /* do_write_pairs */
++}
+
+ static void usage(const char *n)
+ {
+- int i;
++ unsigned int i;
+
+- fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] <base_address> "
++ fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] [-R addr] [-W addr val] <base_address> "
+ "[<name1> <val1> [<name2> <val2> ...]]\n\n", n);
+ fprintf(stderr,
+ "-w write values into EEPROM\n"
+ "-g N:M set GPIO N to level M (only used with -w)\n"
+ "-v verbose output\n"
+ "-f force; suppress question before writing\n"
+- "-d dump eeprom (file 'ath-eeprom-dump.bin' and screen)\n"
++ "-d dump EEPROM (file 'ath-eeprom-dump.bin' and screen)\n"
++ "-R <addr> read register at <addr> (hex)\n"
++ "-W <addr> <val> write <val> (hex) into register at <addr> (hex)\n"
+ "<base_address> device base address (see lspci output)\n\n");
+
+ fprintf(stderr,
+@@ -725,8 +1514,8 @@
+ " %s -w <base_address> regdomain N\n\n"
+ "- set a PCI id field to value N:\n"
+ " %s -w <base_address> <field> N\n"
+- " where <field> is on of:\n ", n, n, n);
+- for (i = 0; i < eeprom_addr_len; i++)
++ " where <field> is one of:\n ", n, n, n);
++ for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+ fprintf(stderr, " %s", eeprom_addr[i].name);
+ fprintf(stderr, "\n\n");
+ fprintf(stderr,
+@@ -739,19 +1528,457 @@
+ "unlawful radio transmissions!\n\n");
+ }
+
++static void dump_capabilities(struct ath5k_eeprom_info *ee)
++{
++ u_int8_t has_a, has_b, has_g, has_rfkill, turbog_dis, turboa_dis;
++ u_int8_t xr2_dis, xr5_dis, has_crystal;
++
++ has_a = AR5K_EEPROM_HDR_11A(ee->ee_header);
++ has_b = AR5K_EEPROM_HDR_11B(ee->ee_header);
++ has_g = AR5K_EEPROM_HDR_11G(ee->ee_header);
++ has_rfkill = AR5K_EEPROM_HDR_RFKILL(ee->ee_header);
++ has_crystal = AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1);
++ turbog_dis = AR5K_EEPROM_HDR_T_2GHZ_DIS(ee->ee_header);
++ turboa_dis = AR5K_EEPROM_HDR_T_5GHZ_DIS(ee->ee_header);
++ xr2_dis = AR5K_EEPROM_HDR_XR2_DIS(ee->ee_misc0);
++ xr5_dis = AR5K_EEPROM_HDR_XR5_DIS(ee->ee_misc0);
++
++ printf("|================= Capabilities ================|\n");
++
++ printf("| 802.11a Support: ");
++ if (has_a)
++ printf(" yes |");
++ else
++ printf(" no |");
++
++ printf(" Turbo-A disabled:");
++ if (turboa_dis)
++ printf(" yes |\n");
++ else
++ printf(" no |\n");
++
++ printf("| 802.11b Support: ");
++ if (has_b)
++ printf(" yes |");
++ else
++ printf(" no |");
++
++ printf(" Turbo-G disabled:");
++ if (turbog_dis)
++ printf(" yes |\n");
++ else
++ printf(" no |\n");
++
++ printf("| 802.11g Support: ");
++ if (has_g)
++ printf(" yes |");
++ else
++ printf(" no |");
++
++ printf(" 2GHz XR disabled:");
++ if (xr2_dis)
++ printf(" yes |\n");
++ else
++ printf(" no |\n");
++
++ printf("| RFKill Support: ");
++ if (has_rfkill)
++ printf(" yes |");
++ else
++ printf(" no |");
++
++ printf(" 5GHz XR disabled:");
++ if (xr5_dis)
++ printf(" yes |\n");
++ else
++ printf(" no |\n");
++
++ if (has_crystal != 2) {
++ printf("| 32kHz Crystal: ");
++ if (has_crystal)
++ printf(" yes |");
++ else
++ printf(" no |");
++
++ printf(" |\n");
++ }
++
++ printf("\\===============================================/\n");
++}
++
++static void dump_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++ int i;
++
++ printf("|=========================================================|\n");
++ printf("| I power: 0x%02x |", ee->ee_i_cal[mode]);
++ printf(" Q power: 0x%02x |\n", ee->ee_q_cal[mode]);
++ printf("| Use fixed bias: 0x%02x |", ee->ee_fixed_bias[mode]);
++ printf(" Max turbo power: 0x%02x |\n", ee->ee_turbo_max_power[mode]);
++ printf("| Max XR power: 0x%02x |", ee->ee_xr_power[mode]);
++ printf(" Switch Settling Time: 0x%02x |\n", ee->ee_switch_settling[mode]);
++ printf("| Tx/Rx attenuation: 0x%02x |", ee->ee_ant_tx_rx[mode]);
++ printf(" TX end to XLNA On: 0x%02x |\n", ee->ee_tx_end2xlna_enable[mode]);
++ printf("| TX end to XPA Off: 0x%02x |", ee->ee_tx_end2xpa_disable[mode]);
++ printf(" TX end to XPA On: 0x%02x |\n", ee->ee_tx_frm2xpa_enable[mode]);
++ printf("| 62db Threshold: 0x%02x |", ee->ee_thr_62[mode]);
++ printf(" XLNA gain: 0x%02x |\n", ee->ee_xlna_gain[mode]);
++ printf("| XPD: 0x%02x |", ee->ee_xpd[mode]);
++ printf(" XPD gain: 0x%02x |\n", ee->ee_x_gain[mode]);
++ printf("| I gain: 0x%02x |", ee->ee_i_gain[mode]);
++ printf(" Tx/Rx margin: 0x%02x |\n", ee->ee_margin_tx_rx[mode]);
++ printf("| False detect backoff: 0x%02x |", ee->ee_false_detect[mode]);
++ printf(" Noise Floor Threshold: %3d |\n", ee->ee_noise_floor_thr[mode]);
++ printf("| ADC desired size: %3d |", ee->ee_adc_desired_size[mode]);
++ printf(" PGA desired size: %3d |\n", ee->ee_pga_desired_size[mode]);
++ printf("|=========================================================|\n");
++ for (i = 0; i < AR5K_EEPROM_N_PCDAC; i++) {
++ printf("| Antenna control %2i: 0x%02x |", i, ee->ee_ant_control[mode][i]);
++ i++;
++ printf(" Antenna control %2i: 0x%02x |\n", i, ee->ee_ant_control[mode][i]);
++ }
++ printf("|=========================================================|\n");
++ for (i = 0; i < AR5K_EEPROM_N_OBDB; i++) {
++ printf("| Octave Band %i: %2i |", i, ee->ee_ob[mode][i]);
++ printf(" db %i: %2i |\n", i, ee->ee_db[mode][i]);
++ }
++ printf("\\=========================================================/\n");
++}
++
++static void dump_power_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++ struct ath5k_chan_pcal_info *chan_pcal_info;
++ u_int16_t cal_piers;
++ int i, c;
++
++ switch (mode) {
++ case AR5K_EEPROM_MODE_11A:
++ chan_pcal_info = ee->ee_pwr_cal_a;
++ cal_piers = ee->ee_cal_piers_a;
++ break;
++ case AR5K_EEPROM_MODE_11B:
++ chan_pcal_info = ee->ee_pwr_cal_b;
++ cal_piers = ee->ee_cal_piers_b;
++ break;
++ case AR5K_EEPROM_MODE_11G:
++ chan_pcal_info = ee->ee_pwr_cal_g;
++ cal_piers = ee->ee_cal_piers_g;
++ break;
++ default:
++ return;
++ }
++
++ printf("/=================== Per channel power calibration ====================\\\n");
++ printf("| Freq | pwr_0 | pwr_1 | pwr_2 | pwr_3 |pwrx3_0|pwrx3_1|pwrx3_2|max_pwr|\n");
++ printf("| | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | |\n");
++
++ for (i = 0; i < cal_piers; i++) {
++ char buf[16];
++
++ printf("|======|=======|=======|=======|=======|=======|=======|=======|=======|\n");
++ printf("| %4i |", chan_pcal_info[i].freq);
++ for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++ printf(" %2i.%02i |", chan_pcal_info[i].pwr_x0[c] / 4,
++ chan_pcal_info[i].pwr_x0[c] % 4);
++ }
++ for (c = 0; c < AR5K_EEPROM_N_XPD3_POINTS; c++) {
++ printf(" %2i.%02i |", chan_pcal_info[i].pwr_x3[c] / 4,
++ chan_pcal_info[i].pwr_x3[c] % 4);
++ }
++ printf(" %2i.%02i |\n", chan_pcal_info[i].max_pwr / 4,
++ chan_pcal_info[i].max_pwr % 4);
++
++ printf("| |");
++ for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++ snprintf(buf, sizeof(buf), "[%i]",
++ chan_pcal_info[i].pcdac_x0[c]);
++ printf("%6s |", buf);
++ }
++ for (c = 0; c < AR5K_EEPROM_N_XPD3_POINTS; c++) {
++ snprintf(buf, sizeof(buf), "[%i]",
++ chan_pcal_info[i].pcdac_x3[c]);
++ printf("%6s |", buf);
++ }
++ printf(" |\n");
++
++ }
++ printf("\\======================================================================/\n");
++}
++
++static void dump_rate_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++ int i;
++ struct ath5k_rate_pcal_info *rate_pcal_info;
++ u_int16_t rate_target_pwr_num;
++
++ switch (mode) {
++ case AR5K_EEPROM_MODE_11A:
++ rate_pcal_info = ee->ee_rate_tpwr_a;
++ rate_target_pwr_num = ee->ee_rate_target_pwr_num_a;
++ break;
++ case AR5K_EEPROM_MODE_11B:
++ rate_pcal_info = ee->ee_rate_tpwr_b;
++ rate_target_pwr_num = ee->ee_rate_target_pwr_num_b;
++ break;
++ case AR5K_EEPROM_MODE_11G:
++ rate_pcal_info = ee->ee_rate_tpwr_g;
++ rate_target_pwr_num = ee->ee_rate_target_pwr_num_g;
++ break;
++ default:
++ return;
++ }
++
++ printf("/============== Per rate power calibration ===========\\\n");
++ if (mode == AR5K_EEPROM_MODE_11B)
++ printf("| Freq | 1Mbit/s | 2Mbit/s | 5.5Mbit/s | 11Mbit/s |\n");
++ else
++ printf("| Freq | 6-24Mbit/s | 36Mbit/s | 48Mbit/s | 54Mbit/s |\n");
++
++ for (i = 0; i < rate_target_pwr_num; i++) {
++
++ printf("|======|============|==========|===========|==========|\n");
++ printf("| %4i |", rate_pcal_info[i].freq);
++ printf(" %2i.%02i |",rate_pcal_info[i].target_power_6to24 /2,
++ rate_pcal_info[i].target_power_6to24 % 2);
++ printf(" %2i.%02i |",rate_pcal_info[i].target_power_36 /2,
++ rate_pcal_info[i].target_power_36 % 2);
++ printf(" %2i.%02i |",rate_pcal_info[i].target_power_48 /2,
++ rate_pcal_info[i].target_power_48 % 2);
++ printf(" %2i.%02i |\n",rate_pcal_info[i].target_power_54 /2,
++ rate_pcal_info[i].target_power_54 % 2);
++ }
++ printf("\\=====================================================/\n");
++}
++
++static u_int32_t extend_tu(u_int32_t base_tu, u_int32_t val, u_int32_t mask)
++{
++ u_int32_t result;
++
++ result = (base_tu & ~mask) | (val & mask);
++ if ((base_tu & mask) > (val & mask))
++ result += mask + 1;
++ return result;
++}
++
++static void dump_timers_register(void *mem, u_int16_t mac_version)
++{
++#define AR5K_TIMER0_5210 0x802c /* next TBTT */
++#define AR5K_TIMER0_5211 0x8028
++#define AR5K_TIMER0 (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
++
++#define AR5K_TIMER1_5210 0x8030 /* next DMA beacon */
++#define AR5K_TIMER1_5211 0x802c
++#define AR5K_TIMER1 (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
++
++#define AR5K_TIMER2_5210 0x8034 /* next SWBA interrupt */
++#define AR5K_TIMER2_5211 0x8030
++#define AR5K_TIMER2 (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
++
++#define AR5K_TIMER3_5210 0x8038 /* next ATIM window */
++#define AR5K_TIMER3_5211 0x8034
++#define AR5K_TIMER3 (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
++
++#define AR5K_TSF_L32_5210 0x806c /* TSF (lower 32 bits) */
++#define AR5K_TSF_L32_5211 0x804c
++#define AR5K_TSF_L32 (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
++
++#define AR5K_TSF_U32_5210 0x8070
++#define AR5K_TSF_U32_5211 0x8050
++#define AR5K_TSF_U32 (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
++
++#define AR5K_BEACON_5210 0x8024
++#define AR5K_BEACON_5211 0x8020
++#define AR5K_BEACON (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_BEACON_5210 : AR5K_BEACON_5211)
++
++#define AR5K_LAST_TSTP 0x8080
++
++ const int timer_mask = 0xffff;
++
++ u_int32_t timer0, timer1, timer2, timer3, now_tu;
++ u_int32_t timer0_tu, timer1_tu, timer2_tu, timer3_tu;
++ u_int64_t now_tsf;
++
++ timer0 = AR5K_REG_READ(AR5K_TIMER0); /* 0x0000ffff */
++ timer1 = AR5K_REG_READ(AR5K_TIMER1_5211); /* 0x0007ffff */
++ timer2 = AR5K_REG_READ(AR5K_TIMER2_5211); /* 0x?1ffffff */
++ timer3 = AR5K_REG_READ(AR5K_TIMER3_5211); /* 0x0000ffff */
++
++ now_tsf = ((u_int64_t)AR5K_REG_READ(AR5K_TSF_U32_5211) << 32)
++ | (u_int64_t)AR5K_REG_READ(AR5K_TSF_L32_5211);
++
++ now_tu = now_tsf >> 10;
++
++ timer0_tu = extend_tu(now_tu, timer0, 0xffff);
++ printf("TIMER0: 0x%08x, TBTT: %5u, TU: 0x%08x\n", timer0,
++ timer0 & timer_mask, timer0_tu);
++ timer1_tu = extend_tu(now_tu, timer1 >> 3, 0x7ffff >> 3);
++ printf("TIMER1: 0x%08x, DMAb: %5u, TU: 0x%08x (%+d)\n", timer1,
++ (timer1 >> 3) & timer_mask, timer1_tu, timer1_tu - timer0_tu);
++ timer2_tu = extend_tu(now_tu, timer2 >> 3, 0x1ffffff >> 3);
++ printf("TIMER2: 0x%08x, SWBA: %5u, TU: 0x%08x (%+d)\n", timer2,
++ (timer2 >> 3) & timer_mask, timer2_tu, timer2_tu - timer0_tu);
++ timer3_tu = extend_tu(now_tu, timer3, 0xffff);
++ printf("TIMER3: 0x%08x, ATIM: %5u, TU: 0x%08x (%+d)\n", timer3,
++ timer3 & timer_mask, timer3_tu, timer3_tu - timer0_tu);
++ printf("TSF: 0x%016llx, TSFTU: %5u, TU: 0x%08x\n",
++ (unsigned long long)now_tsf, now_tu & timer_mask, now_tu);
++
++ printf("BEACON: 0x%08x\n", AR5K_REG_READ(AR5K_BEACON));
++ printf("LAST_TSTP: 0x%08x\n", AR5K_REG_READ(AR5K_LAST_TSTP));
++}
++
++#define AR5K_KEYTABLE_0_5210 0x9000
++#define AR5K_KEYTABLE_0_5211 0x8800
++#define AR5K_KEYTABLE_0 (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_KEYTABLE_0_5210 : \
++ AR5K_KEYTABLE_0_5211)
++
++#define AR5K_KEYTABLE(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5))
++#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + ((x) << 2))
++#define AR5K_KEYTABLE_VALID 0x00008000
++
++#define AR5K_KEYTABLE_SIZE_5210 64
++#define AR5K_KEYTABLE_SIZE_5211 128
++#define AR5K_KEYTABLE_SIZE (mac_version == AR5K_SREV_MAC_AR5210 ? \
++ AR5K_KEYTABLE_SIZE_5210 : \
++ AR5K_KEYTABLE_SIZE_5211)
++
++static void keycache_dump(void *mem, u_int16_t mac_version)
++{
++ int i, keylen;
++ u_int32_t val0, val1, val2, val3, val4, keytype, ant, mac0, mac1;
++
++ /* dump all 128 entries */
++ printf("Dumping keycache entries...\n");
++ for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) {
++ mac1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 7));
++ if (mac1 & AR5K_KEYTABLE_VALID) {
++ val0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 0));
++ val1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 1));
++ val2 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 2));
++ val3 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 3));
++ val4 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 4));
++ keytype = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 5));
++ ant = keytype & 8;
++ keytype &= ~8;
++ switch (keytype) {
++ case 0: /* WEP40 */ keylen = 40 / 8; break;
++ case 1: /* WEP104 */ keylen = 104 / 8; break;
++ case 3: /* WEP128 */ keylen = 128 / 8; break;
++ case 4: /* TKIP */ keylen = 128 / 8; break;
++ case 5: /* AES */ keylen = 128 / 8; break;
++ case 6: /* CCM */ keylen = 128 / 8; break;
++ default: keylen = 0; break;
++ }
++ mac0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 6));
++
++ printf("[%3u] keytype %d [%s%s%s%s%s%s%s%s] mac %02x:%02x:%02x:%02x:%02x:%02x key:%08x-%08x-%08x-%08x-%08x\n",
++ i,
++ keytype,
++ keytype == 0 ? "WEP40 " : "",
++ keytype == 1 ? "WEP104" : "",
++ keytype == 3 ? "WEP128" : "",
++ keytype == 4 ? "TKIP " : "",
++ keytype == 5 ? "AES " : "",
++ keytype == 6 ? "CCM " : "",
++ keytype == 7 ? "NULL " : "",
++ ant == 8 ? "+ANT" : "",
++ ((mac0 << 1) & 0xff),
++ ((mac0 >> 7) & 0xff),
++ ((mac0 >> 15) & 0xff),
++ ((mac0 >> 23) & 0xff),
++ ((mac1 << 1) & 0xff) | (mac0 >> 31),
++ ((mac1 >> 7) & 0xff),
++ val0, val1, val2, val3, val4);
++ }
++ }
++}
++
++/* copy key index (0) to key index (idx) */
++
++static void keycache_copy(void *mem, u_int16_t mac_version, int idx)
++{
++ u_int32_t val0, val1, val2, val3, val4, keytype, mac0, mac1;
++
++ printf("Copying keycache entry 0 to %d\n", idx);
++ if (idx < 0 || idx >= AR5K_KEYTABLE_SIZE) {
++ printf("invalid keycache index\n");
++ return;
++ }
++
++ val0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 0));
++ val1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 1));
++ val2 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 2));
++ val3 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 3));
++ val4 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 4));
++ keytype = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 5));
++ mac0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 6));
++ mac1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 7));
++
++ AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 0), val0);
++ AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 1), val1);
++ AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 2), val2);
++ AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 3), val3);
++ AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 4), val4);
++ AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 5), keytype);
++ AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 6), mac0);
++ AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 7), mac1);
++}
++
++static void sta_id0_id1_dump(void *mem)
++{
++#define AR5K_STA_ID0 0x8000
++#define AR5K_STA_ID1 0x8004
++#define AR5K_STA_ID1_AP 0x00010000
++#define AR5K_STA_ID1_ADHOC 0x00020000
++#define AR5K_STA_ID1_NO_KEYSRCH 0x00080000
++
++ u_int32_t sta_id0, sta_id1;
++
++ sta_id0 = AR5K_REG_READ(AR5K_STA_ID0);
++ sta_id1 = AR5K_REG_READ(AR5K_STA_ID1);
++ printf("STA_ID0: %02x:%02x:%02x:%02x:%02x:%02x\n",
++ (sta_id0 >> 0) & 0xff,
++ (sta_id0 >> 8) & 0xff,
++ (sta_id0 >> 16) & 0xff,
++ (sta_id0 >> 24) & 0xff,
++ (sta_id1 >> 0) & 0xff,
++ (sta_id1 >> 8) & 0xff);
++ printf("STA_ID1: 0x%08x, AP: %d, IBSS: %d, KeyCache Disable: %d\n",
++ sta_id1,
++ sta_id1 & AR5K_STA_ID1_AP ? 1 : 0,
++ sta_id1 & AR5K_STA_ID1_ADHOC ? 1 : 0,
++ sta_id1 & AR5K_STA_ID1_NO_KEYSRCH ? 1 : 0);
++}
++
+ int
+ CMD(athinfo)(int argc, char *argv[])
+ {
+- u_int32_t dev_addr;
+- u_int16_t eeprom_header, srev, phy_rev_5ghz, phy_rev_2ghz;
+- u_int16_t eeprom_version, mac_version, regdomain, has_crystal, ee_magic;
+- u_int8_t error, has_a, has_b, has_g, has_rfkill, eeprom_size;
+- int byte_size = 0;
++ unsigned long long dev_addr;
++ u_int16_t srev, phy_rev_5ghz, phy_rev_2ghz, ee_magic;
++ u_int8_t mac_version, mac_revision;
++ u_int8_t error, eeprom_size, dev_type, eemap;
++ struct ath5k_eeprom_info *ee;
++ unsigned int byte_size = 0;
+ void *mem;
+ int fd;
+- int i, anr = 1;
++ unsigned int i;
++ int anr = 1;
+ int do_write = 0; /* default: read only */
+ int do_dump = 0;
++ int reg_read = 0;
++ int reg_write = 0;
++ unsigned int reg_write_val = 0;
++ unsigned int timer_count = 1;
++ int do_keycache_dump = 0;
++ int keycache_copy_idx = 0;
+
+ struct {
+ int valid;
+@@ -759,7 +1986,7 @@
+ } gpio_set[AR5K_NUM_GPIO];
+ int nr_gpio_set = 0;
+
+- for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++)
++ for (i = 0; i < ARRAY_SIZE(gpio_set); i++)
+ gpio_set[i].valid = 0;
+
+ if (argc < 2) {
+@@ -769,6 +1996,15 @@
+
+ while (anr < argc && argv[anr][0] == '-') {
+ switch (argv[anr][1]) {
++ case 't':
++ if (++anr < argc) {
++ timer_count = atoi(argv[anr]);
++ printf("timer_count:%d\n", timer_count);
++ } else {
++ usage(argv[0]);
++ return 0;
++ }
++ break;
+ case 'w':
+ do_write = 1;
+ break;
+@@ -777,7 +2013,7 @@
+ if (strlen(argv[anr]) != 3 || argv[anr][1] != ':' ||
+ argv[anr][0] < '0' || argv[anr][0] > '5' ||
+ (argv[anr][2] != '0' && argv[anr][2] != '1')) {
+- err("invalid gpio spec. %s", argv[anr]);
++ err("invalid GPIO spec. %s", argv[anr]);
+ return 2;
+ }
+ gpio_set[argv[anr][0] - '0'].valid = 1;
+@@ -797,6 +2033,25 @@
+ do_dump = 1;
+ break;
+
++ case 'R':
++ anr++;
++ reg_read = strtoul(argv[anr], NULL, 16);
++ break;
++
++ case 'W':
++ anr++;
++ reg_write = strtoul(argv[anr++], NULL, 16);
++ reg_write_val = strtoul(argv[anr], NULL, 16);
++ break;
++
++ case 'k':
++ do_keycache_dump = 1;
++ break;
++
++ case 'K':
++ keycache_copy_idx = atoi(argv[++anr]);
++ break;
++
+ case 'h':
+ usage(argv[0]);
+ return 0;
+@@ -805,10 +2060,10 @@
+ default:
+ err("unknown option %s", argv[anr]);
+ return 2;
+- } /* switch (argv[anr][1]) */
++ }
+
+ anr++;
+- } /* while (anr < argc && ...) */
++ }
+
+ if (anr >= argc) {
+ err("missing device address");
+@@ -816,7 +2071,7 @@
+ return 3;
+ }
+
+- dev_addr = strtoul(argv[anr], NULL, 16);
++ dev_addr = strtoull(argv[anr], NULL, 16);
+
+ fd = open("/dev/mem", O_RDWR);
+ if (fd < 0) {
+@@ -828,7 +2083,7 @@
+ MAP_SHARED | MAP_FILE, fd, dev_addr);
+
+ if (mem == MAP_FAILED) {
+- printf("Mmap of device at 0x%08X for 0x%X bytes failed - "
++ printf("mmap of device at 0x%08llX for 0x%X bytes failed - "
+ "%s\n", dev_addr, AR5K_PCI_MEM_SIZE, strerror(errno));
+ return -3;
+ }
+@@ -856,10 +2111,31 @@
+ AR5K_REG_DISABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_SPWR_DN);
+ usleep(500);
+
++ if (reg_read) {
++ printf("READ %04x = %08x\n", reg_read, AR5K_REG_READ(reg_read));
++ return 0;
++ }
++
++ if (reg_write) {
++ printf("WRITE %04x = %08x\n", reg_write, reg_write_val);
++ AR5K_REG_WRITE(reg_write, reg_write_val);
++ return 0;
++ }
++
+ srev = AR5K_REG_READ(AR5K_SREV);
+- mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER) << 4;
++ if (srev >= 0x0100) {
++ printf("MAC revision 0x%04x is not supported!\n", srev);
++ return -1;
++ }
++ mac_version = srev & AR5K_SREV_VER;
++ mac_revision = srev & AR5K_SREV_REV;
+
+- /* Verify eeprom magic value first */
++ printf(" -==Device Information==-\n");
++
++ printf("MAC Revision: %-5s (0x%02x)\n",
++ ath5k_hw_get_mac_name(mac_revision), mac_revision);
++
++ /* Verify EEPROM magic value first */
+ error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MAGIC, &ee_magic,
+ mac_version);
+
+@@ -872,157 +2148,114 @@
+ printf("Warning: Invalid EEPROM Magic number!\n");
+ }
+
+- error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_HDR, &eeprom_header,
+- mac_version);
+-
+- if (error) {
+- printf("Unable to read EEPROM Header!\n");
+- return -1;
+- }
+-
+- error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_VERSION, &eeprom_version,
+- mac_version);
+-
+- if (error) {
+- printf("Unable to read EEPROM version!\n");
++ ee = calloc(sizeof(struct ath5k_eeprom_info), 1);
++ if (!ee) {
++ printf("Cannot allocate memory for EEPROM information\n");
+ return -1;
+ }
+
+- error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_REG_DOMAIN, ®domain,
+- mac_version);
+-
+- if (error) {
+- printf("Unable to read Regdomain!\n");
++ if (ath5k_eeprom_init(mem, mac_version, ee)) {
++ printf("EEPROM init failed\n");
+ return -1;
+ }
+
+- if (eeprom_version >= 0x4000) {
+- error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MISC0,
+- &has_crystal, mac_version);
+-
+- if (error) {
+- printf("Unable to read EEPROM Misc data!\n");
+- return -1;
+- }
+-
+- has_crystal = AR5K_EEPROM_HAS32KHZCRYSTAL(has_crystal);
+- } else {
+- has_crystal = 2;
+- }
+-
+ eeprom_size = AR5K_REG_MS(AR5K_REG_READ(AR5K_PCICFG),
+ AR5K_PCICFG_EESIZE);
+
+- has_a = AR5K_EEPROM_HDR_11A(eeprom_header);
+- has_b = AR5K_EEPROM_HDR_11B(eeprom_header);
+- has_g = AR5K_EEPROM_HDR_11G(eeprom_header);
+- has_rfkill = AR5K_EEPROM_HDR_RFKILL(eeprom_header);
++ dev_type = AR5K_EEPROM_HDR_DEVICE(ee->ee_header);
++ eemap = AR5K_EEPROM_EEMAP(ee->ee_misc0);
+
+- if (has_a)
++ /* 1 = ?? 2 = ?? 3 = card 4 = wmac */
++ printf("Device type: %1i\n", dev_type);
++
++ if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+ phy_rev_5ghz = ath5k_hw_radio_revision(mac_version, mem, 1);
+ else
+ phy_rev_5ghz = 0;
+
+- if (has_b)
++ if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+ phy_rev_2ghz = ath5k_hw_radio_revision(mac_version, mem, 0);
+ else
+ phy_rev_2ghz = 0;
+
+- printf(" -==Device Information==-\n");
+-
+- printf("MAC Version: %-5s (0x%02x)\n",
+- ath5k_hw_get_part_name(AR5K_VERSION_VER, mac_version),
+- mac_version);
+-
+- printf("MAC Revision: %-5s (0x%02x)\n",
+- ath5k_hw_get_part_name(AR5K_VERSION_VER, srev), srev);
+-
+- /* Single-chip PHY with a/b/g support */
+- if (has_b && !phy_rev_2ghz) {
+- printf("PHY Revision: %-5s (0x%02x)\n",
+- ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_5ghz),
+- phy_rev_5ghz);
+- phy_rev_5ghz = 0;
+- }
+-
+- /* Single-chip PHY with b/g support */
+- if (!has_a) {
+- printf("PHY Revision: %-5s (0x%02x)\n",
+- ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_2ghz),
+- phy_rev_2ghz);
+- phy_rev_2ghz = 0;
+- }
+-
+- /* Different chip for 5Ghz and 2Ghz */
+ if (phy_rev_5ghz) {
+- printf("5Ghz PHY Revision: %-5s (0x%2x)\n",
+- ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_5ghz),
+- phy_rev_5ghz);
++ printf("5GHz PHY Revision: %-5s (0x%02x)\n",
++ ath5k_hw_get_phy_name(phy_rev_5ghz), phy_rev_5ghz);
+ }
+ if (phy_rev_2ghz) {
+- printf("2Ghz PHY Revision: %-5s (0x%2x)\n",
+- ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_2ghz),
+- phy_rev_2ghz);
++ printf("2GHz PHY Revision: %-5s (0x%02x)\n",
++ ath5k_hw_get_phy_name(phy_rev_2ghz), phy_rev_2ghz);
+ }
+
+- printf(" -==EEPROM Information==-\n");
+-
+- printf("EEPROM Version: %x.%x\n",
+- (eeprom_version & 0xF000) >> 12, eeprom_version & 0xFFF);
++ printf("\n");
++ printf("/============== EEPROM Information =============\\\n");
++ printf("| EEPROM Version: %1x.%1x |",
++ (ee->ee_version & 0xF000) >> 12, ee->ee_version & 0xFFF);
+
+- printf("EEPROM Size: ");
++ printf(" EEPROM Size: ");
+
+ if (eeprom_size == 0) {
+- printf(" 4K\n");
+- byte_size = 4096;
++ printf(" 4 kbit |\n");
++ byte_size = 4096 / 8;
+ } else if (eeprom_size == 1) {
+- printf(" 8K\n");
+- byte_size = 8192;
++ printf(" 8 kbit |\n");
++ byte_size = 8192 / 8;
+ } else if (eeprom_size == 2) {
+- printf(" 16K\n");
+- byte_size = 16384;
++ printf(" 16 kbit |\n");
++ byte_size = 16384 / 8;
+ } else
+- printf(" ??\n");
++ printf(" unknown |\n");
+
+- printf("Regulatory Domain: 0x%X\n", regdomain);
+-
+- printf(" -==== Capabilities ====-\n");
+-
+- printf("| 802.11a Support: ");
+- if (has_a)
+- printf("yes |\n");
+- else
+- printf("no |\n");
+-
+- printf("| 802.11b Support: ");
+- if (has_b)
+- printf("yes |\n");
+- else
+- printf("no |\n");
++ printf("| EEMAP: %i |", eemap);
+
+- printf("| 802.11g Support: ");
+- if (has_g)
+- printf("yes |\n");
+- else
+- printf("no |\n");
++ printf(" Reg. Domain: 0x%02X |\n", ee->ee_regdomain);
+
+- printf("| RFKill Support: ");
+- if (has_rfkill)
+- printf("yes |\n");
+- else
+- printf("no |\n");
++ dump_capabilities(ee);
++ printf("\n");
+
+- if (has_crystal != 2) {
+- printf("| 32KHz Crystal: ");
+- if (has_crystal)
+- printf("yes |\n");
+- else
+- printf("no |\n");
++ printf("/=========================================================\\\n");
++ printf("| Calibration data common for all modes |\n");
++ printf("|=========================================================|\n");
++ printf("| CCK/OFDM gain delta: %2i |\n", ee->ee_cck_ofdm_gain_delta);
++ printf("| CCK/OFDM power delta: %2i |\n", ee->ee_cck_ofdm_power_delta);
++ printf("| Scaled CCK delta: %2i |\n", ee->ee_scaled_cck_delta);
++ printf("| 2GHz Antenna gain: %2i |\n", AR5K_EEPROM_ANT_GAIN_2GHZ(ee->ee_ant_gain));
++ printf("| 5GHz Antenna gain: %2i |\n", AR5K_EEPROM_ANT_GAIN_5GHZ(ee->ee_ant_gain));
++ printf("| Turbo 2W maximum dBm: %2i |\n", AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header));
++ printf("| Target power start: 0x%03x |\n", AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1));
++ printf("| EAR Start: 0x%03x |\n", AR5K_EEPROM_EARSTART(ee->ee_misc0));
++ printf("\\=========================================================/\n");
++
++ printf("\n");
++ if (AR5K_EEPROM_HDR_11A(ee->ee_header)) {
++ printf("/=========================================================\\\n");
++ printf("| Calibration data for 802.11a operation |\n");
++ dump_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++ dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++ dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++ printf("\n");
++ }
++
++ if (AR5K_EEPROM_HDR_11B(ee->ee_header)) {
++ printf("/=========================================================\\\n");
++ printf("| Calibration data for 802.11b operation |\n");
++ dump_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++ dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++ dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++ printf("\n");
++ }
++
++ if (AR5K_EEPROM_HDR_11G(ee->ee_header)) {
++ printf("/=========================================================\\\n");
++ printf("| Calibration data for 802.11g operation |\n");
++ dump_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++ dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++ dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++ printf("\n");
+ }
+- printf(" ========================\n");
+
+ /* print current GPIO settings */
+- printf("GPIO registers: CR %08x DO %08x DI %08x\n",
++ printf("GPIO registers: CR 0x%08x, DO 0x%08x, DI 0x%08x\n",
+ AR5K_REG_READ(AR5K_GPIOCR), AR5K_REG_READ(AR5K_GPIODO),
+ AR5K_REG_READ(AR5K_GPIODI));
+
+@@ -1030,18 +2263,18 @@
+ u_int16_t data;
+ FILE *dumpfile = fopen("ath-eeprom-dump.bin", "w");
+
+- printf("\nEEPROM dump (%d byte)\n", byte_size);
++ printf("\nEEPROM dump (%d bytes)\n", byte_size);
+ printf("==============================================");
+- for (i = 1; i <= (byte_size / 2); i++) {
++ for (i = 0; i < byte_size / 2; i++) {
+ error =
+ ath5k_hw_eeprom_read(mem, i, &data, mac_version);
+ if (error) {
+ printf("\nUnable to read at %04x\n", i);
+ continue;
+ }
+- if (!((i - 1) % 8))
+- printf("\n%04x: ", i);
+- printf("%04x ", data);
++ if (!(i % 8))
++ printf("\n%04x: ", i);
++ printf(" %04x", data);
+ fwrite(&data, 2, 1, dumpfile);
+ }
+ printf("\n==============================================\n");
+@@ -1054,18 +2287,18 @@
+ u_int32_t old_cr = rcr, old_do = rdo;
+ int rc;
+
+- if (mac_version >= AR5K_SREV_VER_AR5213 && !nr_gpio_set) {
+- dbg("new MAC %x (>= AR5213) set gpio4 to low",
++ if (mac_version >= AR5K_SREV_MAC_AR5213 && !nr_gpio_set) {
++ dbg("new MAC %x (>= AR5213) set GPIO4 to low",
+ mac_version);
+ gpio_set[4].valid = 1;
+ gpio_set[4].value = 0;
+ }
+
+- /* set gpios */
++ /* set GPIOs */
+ dbg("old GPIO CR %08x DO %08x DI %08x",
+ rcr, rdo, AR5K_REG_READ(AR5K_GPIODI));
+
+- for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++) {
++ for (i = 0; i < ARRAY_SIZE(gpio_set); i++) {
+ if (gpio_set[i].valid) {
+ rcr |= AR5K_GPIOCR_OUT(i); /* we use mode 3 */
+ rcr &= ~AR5K_GPIOCR_INT_SEL(i);
+@@ -1111,5 +2344,17 @@
+
+ return rc;
+ }
++
++ sta_id0_id1_dump(mem);
++
++ for (i = 0; i < timer_count; i++)
++ dump_timers_register(mem, mac_version);
++
++ if (do_keycache_dump)
++ keycache_dump(mem, mac_version);
++
++ if (keycache_copy_idx > 0)
++ keycache_copy(mem, mac_version, keycache_copy_idx);
++
+ return 0;
+ }