2 * Copyright (c) 2008 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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, MERCHANTIBILITY
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.
34 #include "ah_internal.h"
35 #include "ah_eeprom_v1.h"
36 #include "ah_eeprom_v3.h"
37 #include "ah_eeprom_v14.h"
39 #define IS_VERS(op, v) (eeprom.ee_version op (v))
50 #define DIR_TEMPLATE _PATH_LOCALBASE "/libdata/athprom"
57 HAL_EEPROM legacy; /* format v3.x ... v5.x */
58 struct ar5416eeprom v14; /* 11n format v14.x ... */
60 #define eeprom eep.legacy
61 #define eepromN eep.v14
63 static void parseTemplate(FILE *ftemplate, FILE *fd);
64 static uint16_t eeread(uint16_t);
65 static void eewrite(uint16_t, uint16_t);
70 fprintf(stderr, "usage: %s [-i ifname] [-t pathname] [offset | offset=value]\n", progname);
75 opentemplate(const char *dir)
77 char filename[PATH_MAX];
80 /* find the template using the eeprom version */
81 snprintf(filename, sizeof(filename), "%s/eeprom-%d.%d",
82 dir, eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
83 fd = fopen(filename, "r");
84 if (fd == NULL && errno == ENOENT) {
85 /* retry with just the major version */
86 snprintf(filename, sizeof(filename), "%s/eeprom-%d",
87 dir, eeprom.ee_version >> 12);
88 fd = fopen(filename, "r");
89 if (fd != NULL) /* XXX verbose */
90 warnx("Using template file %s", filename);
96 main(int argc, char *argv[])
102 s = socket(AF_INET, SOCK_DGRAM, 0);
105 ifname = getenv("ATH");
107 ifname = ATH_DEFAULT;
110 while ((c = getopt(argc, argv, "i:t:")) != -1)
116 fd = fopen(optarg, "r");
118 err(-1, "Cannot open %s", optarg);
127 strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
130 for (; argc > 0; argc--, argv++) {
131 uint16_t off, val, oval;
135 cp = strchr(argv[0], '=');
138 off = (uint16_t) strtoul(argv[0], NULL, 0);
139 if (off == 0 && errno == EINVAL)
140 errx(1, "%s: invalid eeprom offset %s",
143 printf("%04x: %04x\n", off, eeread(off));
145 val = (uint16_t) strtoul(cp+1, NULL, 0);
146 if (val == 0 && errno == EINVAL)
147 errx(1, "%s: invalid eeprom value %s",
150 printf("Write %04x: %04x = %04x? ",
153 if (fgets(line, sizeof(line), stdin) != NULL &&
159 atd.ad_id = HAL_DIAG_EEPROM;
160 atd.ad_out_data = (caddr_t) &eep;
161 atd.ad_out_size = sizeof(eep);
162 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
163 err(1, "ioctl: %s", atd.ad_name);
165 fd = opentemplate(DIR_TEMPLATE);
167 fd = opentemplate(".");
169 errx(-1, "Cannot locate template file for "
170 "v%d.%d EEPROM", eeprom.ee_version >> 12,
171 eeprom.ee_version & 0xfff);
173 parseTemplate(fd, stdout);
180 eeread(u_int16_t off)
184 atd.ad_id = HAL_DIAG_EEREAD | ATH_DIAG_IN | ATH_DIAG_DYN;
185 atd.ad_in_size = sizeof(off);
186 atd.ad_in_data = (caddr_t) &off;
187 atd.ad_out_size = sizeof(eedata);
188 atd.ad_out_data = (caddr_t) &eedata;
189 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
190 err(1, "ioctl: %s", atd.ad_name);
195 eewrite(uint16_t off, uint16_t value)
197 HAL_DIAG_EEVAL eeval;
200 eeval.ee_data = value;
202 atd.ad_id = HAL_DIAG_EEWRITE | ATH_DIAG_IN;
203 atd.ad_in_size = sizeof(eeval);
204 atd.ad_in_data = (caddr_t) &eeval;
206 atd.ad_out_data = NULL;
207 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
208 err(1, "ioctl: %s", atd.ad_name);
216 int curpdgain; /* raw pdgain index */
217 int curlpdgain; /* logical pdgain index */
221 const RAW_DATA_STRUCT_2413 *pRaw;
222 const TRGT_POWER_INFO *pPowerInfo;
223 const DATA_PER_CHANNEL *pDataPerChannel;
224 const EEPROM_POWER_EXPN_5112 *pExpnPower;
228 token(FILE *fd, char id[], int maxid, const char *what)
237 if (!isalnum(c) && c != '_') {
242 warnx("line %d, %s too long", lineno, what);
254 skipto(FILE *fd, const char *what)
263 if (c == '.' && bol) { /* .directive */
264 if (token(fd, id, MAXID, ".directive") == EOF)
266 if (strcasecmp(id, what) == 0)
270 if (c == '\\') { /* escape next character */
281 warnx("EOF with no matching .%s", what);
291 while ((c = getc(fd)) != EOF && isblank(c))
303 EEPROM_POWER_EXPN_5112 *exp;
313 pPowerInfo = eeprom.ee_trgtPwr_11a;
314 pDataPerChannel = eeprom.ee_dataPerChannel11a;
317 pPowerInfo = eeprom.ee_trgtPwr_11b;
318 pDataPerChannel = eeprom.ee_dataPerChannel11b;
321 pPowerInfo = eeprom.ee_trgtPwr_11g;
322 pDataPerChannel = eeprom.ee_dataPerChannel11g;
325 if (IS_VERS(<, AR_EEPROM_VER4_0)) /* nothing to do */
327 if (IS_VERS(<, AR_EEPROM_VER5_0)) {
328 exp = &eeprom.ee_modePowerArray5112[curmode];
329 /* fetch indirect data*/
330 atd.ad_id = HAL_DIAG_EEPROM_EXP_11A+curmode;
331 atd.ad_out_size = roundup(
332 sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t))
333 + sizeof(EXPN_DATA_PER_CHANNEL_5112) * exp->numChannels;
334 atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size);
335 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
336 err(1, "ioctl: %s", atd.ad_name);
337 exp->pChannels = (void *) atd.ad_out_data;
338 exp->pDataPerChannel = (void *)((char *)atd.ad_out_data +
339 roundup(sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t)));
341 numChannels = pExpnPower->numChannels;
342 if (exp->xpdMask != 0x9) {
343 for (singleXpd = 0; singleXpd < NUM_XPD_PER_CHANNEL; singleXpd++)
344 if (exp->xpdMask == (1<<singleXpd))
348 } else if (IS_VERS(<, AR_EEPROM_VER14_2)) {
349 pRaw = &eeprom.ee_rawDataset2413[curmode];
350 numChannels = pRaw->numChannels;
359 for (i = start; i < eeprom.ee_numCtls && eeprom.ee_ctl[i]; i++) {
360 switch (eeprom.ee_ctl[i] & 3) {
362 if (curmode != headerInfo11A)
366 if (curmode != headerInfo11B)
370 if (curmode != headerInfo11G)
380 printAntennaControl(FILE *fd, int ant)
382 fprintf(fd, "0x%02X", eeprom.ee_antennaControl[ant][curmode]);
386 printEdge(FILE *fd, int edge)
388 const RD_EDGES_POWER *pRdEdgePwrInfo =
389 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
391 if (pRdEdgePwrInfo[edge].rdEdge == 0)
394 fprintf(fd, "%04d", pRdEdgePwrInfo[edge].rdEdge);
398 printEdgePower(FILE *fd, int edge)
400 const RD_EDGES_POWER *pRdEdgePwrInfo =
401 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
403 if (pRdEdgePwrInfo[edge].rdEdge == 0)
406 fprintf(fd, "%2d.%d",
407 pRdEdgePwrInfo[edge].twice_rdEdgePower / 2,
408 (pRdEdgePwrInfo[edge].twice_rdEdgePower % 2) * 5);
412 printEdgeFlag(FILE *fd, int edge)
414 const RD_EDGES_POWER *pRdEdgePwrInfo =
415 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
417 if (pRdEdgePwrInfo[edge].rdEdge == 0)
420 fprintf(fd, " %1d", pRdEdgePwrInfo[edge].flag);
424 getMaxPowerV5(const RAW_DATA_PER_CHANNEL_2413 *data)
429 for (i = 0; i < MAX_NUM_PDGAINS_PER_CHANNEL; i++) {
430 numVpd = data->pDataPerPDGain[i].numVpd;
432 return data->pDataPerPDGain[i].pwr_t4[numVpd-1];
438 printQuarterDbmPower(FILE *fd, int16_t power25dBm)
440 fprintf(fd, "%2d.%02d", power25dBm / 4, (power25dBm % 4) * 25);
444 printHalfDbmPower(FILE *fd, int16_t power5dBm)
446 fprintf(fd, "%2d.%d", power5dBm / 2, (power5dBm % 2) * 5);
450 printVpd(FILE *fd, int vpd)
452 fprintf(fd, "[%3d]", vpd);
456 printPcdacValue(FILE *fd, int v)
458 fprintf(fd, "%2d.%02d", v / EEP_SCALE, v % EEP_SCALE);
462 undef(const char *what)
464 warnx("%s undefined for version %d.%d format EEPROM", what,
465 eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
474 if (IS_VERS(<, AR_EEPROM_VER5_0))
475 mask = pExpnPower->xpdMask;
477 mask = pRaw->xpd_mask;
478 for (i = 0; mask != 0; mask >>= 1, i++)
479 if ((mask & 1) && l-- == 0)
481 warnx("can't find logical pdgain %d", lpdgain);
485 #define COUNTRY_ERD_FLAG 0x8000
486 #define WORLDWIDE_ROAMING_FLAG 0x4000
489 eevar(FILE *fd, const char *var)
491 #define streq(a,b) (strcasecmp(a,b) == 0)
492 #define strneq(a,b,n) (strncasecmp(a,b,n) == 0)
493 if (streq(var, "mode")) {
495 curmode == headerInfo11A ? "11a" :
496 curmode == headerInfo11B ? "11b" :
497 curmode == headerInfo11G ? "11g" : "???");
498 } else if (streq(var, "version")) {
499 fprintf(fd, "%04x", eeprom.ee_version);
500 } else if (streq(var, "V_major")) {
501 fprintf(fd, "%2d", eeprom.ee_version >> 12);
502 } else if (streq(var, "V_minor")) {
503 fprintf(fd, "%2d", eeprom.ee_version & 0xfff);
504 } else if (streq(var, "earStart")) {
505 fprintf(fd, "%03x", eeprom.ee_earStart);
506 } else if (streq(var, "tpStart")) {
507 fprintf(fd, "%03x", eeprom.ee_targetPowersStart);
508 } else if (streq(var, "eepMap")) {
509 fprintf(fd, "%3d", eeprom.ee_eepMap);
510 } else if (streq(var, "exist32KHzCrystal")) {
511 fprintf(fd, "%3d", eeprom.ee_exist32kHzCrystal);
512 } else if (streq(var, "eepMap2PowerCalStart")) {
513 fprintf(fd , "%3d", eeprom.ee_eepMap2PowerCalStart);
514 } else if (streq(var, "Amode")) {
515 fprintf(fd , "%1d", eeprom.ee_Amode);
516 } else if (streq(var, "Bmode")) {
517 fprintf(fd , "%1d", eeprom.ee_Bmode);
518 } else if (streq(var, "Gmode")) {
519 fprintf(fd , "%1d", eeprom.ee_Gmode);
520 } else if (streq(var, "regdomain")) {
521 if ((eeprom.ee_regdomain & COUNTRY_ERD_FLAG) == 0)
522 fprintf(fd, "%03X ", eeprom.ee_regdomain >> 15);
524 fprintf(fd, "%-3dC", eeprom.ee_regdomain & 0xfff);
525 } else if (streq(var, "turbo2Disable")) {
526 fprintf(fd, "%1d", eeprom.ee_turbo2Disable);
527 } else if (streq(var, "turbo5Disable")) {
528 fprintf(fd, "%1d", eeprom.ee_turbo5Disable);
529 } else if (streq(var, "rfKill")) {
530 fprintf(fd, "%1d", eeprom.ee_rfKill);
531 } else if (streq(var, "disableXr5")) {
532 fprintf(fd, "%1d", eeprom.ee_disableXr5);
533 } else if (streq(var, "disableXr2")) {
534 fprintf(fd, "%1d", eeprom.ee_disableXr2);
535 } else if (streq(var, "turbo2WMaxPower5")) {
536 fprintf(fd, "%2d", eeprom.ee_turbo2WMaxPower5);
537 } else if (streq(var, "cckOfdmDelta")) {
538 fprintf(fd, "%2d", eeprom.ee_cckOfdmPwrDelta);
539 } else if (streq(var, "gainI")) {
540 fprintf(fd, "%2d", eeprom.ee_gainI[curmode]);
541 } else if (streq(var, "WWR")) {
543 (eeprom.ee_regdomain & WORLDWIDE_ROAMING_FLAG) != 0);
544 } else if (streq(var, "falseDetectBackoff")) {
545 fprintf(fd, "0x%02x", eeprom.ee_falseDetectBackoff[curmode]);
546 } else if (streq(var, "deviceType")) {
547 fprintf(fd, "%1x", eeprom.ee_deviceType);
548 } else if (streq(var, "switchSettling")) {
549 if (IS_VERS(<, AR_EEPROM_VER14_2))
550 fprintf(fd, "0x%02x", eeprom.ee_switchSettling[curmode]);
552 fprintf(fd, "%3d", eepromN.modalHeader[curmode].switchSettling);
553 } else if (streq(var, "adcDesiredSize")) {
554 if (IS_VERS(<, AR_EEPROM_VER14_2))
555 fprintf(fd, "%2d", eeprom.ee_adcDesiredSize[curmode]);
557 fprintf(fd, "%3d", eepromN.modalHeader[curmode].adcDesiredSize);
558 } else if (streq(var, "xlnaGain")) {
559 fprintf(fd, "0x%02x", eeprom.ee_xlnaGain[curmode]);
560 } else if (streq(var, "txEndToXLNAOn")) {
561 fprintf(fd, "0x%02x", eeprom.ee_txEndToXLNAOn[curmode]);
562 } else if (streq(var, "thresh62")) {
563 if (IS_VERS(<, AR_EEPROM_VER14_2))
564 fprintf(fd, "0x%02x", eeprom.ee_thresh62[curmode]);
566 fprintf(fd, "%3d", eepromN.modalHeader[curmode].thresh62);
567 } else if (streq(var, "txEndToRxOn")) {
568 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn);
569 } else if (streq(var, "txEndToXPAOff")) {
570 if (IS_VERS(<, AR_EEPROM_VER14_2))
571 fprintf(fd, "0x%02x", eeprom.ee_txEndToXPAOff[curmode]);
573 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToXpaOff);
574 } else if (streq(var, "txFrameToXPAOn")) {
575 if (IS_VERS(<, AR_EEPROM_VER14_2))
576 fprintf(fd, "0x%02x", eeprom.ee_txFrameToXPAOn[curmode]);
578 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn);
579 } else if (streq(var, "pgaDesiredSize")) {
580 if (IS_VERS(<, AR_EEPROM_VER14_2))
581 fprintf(fd, "%2d", eeprom.ee_pgaDesiredSize[curmode]);
583 fprintf(fd, "%3d", eepromN.modalHeader[curmode].pgaDesiredSize);
584 } else if (streq(var, "noiseFloorThresh")) {
585 fprintf(fd, "%3d", eeprom.ee_noiseFloorThresh[curmode]);
586 } else if (strneq(var, "noiseFloorThreshCh", 18)) {
587 fprintf(fd, "%3d", eepromN.modalHeader[curmode].noiseFloorThreshCh[atoi(var+18)]);
588 } else if (strneq(var, "xlnaGainCh", 10)) {
589 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xlnaGainCh[atoi(var+10)]);
590 } else if (streq(var, "xgain")) {
591 fprintf(fd, "0x%02x", eeprom.ee_xgain[curmode]);
592 } else if (streq(var, "xpd")) {
593 if (IS_VERS(<, AR_EEPROM_VER14_2))
594 fprintf(fd, "%1d", eeprom.ee_xpd[curmode]);
596 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpd);
597 } else if (streq(var, "txrxAtten")) {
598 fprintf(fd, "0x%02x", eeprom.ee_txrxAtten[curmode]);
599 } else if (streq(var, "capField")) {
600 fprintf(fd, "0x%04X", eeprom.ee_capField);
601 } else if (streq(var, "txrxAttenTurbo")) {
602 fprintf(fd, "0x%02x",
603 eeprom.ee_txrxAtten[curmode != headerInfo11A]);
604 } else if (streq(var, "switchSettlingTurbo")) {
605 fprintf(fd, "0x%02X",
606 eeprom.ee_switchSettlingTurbo[curmode != headerInfo11A]);
607 } else if (streq(var, "adcDesiredSizeTurbo")) {
609 eeprom.ee_adcDesiredSizeTurbo[curmode != headerInfo11A]);
610 } else if (streq(var, "pgaDesiredSizeTurbo")) {
612 eeprom.ee_pgaDesiredSizeTurbo[curmode != headerInfo11A]);
613 } else if (streq(var, "rxtxMarginTurbo")) {
614 fprintf(fd, "0x%02x",
615 eeprom.ee_rxtxMarginTurbo[curmode != headerInfo11A]);
616 } else if (strneq(var, "antennaControl", 14)) {
617 printAntennaControl(fd, atoi(var+14));
618 } else if (strneq(var, "antCtrlChain", 12)) {
619 fprintf(fd, "0x%08X",
620 eepromN.modalHeader[curmode].antCtrlChain[atoi(var+12)]);
621 } else if (strneq(var, "antGainCh", 9)) {
623 eepromN.modalHeader[curmode].antennaGainCh[atoi(var+9)]);
624 } else if (strneq(var, "txRxAttenCh", 11)) {
626 eepromN.modalHeader[curmode].txRxAttenCh[atoi(var+11)]);
627 } else if (strneq(var, "rxTxMarginCh", 12)) {
629 eepromN.modalHeader[curmode].rxTxMarginCh[atoi(var+12)]);
630 } else if (streq(var, "xpdGain")) {
631 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpdGain);
632 } else if (strneq(var, "iqCalICh", 8)) {
634 eepromN.modalHeader[curmode].iqCalICh[atoi(var+8)]);
635 } else if (strneq(var, "iqCalQCh", 8)) {
637 eepromN.modalHeader[curmode].iqCalQCh[atoi(var+8)]);
638 } else if (streq(var, "pdGainOverlap")) {
639 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pdGainOverlap);
640 } else if (streq(var, "ob1")) {
641 fprintf(fd, "%1d", eeprom.ee_ob1);
642 } else if (streq(var, "ob2")) {
643 fprintf(fd, "%1d", eeprom.ee_ob2);
644 } else if (streq(var, "ob3")) {
645 fprintf(fd, "%1d", eeprom.ee_ob3);
646 } else if (streq(var, "ob4")) {
647 fprintf(fd, "%1d", eeprom.ee_ob4);
648 } else if (streq(var, "db1")) {
649 fprintf(fd, "%1d", eeprom.ee_db1);
650 } else if (streq(var, "db2")) {
651 fprintf(fd, "%1d", eeprom.ee_db2);
652 } else if (streq(var, "db3")) {
653 fprintf(fd, "%1d", eeprom.ee_db3);
654 } else if (streq(var, "db4")) {
655 fprintf(fd, "%1d", eeprom.ee_db4);
656 } else if (streq(var, "obFor24")) {
657 fprintf(fd, "%1d", eeprom.ee_obFor24);
658 } else if (streq(var, "ob2GHz0")) {
659 fprintf(fd, "%1d", eeprom.ee_ob2GHz[0]);
660 } else if (streq(var, "dbFor24")) {
661 fprintf(fd, "%1d", eeprom.ee_dbFor24);
662 } else if (streq(var, "db2GHz0")) {
663 fprintf(fd, "%1d", eeprom.ee_db2GHz[0]);
664 } else if (streq(var, "obFor24g")) {
665 fprintf(fd, "%1d", eeprom.ee_obFor24g);
666 } else if (streq(var, "ob2GHz1")) {
667 fprintf(fd, "%1d", eeprom.ee_ob2GHz[1]);
668 } else if (streq(var, "dbFor24g")) {
669 fprintf(fd, "%1d", eeprom.ee_dbFor24g);
670 } else if (streq(var, "db2GHz1")) {
671 fprintf(fd, "%1d", eeprom.ee_db2GHz[1]);
672 } else if (streq(var, "ob")) {
673 fprintf(fd, "%3d", eepromN.modalHeader[curmode].ob);
674 } else if (streq(var, "db")) {
675 fprintf(fd, "%3d", eepromN.modalHeader[curmode].db);
676 } else if (streq(var, "xpaBiasLvl")) {
677 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpaBiasLvl);
678 } else if (streq(var, "pwrDecreaseFor2Chain")) {
679 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor2Chain);
680 } else if (streq(var, "pwrDecreaseFor3Chain")) {
681 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor3Chain);
682 } else if (streq(var, "txFrameToDataStart")) {
683 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToDataStart);
684 } else if (streq(var, "txFrameToPaOn")) {
685 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToPaOn);
686 } else if (streq(var, "ht40PowerIncForPdadc")) {
687 fprintf(fd, "%3d", eepromN.modalHeader[curmode].ht40PowerIncForPdadc);
688 } else if (streq(var, "checksum")) {
689 fprintf(fd, "0x%04X", eepromN.baseEepHeader.checksum);
690 } else if (streq(var, "length")) {
691 fprintf(fd, "0x%04X", eepromN.baseEepHeader.length);
692 } else if (streq(var, "regDmn0")) {
693 fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[0]);
694 } else if (streq(var, "regDmn1")) {
695 fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[1]);
696 } else if (streq(var, "txMask")) {
697 fprintf(fd, "0x%04X", eepromN.baseEepHeader.txMask);
698 } else if (streq(var, "rxMask")) {
699 fprintf(fd, "0x%04X", eepromN.baseEepHeader.rxMask);
700 } else if (streq(var, "rfSilent")) {
701 fprintf(fd, "0x%04X", eepromN.baseEepHeader.rfSilent);
702 } else if (streq(var, "btOptions")) {
703 fprintf(fd, "0x%04X", eepromN.baseEepHeader.blueToothOptions);
704 } else if (streq(var, "deviceCap")) {
705 fprintf(fd, "0x%04X", eepromN.baseEepHeader.deviceCap);
706 } else if (strneq(var, "macaddr", 7)) {
708 eepromN.baseEepHeader.macAddr[atoi(var+7)]);
709 } else if (streq(var, "opCapFlags")) {
710 fprintf(fd, "0x%02X", eepromN.baseEepHeader.opCapFlags);
711 } else if (streq(var, "eepMisc")) {
712 fprintf(fd, "0x%02X", eepromN.baseEepHeader.eepMisc);
713 } else if (strneq(var, "binBuildNumber", 14)) {
715 (eepromN.baseEepHeader.binBuildNumber >> (8*atoi(var+14)))
717 } else if (strneq(var, "custData", 8)) {
718 fprintf(fd, "%2.2X", eepromN.custData[atoi(var+8)]);
719 } else if (streq(var, "xpd_mask")) {
720 if (IS_VERS(<, AR_EEPROM_VER5_0))
721 fprintf(fd, "0x%02x", pExpnPower->xpdMask);
723 fprintf(fd, "0x%02x", pRaw->xpd_mask);
724 } else if (streq(var, "numChannels")) {
725 if (IS_VERS(<, AR_EEPROM_VER5_0))
726 fprintf(fd, "%2d", pExpnPower->numChannels);
728 fprintf(fd, "%2d", pRaw->numChannels);
729 } else if (streq(var, "freq")) {
730 if (IS_VERS(<, AR_EEPROM_VER5_0))
731 fprintf(fd, "%4d", pExpnPower->pChannels[curchan]);
733 fprintf(fd, "%4d", pRaw->pChannels[curchan]);
734 } else if (streq(var, "maxpow")) {
736 if (IS_VERS(<, AR_EEPROM_VER5_0)) {
737 maxPower_t4 = pExpnPower->pDataPerChannel[curchan].maxPower_t4;
739 maxPower_t4 = pRaw->pDataPerChannel[curchan].maxPower_t4;
740 if (maxPower_t4 == 0)
741 maxPower_t4 = getMaxPowerV5(&pRaw->pDataPerChannel[curchan]);
743 printQuarterDbmPower(fd, maxPower_t4);
744 } else if (streq(var, "pd_gain")) {
745 fprintf(fd, "%4d", pRaw->pDataPerChannel[curchan].
746 pDataPerPDGain[curpdgain].pd_gain);
747 } else if (strneq(var, "maxpwr", 6)) {
748 int vpd = atoi(var+6);
749 if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd)
750 printQuarterDbmPower(fd, pRaw->pDataPerChannel[curchan].
751 pDataPerPDGain[curpdgain].pwr_t4[vpd]);
754 } else if (strneq(var, "pwr_t4_", 7)) {
755 printQuarterDbmPower(fd, pExpnPower->pDataPerChannel[curchan].
756 pDataPerXPD[singleXpd].pwr_t4[atoi(var+7)]);
757 } else if (strneq(var, "Vpd", 3)) {
758 int vpd = atoi(var+3);
759 if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd)
760 printVpd(fd, pRaw->pDataPerChannel[curchan].
761 pDataPerPDGain[curpdgain].Vpd[vpd]);
764 } else if (streq(var, "CTL")) {
765 fprintf(fd, "0x%2x", eeprom.ee_ctl[curctl] & 0xff);
766 } else if (streq(var, "ctlType")) {
767 static const char *ctlType[16] = {
768 "11a base", "11b", "11g", "11a TURBO", "108g",
769 "2GHT20", "5GHT20", "2GHT40", "5GHT40",
770 "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf",
772 fprintf(fd, "%8s", ctlType[eeprom.ee_ctl[curctl] & CTL_MODE_M]);
773 } else if (streq(var, "ctlRD")) {
774 static const char *ctlRD[8] = {
775 "0x00", " FCC", "0x20", "ETSI",
776 " MKK", "0x50", "0x60", "0x70"
778 fprintf(fd, "%s", ctlRD[(eeprom.ee_ctl[curctl] >> 4) & 7]);
779 } else if (strneq(var, "rdEdgePower", 11)) {
780 printEdgePower(fd, atoi(var+11));
781 } else if (strneq(var, "rdEdgeFlag", 10)) {
782 printEdgeFlag(fd, atoi(var+10));
783 } else if (strneq(var, "rdEdge", 6)) {
784 printEdge(fd, atoi(var+6));
785 } else if (strneq(var, "testChannel", 11)) {
786 fprintf(fd, "%4d", pPowerInfo[atoi(var+11)].testChannel);
787 } else if (strneq(var, "pwr6_24_", 8)) {
788 printHalfDbmPower(fd, pPowerInfo[atoi(var+8)].twicePwr6_24);
789 } else if (strneq(var, "pwr36_", 6)) {
790 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr36);
791 } else if (strneq(var, "pwr48_", 6)) {
792 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr48);
793 } else if (strneq(var, "pwr54_", 6)) {
794 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr54);
795 } else if (strneq(var, "channelValue", 12)) {
796 fprintf(fd, "%4d", pDataPerChannel[atoi(var+12)].channelValue);
797 } else if (strneq(var, "pcdacMin", 8)) {
798 fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMin);
799 } else if (strneq(var, "pcdacMax", 8)) {
800 fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMax);
801 } else if (strneq(var, "pcdac", 5)) {
802 if (IS_VERS(<, AR_EEPROM_VER4_0)) {
803 fprintf(fd, "%02d", pDataPerChannel[atoi(var+5)].
804 PcdacValues[curpcdac]);
805 } else if (IS_VERS(<, AR_EEPROM_VER5_0)) {
807 pExpnPower->pDataPerChannel[curchan].
808 pDataPerXPD[singleXpd].pcdac[atoi(var+5)]);
811 } else if (strneq(var, "pwrValue", 8)) {
813 pDataPerChannel[atoi(var+8)].PwrValues[curpcdac]);
814 } else if (streq(var, "singleXpd")) {
815 fprintf(fd, "%2d", singleXpd);
817 warnx("line %u, unknown EEPROM variable \"%s\"", lineno, var);
823 ifmode(FILE *ftemplate, const char *mode)
825 if (strcasecmp(mode, "11a") == 0) {
826 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
828 setmode(headerInfo11A);
830 skipto(ftemplate, "endmode");
833 if (IS_VERS(>=, AR_EEPROM_VER14_2)) {
834 if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A)
835 setmode(headerInfo11A);
837 skipto(ftemplate, "endmode");
840 } else if (strcasecmp(mode, "11g") == 0) {
841 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
843 setmode(headerInfo11G);
845 skipto(ftemplate, "endmode");
848 if (IS_VERS(>=, AR_EEPROM_VER14_2)) {
849 if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G)
850 setmode(headerInfo11B); /* NB: 2.4GHz */
852 skipto(ftemplate, "endmode");
855 } else if (strcasecmp(mode, "11b") == 0) {
856 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
858 setmode(headerInfo11B);
860 skipto(ftemplate, "endmode");
864 warnx("line %d, unknown/unexpected mode \"%s\" ignored",
866 skipto(ftemplate, "endmode");
870 parseTemplate(FILE *ftemplate, FILE *fd)
874 long forchan, forpdgain, forctl, forpcdac;
878 while ((c = getc(ftemplate)) != EOF) {
879 if (c == '#') { /* comment */
881 while ((c = getc(ftemplate)) != EOF && c != '\n')
889 if (c == '.' && bol) { /* .directive */
890 if (token(ftemplate, id, MAXID, ".directive") == EOF)
892 /* process directive */
893 if (strcasecmp(id, "ifmode") == 0) {
895 if (token(ftemplate, id, MAXID, "id") == EOF)
897 ifmode(ftemplate, id);
898 } else if (strcasecmp(id, "endmode") == 0) {
899 /* XXX free malloc'd indirect data */
900 curmode = -1; /* NB: undefined */
901 } else if (strcasecmp(id, "forchan") == 0) {
902 forchan = ftell(ftemplate) - sizeof("forchan");
905 } else if (strcasecmp(id, "endforchan") == 0) {
906 if (++curchan < numChannels)
907 fseek(ftemplate, forchan, SEEK_SET);
910 } else if (strcasecmp(id, "ifpdgain") == 0) {
912 if (token(ftemplate, id, MAXID, "pdgain") == EOF)
914 curlpdgain = strtoul(id, NULL, 0);
915 if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) {
916 skipto(ftemplate, "endpdgain");
919 curpdgain = pdgain(curlpdgain);
920 } else if (strcasecmp(id, "endpdgain") == 0) {
921 curlpdgain = curpdgain = -1;
922 } else if (strcasecmp(id, "forpdgain") == 0) {
923 forpdgain = ftell(ftemplate) - sizeof("forpdgain");
924 if (curlpdgain == -1) {
926 if (token(ftemplate, id, MAXID, "pdgain") == EOF)
928 curlpdgain = strtoul(id, NULL, 0);
929 if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) {
930 skipto(ftemplate, "endforpdgain");
933 curpdgain = pdgain(curlpdgain);
935 } else if (strcasecmp(id, "endforpdgain") == 0) {
936 if (++curpdgain < pRaw->pDataPerChannel[curchan].numPdGains)
937 fseek(ftemplate, forpdgain, SEEK_SET);
940 } else if (strcasecmp(id, "forpcdac") == 0) {
941 forpcdac = ftell(ftemplate) - sizeof("forpcdac");
944 } else if (strcasecmp(id, "endforpcdac") == 0) {
945 if (++curpcdac < pDataPerChannel[0].numPcdacValues)
946 fseek(ftemplate, forpcdac, SEEK_SET);
949 } else if (strcasecmp(id, "forctl") == 0) {
950 forctl = ftell(ftemplate) - sizeof("forchan");
953 } else if (strcasecmp(id, "endforctl") == 0) {
954 curctl = nextctl(curctl+1);
956 fseek(ftemplate, forctl, SEEK_SET);
958 warnx("line %d, unknown directive %s ignored",
963 if (c == '$') { /* $variable reference */
964 if (token(ftemplate, id, MAXID, "$var") == EOF)
966 /* XXX not valid if variable depends on curmode */
970 if (c == '\\') { /* escape next character */