/************************************************************************* * (C) 2010 AITNET - Sofia/Bulgaria - * by Michael Pounov * * $Author: misho $ * $Id: athctl.c,v 1.2 2011/06/08 12:45:41 misho Exp $ * *************************************************************************/ #include "global.h" #include "athctl.h" int Verbose; extern char compiled[], compiledby[], compilehost[]; static void Usage() { printf( "athCtl is tool for Atheros WiFi cards managment \n" "=== %s === %s@%s ===\n\n" " Syntax: athctl [options] [[0xMemory_Address] new_value]\n" " athctl [-v] -t [-i ]\n" " athctl [-v] -c [-i ]\n" " athctl [-v] -d [-i ]\n" " athctl [-v] -r <0xoffset> <0xMemory_Address>\n" " athctl [-v] -w <0xoffset> <0xMemory_Address> \n" " athctl [-v] -s <0xMemory_Address>\n" " athctl [-v] -u <0xMemory_Address>\n" " athctl [-v] -R <0xMemory_Address> [new_regdomain]\n" "\n" "\t-v\t\tVerbose ...\n" "\t-t\t\tGet current Atheros maximum range in meters\n" "\t-i \tApply to this Atheros interface number (like ath0 == 0)\n" "\t-d \tMode distance, meters to target\n" "\t-c \tMode distance, mS timeouts correction\n" "\t-R\t\tRead or Write EEPROM Regulatory domain\n" "\t-s \tDump EEPROM to file\n" "\t-u \tUpdate EEPROM from file\n" "\t-r \tRead EEPROM word from PCI mapped memory address\n" "\t-w \tWrite EEPROM word to PCI mapped memory address\n" "\n", compiled, compiledby, compilehost); } static int calcDistance(int ifid, int dist, int cor) { int slottime[2], timeout[2]; size_t len; char szStr[STRSIZ]; slottime[0] = 9 + (dist / 300) + (dist % 300 ? 1 : 0); timeout[0] = slottime[0] * 2 + 3 + cor; VERB(3) printf("Info:: slottime=%d timeout=%d\n", slottime[0], timeout[0]); memset(szStr, 0, STRSIZ); snprintf(szStr, STRSIZ, SC_SLOTTIME, ifid); if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else if (sysctlbyname(szStr, &slottime[1], &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else if (sysctlbyname(szStr, NULL, NULL, &slottime[0], sizeof slottime[0]) == -1) { printf("Error:: set sysctl %s from %d #%d - %s\n", szStr, slottime[1], errno, strerror(errno)); return -1; } else VERB(1) printf("Info:: set slottime(%d) from %d to %d ... OK!\n", len, slottime[1], slottime[0]); memset(szStr, 0, STRSIZ); snprintf(szStr, STRSIZ, SC_ACKTIMEOUT, ifid); if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else if (sysctlbyname(szStr, &timeout[1], &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else if (sysctlbyname(szStr, NULL, NULL, &timeout[0], sizeof timeout[0]) == -1) { printf("Error:: set sysctl %s from %d #%d - %s\n", szStr, timeout[1], errno, strerror(errno)); return -1; } else VERB(1) printf("Info:: set acktimeout(%d) from %d to %d ... OK!\n", len, timeout[1], timeout[0]); memset(szStr, 0, STRSIZ); snprintf(szStr, STRSIZ, SC_CTSTIMEOUT, ifid); if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else if (sysctlbyname(szStr, &timeout[1], &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else if (sysctlbyname(szStr, NULL, NULL, &timeout[0], sizeof timeout[0]) == -1) { printf("Error:: set sysctl %s from %d #%d - %s\n", szStr, timeout[1], errno, strerror(errno)); return -1; } else VERB(1) printf("Info:: set ctstimeout(%d) from %d to %d ... OK!\n", len, timeout[1], timeout[0]); return timeout[0]; } static int calcTimeout(int ifid, int cor) { int slottime[2], timeout[2]; size_t len; char szStr[STRSIZ]; memset(szStr, 0, STRSIZ); snprintf(szStr, STRSIZ, SC_SLOTTIME, ifid); if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else if (sysctlbyname(szStr, &slottime[1], &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else VERB(1) printf("Info:: get slottime(%d) %d ... OK!\n", len, slottime[1]); memset(szStr, 0, STRSIZ); snprintf(szStr, STRSIZ, SC_ACKTIMEOUT, ifid); if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else if (sysctlbyname(szStr, &timeout[1], &len, NULL, 0) == -1) { printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno)); return -1; } else VERB(1) printf("Info:: get acktimeout(%d) %d ... OK!\n", len, timeout[1]); slottime[0] = (timeout[1] - 3 - cor) / 2; VERB(3) printf("Info:: calculated slottime=%d\n", slottime[0]); timeout[0] = (slottime[0] - 10) * 300; VERB(3) printf("Info:: calculated timeout=%d\n", timeout[0]); return timeout[0]; } static inline void * devOpen(u_long baseaddr) { int fd; void *basemem; fd = open("/dev/mem", O_RDWR); if (fd == -1) { printf("Error:: open device #%d - %s\n", errno, strerror(errno)); return NULL; } basemem = mmap(NULL, ATH_PCI_MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr); if (basemem == MAP_FAILED) { printf("Error:: map device #%d - %s\n", errno, strerror(errno)); close(fd); return NULL; } else close(fd); return basemem; } static inline void devClose(void *basemem) { if (basemem) munmap(basemem, ATH_PCI_MEM_SIZE); } static inline int readWord(u_char *mem, u_long offset) { register int timeout = ATH_ACCESS_TIMEOUT; u_long stat; VERB(9) printf("Reading EEPROM memory %p+%lx ...\n", mem, offset); ATH_OUT(mem, AR5211_EEPROM_CONF, 0); usleep(ATH_ACCESS_WAIT); /* enable eeprom access */ ATH_OUT(mem, AR5211_EEPROM_COMD, ATH_IN(mem, AR5211_EEPROM_COMD) | AR5211_EEPROM_COMD_RESET); usleep(ATH_ACCESS_WAIT); /* set address */ ATH_OUT(mem, AR5211_EEPROM_ADDR, offset); usleep(ATH_ACCESS_WAIT); /* enable eeprom read access */ ATH_OUT(mem, AR5211_EEPROM_COMD, ATH_IN(mem, AR5211_EEPROM_COMD) | AR5211_EEPROM_COMD_READ); usleep(ATH_ACCESS_WAIT); while (timeout--) { usleep(1); stat = ATH_IN(mem, AR5211_EEPROM_STATUS); if (stat & AR5211_EEPROM_STAT_RDDONE) { if (stat & AR5211_EEPROM_STAT_RDERR) { printf("Error:: EEPROM read failed!\n"); return -1; } stat = ATH_IN(mem, AR5211_EEPROM_DATA); return (stat & 0x0000ffff) << 16; } } printf("Error:: EEPROM read timeout!\n"); return -1; } static inline int writeWord(u_char *mem, u_long offset, u_short newval) { register int i = ATH_WRITE_RETRY, timeout; u_long pcicfg, stat; int chk; VERB(9) printf("Writing EEPROM memory %p+%lx ...\n", mem, offset); /* enable pci write access */ pcicfg = ATH_IN(mem, AR5K_PCICFG); ATH_OUT(mem, AR5K_PCICFG, (pcicfg & ~AR5K_PCICFG_SPWR_DN)); usleep(ATH_ACCESS_WAITDOWN); ATH_OUT(mem, AR5K_PCICFG, pcicfg | AR5K_PCICFG_EEAE /* | 0x2 */); usleep(ATH_ACCESS_WAITPCI); ATH_OUT(mem, AR5211_EEPROM_STATUS, 0); usleep(ATH_ACCESS_WAITPCI); /* ATH_OUT(mem, AR5211_EEPROM_CONF, 1); */ ATH_OUT(mem, AR5211_EEPROM_CONF, 0); do { /* enable eeprom write access */ ATH_OUT(mem, AR5211_EEPROM_COMD, AR5211_EEPROM_COMD_RESET); usleep(ATH_ACCESS_WAITDOWN); ATH_OUT(mem, AR5211_EEPROM_DATA, newval); usleep(ATH_ACCESS_WAIT); ATH_OUT(mem, AR5211_EEPROM_ADDR, offset); usleep(ATH_ACCESS_WAIT); ATH_OUT(mem, AR5211_EEPROM_COMD, AR5211_EEPROM_COMD_WRITE); usleep(ATH_ACCESS_WAIT); for (timeout = ATH_ACCESS_TIMEOUT; timeout; timeout--) { stat = ATH_IN(mem, AR5211_EEPROM_STATUS); if (stat & 0xc) { if (stat & AR5211_EEPROM_STAT_WRERR) { printf("Error:: EEPROM write failed!\n"); return -1; } ATH_OUT(mem, AR5211_EEPROM_STATUS, 0); usleep(ATH_ACCESS_WAIT * 2); break; } usleep(ATH_ACCESS_WAIT * 2); } chk = readWord(mem, offset); if (chk == (u_short) -1) return -1; if ((u_short) (chk >> 16) == newval) return chk; else VERB(1) printf("Write & Read don`t match 0x%04X != 0x%04X\n", newval, (u_short) (chk >> 16)); if (i) printf("Warning:: Retrying EEPROM write ...\n"); } while (--i); printf("Error:: EEPROM write timeout!\n"); return -1; } static int dumpFile(const char *csName, u_char *mem) { register u_long i; u_short d1, d2; u_char eeprom[ATH_EEPROM_SIZE] = { 0 }; int f, data; VERB(2) printf("Reading EEPROM memory %p ::\n", mem); for (i = 0; i < ATH_EEPROM_SIZE / 2; i++) { if (!(i % 0x40)) { if (i) printf("]\n"); printf("0x%04lX [", i * 2); } if ((data = readWord(mem, i)) == -1) return -1; else { d1 = ((u_short)(data >> 16)) / 0x100; d2 = ((u_short)(data >> 16)) % 0x100; VERB(5) printf( "Current value 0x%04X on position 0x%04lX will change 0x%02X 0x%02X\n", (u_short) (data >> 16), i, d1, d2); } eeprom[i * 2] = d2; eeprom[i * 2 + 1] = d1; printf("."); usleep(ATH_ACCESS_WAITDOWN); } printf("]\n"); VERB(2) printf("Saving EEPROM to file %s ... ", csName); f = open(csName, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (f == -1) { printf("Failed!\nError:: in create file %s #%d - %s\n", csName, errno, strerror(errno)); return 0; } if (write(f, eeprom, ATH_EEPROM_SIZE) == -1) { printf("Failed!\nError:: in write to file %s #%d - %s\n", csName, errno, strerror(errno)); close(f); return 0; } close(f); printf("OK!\n"); return 1; } static int flashFile(const char *csName, u_char *mem) { register u_long i; u_short d1; u_char eeprom[ATH_EEPROM_SIZE] = { 0 }; int f, data; VERB(2) printf("Reading EEPROM from file %s ... ", csName); f = open(csName, O_RDONLY); if (f == -1) { printf("Failed!\nError:: in open file %s #%d - %s\n", csName, errno, strerror(errno)); return 0; } if (read(f, eeprom, ATH_EEPROM_SIZE) != ATH_EEPROM_SIZE) { printf("Failed!\nError:: failed load image from file %s\n", csName); close(f); return 0; } close(f); VERB(2) printf("OK!\n"); VERB(2) printf("Writing EEPROM memory %p ::\n", mem); for (i = 0; i < ATH_EEPROM_SIZE / 2; i++) { if (!(i % 0x40)) { if (i) printf("]\n"); printf("0x%04lX [", i * 2); } if ((data = readWord(mem, i)) == -1) return -1; else d1 = eeprom[i * 2 + 1] * 0x100 + eeprom[i * 2]; VERB(5) printf("eeprom_data=0x%04X read_d1=0x%04X\n", (u_char) (data >> 16), d1); if (((u_short) (data >> 16)) == d1) printf("."); else { if (writeWord(mem, i, d1) < 1) printf("!"); else printf("x"); } usleep(ATH_ACCESS_WAITDOWN); } printf("]\n"); return 0; } static int regDomain(u_char *mem, u_short newval) { int ret, data; if ((data = readWord(mem, ATH_OFFSET_REGDOMAIN)) == -1) return -1; printf("Current value 0x%04X ", (u_short) (data >> 16)); if (newval != (u_short) -1) { printf("will change to 0x%04X\n", newval); if ((ret = writeWord(mem, ATH_OFFSET_REGDOMAIN, newval)) == -1) return -1; printf("Updated regulatory domain is 0x%04X\n", (u_short) (ret >> 16)); } else printf("\nCurrent regulatory domain is 0x%04X\n", (u_short) (data >> 16)); return 0; } // ---------------------------------------------------- int main(int argc, char **argv) { char ch, szName[MAXPATHLEN] = { 0 }, mode = 0; int ret = 0, dist = 0, cor = 0, ino = 0; u_long offset = 0, baseaddr = (u_long) -1; u_short newval = 0; void *basemem = NULL; while ((ch = getopt(argc, argv, "hvRtr:w:i:d:c:u:s:")) != -1) switch (ch) { case 'v': Verbose++; break; case 't': mode |= 2; break; case 'i': ino = strtol(optarg, NULL, 0); if (ino < 0) { printf("Error:: in interface number %d\n", ino); return 1; } break; case 'd': mode |= 1; dist = strtol(optarg, NULL, 0); if (dist < 1) { printf("Error:: in distance meters %d\n", dist); return 1; } break; case 'c': mode |= 1; cor = strtol(optarg, NULL, 0); break; case 's': mode = 0x10; strlcpy(szName, optarg, MAXPATHLEN); break; case 'u': mode = 0x20; strlcpy(szName, optarg, MAXPATHLEN); break; case 'R': mode = 0x40; break; case 'r': mode = 4; offset = strtoul(optarg, NULL, 0); break; case 'w': mode = 8; offset = strtoul(optarg, NULL, 0); break; case 'h': default: Usage(); return 1; } argc -= optind; argv += optind; if (argc && *argv) baseaddr = strtoul(*argv, NULL, 0); if (!mode) { printf("Error:: not selected mode for operation ...\n"); return 1; } if (mode > 3 && baseaddr == (u_long) -1) { printf("Error:: in this mode for operation, must give memory mapped address ...\n"); return 1; } if (mode & 8) { if (!argv[1]) { printf("Error:: in write word mode, must give memory mapped address and new value ...\n"); return 1; } else newval = (u_short) strtoul(argv[1], NULL, 0); } if (mode & 0x40) { if (argv[1]) newval = (u_short) strtoul(argv[1], NULL, 0); else newval = (u_short) -1; } if (mode & 1) if ((ret = calcDistance(ino, dist, cor)) < 1) return 2; if (mode & 2) { if ((ret = calcTimeout(ino, cor)) < 1) return 2; else { VERB(1) printf("Maximum approximate distance ~%d meters\n", ret); else printf("~%d\n", ret); } } if (mode & 4) { if (!(basemem = devOpen(baseaddr))) return 2; if ((ret = readWord(basemem, offset)) == -1) { devClose(basemem); return 3; } else printf("EEPROM readed value 0x%04X\n", (u_short) (ret >> 16)); devClose(basemem); } if (mode & 8) { if (!(basemem = devOpen(baseaddr))) return 2; if ((ret = writeWord(basemem, offset, newval)) == -1) { devClose(basemem); return 3; } else printf("EEPROM writed value 0x%04X\n", (u_short) (ret >> 16)); devClose(basemem); } if (mode & 0x10) { if (!(basemem = devOpen(baseaddr))) return 2; if ((ret = dumpFile(szName, basemem)) < 1) { devClose(basemem); return 3; } devClose(basemem); } if (mode & 0x20) { if (!(basemem = devOpen(baseaddr))) return 2; if ((ret = flashFile(szName, basemem)) < 1) { devClose(basemem); return 3; } devClose(basemem); } if (mode & 0x40) { if (!(basemem = devOpen(baseaddr))) return 2; if ((ret = regDomain(basemem, newval)) < 1) { devClose(basemem); return 3; } devClose(basemem); } return 0; }