📄 ath_info.c
字号:
/* -*- linux-c -*- *//*- * Copyright (c) 2007 Nick Kossifidis <mickflemm@gmail.com> * Copyright (c) 2007 Joerg Albert <jal2 *at* gmx.de> * * This program is free software you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY, without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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. * */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <fcntl.h>#include <sys/mman.h>#include <endian.h>#include <byteswap.h>#define dbg(fmt, __args__...) \do { \ if (verbose) \ printf("#DBG %s: " fmt "\n", __FUNCTION__, ##__args__); \ } while (0)#define err(fmt, __args__...) \fprintf(stderr, "#ERR %s: " fmt "\n", __FUNCTION__, ##__args__)#define AR5K_PCI_MEM_SIZE 0x10000#define AR5K_ELEMENTS(_array) (sizeof(_array) / sizeof(_array[0]))#define AR5K_NUM_GPIO 6#define AR5K_GPIOCR 0x4014 /* Register Address */#define AR5K_GPIOCR_OUT(n) (3 << ((n) * 2)) /* Mode 3 for pin n */#define AR5K_GPIOCR_INT_SEL(n) ((n) << 12) /* Interrupt for GPIO pin n *//* * GPIO (General Purpose Input/Output) data output register */#define AR5K_GPIODO 0x4018/* * GPIO (General Purpose Input/Output) data input register */#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;};#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},};/* * 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/* * PHY chip revision register */#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_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_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) */#define AR5K_RESET_CTL_CHIP (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA | \ AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY)/* * Sleep control register */#define AR5K_SLEEP_CTL 0x4004 /* Register Address */#define AR5K_SLEEP_CTL_SLDUR 0x0000ffff /* Sleep duration mask */#define AR5K_SLEEP_CTL_SLDUR_S 0#define AR5K_SLEEP_CTL_SLE 0x00030000 /* Sleep enable mask */#define AR5K_SLEEP_CTL_SLE_S 16#define AR5K_SLEEP_CTL_SLE_WAKE 0x00000000 /* Force chip awake */#define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /* Force chip sleep */#define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000#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_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */#define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */#define AR5K_PCICFG_EESIZE_S 3#define AR5K_PCICFG_EESIZE_4K 0 /* 4K */#define AR5K_PCICFG_EESIZE_8K 1 /* 8K */#define AR5K_PCICFG_EESIZE_16K 2 /* 16K */#define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size (?) [5211+] */#define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status (5210) */#define AR5K_EEPROM_BASE 0x6000#define AR5K_EEPROM_MAGIC 0x003d /* Offset for 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 *//* * 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 ? \ AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)/* * EEPROM command register */#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */#define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */#define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */#define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset *//* * 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 ? \ 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#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1)#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 *//* 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)/* * Read data by masking */#define AR5K_REG_MS(_val, _flags) \ (((_val) & (_flags)) >> _flags##_S)/* * Access device registers */#if __BYTE_ORDER == __BIG_ENDIAN#define AR5K_REG_READ(_reg) \ __bswap_32(*((volatile u_int32_t *)(mem + (_reg))))#define AR5K_REG_WRITE(_reg, _val) \ (*((volatile u_int32_t *)(mem + (_reg))) = __bswap_32(_val))#else#define AR5K_REG_READ(_reg) \ (*((volatile u_int32_t *)(mem + (_reg))))#define AR5K_REG_WRITE(_reg, _val) \ (*((volatile u_int32_t *)(mem + (_reg))) = (_val))#endif#define AR5K_REG_ENABLE_BITS(_reg, _flags) \ AR5K_REG_WRITE(_reg, AR5K_REG_READ(_reg) | (_flags))#define AR5K_REG_DISABLE_BITS(_reg, _flags) \ AR5K_REG_WRITE(_reg, AR5K_REG_READ(_reg) & ~(_flags))#define AR5K_TUNE_REGISTER_TIMEOUT 20000/* names for eeprom fields */struct eeprom_entry { const char *name; int addr;};static const struct eeprom_entry eeprom_addr[] = { {"pci_dev_id", 0}, {"pci_vendor_id", 1}, {"pci_class", 2}, {"pci_rev_id", 3}, {"pci_subsys_dev_id", 7}, {"pci_subsys_vendor_id", 8}, {"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;/* forward decl. */static void usage(const char *n);static u_int32_t ath5k_hw_bitswap(u_int32_t val, u_int bits){ u_int32_t retval = 0, bit, i; for (i = 0; i < bits; i++) { bit = (val >> i) & 1; retval = (retval << 1) | bit; } return (retval);}/* * Get the PHY Chip revision */static u_int16_tath5k_hw_radio_revision(u_int16_t mac_version, void *mem, u_int8_t chip){ int i; u_int32_t srev; u_int16_t ret; /* * Set the radio chip access register */ switch (chip) { case 0: AR5K_REG_WRITE(AR5K_PHY(0), AR5K_PHY_SHIFT_2GHZ); break; case 1: AR5K_REG_WRITE(AR5K_PHY(0), AR5K_PHY_SHIFT_5GHZ); break; default: return (0); } usleep(2000); /* ...wait until PHY is ready and read the selected radio revision */ AR5K_REG_WRITE(AR5K_PHY(0x34), 0x00001c16); for (i = 0; i < 8; i++) AR5K_REG_WRITE(AR5K_PHY(0x20), 0x00010000); if (mac_version == AR5K_SREV_VER_AR5210) { srev = AR5K_REG_READ(AR5K_PHY(256) >> 28) & 0xf; ret = (u_int16_t)ath5k_hw_bitswap(srev, 4) + 1; } else { srev = (AR5K_REG_READ(AR5K_PHY(0x100)) >> 24) & 0xff; ret = (u_int16_t)ath5k_hw_bitswap(((srev & 0xf0) >> 4) | ((srev & 0x0f) << 4), 8); } /* Reset to the 5GHz mode */ AR5K_REG_WRITE(AR5K_PHY(0), AR5K_PHY_SHIFT_5GHZ); return (ret);}/* * Write to EEPROM */static intath5k_hw_eeprom_write(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) { AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE); /* data to write */ (void)AR5K_REG_WRITE(AR5K_EEPROM_BASE + (4 * offset), data); } else { /* not 5210 */ /* reset eeprom access */ AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_RESET); usleep(5); AR5K_REG_WRITE(AR5K_EEPROM_DATA, data); /* set offset in EEPROM to write to */ AR5K_REG_WRITE(AR5K_EEPROM_BASE, offset); usleep(5); /* issue write command */ AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_WRITE); } for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { 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", offset); return 1; } return 0; } usleep(15); } return 1;}/* * Read from EEPROM */static intath5k_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) { AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE); (void)AR5K_REG_READ(AR5K_EEPROM_BASE + (4 * offset)); } else { AR5K_REG_WRITE(AR5K_EEPROM_BASE, offset); AR5K_REG_ENABLE_BITS(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_READ); } for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { status = AR5K_REG_READ(AR5K_EEPROM_STATUS); if (status & AR5K_EEPROM_STAT_RDDONE) { if (status & AR5K_EEPROM_STAT_RDERR) return 1; *data = (u_int16_t) (AR5K_REG_READ(AR5K_EEPROM_DATA) & 0xffff); return (0); } usleep(15); } return 1;}static const char *ath5k_hw_get_part_name(enum ath5k_srev_type type, u_int32_t val){ const char *name = "xxxxx"; int i; for (i = 0; i < AR5K_ELEMENTS(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; break; } } return (name);}/* returns -1 on unknown name */static int eeprom_name2addr(const char *name){ int i; if (!name || !name[0]) return -1; for (i = 0; i < eeprom_addr_len; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -