|
|
| version 1.1.2.1, 2010/10/22 09:16:27 | version 1.1.2.10, 2010/11/03 14:34:58 |
|---|---|
| Line 1 | Line 1 |
| /************************************************************************* | |
| * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com> | |
| * by Michael Pounov <misho@aitbg.com> | |
| * | |
| * $Author$ | |
| * $Id$ | |
| * | |
| *************************************************************************/ | |
| #include "global.h" | #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 <iface_no>]\n" | |
| " athctl [-v] -c <timeout> [-i <iface_no>]\n" | |
| " athctl [-v] -d <distance> [-i <iface_no>]\n" | |
| " athctl [-v] -r <0xoffset> <0xMemory_Address>\n" | |
| " athctl [-v] -w <0xoffset> <0xMemory_Address> <uint16_value>\n" | |
| " athctl [-v] -s <file> <0xMemory_Address>\n" | |
| " athctl [-v] -w <file> <0xMemory_Address>\n" | |
| "\n" | |
| "\t-v\t\tVerbose ...\n" | |
| "\t-t\t\tGet current Atheros maximum range in meters\n" | |
| "\t-i <iface_no>\tApply to this Atheros interface number (like ath0 == 0)\n" | |
| "\t-d <distance>\tMode distance, meters to target\n" | |
| "\t-c <timeout>\tMode distance, mS timeouts correction\n" | |
| "\t-s <file>\tDump EEPROM to file\n" | |
| "\t-u <file>\tUpdate EEPROM from file\n" | |
| "\t-r <offset>\tRead EEPROM word from PCI mapped memory address\n" | |
| "\t-w <offset>\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(2) 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; | |
| u_short chk; | |
| VERB(2) 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 (chk == newval) | |
| return chk << 16; | |
| else | |
| VERB(1) printf("Write & Read don`t match 0x%04X != 0x%04X\n", newval, chk); | |
| 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_short 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; | |
| } | |
| 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_short 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); | |
| 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]; | |
| if ((data >> 16) == d1) | |
| printf("."); | |
| else { | |
| printf("x"); | |
| if (writeWord(mem, i, d1) < 1) | |
| return -1; | |
| } | |
| usleep(ATH_ACCESS_WAITDOWN); | |
| } | |
| printf("]\n"); | |
| return 0; | |
| } | |
| // ---------------------------------------------------- | |
| int | int |
| main(int argc, char **argv) | 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, "hvtr: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 = 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 & 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); | |
| 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); | |
| } | |
| return 0; | return 0; |
| } | } |