--- embedtools/src/athctl.c 2010/10/22 09:16:27 1.1 +++ embedtools/src/athctl.c 2011/06/08 12:45:41 1.2 @@ -0,0 +1,553 @@ +/************************************************************************* + * (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; +}