1 /*-
2 * Copyright (c) 2008 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 * redistribution must be conditioned upon including a substantially
14 * similar Disclaimer requirement for further binary redistribution.
15 *
16 * NO WARRANTY
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTABILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
28 *
29 * $FreeBSD: src/tools/tools/ath/athprom/athprom.c,v 1.1 2008/12/07 19:17:33 sam Exp $
30 */
31 #include "diag.h"
32
33 #include "ah.h"
34 #include "ah_internal.h"
35 #include "ah_eeprom_v1.h"
36 #include "ah_eeprom_v3.h"
37 #include "ah_eeprom_v14.h"
38
39 #define IS_VERS(op, v) (eeprom.ee_version op (v))
40
41 #include <getopt.h>
42 #include <errno.h>
43 #include <err.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #ifndef DIR_TEMPLATE
48 #define DIR_TEMPLATE "/usr/local/libdata/athprom"
49 #endif
50
51 struct ath_diag atd;
52 int s;
53 const char *progname;
54 union {
55 HAL_EEPROM legacy; /* format v3.x ... v5.x */
56 struct ar5416eeprom v14; /* 11n format v14.x ... */
57 } eep;
58 #define eeprom eep.legacy
59 #define eepromN eep.v14
60
61 static void parseTemplate(FILE *ftemplate, FILE *fd);
62 static uint16_t eeread(uint16_t);
63 static void eewrite(uint16_t, uint16_t);
64
65 static void
usage()66 usage()
67 {
68 fprintf(stderr, "usage: %s [-i ifname] [-t pathname] [offset | offset=value]\n", progname);
69 exit(-1);
70 }
71
72 static FILE *
opentemplate(const char * dir)73 opentemplate(const char *dir)
74 {
75 char filename[PATH_MAX];
76 FILE *fd;
77
78 /* find the template using the eeprom version */
79 snprintf(filename, sizeof(filename), "%s/eeprom-%d.%d",
80 dir, eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
81 fd = fopen(filename, "r");
82 if (fd == NULL && errno == ENOENT) {
83 /* retry with just the major version */
84 snprintf(filename, sizeof(filename), "%s/eeprom-%d",
85 dir, eeprom.ee_version >> 12);
86 fd = fopen(filename, "r");
87 if (fd != NULL) /* XXX verbose */
88 warnx("Using template file %s", filename);
89 }
90 return fd;
91 }
92
93 int
main(int argc,char * argv[])94 main(int argc, char *argv[])
95 {
96 FILE *fd = NULL;
97 const char *ifname;
98 int c;
99
100 s = socket(AF_INET, SOCK_DGRAM, 0);
101 if (s < 0)
102 err(1, "socket");
103 ifname = getenv("ATH");
104 if (!ifname)
105 ifname = ATH_DEFAULT;
106
107 progname = argv[0];
108 while ((c = getopt(argc, argv, "i:t:")) != -1)
109 switch (c) {
110 case 'i':
111 ifname = optarg;
112 break;
113 case 't':
114 fd = fopen(optarg, "r");
115 if (fd == NULL)
116 err(-1, "Cannot open %s", optarg);
117 break;
118 default:
119 usage();
120 /*NOTREACHED*/
121 }
122 argc -= optind;
123 argv += optind;
124
125 strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
126
127 if (argc != 0) {
128 for (; argc > 0; argc--, argv++) {
129 uint16_t off, val, oval;
130 char line[256];
131 char *cp;
132
133 cp = strchr(argv[0], '=');
134 if (cp != NULL)
135 *cp = '\0';
136 off = (uint16_t) strtoul(argv[0], NULL, 0);
137 if (off == 0 && errno == EINVAL)
138 errx(1, "%s: invalid eeprom offset %s",
139 progname, argv[0]);
140 if (cp == NULL) {
141 printf("%04x: %04x\n", off, eeread(off));
142 } else {
143 val = (uint16_t) strtoul(cp+1, NULL, 0);
144 if (val == 0 && errno == EINVAL)
145 errx(1, "%s: invalid eeprom value %s",
146 progname, cp+1);
147 oval = eeread(off);
148 printf("Write %04x: %04x = %04x? ",
149 off, oval, val);
150 fflush(stdout);
151 if (fgets(line, sizeof(line), stdin) != NULL &&
152 line[0] == 'y')
153 eewrite(off, val);
154 }
155 }
156 } else {
157 atd.ad_id = HAL_DIAG_EEPROM;
158 atd.ad_out_data = (caddr_t) &eep;
159 atd.ad_out_size = sizeof(eep);
160 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
161 err(1, atd.ad_name);
162 if (fd == NULL) {
163 fd = opentemplate(DIR_TEMPLATE);
164 if (fd == NULL)
165 fd = opentemplate(".");
166 if (fd == NULL)
167 errx(-1, "Cannot locate template file for "
168 "v%d.%d EEPROM", eeprom.ee_version >> 12,
169 eeprom.ee_version & 0xfff);
170 }
171 parseTemplate(fd, stdout);
172 fclose(fd);
173 }
174 return 0;
175 }
176
177 static u_int16_t
eeread(u_int16_t off)178 eeread(u_int16_t off)
179 {
180 u_int16_t eedata;
181
182 atd.ad_id = HAL_DIAG_EEREAD | ATH_DIAG_IN | ATH_DIAG_DYN;
183 atd.ad_in_size = sizeof(off);
184 atd.ad_in_data = (caddr_t) &off;
185 atd.ad_out_size = sizeof(eedata);
186 atd.ad_out_data = (caddr_t) &eedata;
187 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
188 err(1, atd.ad_name);
189 return eedata;
190 }
191
192 static void
eewrite(uint16_t off,uint16_t value)193 eewrite(uint16_t off, uint16_t value)
194 {
195 HAL_DIAG_EEVAL eeval;
196
197 eeval.ee_off = off;
198 eeval.ee_data = value;
199
200 atd.ad_id = HAL_DIAG_EEWRITE | ATH_DIAG_IN;
201 atd.ad_in_size = sizeof(eeval);
202 atd.ad_in_data = (caddr_t) &eeval;
203 atd.ad_out_size = 0;
204 atd.ad_out_data = NULL;
205 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
206 err(1, atd.ad_name);
207 }
208
209 #define MAXID 128
210 int lineno;
211 int bol;
212 int curmode = -1;
213 int curchan;
214 int curpdgain; /* raw pdgain index */
215 int curlpdgain; /* logical pdgain index */
216 int curpcdac;
217 int curctl;
218 int numChannels;
219 const RAW_DATA_STRUCT_2413 *pRaw;
220 const TRGT_POWER_INFO *pPowerInfo;
221 const DATA_PER_CHANNEL *pDataPerChannel;
222 const EEPROM_POWER_EXPN_5112 *pExpnPower;
223 int singleXpd;
224
225 static int
token(FILE * fd,char id[],int maxid,const char * what)226 token(FILE *fd, char id[], int maxid, const char *what)
227 {
228 int c, i;
229
230 i = 0;
231 for (;;) {
232 c = getc(fd);
233 if (c == EOF)
234 return EOF;
235 if (!isalnum(c) && c != '_') {
236 ungetc(c, fd);
237 break;
238 }
239 if (i == maxid-1) {
240 warnx("line %d, %s too long", lineno, what);
241 break;
242 }
243 id[i++] = c;
244 }
245 id[i] = '\0';
246 if (i != 0)
247 bol = 0;
248 return i;
249 }
250
251 static int
skipto(FILE * fd,const char * what)252 skipto(FILE *fd, const char *what)
253 {
254 char id[MAXID];
255 int c;
256
257 for (;;) {
258 c = getc(fd);
259 if (c == EOF)
260 goto bad;
261 if (c == '.' && bol) { /* .directive */
262 if (token(fd, id, MAXID, ".directive") == EOF)
263 goto bad;
264 if (strcasecmp(id, what) == 0)
265 break;
266 continue;
267 }
268 if (c == '\\') { /* escape next character */
269 c = getc(fd);
270 if (c == EOF)
271 goto bad;
272 }
273 bol = (c == '\n');
274 if (bol)
275 lineno++;
276 }
277 return 0;
278 bad:
279 warnx("EOF with no matching .%s", what);
280 return EOF;
281 }
282
283 static int
skipws(FILE * fd)284 skipws(FILE *fd)
285 {
286 int c, i;
287
288 i = 0;
289 while ((c = getc(fd)) != EOF && isblank(c))
290 i++;
291 if (c != EOF)
292 ungetc(c, fd);
293 if (i != 0)
294 bol = 0;
295 return 0;
296 }
297
298 static void
_setmode(int mode)299 _setmode(int mode)
300 {
301 EEPROM_POWER_EXPN_5112 *exp;
302
303 curmode = mode;
304 curchan = -1;
305 curctl = -1;
306 curpdgain = -1;
307 curlpdgain = -1;
308 curpcdac = -1;
309 switch (curmode) {
310 case headerInfo11A:
311 pPowerInfo = eeprom.ee_trgtPwr_11a;
312 pDataPerChannel = eeprom.ee_dataPerChannel11a;
313 break;
314 case headerInfo11B:
315 pPowerInfo = eeprom.ee_trgtPwr_11b;
316 pDataPerChannel = eeprom.ee_dataPerChannel11b;
317 break;
318 case headerInfo11G:
319 pPowerInfo = eeprom.ee_trgtPwr_11g;
320 pDataPerChannel = eeprom.ee_dataPerChannel11g;
321 break;
322 }
323 if (IS_VERS(<, AR_EEPROM_VER4_0)) /* nothing to do */
324 return;
325 if (IS_VERS(<, AR_EEPROM_VER5_0)) {
326 exp = &eeprom.ee_modePowerArray5112[curmode];
327 /* fetch indirect data*/
328 atd.ad_id = HAL_DIAG_EEPROM_EXP_11A+curmode;
329 atd.ad_out_size = roundup(
330 sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t))
331 + sizeof(EXPN_DATA_PER_CHANNEL_5112) * exp->numChannels;
332 atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size);
333 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
334 err(1, atd.ad_name);
335 exp->pChannels = (void *) atd.ad_out_data;
336 exp->pDataPerChannel = (void *)((char *)atd.ad_out_data +
337 roundup(sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t)));
338 pExpnPower = exp;
339 numChannels = pExpnPower->numChannels;
340 if (exp->xpdMask != 0x9) {
341 for (singleXpd = 0; singleXpd < NUM_XPD_PER_CHANNEL; singleXpd++)
342 if (exp->xpdMask == (1<<singleXpd))
343 break;
344 } else
345 singleXpd = 0;
346 } else if (IS_VERS(<, AR_EEPROM_VER14_2)) {
347 pRaw = &eeprom.ee_rawDataset2413[curmode];
348 numChannels = pRaw->numChannels;
349 }
350 }
351
352 int
nextctl(int start)353 nextctl(int start)
354 {
355 int i;
356
357 for (i = start; i < eeprom.ee_numCtls && eeprom.ee_ctl[i]; i++) {
358 switch (eeprom.ee_ctl[i] & 3) {
359 case 0: case 3:
360 if (curmode != headerInfo11A)
361 continue;
362 break;
363 case 1:
364 if (curmode != headerInfo11B)
365 continue;
366 break;
367 case 2:
368 if (curmode != headerInfo11G)
369 continue;
370 break;
371 }
372 return i;
373 }
374 return -1;
375 }
376
377 static void
printAntennaControl(FILE * fd,int ant)378 printAntennaControl(FILE *fd, int ant)
379 {
380 fprintf(fd, "0x%02X", eeprom.ee_antennaControl[ant][curmode]);
381 }
382
383 static void
printEdge(FILE * fd,int edge)384 printEdge(FILE *fd, int edge)
385 {
386 const RD_EDGES_POWER *pRdEdgePwrInfo =
387 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
388
389 if (pRdEdgePwrInfo[edge].rdEdge == 0)
390 fprintf(fd, " -- ");
391 else
392 fprintf(fd, "%04d", pRdEdgePwrInfo[edge].rdEdge);
393 }
394
395 static void
printEdgePower(FILE * fd,int edge)396 printEdgePower(FILE *fd, int edge)
397 {
398 const RD_EDGES_POWER *pRdEdgePwrInfo =
399 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
400
401 if (pRdEdgePwrInfo[edge].rdEdge == 0)
402 fprintf(fd, " -- ");
403 else
404 fprintf(fd, "%2d.%d",
405 pRdEdgePwrInfo[edge].twice_rdEdgePower / 2,
406 (pRdEdgePwrInfo[edge].twice_rdEdgePower % 2) * 5);
407 }
408
409 static void
printEdgeFlag(FILE * fd,int edge)410 printEdgeFlag(FILE *fd, int edge)
411 {
412 const RD_EDGES_POWER *pRdEdgePwrInfo =
413 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
414
415 if (pRdEdgePwrInfo[edge].rdEdge == 0)
416 fprintf(fd, "--");
417 else
418 fprintf(fd, " %1d", pRdEdgePwrInfo[edge].flag);
419 }
420
421 static int16_t
getMaxPowerV5(const RAW_DATA_PER_CHANNEL_2413 * data)422 getMaxPowerV5(const RAW_DATA_PER_CHANNEL_2413 *data)
423 {
424 uint32_t i;
425 uint16_t numVpd;
426
427 for (i = 0; i < MAX_NUM_PDGAINS_PER_CHANNEL; i++) {
428 numVpd = data->pDataPerPDGain[i].numVpd;
429 if (numVpd > 0)
430 return data->pDataPerPDGain[i].pwr_t4[numVpd-1];
431 }
432 return 0;
433 }
434
435 static void
printQuarterDbmPower(FILE * fd,int16_t power25dBm)436 printQuarterDbmPower(FILE *fd, int16_t power25dBm)
437 {
438 fprintf(fd, "%2d.%02d", power25dBm / 4, (power25dBm % 4) * 25);
439 }
440
441 static void
printHalfDbmPower(FILE * fd,int16_t power5dBm)442 printHalfDbmPower(FILE *fd, int16_t power5dBm)
443 {
444 fprintf(fd, "%2d.%d", power5dBm / 2, (power5dBm % 2) * 5);
445 }
446
447 static void
printVpd(FILE * fd,int vpd)448 printVpd(FILE *fd, int vpd)
449 {
450 fprintf(fd, "[%3d]", vpd);
451 }
452
453 static void
printPcdacValue(FILE * fd,int v)454 printPcdacValue(FILE *fd, int v)
455 {
456 fprintf(fd, "%2d.%02d", v / EEP_SCALE, v % EEP_SCALE);
457 }
458
459 static void
undef(const char * what)460 undef(const char *what)
461 {
462 warnx("%s undefined for version %d.%d format EEPROM", what,
463 eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
464 }
465
466 static int
pdgain(int lpdgain)467 pdgain(int lpdgain)
468 {
469 uint32_t mask;
470 int i, l = lpdgain;
471
472 if (IS_VERS(<, AR_EEPROM_VER5_0))
473 mask = pExpnPower->xpdMask;
474 else
475 mask = pRaw->xpd_mask;
476 for (i = 0; mask != 0; mask >>= 1, i++)
477 if ((mask & 1) && l-- == 0)
478 return i;
479 warnx("can't find logical pdgain %d", lpdgain);
480 return -1;
481 }
482
483 #define COUNTRY_ERD_FLAG 0x8000
484 #define WORLDWIDE_ROAMING_FLAG 0x4000
485
486 void
eevar(FILE * fd,const char * var)487 eevar(FILE *fd, const char *var)
488 {
489 #define streq(a,b) (strcasecmp(a,b) == 0)
490 #define strneq(a,b,n) (strncasecmp(a,b,n) == 0)
491 if (streq(var, "mode")) {
492 fprintf(fd, "%s",
493 curmode == headerInfo11A ? "11a" :
494 curmode == headerInfo11B ? "11b" :
495 curmode == headerInfo11G ? "11g" : "???");
496 } else if (streq(var, "version")) {
497 fprintf(fd, "%04x", eeprom.ee_version);
498 } else if (streq(var, "V_major")) {
499 fprintf(fd, "%2d", eeprom.ee_version >> 12);
500 } else if (streq(var, "V_minor")) {
501 fprintf(fd, "%2d", eeprom.ee_version & 0xfff);
502 } else if (streq(var, "earStart")) {
503 fprintf(fd, "%03x", eeprom.ee_earStart);
504 } else if (streq(var, "tpStart")) {
505 fprintf(fd, "%03x", eeprom.ee_targetPowersStart);
506 } else if (streq(var, "eepMap")) {
507 fprintf(fd, "%3d", eeprom.ee_eepMap);
508 } else if (streq(var, "exist32KHzCrystal")) {
509 fprintf(fd, "%3d", eeprom.ee_exist32kHzCrystal);
510 } else if (streq(var, "eepMap2PowerCalStart")) {
511 fprintf(fd , "%3d", eeprom.ee_eepMap2PowerCalStart);
512 } else if (streq(var, "Amode")) {
513 fprintf(fd , "%1d", eeprom.ee_Amode);
514 } else if (streq(var, "Bmode")) {
515 fprintf(fd , "%1d", eeprom.ee_Bmode);
516 } else if (streq(var, "Gmode")) {
517 fprintf(fd , "%1d", eeprom.ee_Gmode);
518 } else if (streq(var, "regdomain")) {
519 if ((eeprom.ee_regdomain & COUNTRY_ERD_FLAG) == 0)
520 fprintf(fd, "%03X ", eeprom.ee_regdomain >> 15);
521 else
522 fprintf(fd, "%-3dC", eeprom.ee_regdomain & 0xfff);
523 } else if (streq(var, "turbo2Disable")) {
524 fprintf(fd, "%1d", eeprom.ee_turbo2Disable);
525 } else if (streq(var, "turbo5Disable")) {
526 fprintf(fd, "%1d", eeprom.ee_turbo5Disable);
527 } else if (streq(var, "rfKill")) {
528 fprintf(fd, "%1d", eeprom.ee_rfKill);
529 } else if (streq(var, "disableXr5")) {
530 fprintf(fd, "%1d", eeprom.ee_disableXr5);
531 } else if (streq(var, "disableXr2")) {
532 fprintf(fd, "%1d", eeprom.ee_disableXr2);
533 } else if (streq(var, "turbo2WMaxPower5")) {
534 fprintf(fd, "%2d", eeprom.ee_turbo2WMaxPower5);
535 } else if (streq(var, "cckOfdmDelta")) {
536 fprintf(fd, "%2d", eeprom.ee_cckOfdmPwrDelta);
537 } else if (streq(var, "gainI")) {
538 fprintf(fd, "%2d", eeprom.ee_gainI[curmode]);
539 } else if (streq(var, "WWR")) {
540 fprintf(fd, "%1x",
541 (eeprom.ee_regdomain & WORLDWIDE_ROAMING_FLAG) != 0);
542 } else if (streq(var, "falseDetectBackoff")) {
543 fprintf(fd, "0x%02x", eeprom.ee_falseDetectBackoff[curmode]);
544 } else if (streq(var, "deviceType")) {
545 fprintf(fd, "%1x", eeprom.ee_deviceType);
546 } else if (streq(var, "switchSettling")) {
547 if (IS_VERS(<, AR_EEPROM_VER14_2))
548 fprintf(fd, "0x%02x", eeprom.ee_switchSettling[curmode]);
549 else
550 fprintf(fd, "%3d", eepromN.modalHeader[curmode].switchSettling);
551 } else if (streq(var, "adcDesiredSize")) {
552 if (IS_VERS(<, AR_EEPROM_VER14_2))
553 fprintf(fd, "%2d", eeprom.ee_adcDesiredSize[curmode]);
554 else
555 fprintf(fd, "%3d", eepromN.modalHeader[curmode].adcDesiredSize);
556 } else if (streq(var, "xlnaGain")) {
557 fprintf(fd, "0x%02x", eeprom.ee_xlnaGain[curmode]);
558 } else if (streq(var, "txEndToXLNAOn")) {
559 fprintf(fd, "0x%02x", eeprom.ee_txEndToXLNAOn[curmode]);
560 } else if (streq(var, "thresh62")) {
561 if (IS_VERS(<, AR_EEPROM_VER14_2))
562 fprintf(fd, "0x%02x", eeprom.ee_thresh62[curmode]);
563 else
564 fprintf(fd, "%3d", eepromN.modalHeader[curmode].thresh62);
565 } else if (streq(var, "txEndToRxOn")) {
566 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn);
567 } else if (streq(var, "txEndToXPAOff")) {
568 if (IS_VERS(<, AR_EEPROM_VER14_2))
569 fprintf(fd, "0x%02x", eeprom.ee_txEndToXPAOff[curmode]);
570 else
571 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToXpaOff);
572 } else if (streq(var, "txFrameToXPAOn")) {
573 if (IS_VERS(<, AR_EEPROM_VER14_2))
574 fprintf(fd, "0x%02x", eeprom.ee_txFrameToXPAOn[curmode]);
575 else
576 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn);
577 } else if (streq(var, "pgaDesiredSize")) {
578 if (IS_VERS(<, AR_EEPROM_VER14_2))
579 fprintf(fd, "%2d", eeprom.ee_pgaDesiredSize[curmode]);
580 else
581 fprintf(fd, "%3d", eepromN.modalHeader[curmode].pgaDesiredSize);
582 } else if (streq(var, "noiseFloorThresh")) {
583 fprintf(fd, "%3d", eeprom.ee_noiseFloorThresh[curmode]);
584 } else if (strneq(var, "noiseFloorThreshCh", 18)) {
585 fprintf(fd, "%3d", eepromN.modalHeader[curmode].noiseFloorThreshCh[atoi(var+18)]);
586 } else if (strneq(var, "xlnaGainCh", 10)) {
587 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xlnaGainCh[atoi(var+10)]);
588 } else if (streq(var, "xgain")) {
589 fprintf(fd, "0x%02x", eeprom.ee_xgain[curmode]);
590 } else if (streq(var, "xpd")) {
591 if (IS_VERS(<, AR_EEPROM_VER14_2))
592 fprintf(fd, "%1d", eeprom.ee_xpd[curmode]);
593 else
594 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpd);
595 } else if (streq(var, "txrxAtten")) {
596 fprintf(fd, "0x%02x", eeprom.ee_txrxAtten[curmode]);
597 } else if (streq(var, "capField")) {
598 fprintf(fd, "0x%04X", eeprom.ee_capField);
599 } else if (streq(var, "txrxAttenTurbo")) {
600 fprintf(fd, "0x%02x",
601 eeprom.ee_txrxAtten[curmode != headerInfo11A]);
602 } else if (streq(var, "switchSettlingTurbo")) {
603 fprintf(fd, "0x%02X",
604 eeprom.ee_switchSettlingTurbo[curmode != headerInfo11A]);
605 } else if (streq(var, "adcDesiredSizeTurbo")) {
606 fprintf(fd, "%2d",
607 eeprom.ee_adcDesiredSizeTurbo[curmode != headerInfo11A]);
608 } else if (streq(var, "pgaDesiredSizeTurbo")) {
609 fprintf(fd, "%2d",
610 eeprom.ee_pgaDesiredSizeTurbo[curmode != headerInfo11A]);
611 } else if (streq(var, "rxtxMarginTurbo")) {
612 fprintf(fd, "0x%02x",
613 eeprom.ee_rxtxMarginTurbo[curmode != headerInfo11A]);
614 } else if (strneq(var, "antennaControl", 14)) {
615 printAntennaControl(fd, atoi(var+14));
616 } else if (strneq(var, "antCtrlChain", 12)) {
617 fprintf(fd, "0x%08X",
618 eepromN.modalHeader[curmode].antCtrlChain[atoi(var+12)]);
619 } else if (strneq(var, "antGainCh", 9)) {
620 fprintf(fd, "%3d",
621 eepromN.modalHeader[curmode].antennaGainCh[atoi(var+9)]);
622 } else if (strneq(var, "txRxAttenCh", 11)) {
623 fprintf(fd, "%3d",
624 eepromN.modalHeader[curmode].txRxAttenCh[atoi(var+11)]);
625 } else if (strneq(var, "rxTxMarginCh", 12)) {
626 fprintf(fd, "%3d",
627 eepromN.modalHeader[curmode].rxTxMarginCh[atoi(var+12)]);
628 } else if (streq(var, "xpdGain")) {
629 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpdGain);
630 } else if (strneq(var, "iqCalICh", 8)) {
631 fprintf(fd, "%3d",
632 eepromN.modalHeader[curmode].iqCalICh[atoi(var+8)]);
633 } else if (strneq(var, "iqCalQCh", 8)) {
634 fprintf(fd, "%3d",
635 eepromN.modalHeader[curmode].iqCalQCh[atoi(var+8)]);
636 } else if (streq(var, "pdGainOverlap")) {
637 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pdGainOverlap);
638 } else if (streq(var, "ob1")) {
639 fprintf(fd, "%1d", eeprom.ee_ob1);
640 } else if (streq(var, "ob2")) {
641 fprintf(fd, "%1d", eeprom.ee_ob2);
642 } else if (streq(var, "ob3")) {
643 fprintf(fd, "%1d", eeprom.ee_ob3);
644 } else if (streq(var, "ob4")) {
645 fprintf(fd, "%1d", eeprom.ee_ob4);
646 } else if (streq(var, "db1")) {
647 fprintf(fd, "%1d", eeprom.ee_db1);
648 } else if (streq(var, "db2")) {
649 fprintf(fd, "%1d", eeprom.ee_db2);
650 } else if (streq(var, "db3")) {
651 fprintf(fd, "%1d", eeprom.ee_db3);
652 } else if (streq(var, "db4")) {
653 fprintf(fd, "%1d", eeprom.ee_db4);
654 } else if (streq(var, "obFor24")) {
655 fprintf(fd, "%1d", eeprom.ee_obFor24);
656 } else if (streq(var, "ob2GHz0")) {
657 fprintf(fd, "%1d", eeprom.ee_ob2GHz[0]);
658 } else if (streq(var, "dbFor24")) {
659 fprintf(fd, "%1d", eeprom.ee_dbFor24);
660 } else if (streq(var, "db2GHz0")) {
661 fprintf(fd, "%1d", eeprom.ee_db2GHz[0]);
662 } else if (streq(var, "obFor24g")) {
663 fprintf(fd, "%1d", eeprom.ee_obFor24g);
664 } else if (streq(var, "ob2GHz1")) {
665 fprintf(fd, "%1d", eeprom.ee_ob2GHz[1]);
666 } else if (streq(var, "dbFor24g")) {
667 fprintf(fd, "%1d", eeprom.ee_dbFor24g);
668 } else if (streq(var, "db2GHz1")) {
669 fprintf(fd, "%1d", eeprom.ee_db2GHz[1]);
670 } else if (streq(var, "ob")) {
671 fprintf(fd, "%3d", eepromN.modalHeader[curmode].ob);
672 } else if (streq(var, "db")) {
673 fprintf(fd, "%3d", eepromN.modalHeader[curmode].db);
674 } else if (streq(var, "xpaBiasLvl")) {
675 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpaBiasLvl);
676 } else if (streq(var, "pwrDecreaseFor2Chain")) {
677 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor2Chain);
678 } else if (streq(var, "pwrDecreaseFor3Chain")) {
679 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor3Chain);
680 } else if (streq(var, "txFrameToDataStart")) {
681 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToDataStart);
682 } else if (streq(var, "txFrameToPaOn")) {
683 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToPaOn);
684 } else if (streq(var, "ht40PowerIncForPdadc")) {
685 fprintf(fd, "%3d", eepromN.modalHeader[curmode].ht40PowerIncForPdadc);
686 } else if (streq(var, "checksum")) {
687 fprintf(fd, "0x%04X", eepromN.baseEepHeader.checksum);
688 } else if (streq(var, "length")) {
689 fprintf(fd, "0x%04X", eepromN.baseEepHeader.length);
690 } else if (streq(var, "regDmn0")) {
691 fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[0]);
692 } else if (streq(var, "regDmn1")) {
693 fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[1]);
694 } else if (streq(var, "txMask")) {
695 fprintf(fd, "0x%04X", eepromN.baseEepHeader.txMask);
696 } else if (streq(var, "rxMask")) {
697 fprintf(fd, "0x%04X", eepromN.baseEepHeader.rxMask);
698 } else if (streq(var, "rfSilent")) {
699 fprintf(fd, "0x%04X", eepromN.baseEepHeader.rfSilent);
700 } else if (streq(var, "btOptions")) {
701 fprintf(fd, "0x%04X", eepromN.baseEepHeader.blueToothOptions);
702 } else if (streq(var, "deviceCap")) {
703 fprintf(fd, "0x%04X", eepromN.baseEepHeader.deviceCap);
704 } else if (strneq(var, "macaddr", 7)) {
705 fprintf(fd, "%02X",
706 eepromN.baseEepHeader.macAddr[atoi(var+7)]);
707 } else if (streq(var, "opCapFlags")) {
708 fprintf(fd, "0x%02X", eepromN.baseEepHeader.opCapFlags);
709 } else if (streq(var, "eepMisc")) {
710 fprintf(fd, "0x%02X", eepromN.baseEepHeader.eepMisc);
711 } else if (strneq(var, "binBuildNumber", 14)) {
712 fprintf(fd, "%3d",
713 (eepromN.baseEepHeader.binBuildNumber >> (8*atoi(var+14)))
714 & 0xff);
715 } else if (strneq(var, "custData", 8)) {
716 fprintf(fd, "%2.2X", eepromN.custData[atoi(var+8)]);
717 } else if (streq(var, "xpd_mask")) {
718 if (IS_VERS(<, AR_EEPROM_VER5_0))
719 fprintf(fd, "0x%02x", pExpnPower->xpdMask);
720 else
721 fprintf(fd, "0x%02x", pRaw->xpd_mask);
722 } else if (streq(var, "numChannels")) {
723 if (IS_VERS(<, AR_EEPROM_VER5_0))
724 fprintf(fd, "%2d", pExpnPower->numChannels);
725 else
726 fprintf(fd, "%2d", pRaw->numChannels);
727 } else if (streq(var, "freq")) {
728 if (IS_VERS(<, AR_EEPROM_VER5_0))
729 fprintf(fd, "%4d", pExpnPower->pChannels[curchan]);
730 else
731 fprintf(fd, "%4d", pRaw->pChannels[curchan]);
732 } else if (streq(var, "maxpow")) {
733 int16_t maxPower_t4;
734 if (IS_VERS(<, AR_EEPROM_VER5_0)) {
735 maxPower_t4 = pExpnPower->pDataPerChannel[curchan].maxPower_t4;
736 } else {
737 maxPower_t4 = pRaw->pDataPerChannel[curchan].maxPower_t4;
738 if (maxPower_t4 == 0)
739 maxPower_t4 = getMaxPowerV5(&pRaw->pDataPerChannel[curchan]);
740 }
741 printQuarterDbmPower(fd, maxPower_t4);
742 } else if (streq(var, "pd_gain")) {
743 fprintf(fd, "%4d", pRaw->pDataPerChannel[curchan].
744 pDataPerPDGain[curpdgain].pd_gain);
745 } else if (strneq(var, "maxpwr", 6)) {
746 int vpd = atoi(var+6);
747 if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd)
748 printQuarterDbmPower(fd, pRaw->pDataPerChannel[curchan].
749 pDataPerPDGain[curpdgain].pwr_t4[vpd]);
750 else
751 fprintf(fd, " ");
752 } else if (strneq(var, "pwr_t4_", 7)) {
753 printQuarterDbmPower(fd, pExpnPower->pDataPerChannel[curchan].
754 pDataPerXPD[singleXpd].pwr_t4[atoi(var+7)]);
755 } else if (strneq(var, "Vpd", 3)) {
756 int vpd = atoi(var+3);
757 if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd)
758 printVpd(fd, pRaw->pDataPerChannel[curchan].
759 pDataPerPDGain[curpdgain].Vpd[vpd]);
760 else
761 fprintf(fd, " ");
762 } else if (streq(var, "CTL")) {
763 fprintf(fd, "0x%2x", eeprom.ee_ctl[curctl] & 0xff);
764 } else if (streq(var, "ctlType")) {
765 static const char *ctlType[16] = {
766 "11a base", "11b", "11g", "11a TURBO", "108g",
767 "2GHT20", "5GHT20", "2GHT40", "5GHT40",
768 "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf",
769 };
770 fprintf(fd, "%8s", ctlType[eeprom.ee_ctl[curctl] & CTL_MODE_M]);
771 } else if (streq(var, "ctlRD")) {
772 static const char *ctlRD[8] = {
773 "0x00", " FCC", "0x20", "ETSI",
774 " MKK", "0x50", "0x60", "0x70"
775 };
776 fprintf(fd, "%s", ctlRD[(eeprom.ee_ctl[curctl] >> 4) & 7]);
777 } else if (strneq(var, "rdEdgePower", 11)) {
778 printEdgePower(fd, atoi(var+11));
779 } else if (strneq(var, "rdEdgeFlag", 10)) {
780 printEdgeFlag(fd, atoi(var+10));
781 } else if (strneq(var, "rdEdge", 6)) {
782 printEdge(fd, atoi(var+6));
783 } else if (strneq(var, "testChannel", 11)) {
784 fprintf(fd, "%4d", pPowerInfo[atoi(var+11)].testChannel);
785 } else if (strneq(var, "pwr6_24_", 8)) {
786 printHalfDbmPower(fd, pPowerInfo[atoi(var+8)].twicePwr6_24);
787 } else if (strneq(var, "pwr36_", 6)) {
788 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr36);
789 } else if (strneq(var, "pwr48_", 6)) {
790 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr48);
791 } else if (strneq(var, "pwr54_", 6)) {
792 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr54);
793 } else if (strneq(var, "channelValue", 12)) {
794 fprintf(fd, "%4d", pDataPerChannel[atoi(var+12)].channelValue);
795 } else if (strneq(var, "pcdacMin", 8)) {
796 fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMin);
797 } else if (strneq(var, "pcdacMax", 8)) {
798 fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMax);
799 } else if (strneq(var, "pcdac", 5)) {
800 if (IS_VERS(<, AR_EEPROM_VER4_0)) {
801 fprintf(fd, "%02d", pDataPerChannel[atoi(var+5)].
802 PcdacValues[curpcdac]);
803 } else if (IS_VERS(<, AR_EEPROM_VER5_0)) {
804 fprintf(fd, "%02d",
805 pExpnPower->pDataPerChannel[curchan].
806 pDataPerXPD[singleXpd].pcdac[atoi(var+5)]);
807 } else
808 undef("pcdac");
809 } else if (strneq(var, "pwrValue", 8)) {
810 printPcdacValue(fd,
811 pDataPerChannel[atoi(var+8)].PwrValues[curpcdac]);
812 } else if (streq(var, "singleXpd")) {
813 fprintf(fd, "%2d", singleXpd);
814 } else
815 warnx("line %u, unknown EEPROM variable \"%s\"", lineno, var);
816 #undef strneq
817 #undef streq
818 }
819
820 static void
ifmode(FILE * ftemplate,const char * mode)821 ifmode(FILE *ftemplate, const char *mode)
822 {
823 if (strcasecmp(mode, "11a") == 0) {
824 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
825 if (eeprom.ee_Amode)
826 _setmode(headerInfo11A);
827 else
828 skipto(ftemplate, "endmode");
829 return;
830 }
831 if (IS_VERS(>=, AR_EEPROM_VER14_2)) {
832 if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A)
833 _setmode(headerInfo11A);
834 else
835 skipto(ftemplate, "endmode");
836 return;
837 }
838 } else if (strcasecmp(mode, "11g") == 0) {
839 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
840 if (eeprom.ee_Gmode)
841 _setmode(headerInfo11G);
842 else
843 skipto(ftemplate, "endmode");
844 return;
845 }
846 if (IS_VERS(>=, AR_EEPROM_VER14_2)) {
847 if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G)
848 _setmode(headerInfo11B); /* NB: 2.4GHz */
849 else
850 skipto(ftemplate, "endmode");
851 return;
852 }
853 } else if (strcasecmp(mode, "11b") == 0) {
854 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
855 if (eeprom.ee_Bmode)
856 _setmode(headerInfo11B);
857 else
858 skipto(ftemplate, "endmode");
859 return;
860 }
861 }
862 warnx("line %d, unknown/unexpected mode \"%s\" ignored",
863 lineno, mode);
864 skipto(ftemplate, "endmode");
865 }
866
867 static void
parseTemplate(FILE * ftemplate,FILE * fd)868 parseTemplate(FILE *ftemplate, FILE *fd)
869 {
870 int c, i;
871 char id[MAXID];
872 long forchan, forpdgain, forctl, forpcdac;
873
874 lineno = 1;
875 bol = 1;
876 while ((c = getc(ftemplate)) != EOF) {
877 if (c == '#') { /* comment */
878 skiptoeol:
879 while ((c = getc(ftemplate)) != EOF && c != '\n')
880 ;
881 if (c == EOF)
882 return;
883 lineno++;
884 bol = 1;
885 continue;
886 }
887 if (c == '.' && bol) { /* .directive */
888 if (token(ftemplate, id, MAXID, ".directive") == EOF)
889 return;
890 /* process directive */
891 if (strcasecmp(id, "ifmode") == 0) {
892 skipws(ftemplate);
893 if (token(ftemplate, id, MAXID, "id") == EOF)
894 return;
895 ifmode(ftemplate, id);
896 } else if (strcasecmp(id, "endmode") == 0) {
897 /* XXX free malloc'd indirect data */
898 curmode = -1; /* NB: undefined */
899 } else if (strcasecmp(id, "forchan") == 0) {
900 forchan = ftell(ftemplate) - sizeof("forchan");
901 if (curchan == -1)
902 curchan = 0;
903 } else if (strcasecmp(id, "endforchan") == 0) {
904 if (++curchan < numChannels)
905 fseek(ftemplate, forchan, SEEK_SET);
906 else
907 curchan = -1;
908 } else if (strcasecmp(id, "ifpdgain") == 0) {
909 skipws(ftemplate);
910 if (token(ftemplate, id, MAXID, "pdgain") == EOF)
911 return;
912 curlpdgain = strtoul(id, NULL, 0);
913 if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) {
914 skipto(ftemplate, "endpdgain");
915 curlpdgain = -1;
916 } else
917 curpdgain = pdgain(curlpdgain);
918 } else if (strcasecmp(id, "endpdgain") == 0) {
919 curlpdgain = curpdgain = -1;
920 } else if (strcasecmp(id, "forpdgain") == 0) {
921 forpdgain = ftell(ftemplate) - sizeof("forpdgain");
922 if (curlpdgain == -1) {
923 skipws(ftemplate);
924 if (token(ftemplate, id, MAXID, "pdgain") == EOF)
925 return;
926 curlpdgain = strtoul(id, NULL, 0);
927 if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) {
928 skipto(ftemplate, "endforpdgain");
929 curlpdgain = -1;
930 } else
931 curpdgain = pdgain(curlpdgain);
932 }
933 } else if (strcasecmp(id, "endforpdgain") == 0) {
934 if (++curpdgain < pRaw->pDataPerChannel[curchan].numPdGains)
935 fseek(ftemplate, forpdgain, SEEK_SET);
936 else
937 curpdgain = -1;
938 } else if (strcasecmp(id, "forpcdac") == 0) {
939 forpcdac = ftell(ftemplate) - sizeof("forpcdac");
940 if (curpcdac == -1)
941 curpcdac = 0;
942 } else if (strcasecmp(id, "endforpcdac") == 0) {
943 if (++curpcdac < pDataPerChannel[0].numPcdacValues)
944 fseek(ftemplate, forpcdac, SEEK_SET);
945 else
946 curpcdac = -1;
947 } else if (strcasecmp(id, "forctl") == 0) {
948 forctl = ftell(ftemplate) - sizeof("forchan");
949 if (curctl == -1)
950 curctl = nextctl(0);
951 } else if (strcasecmp(id, "endforctl") == 0) {
952 curctl = nextctl(curctl+1);
953 if (curctl != -1)
954 fseek(ftemplate, forctl, SEEK_SET);
955 } else {
956 warnx("line %d, unknown directive %s ignored",
957 lineno, id);
958 }
959 goto skiptoeol;
960 }
961 if (c == '$') { /* $variable reference */
962 if (token(ftemplate, id, MAXID, "$var") == EOF)
963 return;
964 /* XXX not valid if variable depends on curmode */
965 eevar(fd, id);
966 continue;
967 }
968 if (c == '\\') { /* escape next character */
969 c = getc(ftemplate);
970 if (c == EOF)
971 return;
972 }
973 fputc(c, fd);
974 bol = (c == '\n');
975 if (bol)
976 lineno++;
977 }
978 }
979