📄 ath_info.c
字号:
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++) if (eeprom_addr[i].addr == addr) return eeprom_addr[i].name; return "<unknown>";} /* eeprom_addr2name */static intdo_write_pairs(int anr, int argc, char **argv, unsigned char *mem, int mac_version){#define MAX_NR_WRITES 16 struct { int addr; unsigned int val; } wr_ops[MAX_NR_WRITES]; int wr_ops_len = 0; int i; char *end; int errors = 0; /* count errors during write/verify */ if (anr >= argc) { err("missing values to write."); usage(argv[0]); return 1; } if ((argc - anr) % 2) { err("write spec. needs an even number of arguments."); usage(argv[0]); return 2; } if ((argc - anr) / 2 > MAX_NR_WRITES) { err("too many values to write (max. %d)", MAX_NR_WRITES); return 3; } /* get the (addr,val) pairs we have to write */ i = 0; while (anr < (argc - 1)) { wr_ops[i].addr = strtoul(argv[anr], &end, 16); if (end == argv[anr]) { /* maybe a symbolic name for the address? */ if ((wr_ops[i].addr = eeprom_name2addr(argv[anr])) == -1) { err("pair %d: bad address %s", i, argv[anr]); return 4; } } if (wr_ops[i].addr >= AR5K_EEPROM_INFO_BASE) { err("offset 0x%04x in CRC protected area is " "not supported", wr_ops[i].addr); return 5; } anr++; wr_ops[i].val = strtoul(argv[anr], &end, 16); if (end == argv[anr]) { err("pair %d: bad val %s", i, argv[anr]); return 5; } if (wr_ops[i].val > 0xffff) { err("pair %d: value %u too large", i, wr_ops[i].val); return 6; } anr++; i++; } /* while (anr < (argc-1)) */ if (!(wr_ops_len = i)) { err("no (addr,val) pairs given"); return 7; } if (verbose || !force_write) { for (i = 0; i < wr_ops_len; i++) printf("%20s (0x%04x) := 0x%04x\n", eeprom_addr2name(wr_ops[i].addr), wr_ops[i].addr, wr_ops[i].val); } if (!force_write) { int c; printf ("WARNING: The write function may easy brick your device or\n" "violate state regulation on frequency usage.\n" "Proceed on your own risk!\n" "Shall I write the above value(s)? (y/n)\n"); c = getchar(); if (c != 'y' && c != 'Y') { printf("user abort\n"); return 0; } } for (i = 0; i < wr_ops_len; i++) { u_int16_t oldval, u; if (ath5k_hw_eeprom_read (mem, wr_ops[i].addr, &oldval, mac_version)) { err("failed to read old value from offset 0x%04x ", wr_ops[i].addr); errors++; } if (oldval == wr_ops[i].val) { dbg("pair %d: skipped, value already there", i); continue; } dbg("writing *0x%04x := 0x%04x", wr_ops[i].addr, wr_ops[i].val); if (ath5k_hw_eeprom_write (mem, wr_ops[i].addr, wr_ops[i].val, mac_version)) { err("failed to write 0x%04x to offset 0x%04x", wr_ops[i].val, wr_ops[i].addr); errors++; } else { if (ath5k_hw_eeprom_read (mem, wr_ops[i].addr, &u, mac_version)) { err("failed to read offset 0x%04x for " "verification", wr_ops[i].addr); errors++; } else { if (u != wr_ops[i].val) { err("offset 0x%04x: wrote 0x%04x but " "read 0x%04x", wr_ops[i].addr, wr_ops[i].val, u); errors++; } } } } return errors ? 11 : 0;} /* do_write_pairs */static void usage(const char *n){ int i; fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] <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" "<base_address> device base address (see lspci output)\n\n"); fprintf(stderr, "- read info:\n" " %s <base_address>\n\n" "- set regdomain to N:\n" " %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++) fprintf(stderr, " %s", eeprom_addr[i].name); fprintf(stderr, "\n\n"); fprintf(stderr, "You may need to set a GPIO to a certain value in order to enable\n" "writing to the EEPROM with newer chipsets, e.g. set GPIO 4 to low:\n" " %s -g 4:0 -w <base_address> regdomain N\n", n); fprintf(stderr, "\nDISCLAIMER: The authors are not responsible for any damages caused by\n" "this program. Writing improper values may damage the card or cause\n" "unlawful radio transmissions!\n\n");}int main(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; void *mem; int fd; int i, anr = 1; int do_write = 0; /* default: read only */ int do_dump = 0; struct { int valid; int value; } gpio_set[AR5K_NUM_GPIO]; int nr_gpio_set = 0; for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++) gpio_set[i].valid = 0; if (argc < 2) { usage(argv[0]); return -1; } while (anr < argc && argv[anr][0] == '-') { switch (argv[anr][1]) { case 'w': do_write = 1; break; case 'g': anr++; 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]); return 2; } gpio_set[argv[anr][0] - '0'].valid = 1; gpio_set[argv[anr][0] - '0'].value = argv[anr][2] - '0'; nr_gpio_set++; break; case 'f': force_write = 1; break; case 'v': verbose = 1; break; case 'd': do_dump = 1; break; case 'h': usage(argv[0]); return 0; break; default: err("unknown option %s", argv[anr]); return 2; } /* switch (argv[anr][1]) */ anr++; } /* while (anr < argc && ...) */ if (anr >= argc) { err("missing device address"); usage(argv[0]); return 3; } dev_addr = strtoul(argv[anr], NULL, 16); fd = open("/dev/mem", O_RDWR); if (fd < 0) { printf("Opening /dev/mem failed!\n"); return -2; } mem = mmap(NULL, AR5K_PCI_MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, dev_addr); if (mem == MAP_FAILED) { printf("Mmap of device at 0x%08X for 0x%X bytes failed - " "%s\n", dev_addr, AR5K_PCI_MEM_SIZE, strerror(errno)); return -3; } /* wake from power-down and remove reset (in case the driver isn't running) */ { u_int32_t sleep_ctl = AR5K_REG_READ(AR5K_SLEEP_CTL), reset_ctl = AR5K_REG_READ(AR5K_RESET_CTL); dbg("sleep_ctl reg %08x reset_ctl reg %08x", sleep_ctl, reset_ctl); if (sleep_ctl & AR5K_SLEEP_CTL_SLE_SLP) { dbg("waking up the chip"); AR5K_REG_WRITE(AR5K_SLEEP_CTL, (sleep_ctl & ~AR5K_SLEEP_CTL_SLE_SLP)); } if (reset_ctl) { dbg("removing resets"); AR5K_REG_WRITE(AR5K_RESET_CTL, 0); } } AR5K_REG_DISABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_SPWR_DN); usleep(500); srev = AR5K_REG_READ(AR5K_SREV); mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER) << 4; /* Verify eeprom magic value first */ error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MAGIC, &ee_magic, mac_version); if (error) { printf("Unable to read EEPROM Magic value!\n"); return -1; } if (ee_magic != AR5K_EEPROM_MAGIC_VALUE) { 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"); return -1; } error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_REG_DOMAIN, ®domain, mac_version); if (error) { printf("Unable to read Regdomain!\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); if (has_a) phy_rev_5ghz = ath5k_hw_radio_revision(mac_version, mem, 1); else phy_rev_5ghz = 0; if (has_b) 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); } 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(" -==EEPROM Information==-\n"); printf("EEPROM Version: %x.%x\n", (eeprom_version & 0xF000) >> 12, eeprom_version & 0xFFF); printf("EEPROM Size: "); if (eeprom_size == 0) { printf(" 4K\n"); byte_size = 4096; } else if (eeprom_size == 1) { printf(" 8K\n"); byte_size = 8192; } else if (eeprom_size == 2) { printf(" 16K\n"); byte_size = 16384; } else printf(" ??\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("| 802.11g Support: "); if (has_g) printf("yes |\n"); else printf("no |\n"); printf("| RFKill Support: "); if (has_rfkill) printf("yes |\n"); else printf("no |\n"); if (has_crystal != 2) { printf("| 32KHz Crystal: "); if (has_crystal) printf("yes |\n"); else printf("no |\n"); } printf(" ========================\n"); /* print current GPIO settings */ printf("GPIO registers: CR %08x DO %08x DI %08x\n", AR5K_REG_READ(AR5K_GPIOCR), AR5K_REG_READ(AR5K_GPIODO), AR5K_REG_READ(AR5K_GPIODI)); if (do_dump) { u_int16_t data; FILE *dumpfile = fopen("ath-eeprom-dump.bin", "w"); printf("\nEEPROM dump (%d byte)\n", byte_size); printf("=============================================="); for (i = 1; 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); fwrite(&data, 2, 1, dumpfile); } printf("\n==============================================\n"); fclose(dumpfile); } if (do_write) { u_int32_t rcr = AR5K_REG_READ(AR5K_GPIOCR), rdo = AR5K_REG_READ(AR5K_GPIODO); 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", mac_version); gpio_set[4].valid = 1; gpio_set[4].value = 0; } /* 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++) { if (gpio_set[i].valid) { rcr |= AR5K_GPIOCR_OUT(i); /* we use mode 3 */ rcr &= ~AR5K_GPIOCR_INT_SEL(i); rdo &= ~(1 << i); rdo |= (gpio_set[i].value << i); } } if (rcr != old_cr) { dbg("GPIO CR %x -> %x", old_cr, rcr); AR5K_REG_WRITE(AR5K_GPIOCR, rcr); } usleep(5); if (rdo != old_do) { dbg("GPIO CR %x -> %x", old_do, rdo); AR5K_REG_WRITE(AR5K_GPIODO, rdo); } /* dump current values again if we have written anything */ if (rcr != old_cr || rdo != old_do) dbg("new GPIO CR %08x DO %08x DI %08x", AR5K_REG_READ(AR5K_GPIOCR), AR5K_REG_READ(AR5K_GPIODO), AR5K_REG_READ(AR5K_GPIODI)); /* let argv[anr] be the first write parameter */ anr++; rc = do_write_pairs(anr, argc, argv, mem, mac_version); /* restore old GPIO settings */ if (rcr != old_cr) { dbg("restoring GPIO CR %x -> %x", rcr, old_cr); AR5K_REG_WRITE(AR5K_GPIOCR, old_cr); } usleep(5); if (rdo != old_do) { dbg("restoring GPIO CR %x -> %x", rdo, old_do); AR5K_REG_WRITE(AR5K_GPIODO, old_do); } return rc; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -