File:  [ELWIX - Embedded LightWeight unIX -] / embedtools / src / athctl.c
Revision 1.1.2.11: download - view: text, annotated - select for diffs - revision graph
Fri Nov 5 00:43:27 2010 UTC (13 years, 7 months ago) by misho
Branches: tools1_0
finish all work and start regdomain

/*************************************************************************
 * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com>
 *  by Michael Pounov <misho@aitbg.com>
 *
 * $Author: misho $
 * $Id: athctl.c,v 1.1.2.11 2010/11/05 00:43:27 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 <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] -u <file> <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 <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-R\t\tRead or Write EEPROM Regulatory domain\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(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;
}

// ----------------------------------------------------

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 && argv[1])
		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 >> 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;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>