1: /*************************************************************************
2: * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com>
3: * by Michael Pounov <misho@aitbg.com>
4: *
5: * $Author: misho $
6: * $Id: athctl.c,v 1.3.4.1 2014/01/30 01:03:20 misho Exp $
7: *
8: *************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004 - 2014
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47: #include "athctl.h"
48:
49:
50: int Verbose;
51: extern char compiled[], compiledby[], compilehost[];
52:
53:
54: static void
55: Usage()
56: {
57: printf( "athCtl is tool for Atheros WiFi cards managment \n"
58: "=== %s === %s@%s ===\n\n"
59: " Syntax: athctl [options] [[0xMemory_Address] new_value]\n"
60: " athctl [-v] -t [-i <iface_no>]\n"
61: " athctl [-v] -c <timeout> [-i <iface_no>]\n"
62: " athctl [-v] -d <distance> [-i <iface_no>]\n"
63: " athctl [-v] -r <0xoffset> <0xMemory_Address>\n"
64: " athctl [-v] -w <0xoffset> <0xMemory_Address> <uint16_value>\n"
65: " athctl [-v] -s <file> <0xMemory_Address>\n"
66: " athctl [-v] -u <file> <0xMemory_Address>\n"
67: " athctl [-v] -R <0xMemory_Address> [new_regdomain]\n"
68: "\n"
69: "\t-v\t\tVerbose ...\n"
70: "\t-t\t\tGet current Atheros maximum range in meters\n"
71: "\t-i <iface_no>\tApply to this Atheros interface number (like ath0 == 0)\n"
72: "\t-d <distance>\tMode distance, meters to target\n"
73: "\t-c <timeout>\tMode distance, mS timeouts correction\n"
74: "\t-R\t\tRead or Write EEPROM Regulatory domain\n"
75: "\t-s <file>\tDump EEPROM to file\n"
76: "\t-u <file>\tUpdate EEPROM from file\n"
77: "\t-r <offset>\tRead EEPROM word from PCI mapped memory address\n"
78: "\t-w <offset>\tWrite EEPROM word to PCI mapped memory address\n"
79: "\n", compiled, compiledby, compilehost);
80: }
81:
82: static int
83: calcDistance(int ifid, int dist, int cor)
84: {
85: int slottime[2], timeout[2];
86: size_t len;
87: char szStr[STRSIZ];
88:
89: slottime[0] = 9 + (dist / 300) + (dist % 300 ? 1 : 0);
90: timeout[0] = slottime[0] * 2 + 3 + cor;
91: VERB(3) printf("Info:: slottime=%d timeout=%d\n", slottime[0], timeout[0]);
92:
93: memset(szStr, 0, STRSIZ);
94: snprintf(szStr, STRSIZ, SC_SLOTTIME, ifid);
95: if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) {
96: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
97: return -1;
98: } else if (sysctlbyname(szStr, &slottime[1], &len, NULL, 0) == -1) {
99: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
100: return -1;
101: } else if (sysctlbyname(szStr, NULL, NULL, &slottime[0], sizeof slottime[0]) == -1) {
102: printf("Error:: set sysctl %s from %d #%d - %s\n", szStr, slottime[1],
103: errno, strerror(errno));
104: return -1;
105: } else
106: VERB(1) printf("Info:: set slottime(%d) from %d to %d ... OK!\n", len,
107: slottime[1], slottime[0]);
108:
109: memset(szStr, 0, STRSIZ);
110: snprintf(szStr, STRSIZ, SC_ACKTIMEOUT, ifid);
111: if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) {
112: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
113: return -1;
114: } else if (sysctlbyname(szStr, &timeout[1], &len, NULL, 0) == -1) {
115: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
116: return -1;
117: } else if (sysctlbyname(szStr, NULL, NULL, &timeout[0], sizeof timeout[0]) == -1) {
118: printf("Error:: set sysctl %s from %d #%d - %s\n", szStr, timeout[1],
119: errno, strerror(errno));
120: return -1;
121: } else
122: VERB(1) printf("Info:: set acktimeout(%d) from %d to %d ... OK!\n", len,
123: timeout[1], timeout[0]);
124:
125: memset(szStr, 0, STRSIZ);
126: snprintf(szStr, STRSIZ, SC_CTSTIMEOUT, ifid);
127: if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) {
128: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
129: return -1;
130: } else if (sysctlbyname(szStr, &timeout[1], &len, NULL, 0) == -1) {
131: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
132: return -1;
133: } else if (sysctlbyname(szStr, NULL, NULL, &timeout[0], sizeof timeout[0]) == -1) {
134: printf("Error:: set sysctl %s from %d #%d - %s\n", szStr, timeout[1],
135: errno, strerror(errno));
136: return -1;
137: } else
138: VERB(1) printf("Info:: set ctstimeout(%d) from %d to %d ... OK!\n", len,
139: timeout[1], timeout[0]);
140:
141: return timeout[0];
142: }
143:
144:
145: static int
146: calcTimeout(int ifid, int cor)
147: {
148: int slottime[2], timeout[2];
149: size_t len;
150: char szStr[STRSIZ];
151:
152: memset(szStr, 0, STRSIZ);
153: snprintf(szStr, STRSIZ, SC_SLOTTIME, ifid);
154: if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) {
155: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
156: return -1;
157: } else if (sysctlbyname(szStr, &slottime[1], &len, NULL, 0) == -1) {
158: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
159: return -1;
160: } else
161: VERB(1) printf("Info:: get slottime(%d) %d ... OK!\n", len, slottime[1]);
162:
163: memset(szStr, 0, STRSIZ);
164: snprintf(szStr, STRSIZ, SC_ACKTIMEOUT, ifid);
165: if (sysctlbyname(szStr, NULL, &len, NULL, 0) == -1) {
166: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
167: return -1;
168: } else if (sysctlbyname(szStr, &timeout[1], &len, NULL, 0) == -1) {
169: printf("Error:: get sysctl %s #%d - %s\n", szStr, errno, strerror(errno));
170: return -1;
171: } else
172: VERB(1) printf("Info:: get acktimeout(%d) %d ... OK!\n", len, timeout[1]);
173:
174: slottime[0] = (timeout[1] - 3 - cor) / 2;
175: VERB(3) printf("Info:: calculated slottime=%d\n", slottime[0]);
176: timeout[0] = (slottime[0] - 10) * 300;
177: VERB(3) printf("Info:: calculated timeout=%d\n", timeout[0]);
178:
179: return timeout[0];
180: }
181:
182:
183: static inline void *
184: devOpen(u_long baseaddr)
185: {
186: int fd;
187: void *basemem;
188:
189: fd = open("/dev/mem", O_RDWR);
190: if (fd == -1) {
191: printf("Error:: open device #%d - %s\n", errno, strerror(errno));
192: return NULL;
193: }
194: basemem = mmap(NULL, ATH_PCI_MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
195: if (basemem == MAP_FAILED) {
196: printf("Error:: map device #%d - %s\n", errno, strerror(errno));
197: close(fd);
198: return NULL;
199: } else
200: close(fd);
201:
202: return basemem;
203: }
204:
205: static inline void
206: devClose(void *basemem)
207: {
208: if (basemem)
209: munmap(basemem, ATH_PCI_MEM_SIZE);
210: }
211:
212: static inline int
213: readWord(u_char *mem, u_long offset)
214: {
215: register int timeout = ATH_ACCESS_TIMEOUT;
216: u_long stat;
217:
218: VERB(9) printf("Reading EEPROM memory %p+%lx ...\n", mem, offset);
219: ATH_OUT(mem, AR5211_EEPROM_CONF, 0);
220: usleep(ATH_ACCESS_WAIT);
221: /* enable eeprom access */
222: ATH_OUT(mem, AR5211_EEPROM_COMD, ATH_IN(mem, AR5211_EEPROM_COMD) | AR5211_EEPROM_COMD_RESET);
223: usleep(ATH_ACCESS_WAIT);
224: /* set address */
225: ATH_OUT(mem, AR5211_EEPROM_ADDR, offset);
226: usleep(ATH_ACCESS_WAIT);
227: /* enable eeprom read access */
228: ATH_OUT(mem, AR5211_EEPROM_COMD, ATH_IN(mem, AR5211_EEPROM_COMD) | AR5211_EEPROM_COMD_READ);
229: usleep(ATH_ACCESS_WAIT);
230:
231: while (timeout--) {
232: usleep(1);
233: stat = ATH_IN(mem, AR5211_EEPROM_STATUS);
234: if (stat & AR5211_EEPROM_STAT_RDDONE) {
235: if (stat & AR5211_EEPROM_STAT_RDERR) {
236: printf("Error:: EEPROM read failed!\n");
237: return -1;
238: }
239:
240: stat = ATH_IN(mem, AR5211_EEPROM_DATA);
241: return (stat & 0x0000ffff) << 16;
242: }
243: }
244:
245: printf("Error:: EEPROM read timeout!\n");
246: return -1;
247: }
248:
249: static inline int
250: writeWord(u_char *mem, u_long offset, u_short newval)
251: {
252: register int i = ATH_WRITE_RETRY, timeout;
253: u_long pcicfg, stat;
254: int chk;
255:
256: VERB(9) printf("Writing EEPROM memory %p+%lx ...\n", mem, offset);
257: /* enable pci write access */
258: pcicfg = ATH_IN(mem, AR5K_PCICFG);
259: ATH_OUT(mem, AR5K_PCICFG, (pcicfg & ~AR5K_PCICFG_SPWR_DN));
260: usleep(ATH_ACCESS_WAITDOWN);
261: ATH_OUT(mem, AR5K_PCICFG, pcicfg | AR5K_PCICFG_EEAE /* | 0x2 */);
262: usleep(ATH_ACCESS_WAITPCI);
263: ATH_OUT(mem, AR5211_EEPROM_STATUS, 0);
264: usleep(ATH_ACCESS_WAITPCI);
265: /* ATH_OUT(mem, AR5211_EEPROM_CONF, 1); */
266: ATH_OUT(mem, AR5211_EEPROM_CONF, 0);
267:
268: do {
269: /* enable eeprom write access */
270: ATH_OUT(mem, AR5211_EEPROM_COMD, AR5211_EEPROM_COMD_RESET);
271: usleep(ATH_ACCESS_WAITDOWN);
272: ATH_OUT(mem, AR5211_EEPROM_DATA, newval);
273: usleep(ATH_ACCESS_WAIT);
274: ATH_OUT(mem, AR5211_EEPROM_ADDR, offset);
275: usleep(ATH_ACCESS_WAIT);
276: ATH_OUT(mem, AR5211_EEPROM_COMD, AR5211_EEPROM_COMD_WRITE);
277: usleep(ATH_ACCESS_WAIT);
278:
279: for (timeout = ATH_ACCESS_TIMEOUT; timeout; timeout--) {
280: stat = ATH_IN(mem, AR5211_EEPROM_STATUS);
281: if (stat & 0xc) {
282: if (stat & AR5211_EEPROM_STAT_WRERR) {
283: printf("Error:: EEPROM write failed!\n");
284: return -1;
285: }
286:
287: ATH_OUT(mem, AR5211_EEPROM_STATUS, 0);
288: usleep(ATH_ACCESS_WAIT * 2);
289: break;
290: }
291: usleep(ATH_ACCESS_WAIT * 2);
292: }
293:
294: chk = readWord(mem, offset);
295: if (chk == (u_short) -1)
296: return -1;
297: if ((u_short) (chk >> 16) == newval)
298: return chk;
299: else
300: VERB(1) printf("Write & Read don`t match 0x%04X != 0x%04X\n", newval, (u_short) (chk >> 16));
301: if (i)
302: printf("Warning:: Retrying EEPROM write ...\n");
303: } while (--i);
304:
305: printf("Error:: EEPROM write timeout!\n");
306: return -1;
307: }
308:
309: static int
310: dumpFile(const char *csName, u_char *mem)
311: {
312: register u_long i;
313: u_short d1, d2;
314: u_char eeprom[ATH_EEPROM_SIZE] = { 0 };
315: int f, data;
316:
317: VERB(2) printf("Reading EEPROM memory %p ::\n", mem);
318: for (i = 0; i < ATH_EEPROM_SIZE / 2; i++) {
319: if (!(i % 0x40)) {
320: if (i)
321: printf("]\n");
322: printf("0x%04lX [", i * 2);
323: }
324:
325: if ((data = readWord(mem, i)) == -1)
326: return -1;
327: else {
328: d1 = ((u_short)(data >> 16)) / 0x100;
329: d2 = ((u_short)(data >> 16)) % 0x100;
330:
331: VERB(5) printf( "Current value 0x%04X on position 0x%04lX will change 0x%02X 0x%02X\n",
332: (u_short) (data >> 16), i, d1, d2);
333: }
334:
335: eeprom[i * 2] = d2;
336: eeprom[i * 2 + 1] = d1;
337:
338: printf(".");
339: usleep(ATH_ACCESS_WAITDOWN);
340: }
341: printf("]\n");
342:
343: VERB(2) printf("Saving EEPROM to file %s ... ", csName);
344: f = open(csName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
345: if (f == -1) {
346: printf("Failed!\nError:: in create file %s #%d - %s\n", csName,
347: errno, strerror(errno));
348: return 0;
349: }
350: if (write(f, eeprom, ATH_EEPROM_SIZE) == -1) {
351: printf("Failed!\nError:: in write to file %s #%d - %s\n", csName,
352: errno, strerror(errno));
353: close(f);
354: return 0;
355: }
356: close(f);
357: printf("OK!\n");
358: return 1;
359: }
360:
361: static int
362: flashFile(const char *csName, u_char *mem)
363: {
364: register u_long i;
365: u_short d1;
366: u_char eeprom[ATH_EEPROM_SIZE] = { 0 };
367: int f, data;
368:
369: VERB(2) printf("Reading EEPROM from file %s ... ", csName);
370: f = open(csName, O_RDONLY);
371: if (f == -1) {
372: printf("Failed!\nError:: in open file %s #%d - %s\n", csName,
373: errno, strerror(errno));
374: return 0;
375: }
376: if (read(f, eeprom, ATH_EEPROM_SIZE) != ATH_EEPROM_SIZE) {
377: printf("Failed!\nError:: failed load image from file %s\n", csName);
378: close(f);
379: return 0;
380: }
381: close(f);
382: VERB(2) printf("OK!\n");
383:
384: VERB(2) printf("Writing EEPROM memory %p ::\n", mem);
385: for (i = 0; i < ATH_EEPROM_SIZE / 2; i++) {
386: if (!(i % 0x40)) {
387: if (i)
388: printf("]\n");
389: printf("0x%04lX [", i * 2);
390: }
391:
392: if ((data = readWord(mem, i)) == -1)
393: return -1;
394: else
395: d1 = eeprom[i * 2 + 1] * 0x100 + eeprom[i * 2];
396: VERB(5) printf("eeprom_data=0x%04X read_d1=0x%04X\n", (u_char) (data >> 16), d1);
397:
398: if (((u_short) (data >> 16)) == d1)
399: printf(".");
400: else {
401:
402: if (writeWord(mem, i, d1) < 1)
403: printf("!");
404: else
405: printf("x");
406: }
407:
408: usleep(ATH_ACCESS_WAITDOWN);
409: }
410: printf("]\n");
411:
412: return 0;
413: }
414:
415: static int
416: regDomain(u_char *mem, u_short newval)
417: {
418: int ret, data;
419:
420: if ((data = readWord(mem, ATH_OFFSET_REGDOMAIN)) == -1)
421: return -1;
422:
423: printf("Current value 0x%04X ", (u_short) (data >> 16));
424: if (newval != (u_short) -1) {
425: printf("will change to 0x%04X\n", newval);
426:
427: if ((ret = writeWord(mem, ATH_OFFSET_REGDOMAIN, newval)) == -1)
428: return -1;
429:
430: printf("Updated regulatory domain is 0x%04X\n", (u_short) (ret >> 16));
431: } else
432: printf("\nCurrent regulatory domain is 0x%04X\n", (u_short) (data >> 16));
433:
434: return 0;
435: }
436:
437: // ----------------------------------------------------
438:
439: int
440: main(int argc, char **argv)
441: {
442: char ch, szName[MAXPATHLEN] = { 0 }, mode = 0;
443: int ret = 0, dist = 0, cor = 0, ino = 0;
444: u_long offset = 0, baseaddr = (u_long) -1;
445: u_short newval = 0;
446: void *basemem = NULL;
447:
448: while ((ch = getopt(argc, argv, "hvRtr:w:i:d:c:u:s:")) != -1)
449: switch (ch) {
450: case 'v':
451: Verbose++;
452: break;
453: case 't':
454: mode |= 2;
455: break;
456: case 'i':
457: ino = strtol(optarg, NULL, 0);
458: if (ino < 0) {
459: printf("Error:: in interface number %d\n", ino);
460: return 1;
461: }
462: break;
463: case 'd':
464: mode |= 1;
465: dist = strtol(optarg, NULL, 0);
466: if (dist < 1) {
467: printf("Error:: in distance meters %d\n", dist);
468: return 1;
469: }
470: break;
471: case 'c':
472: mode |= 1;
473: cor = strtol(optarg, NULL, 0);
474: break;
475: case 's':
476: mode = 0x10;
477: strlcpy(szName, optarg, MAXPATHLEN);
478: break;
479: case 'u':
480: mode = 0x20;
481: strlcpy(szName, optarg, MAXPATHLEN);
482: break;
483: case 'R':
484: mode = 0x40;
485: break;
486: case 'r':
487: mode = 4;
488: offset = strtoul(optarg, NULL, 0);
489: break;
490: case 'w':
491: mode = 8;
492: offset = strtoul(optarg, NULL, 0);
493: break;
494: case 'h':
495: default:
496: Usage();
497: return 1;
498: }
499: argc -= optind;
500: argv += optind;
501: if (argc && *argv)
502: baseaddr = strtoul(*argv, NULL, 0);
503: if (!mode) {
504: printf("Error:: not selected mode for operation ...\n");
505: return 1;
506: }
507: if (mode > 3 && baseaddr == (u_long) -1) {
508: printf("Error:: in this mode for operation, must give memory mapped address ...\n");
509: return 1;
510: }
511: if (mode & 8) {
512: if (!argv[1]) {
513: printf("Error:: in write word mode, must give memory mapped address and new value ...\n");
514: return 1;
515: } else
516: newval = (u_short) strtoul(argv[1], NULL, 0);
517: }
518: if (mode & 0x40) {
519: if (argv[1])
520: newval = (u_short) strtoul(argv[1], NULL, 0);
521: else
522: newval = (u_short) -1;
523: }
524:
525: if (mode & 1)
526: if ((ret = calcDistance(ino, dist, cor)) < 1)
527: return 2;
528: if (mode & 2) {
529: if ((ret = calcTimeout(ino, cor)) < 1)
530: return 2;
531: else {
532: VERB(1)
533: printf("Maximum approximate distance ~%d meters\n", ret);
534: else
535: printf("~%d\n", ret);
536: }
537: }
538:
539: if (mode & 4) {
540: if (!(basemem = devOpen(baseaddr)))
541: return 2;
542: if ((ret = readWord(basemem, offset)) == -1) {
543: devClose(basemem);
544: return 3;
545: } else
546: printf("EEPROM readed value 0x%04X\n", (u_short) (ret >> 16));
547: devClose(basemem);
548: }
549: if (mode & 8) {
550: if (!(basemem = devOpen(baseaddr)))
551: return 2;
552: if ((ret = writeWord(basemem, offset, newval)) == -1) {
553: devClose(basemem);
554: return 3;
555: } else
556: printf("EEPROM writed value 0x%04X\n", (u_short) (ret >> 16));
557: devClose(basemem);
558: }
559:
560: if (mode & 0x10) {
561: if (!(basemem = devOpen(baseaddr)))
562: return 2;
563: if ((ret = dumpFile(szName, basemem)) < 1) {
564: devClose(basemem);
565: return 3;
566: }
567: devClose(basemem);
568: }
569: if (mode & 0x20) {
570: if (!(basemem = devOpen(baseaddr)))
571: return 2;
572: if ((ret = flashFile(szName, basemem)) < 1) {
573: devClose(basemem);
574: return 3;
575: }
576: devClose(basemem);
577: }
578:
579: if (mode & 0x40) {
580: if (!(basemem = devOpen(baseaddr)))
581: return 2;
582: if ((ret = regDomain(basemem, newval)) < 1) {
583: devClose(basemem);
584: return 3;
585: }
586: devClose(basemem);
587: }
588:
589: return 0;
590: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>