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))
49 #define DIR_TEMPLATE "/usr/local/libdata/athprom"
56 HAL_EEPROM legacy; /* format v3.x ... v5.x */
57 struct ar5416eeprom v14; /* 11n format v14.x ... */
59 #define eeprom eep.legacy
60 #define eepromN eep.v14
62 static void parseTemplate(FILE *ftemplate, FILE *fd);
63 static uint16_t eeread(uint16_t);
64 static void eewrite(uint16_t, uint16_t);
69 fprintf(stderr, "usage: %s [-i ifname] [-t pathname] [offset | offset=value]\n", progname);
74 opentemplate(const char *dir)
76 char filename[PATH_MAX];
79 /* find the template using the eeprom version */
80 snprintf(filename, sizeof(filename), "%s/eeprom-%d.%d",
81 dir, eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
82 fd = fopen(filename, "r");
83 if (fd == NULL && errno == ENOENT) {
84 /* retry with just the major version */
85 snprintf(filename, sizeof(filename), "%s/eeprom-%d",
86 dir, eeprom.ee_version >> 12);
87 fd = fopen(filename, "r");
88 if (fd != NULL) /* XXX verbose */
89 warnx("Using template file %s", filename);
95 main(int argc, char *argv[])
101 s = socket(AF_INET, SOCK_DGRAM, 0);
104 ifname = getenv("ATH");
106 ifname = ATH_DEFAULT;
109 while ((c = getopt(argc, argv, "i:t:")) != -1)
115 fd = fopen(optarg, "r");
117 err(-1, "Cannot open %s", optarg);
126 strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
129 for (; argc > 0; argc--, argv++) {
130 uint16_t off, val, oval;
134 cp = strchr(argv[0], '=');
137 off = (uint16_t) strtoul(argv[0], NULL, 0);
138 if (off == 0 && errno == EINVAL)
139 errx(1, "%s: invalid eeprom offset %s",
142 printf("%04x: %04x\n", off, eeread(off));
144 val = (uint16_t) strtoul(cp+1, NULL, 0);
145 if (val == 0 && errno == EINVAL)
146 errx(1, "%s: invalid eeprom value %s",
149 printf("Write %04x: %04x = %04x? ",
152 if (fgets(line, sizeof(line), stdin) != NULL &&
158 atd.ad_id = HAL_DIAG_EEPROM;
159 atd.ad_out_data = (caddr_t) &eep;
160 atd.ad_out_size = sizeof(eep);
161 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
164 fd = opentemplate(DIR_TEMPLATE);
166 fd = opentemplate(".");
168 errx(-1, "Cannot locate template file for "
169 "v%d.%d EEPROM", eeprom.ee_version >> 12,
170 eeprom.ee_version & 0xfff);
172 parseTemplate(fd, stdout);
179 eeread(u_int16_t off)
183 atd.ad_id = HAL_DIAG_EEREAD | ATH_DIAG_IN | ATH_DIAG_DYN;
184 atd.ad_in_size = sizeof(off);
185 atd.ad_in_data = (caddr_t) &off;
186 atd.ad_out_size = sizeof(eedata);
187 atd.ad_out_data = (caddr_t) &eedata;
188 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
194 eewrite(uint16_t off, uint16_t value)
196 HAL_DIAG_EEVAL eeval;
199 eeval.ee_data = value;
201 atd.ad_id = HAL_DIAG_EEWRITE | ATH_DIAG_IN;
202 atd.ad_in_size = sizeof(eeval);
203 atd.ad_in_data = (caddr_t) &eeval;
205 atd.ad_out_data = NULL;
206 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
215 int curpdgain; /* raw pdgain index */
216 int curlpdgain; /* logical pdgain index */
220 const RAW_DATA_STRUCT_2413 *pRaw;
221 const TRGT_POWER_INFO *pPowerInfo;
222 const DATA_PER_CHANNEL *pDataPerChannel;
223 const EEPROM_POWER_EXPN_5112 *pExpnPower;
227 token(FILE *fd, char id[], int maxid, const char *what)
236 if (!isalnum(c) && c != '_') {
241 warnx("line %d, %s too long", lineno, what);
253 skipto(FILE *fd, const char *what)
262 if (c == '.' && bol) { /* .directive */
263 if (token(fd, id, MAXID, ".directive") == EOF)
265 if (strcasecmp(id, what) == 0)
269 if (c == '\\') { /* escape next character */
280 warnx("EOF with no matching .%s", what);
290 while ((c = getc(fd)) != EOF && isblank(c))
302 EEPROM_POWER_EXPN_5112 *exp;
312 pPowerInfo = eeprom.ee_trgtPwr_11a;
313 pDataPerChannel = eeprom.ee_dataPerChannel11a;
316 pPowerInfo = eeprom.ee_trgtPwr_11b;
317 pDataPerChannel = eeprom.ee_dataPerChannel11b;
320 pPowerInfo = eeprom.ee_trgtPwr_11g;
321 pDataPerChannel = eeprom.ee_dataPerChannel11g;
324 if (IS_VERS(<, AR_EEPROM_VER4_0)) /* nothing to do */
326 if (IS_VERS(<, AR_EEPROM_VER5_0)) {
327 exp = &eeprom.ee_modePowerArray5112[curmode];
328 /* fetch indirect data*/
329 atd.ad_id = HAL_DIAG_EEPROM_EXP_11A+curmode;
330 atd.ad_out_size = roundup(
331 sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t))
332 + sizeof(EXPN_DATA_PER_CHANNEL_5112) * exp->numChannels;
333 atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size);
334 if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
336 exp->pChannels = (void *) atd.ad_out_data;
337 exp->pDataPerChannel = (void *)((char *)atd.ad_out_data +
338 roundup(sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t)));
340 numChannels = pExpnPower->numChannels;
341 if (exp->xpdMask != 0x9) {
342 for (singleXpd = 0; singleXpd < NUM_XPD_PER_CHANNEL; singleXpd++)
343 if (exp->xpdMask == (1<<singleXpd))
347 } else if (IS_VERS(<, AR_EEPROM_VER14_2)) {
348 pRaw = &eeprom.ee_rawDataset2413[curmode];
349 numChannels = pRaw->numChannels;
358 for (i = start; i < eeprom.ee_numCtls && eeprom.ee_ctl[i]; i++) {
359 switch (eeprom.ee_ctl[i] & 3) {
361 if (curmode != headerInfo11A)
365 if (curmode != headerInfo11B)
369 if (curmode != headerInfo11G)
379 printAntennaControl(FILE *fd, int ant)
381 fprintf(fd, "0x%02X", eeprom.ee_antennaControl[ant][curmode]);
385 printEdge(FILE *fd, int edge)
387 const RD_EDGES_POWER *pRdEdgePwrInfo =
388 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
390 if (pRdEdgePwrInfo[edge].rdEdge == 0)
393 fprintf(fd, "%04d", pRdEdgePwrInfo[edge].rdEdge);
397 printEdgePower(FILE *fd, int edge)
399 const RD_EDGES_POWER *pRdEdgePwrInfo =
400 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
402 if (pRdEdgePwrInfo[edge].rdEdge == 0)
405 fprintf(fd, "%2d.%d",
406 pRdEdgePwrInfo[edge].twice_rdEdgePower / 2,
407 (pRdEdgePwrInfo[edge].twice_rdEdgePower % 2) * 5);
411 printEdgeFlag(FILE *fd, int edge)
413 const RD_EDGES_POWER *pRdEdgePwrInfo =
414 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
416 if (pRdEdgePwrInfo[edge].rdEdge == 0)
419 fprintf(fd, " %1d", pRdEdgePwrInfo[edge].flag);
423 getMaxPowerV5(const RAW_DATA_PER_CHANNEL_2413 *data)
428 for (i = 0; i < MAX_NUM_PDGAINS_PER_CHANNEL; i++) {
429 numVpd = data->pDataPerPDGain[i].numVpd;
431 return data->pDataPerPDGain[i].pwr_t4[numVpd-1];
437 printQuarterDbmPower(FILE *fd, int16_t power25dBm)
439 fprintf(fd, "%2d.%02d", power25dBm / 4, (power25dBm % 4) * 25);
443 printHalfDbmPower(FILE *fd, int16_t power5dBm)
445 fprintf(fd, "%2d.%d", power5dBm / 2, (power5dBm % 2) * 5);
449 printVpd(FILE *fd, int vpd)
451 fprintf(fd, "[%3d]", vpd);
455 printPcdacValue(FILE *fd, int v)
457 fprintf(fd, "%2d.%02d", v / EEP_SCALE, v % EEP_SCALE);
461 undef(const char *what)
463 warnx("%s undefined for version %d.%d format EEPROM", what,
464 eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
473 if (IS_VERS(<, AR_EEPROM_VER5_0))
474 mask = pExpnPower->xpdMask;
476 mask = pRaw->xpd_mask;
477 for (i = 0; mask != 0; mask >>= 1, i++)
478 if ((mask & 1) && l-- == 0)
480 warnx("can't find logical pdgain %d", lpdgain);
484 #define COUNTRY_ERD_FLAG 0x8000
485 #define WORLDWIDE_ROAMING_FLAG 0x4000
488 eevar(FILE *fd, const char *var)
490 #define streq(a,b) (strcasecmp(a,b) == 0)
491 #define strneq(a,b,n) (strncasecmp(a,b,n) == 0)
492 if (streq(var, "mode")) {
494 curmode == headerInfo11A ? "11a" :
495 curmode == headerInfo11B ? "11b" :
496 curmode == headerInfo11G ? "11g" : "???");
497 } else if (streq(var, "version")) {
498 fprintf(fd, "%04x", eeprom.ee_version);
499 } else if (streq(var, "V_major")) {
500 fprintf(fd, "%2d", eeprom.ee_version >> 12);
501 } else if (streq(var, "V_minor")) {
502 fprintf(fd, "%2d", eeprom.ee_version & 0xfff);
503 } else if (streq(var, "earStart")) {
504 fprintf(fd, "%03x", eeprom.ee_earStart);
505 } else if (streq(var, "tpStart")) {
506 fprintf(fd, "%03x", eeprom.ee_targetPowersStart);
507 } else if (streq(var, "eepMap")) {
508 fprintf(fd, "%3d", eeprom.ee_eepMap);
509 } else if (streq(var, "exist32KHzCrystal")) {
510 fprintf(fd, "%3d", eeprom.ee_exist32kHzCrystal);
511 } else if (streq(var, "eepMap2PowerCalStart")) {
512 fprintf(fd , "%3d", eeprom.ee_eepMap2PowerCalStart);
513 } else if (streq(var, "Amode")) {
514 fprintf(fd , "%1d", eeprom.ee_Amode);
515 } else if (streq(var, "Bmode")) {
516 fprintf(fd , "%1d", eeprom.ee_Bmode);
517 } else if (streq(var, "Gmode")) {
518 fprintf(fd , "%1d", eeprom.ee_Gmode);
519 } else if (streq(var, "regdomain")) {
520 if ((eeprom.ee_regdomain & COUNTRY_ERD_FLAG) == 0)
521 fprintf(fd, "%03X ", eeprom.ee_regdomain >> 15);
523 fprintf(fd, "%-3dC", eeprom.ee_regdomain & 0xfff);
524 } else if (streq(var, "turbo2Disable")) {
525 fprintf(fd, "%1d", eeprom.ee_turbo2Disable);
526 } else if (streq(var, "turbo5Disable")) {
527 fprintf(fd, "%1d", eeprom.ee_turbo5Disable);
528 } else if (streq(var, "rfKill")) {
529 fprintf(fd, "%1d", eeprom.ee_rfKill);
530 } else if (streq(var, "disableXr5")) {
531 fprintf(fd, "%1d", eeprom.ee_disableXr5);
532 } else if (streq(var, "disableXr2")) {
533 fprintf(fd, "%1d", eeprom.ee_disableXr2);
534 } else if (streq(var, "turbo2WMaxPower5")) {
535 fprintf(fd, "%2d", eeprom.ee_turbo2WMaxPower5);
536 } else if (streq(var, "cckOfdmDelta")) {
537 fprintf(fd, "%2d", eeprom.ee_cckOfdmPwrDelta);
538 } else if (streq(var, "gainI")) {
539 fprintf(fd, "%2d", eeprom.ee_gainI[curmode]);
540 } else if (streq(var, "WWR")) {
542 (eeprom.ee_regdomain & WORLDWIDE_ROAMING_FLAG) != 0);
543 } else if (streq(var, "falseDetectBackoff")) {
544 fprintf(fd, "0x%02x", eeprom.ee_falseDetectBackoff[curmode]);
545 } else if (streq(var, "deviceType")) {
546 fprintf(fd, "%1x", eeprom.ee_deviceType);
547 } else if (streq(var, "switchSettling")) {
548 if (IS_VERS(<, AR_EEPROM_VER14_2))
549 fprintf(fd, "0x%02x", eeprom.ee_switchSettling[curmode]);
551 fprintf(fd, "%3d", eepromN.modalHeader[curmode].switchSettling);
552 } else if (streq(var, "adcDesiredSize")) {
553 if (IS_VERS(<, AR_EEPROM_VER14_2))
554 fprintf(fd, "%2d", eeprom.ee_adcDesiredSize[curmode]);
556 fprintf(fd, "%3d", eepromN.modalHeader[curmode].adcDesiredSize);
557 } else if (streq(var, "xlnaGain")) {
558 fprintf(fd, "0x%02x", eeprom.ee_xlnaGain[curmode]);
559 } else if (streq(var, "txEndToXLNAOn")) {
560 fprintf(fd, "0x%02x", eeprom.ee_txEndToXLNAOn[curmode]);
561 } else if (streq(var, "thresh62")) {
562 if (IS_VERS(<, AR_EEPROM_VER14_2))
563 fprintf(fd, "0x%02x", eeprom.ee_thresh62[curmode]);
565 fprintf(fd, "%3d", eepromN.modalHeader[curmode].thresh62);
566 } else if (streq(var, "txEndToRxOn")) {
567 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn);
568 } else if (streq(var, "txEndToXPAOff")) {
569 if (IS_VERS(<, AR_EEPROM_VER14_2))
570 fprintf(fd, "0x%02x", eeprom.ee_txEndToXPAOff[curmode]);
572 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToXpaOff);
573 } else if (streq(var, "txFrameToXPAOn")) {
574 if (IS_VERS(<, AR_EEPROM_VER14_2))
575 fprintf(fd, "0x%02x", eeprom.ee_txFrameToXPAOn[curmode]);
577 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn);
578 } else if (streq(var, "pgaDesiredSize")) {
579 if (IS_VERS(<, AR_EEPROM_VER14_2))
580 fprintf(fd, "%2d", eeprom.ee_pgaDesiredSize[curmode]);
582 fprintf(fd, "%3d", eepromN.modalHeader[curmode].pgaDesiredSize);
583 } else if (streq(var, "noiseFloorThresh")) {
584 fprintf(fd, "%3d", eeprom.ee_noiseFloorThresh[curmode]);
585 } else if (strneq(var, "noiseFloorThreshCh", 18)) {
586 fprintf(fd, "%3d", eepromN.modalHeader[curmode].noiseFloorThreshCh[atoi(var+18)]);
587 } else if (strneq(var, "xlnaGainCh", 10)) {
588 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xlnaGainCh[atoi(var+10)]);
589 } else if (streq(var, "xgain")) {
590 fprintf(fd, "0x%02x", eeprom.ee_xgain[curmode]);
591 } else if (streq(var, "xpd")) {
592 if (IS_VERS(<, AR_EEPROM_VER14_2))
593 fprintf(fd, "%1d", eeprom.ee_xpd[curmode]);
595 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpd);
596 } else if (streq(var, "txrxAtten")) {
597 fprintf(fd, "0x%02x", eeprom.ee_txrxAtten[curmode]);
598 } else if (streq(var, "capField")) {
599 fprintf(fd, "0x%04X", eeprom.ee_capField);
600 } else if (streq(var, "txrxAttenTurbo")) {
601 fprintf(fd, "0x%02x",
602 eeprom.ee_txrxAtten[curmode != headerInfo11A]);
603 } else if (streq(var, "switchSettlingTurbo")) {
604 fprintf(fd, "0x%02X",
605 eeprom.ee_switchSettlingTurbo[curmode != headerInfo11A]);
606 } else if (streq(var, "adcDesiredSizeTurbo")) {
608 eeprom.ee_adcDesiredSizeTurbo[curmode != headerInfo11A]);
609 } else if (streq(var, "pgaDesiredSizeTurbo")) {
611 eeprom.ee_pgaDesiredSizeTurbo[curmode != headerInfo11A]);
612 } else if (streq(var, "rxtxMarginTurbo")) {
613 fprintf(fd, "0x%02x",
614 eeprom.ee_rxtxMarginTurbo[curmode != headerInfo11A]);
615 } else if (strneq(var, "antennaControl", 14)) {
616 printAntennaControl(fd, atoi(var+14));
617 } else if (strneq(var, "antCtrlChain", 12)) {
618 fprintf(fd, "0x%08X",
619 eepromN.modalHeader[curmode].antCtrlChain[atoi(var+12)]);
620 } else if (strneq(var, "antGainCh", 9)) {
622 eepromN.modalHeader[curmode].antennaGainCh[atoi(var+9)]);
623 } else if (strneq(var, "txRxAttenCh", 11)) {
625 eepromN.modalHeader[curmode].txRxAttenCh[atoi(var+11)]);
626 } else if (strneq(var, "rxTxMarginCh", 12)) {
628 eepromN.modalHeader[curmode].rxTxMarginCh[atoi(var+12)]);
629 } else if (streq(var, "xpdGain")) {
630 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpdGain);
631 } else if (strneq(var, "iqCalICh", 8)) {
633 eepromN.modalHeader[curmode].iqCalICh[atoi(var+8)]);
634 } else if (strneq(var, "iqCalQCh", 8)) {
636 eepromN.modalHeader[curmode].iqCalQCh[atoi(var+8)]);
637 } else if (streq(var, "pdGainOverlap")) {
638 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pdGainOverlap);
639 } else if (streq(var, "ob1")) {
640 fprintf(fd, "%1d", eeprom.ee_ob1);
641 } else if (streq(var, "ob2")) {
642 fprintf(fd, "%1d", eeprom.ee_ob2);
643 } else if (streq(var, "ob3")) {
644 fprintf(fd, "%1d", eeprom.ee_ob3);
645 } else if (streq(var, "ob4")) {
646 fprintf(fd, "%1d", eeprom.ee_ob4);
647 } else if (streq(var, "db1")) {
648 fprintf(fd, "%1d", eeprom.ee_db1);
649 } else if (streq(var, "db2")) {
650 fprintf(fd, "%1d", eeprom.ee_db2);
651 } else if (streq(var, "db3")) {
652 fprintf(fd, "%1d", eeprom.ee_db3);
653 } else if (streq(var, "db4")) {
654 fprintf(fd, "%1d", eeprom.ee_db4);
655 } else if (streq(var, "obFor24")) {
656 fprintf(fd, "%1d", eeprom.ee_obFor24);
657 } else if (streq(var, "ob2GHz0")) {
658 fprintf(fd, "%1d", eeprom.ee_ob2GHz[0]);
659 } else if (streq(var, "dbFor24")) {
660 fprintf(fd, "%1d", eeprom.ee_dbFor24);
661 } else if (streq(var, "db2GHz0")) {
662 fprintf(fd, "%1d", eeprom.ee_db2GHz[0]);
663 } else if (streq(var, "obFor24g")) {
664 fprintf(fd, "%1d", eeprom.ee_obFor24g);
665 } else if (streq(var, "ob2GHz1")) {
666 fprintf(fd, "%1d", eeprom.ee_ob2GHz[1]);
667 } else if (streq(var, "dbFor24g")) {
668 fprintf(fd, "%1d", eeprom.ee_dbFor24g);
669 } else if (streq(var, "db2GHz1")) {
670 fprintf(fd, "%1d", eeprom.ee_db2GHz[1]);
671 } else if (streq(var, "ob")) {
672 fprintf(fd, "%3d", eepromN.modalHeader[curmode].ob);
673 } else if (streq(var, "db")) {
674 fprintf(fd, "%3d", eepromN.modalHeader[curmode].db);
675 } else if (streq(var, "xpaBiasLvl")) {
676 fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpaBiasLvl);
677 } else if (streq(var, "pwrDecreaseFor2Chain")) {
678 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor2Chain);
679 } else if (streq(var, "pwrDecreaseFor3Chain")) {
680 printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor3Chain);
681 } else if (streq(var, "txFrameToDataStart")) {
682 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToDataStart);
683 } else if (streq(var, "txFrameToPaOn")) {
684 fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToPaOn);
685 } else if (streq(var, "ht40PowerIncForPdadc")) {
686 fprintf(fd, "%3d", eepromN.modalHeader[curmode].ht40PowerIncForPdadc);
687 } else if (streq(var, "checksum")) {
688 fprintf(fd, "0x%04X", eepromN.baseEepHeader.checksum);
689 } else if (streq(var, "length")) {
690 fprintf(fd, "0x%04X", eepromN.baseEepHeader.length);
691 } else if (streq(var, "regDmn0")) {
692 fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[0]);
693 } else if (streq(var, "regDmn1")) {
694 fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[1]);
695 } else if (streq(var, "txMask")) {
696 fprintf(fd, "0x%04X", eepromN.baseEepHeader.txMask);
697 } else if (streq(var, "rxMask")) {
698 fprintf(fd, "0x%04X", eepromN.baseEepHeader.rxMask);
699 } else if (streq(var, "rfSilent")) {
700 fprintf(fd, "0x%04X", eepromN.baseEepHeader.rfSilent);
701 } else if (streq(var, "btOptions")) {
702 fprintf(fd, "0x%04X", eepromN.baseEepHeader.blueToothOptions);
703 } else if (streq(var, "deviceCap")) {
704 fprintf(fd, "0x%04X", eepromN.baseEepHeader.deviceCap);
705 } else if (strneq(var, "macaddr", 7)) {
707 eepromN.baseEepHeader.macAddr[atoi(var+7)]);
708 } else if (streq(var, "opCapFlags")) {
709 fprintf(fd, "0x%02X", eepromN.baseEepHeader.opCapFlags);
710 } else if (streq(var, "eepMisc")) {
711 fprintf(fd, "0x%02X", eepromN.baseEepHeader.eepMisc);
712 } else if (strneq(var, "binBuildNumber", 14)) {
714 (eepromN.baseEepHeader.binBuildNumber >> (8*atoi(var+14)))
716 } else if (strneq(var, "custData", 8)) {
717 fprintf(fd, "%2.2X", eepromN.custData[atoi(var+8)]);
718 } else if (streq(var, "xpd_mask")) {
719 if (IS_VERS(<, AR_EEPROM_VER5_0))
720 fprintf(fd, "0x%02x", pExpnPower->xpdMask);
722 fprintf(fd, "0x%02x", pRaw->xpd_mask);
723 } else if (streq(var, "numChannels")) {
724 if (IS_VERS(<, AR_EEPROM_VER5_0))
725 fprintf(fd, "%2d", pExpnPower->numChannels);
727 fprintf(fd, "%2d", pRaw->numChannels);
728 } else if (streq(var, "freq")) {
729 if (IS_VERS(<, AR_EEPROM_VER5_0))
730 fprintf(fd, "%4d", pExpnPower->pChannels[curchan]);
732 fprintf(fd, "%4d", pRaw->pChannels[curchan]);
733 } else if (streq(var, "maxpow")) {
735 if (IS_VERS(<, AR_EEPROM_VER5_0)) {
736 maxPower_t4 = pExpnPower->pDataPerChannel[curchan].maxPower_t4;
738 maxPower_t4 = pRaw->pDataPerChannel[curchan].maxPower_t4;
739 if (maxPower_t4 == 0)
740 maxPower_t4 = getMaxPowerV5(&pRaw->pDataPerChannel[curchan]);
742 printQuarterDbmPower(fd, maxPower_t4);
743 } else if (streq(var, "pd_gain")) {
744 fprintf(fd, "%4d", pRaw->pDataPerChannel[curchan].
745 pDataPerPDGain[curpdgain].pd_gain);
746 } else if (strneq(var, "maxpwr", 6)) {
747 int vpd = atoi(var+6);
748 if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd)
749 printQuarterDbmPower(fd, pRaw->pDataPerChannel[curchan].
750 pDataPerPDGain[curpdgain].pwr_t4[vpd]);
753 } else if (strneq(var, "pwr_t4_", 7)) {
754 printQuarterDbmPower(fd, pExpnPower->pDataPerChannel[curchan].
755 pDataPerXPD[singleXpd].pwr_t4[atoi(var+7)]);
756 } else if (strneq(var, "Vpd", 3)) {
757 int vpd = atoi(var+3);
758 if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd)
759 printVpd(fd, pRaw->pDataPerChannel[curchan].
760 pDataPerPDGain[curpdgain].Vpd[vpd]);
763 } else if (streq(var, "CTL")) {
764 fprintf(fd, "0x%2x", eeprom.ee_ctl[curctl] & 0xff);
765 } else if (streq(var, "ctlType")) {
766 static const char *ctlType[16] = {
767 "11a base", "11b", "11g", "11a TURBO", "108g",
768 "2GHT20", "5GHT20", "2GHT40", "5GHT40",
769 "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf",
771 fprintf(fd, "%8s", ctlType[eeprom.ee_ctl[curctl] & CTL_MODE_M]);
772 } else if (streq(var, "ctlRD")) {
773 static const char *ctlRD[8] = {
774 "0x00", " FCC", "0x20", "ETSI",
775 " MKK", "0x50", "0x60", "0x70"
777 fprintf(fd, "%s", ctlRD[(eeprom.ee_ctl[curctl] >> 4) & 7]);
778 } else if (strneq(var, "rdEdgePower", 11)) {
779 printEdgePower(fd, atoi(var+11));
780 } else if (strneq(var, "rdEdgeFlag", 10)) {
781 printEdgeFlag(fd, atoi(var+10));
782 } else if (strneq(var, "rdEdge", 6)) {
783 printEdge(fd, atoi(var+6));
784 } else if (strneq(var, "testChannel", 11)) {
785 fprintf(fd, "%4d", pPowerInfo[atoi(var+11)].testChannel);
786 } else if (strneq(var, "pwr6_24_", 8)) {
787 printHalfDbmPower(fd, pPowerInfo[atoi(var+8)].twicePwr6_24);
788 } else if (strneq(var, "pwr36_", 6)) {
789 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr36);
790 } else if (strneq(var, "pwr48_", 6)) {
791 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr48);
792 } else if (strneq(var, "pwr54_", 6)) {
793 printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr54);
794 } else if (strneq(var, "channelValue", 12)) {
795 fprintf(fd, "%4d", pDataPerChannel[atoi(var+12)].channelValue);
796 } else if (strneq(var, "pcdacMin", 8)) {
797 fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMin);
798 } else if (strneq(var, "pcdacMax", 8)) {
799 fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMax);
800 } else if (strneq(var, "pcdac", 5)) {
801 if (IS_VERS(<, AR_EEPROM_VER4_0)) {
802 fprintf(fd, "%02d", pDataPerChannel[atoi(var+5)].
803 PcdacValues[curpcdac]);
804 } else if (IS_VERS(<, AR_EEPROM_VER5_0)) {
806 pExpnPower->pDataPerChannel[curchan].
807 pDataPerXPD[singleXpd].pcdac[atoi(var+5)]);
810 } else if (strneq(var, "pwrValue", 8)) {
812 pDataPerChannel[atoi(var+8)].PwrValues[curpcdac]);
813 } else if (streq(var, "singleXpd")) {
814 fprintf(fd, "%2d", singleXpd);
816 warnx("line %u, unknown EEPROM variable \"%s\"", lineno, var);
822 ifmode(FILE *ftemplate, const char *mode)
824 if (strcasecmp(mode, "11a") == 0) {
825 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
827 setmode(headerInfo11A);
829 skipto(ftemplate, "endmode");
832 if (IS_VERS(>=, AR_EEPROM_VER14_2)) {
833 if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A)
834 setmode(headerInfo11A);
836 skipto(ftemplate, "endmode");
839 } else if (strcasecmp(mode, "11g") == 0) {
840 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
842 setmode(headerInfo11G);
844 skipto(ftemplate, "endmode");
847 if (IS_VERS(>=, AR_EEPROM_VER14_2)) {
848 if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G)
849 setmode(headerInfo11B); /* NB: 2.4GHz */
851 skipto(ftemplate, "endmode");
854 } else if (strcasecmp(mode, "11b") == 0) {
855 if (IS_VERS(<, AR_EEPROM_VER14_2)) {
857 setmode(headerInfo11B);
859 skipto(ftemplate, "endmode");
863 warnx("line %d, unknown/unexpected mode \"%s\" ignored",
865 skipto(ftemplate, "endmode");
869 parseTemplate(FILE *ftemplate, FILE *fd)
873 long forchan, forpdgain, forctl, forpcdac;
877 while ((c = getc(ftemplate)) != EOF) {
878 if (c == '#') { /* comment */
880 while ((c = getc(ftemplate)) != EOF && c != '\n')
888 if (c == '.' && bol) { /* .directive */
889 if (token(ftemplate, id, MAXID, ".directive") == EOF)
891 /* process directive */
892 if (strcasecmp(id, "ifmode") == 0) {
894 if (token(ftemplate, id, MAXID, "id") == EOF)
896 ifmode(ftemplate, id);
897 } else if (strcasecmp(id, "endmode") == 0) {
898 /* XXX free malloc'd indirect data */
899 curmode = -1; /* NB: undefined */
900 } else if (strcasecmp(id, "forchan") == 0) {
901 forchan = ftell(ftemplate) - sizeof("forchan");
904 } else if (strcasecmp(id, "endforchan") == 0) {
905 if (++curchan < numChannels)
906 fseek(ftemplate, forchan, SEEK_SET);
909 } else if (strcasecmp(id, "ifpdgain") == 0) {
911 if (token(ftemplate, id, MAXID, "pdgain") == EOF)
913 curlpdgain = strtoul(id, NULL, 0);
914 if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) {
915 skipto(ftemplate, "endpdgain");
918 curpdgain = pdgain(curlpdgain);
919 } else if (strcasecmp(id, "endpdgain") == 0) {
920 curlpdgain = curpdgain = -1;
921 } else if (strcasecmp(id, "forpdgain") == 0) {
922 forpdgain = ftell(ftemplate) - sizeof("forpdgain");
923 if (curlpdgain == -1) {
925 if (token(ftemplate, id, MAXID, "pdgain") == EOF)
927 curlpdgain = strtoul(id, NULL, 0);
928 if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) {
929 skipto(ftemplate, "endforpdgain");
932 curpdgain = pdgain(curlpdgain);
934 } else if (strcasecmp(id, "endforpdgain") == 0) {
935 if (++curpdgain < pRaw->pDataPerChannel[curchan].numPdGains)
936 fseek(ftemplate, forpdgain, SEEK_SET);
939 } else if (strcasecmp(id, "forpcdac") == 0) {
940 forpcdac = ftell(ftemplate) - sizeof("forpcdac");
943 } else if (strcasecmp(id, "endforpcdac") == 0) {
944 if (++curpcdac < pDataPerChannel[0].numPcdacValues)
945 fseek(ftemplate, forpcdac, SEEK_SET);
948 } else if (strcasecmp(id, "forctl") == 0) {
949 forctl = ftell(ftemplate) - sizeof("forchan");
952 } else if (strcasecmp(id, "endforctl") == 0) {
953 curctl = nextctl(curctl+1);
955 fseek(ftemplate, forctl, SEEK_SET);
957 warnx("line %d, unknown directive %s ignored",
962 if (c == '$') { /* $variable reference */
963 if (token(ftemplate, id, MAXID, "$var") == EOF)
965 /* XXX not valid if variable depends on curmode */
969 if (c == '\\') { /* escape next character */