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, 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. 28 * 29 * $FreeBSD$ 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#include <ctype.h> 47 48#ifndef DIR_TEMPLATE 49#define DIR_TEMPLATE "/usr/local/libdata/athprom" 50#endif 51 52struct ath_diag atd; 53int s; 54const char *progname; 55union { 56 HAL_EEPROM legacy; /* format v3.x ... v5.x */ 57 struct ar5416eeprom v14; /* 11n format v14.x ... */ 58} eep; 59#define eeprom eep.legacy 60#define eepromN eep.v14 61 62static void parseTemplate(FILE *ftemplate, FILE *fd); 63static uint16_t eeread(uint16_t); 64static void eewrite(uint16_t, uint16_t); 65 66static void 67usage() 68{ 69 fprintf(stderr, "usage: %s [-i ifname] [-t pathname] [offset | offset=value]\n", progname); 70 exit(-1); 71} 72 73static FILE * 74opentemplate(const char *dir) 75{ 76 char filename[PATH_MAX]; 77 FILE *fd; 78 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); 90 } 91 return fd; 92} 93 94int 95main(int argc, char *argv[]) 96{ 97 FILE *fd = NULL; 98 const char *ifname; 99 int c; 100 101 s = socket(AF_INET, SOCK_DGRAM, 0); 102 if (s < 0) 103 err(1, "socket"); 104 ifname = getenv("ATH"); 105 if (!ifname) 106 ifname = ATH_DEFAULT; 107 108 progname = argv[0]; 109 while ((c = getopt(argc, argv, "i:t:")) != -1) 110 switch (c) { 111 case 'i': 112 ifname = optarg; 113 break; 114 case 't': 115 fd = fopen(optarg, "r"); 116 if (fd == NULL) 117 err(-1, "Cannot open %s", optarg); 118 break; 119 default: 120 usage(); 121 /*NOTREACHED*/ 122 } 123 argc -= optind; 124 argv += optind; 125 126 strncpy(atd.ad_name, ifname, sizeof (atd.ad_name)); 127 128 if (argc != 0) { 129 for (; argc > 0; argc--, argv++) { 130 uint16_t off, val, oval; 131 char line[256]; 132 char *cp; 133 134 cp = strchr(argv[0], '='); 135 if (cp != NULL) 136 *cp = '\0'; 137 off = (uint16_t) strtoul(argv[0], NULL, 0); 138 if (off == 0 && errno == EINVAL) 139 errx(1, "%s: invalid eeprom offset %s", 140 progname, argv[0]); 141 if (cp == NULL) { 142 printf("%04x: %04x\n", off, eeread(off)); 143 } else { 144 val = (uint16_t) strtoul(cp+1, NULL, 0); 145 if (val == 0 && errno == EINVAL) 146 errx(1, "%s: invalid eeprom value %s", 147 progname, cp+1); 148 oval = eeread(off); 149 printf("Write %04x: %04x = %04x? ", 150 off, oval, val); 151 fflush(stdout); 152 if (fgets(line, sizeof(line), stdin) != NULL && 153 line[0] == 'y') 154 eewrite(off, val); 155 } 156 } 157 } else { 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) 162 err(1, "ioctl: %s", atd.ad_name); 163 if (fd == NULL) { 164 fd = opentemplate(DIR_TEMPLATE); 165 if (fd == NULL) 166 fd = opentemplate("."); 167 if (fd == NULL) 168 errx(-1, "Cannot locate template file for " 169 "v%d.%d EEPROM", eeprom.ee_version >> 12, 170 eeprom.ee_version & 0xfff); 171 } 172 parseTemplate(fd, stdout); 173 fclose(fd); 174 } 175 return 0; 176} 177 178static u_int16_t 179eeread(u_int16_t off) 180{ 181 u_int16_t eedata; 182 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) 189 err(1, "ioctl: %s", atd.ad_name); 190 return eedata; 191} 192 193static void 194eewrite(uint16_t off, uint16_t value) 195{ 196 HAL_DIAG_EEVAL eeval; 197 198 eeval.ee_off = off; 199 eeval.ee_data = value; 200 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; 204 atd.ad_out_size = 0; 205 atd.ad_out_data = NULL; 206 if (ioctl(s, SIOCGATHDIAG, &atd) < 0) 207 err(1, "ioctl: %s", atd.ad_name); 208} 209 210#define MAXID 128 211int lineno; 212int bol; 213int curmode = -1; 214int curchan; 215int curpdgain; /* raw pdgain index */ 216int curlpdgain; /* logical pdgain index */ 217int curpcdac; 218int curctl; 219int numChannels; 220const RAW_DATA_STRUCT_2413 *pRaw; 221const TRGT_POWER_INFO *pPowerInfo; 222const DATA_PER_CHANNEL *pDataPerChannel; 223const EEPROM_POWER_EXPN_5112 *pExpnPower; 224int singleXpd; 225 226static int 227token(FILE *fd, char id[], int maxid, const char *what) 228{ 229 int c, i; 230 231 i = 0; 232 for (;;) { 233 c = getc(fd); 234 if (c == EOF) 235 return EOF; 236 if (!isalnum(c) && c != '_') { 237 ungetc(c, fd); 238 break; 239 } 240 if (i == maxid-1) { 241 warnx("line %d, %s too long", lineno, what); 242 break; 243 } 244 id[i++] = c; 245 } 246 id[i] = '\0'; 247 if (i != 0) 248 bol = 0; 249 return i; 250} 251 252static int 253skipto(FILE *fd, const char *what) 254{ 255 char id[MAXID]; 256 int c; 257 258 for (;;) { 259 c = getc(fd); 260 if (c == EOF) 261 goto bad; 262 if (c == '.' && bol) { /* .directive */ 263 if (token(fd, id, MAXID, ".directive") == EOF) 264 goto bad; 265 if (strcasecmp(id, what) == 0) 266 break; 267 continue; 268 } 269 if (c == '\\') { /* escape next character */ 270 c = getc(fd); 271 if (c == EOF) 272 goto bad; 273 } 274 bol = (c == '\n'); 275 if (bol) 276 lineno++; 277 } 278 return 0; 279bad: 280 warnx("EOF with no matching .%s", what); 281 return EOF; 282} 283 284static int 285skipws(FILE *fd) 286{ 287 int c, i; 288 289 i = 0; 290 while ((c = getc(fd)) != EOF && isblank(c)) 291 i++; 292 if (c != EOF) 293 ungetc(c, fd); 294 if (i != 0) 295 bol = 0; 296 return 0; 297} 298 299static void 300setmode(int mode) 301{ 302 EEPROM_POWER_EXPN_5112 *exp; 303 304 curmode = mode; 305 curchan = -1; 306 curctl = -1; 307 curpdgain = -1; 308 curlpdgain = -1; 309 curpcdac = -1; 310 switch (curmode) { 311 case headerInfo11A: 312 pPowerInfo = eeprom.ee_trgtPwr_11a; 313 pDataPerChannel = eeprom.ee_dataPerChannel11a; 314 break; 315 case headerInfo11B: 316 pPowerInfo = eeprom.ee_trgtPwr_11b; 317 pDataPerChannel = eeprom.ee_dataPerChannel11b; 318 break; 319 case headerInfo11G: 320 pPowerInfo = eeprom.ee_trgtPwr_11g; 321 pDataPerChannel = eeprom.ee_dataPerChannel11g; 322 break; 323 } 324 if (IS_VERS(<, AR_EEPROM_VER4_0)) /* nothing to do */ 325 return; 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) 335 err(1, "ioctl: %s", atd.ad_name); 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))); 339 pExpnPower = exp; 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)) 344 break; 345 } else 346 singleXpd = 0; 347 } else if (IS_VERS(<, AR_EEPROM_VER14_2)) { 348 pRaw = &eeprom.ee_rawDataset2413[curmode]; 349 numChannels = pRaw->numChannels; 350 } 351} 352 353int 354nextctl(int start) 355{ 356 int i; 357 358 for (i = start; i < eeprom.ee_numCtls && eeprom.ee_ctl[i]; i++) { 359 switch (eeprom.ee_ctl[i] & 3) { 360 case 0: case 3: 361 if (curmode != headerInfo11A) 362 continue; 363 break; 364 case 1: 365 if (curmode != headerInfo11B) 366 continue; 367 break; 368 case 2: 369 if (curmode != headerInfo11G) 370 continue; 371 break; 372 } 373 return i; 374 } 375 return -1; 376} 377 378static void 379printAntennaControl(FILE *fd, int ant) 380{ 381 fprintf(fd, "0x%02X", eeprom.ee_antennaControl[ant][curmode]); 382} 383 384static void 385printEdge(FILE *fd, int edge) 386{ 387 const RD_EDGES_POWER *pRdEdgePwrInfo = 388 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES]; 389 390 if (pRdEdgePwrInfo[edge].rdEdge == 0) 391 fprintf(fd, " -- "); 392 else 393 fprintf(fd, "%04d", pRdEdgePwrInfo[edge].rdEdge); 394} 395 396static void 397printEdgePower(FILE *fd, int edge) 398{ 399 const RD_EDGES_POWER *pRdEdgePwrInfo = 400 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES]; 401 402 if (pRdEdgePwrInfo[edge].rdEdge == 0) 403 fprintf(fd, " -- "); 404 else 405 fprintf(fd, "%2d.%d", 406 pRdEdgePwrInfo[edge].twice_rdEdgePower / 2, 407 (pRdEdgePwrInfo[edge].twice_rdEdgePower % 2) * 5); 408} 409 410static void 411printEdgeFlag(FILE *fd, int edge) 412{ 413 const RD_EDGES_POWER *pRdEdgePwrInfo = 414 &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES]; 415 416 if (pRdEdgePwrInfo[edge].rdEdge == 0) 417 fprintf(fd, "--"); 418 else 419 fprintf(fd, " %1d", pRdEdgePwrInfo[edge].flag); 420} 421 422static int16_t 423getMaxPowerV5(const RAW_DATA_PER_CHANNEL_2413 *data) 424{ 425 uint32_t i; 426 uint16_t numVpd; 427 428 for (i = 0; i < MAX_NUM_PDGAINS_PER_CHANNEL; i++) { 429 numVpd = data->pDataPerPDGain[i].numVpd; 430 if (numVpd > 0) 431 return data->pDataPerPDGain[i].pwr_t4[numVpd-1]; 432 } 433 return 0; 434} 435 436static void 437printQuarterDbmPower(FILE *fd, int16_t power25dBm) 438{ 439 fprintf(fd, "%2d.%02d", power25dBm / 4, (power25dBm % 4) * 25); 440} 441 442static void 443printHalfDbmPower(FILE *fd, int16_t power5dBm) 444{ 445 fprintf(fd, "%2d.%d", power5dBm / 2, (power5dBm % 2) * 5); 446} 447 448static void 449printVpd(FILE *fd, int vpd) 450{ 451 fprintf(fd, "[%3d]", vpd); 452} 453 454static void 455printPcdacValue(FILE *fd, int v) 456{ 457 fprintf(fd, "%2d.%02d", v / EEP_SCALE, v % EEP_SCALE); 458} 459 460static void 461undef(const char *what) 462{ 463 warnx("%s undefined for version %d.%d format EEPROM", what, 464 eeprom.ee_version >> 12, eeprom.ee_version & 0xfff); 465} 466 467static int 468pdgain(int lpdgain) 469{ 470 uint32_t mask; 471 int i, l = lpdgain; 472 473 if (IS_VERS(<, AR_EEPROM_VER5_0)) 474 mask = pExpnPower->xpdMask; 475 else 476 mask = pRaw->xpd_mask; 477 for (i = 0; mask != 0; mask >>= 1, i++) 478 if ((mask & 1) && l-- == 0) 479 return i; 480 warnx("can't find logical pdgain %d", lpdgain); 481 return -1; 482} 483 484#define COUNTRY_ERD_FLAG 0x8000 485#define WORLDWIDE_ROAMING_FLAG 0x4000 486 487void 488eevar(FILE *fd, const char *var) 489{ 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")) { 493 fprintf(fd, "%s", 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); 522 else 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")) { 541 fprintf(fd, "%1x", 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]); 550 else 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]); 555 else 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]); 564 else 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]); 571 else 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]); 576 else 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]); 581 else 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]); 594 else 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")) { 607 fprintf(fd, "%2d", 608 eeprom.ee_adcDesiredSizeTurbo[curmode != headerInfo11A]); 609 } else if (streq(var, "pgaDesiredSizeTurbo")) { 610 fprintf(fd, "%2d", 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)) { 621 fprintf(fd, "%3d", 622 eepromN.modalHeader[curmode].antennaGainCh[atoi(var+9)]); 623 } else if (strneq(var, "txRxAttenCh", 11)) { 624 fprintf(fd, "%3d", 625 eepromN.modalHeader[curmode].txRxAttenCh[atoi(var+11)]); 626 } else if (strneq(var, "rxTxMarginCh", 12)) { 627 fprintf(fd, "%3d", 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)) { 632 fprintf(fd, "%3d", 633 eepromN.modalHeader[curmode].iqCalICh[atoi(var+8)]); 634 } else if (strneq(var, "iqCalQCh", 8)) { 635 fprintf(fd, "%3d", 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)) { 706 fprintf(fd, "%02X", 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)) { 713 fprintf(fd, "%3d", 714 (eepromN.baseEepHeader.binBuildNumber >> (8*atoi(var+14))) 715 & 0xff); 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); 721 else 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); 726 else 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]); 731 else 732 fprintf(fd, "%4d", pRaw->pChannels[curchan]); 733 } else if (streq(var, "maxpow")) { 734 int16_t maxPower_t4; 735 if (IS_VERS(<, AR_EEPROM_VER5_0)) { 736 maxPower_t4 = pExpnPower->pDataPerChannel[curchan].maxPower_t4; 737 } else { 738 maxPower_t4 = pRaw->pDataPerChannel[curchan].maxPower_t4; 739 if (maxPower_t4 == 0) 740 maxPower_t4 = getMaxPowerV5(&pRaw->pDataPerChannel[curchan]); 741 } 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]); 751 else 752 fprintf(fd, " "); 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]); 761 else 762 fprintf(fd, " "); 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", 770 }; 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" 776 }; 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)) { 805 fprintf(fd, "%02d", 806 pExpnPower->pDataPerChannel[curchan]. 807 pDataPerXPD[singleXpd].pcdac[atoi(var+5)]); 808 } else 809 undef("pcdac"); 810 } else if (strneq(var, "pwrValue", 8)) { 811 printPcdacValue(fd, 812 pDataPerChannel[atoi(var+8)].PwrValues[curpcdac]); 813 } else if (streq(var, "singleXpd")) { 814 fprintf(fd, "%2d", singleXpd); 815 } else 816 warnx("line %u, unknown EEPROM variable \"%s\"", lineno, var); 817#undef strneq 818#undef streq 819} 820 821static void 822ifmode(FILE *ftemplate, const char *mode) 823{ 824 if (strcasecmp(mode, "11a") == 0) { 825 if (IS_VERS(<, AR_EEPROM_VER14_2)) { 826 if (eeprom.ee_Amode) 827 setmode(headerInfo11A); 828 else 829 skipto(ftemplate, "endmode"); 830 return; 831 } 832 if (IS_VERS(>=, AR_EEPROM_VER14_2)) { 833 if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A) 834 setmode(headerInfo11A); 835 else 836 skipto(ftemplate, "endmode"); 837 return; 838 } 839 } else if (strcasecmp(mode, "11g") == 0) { 840 if (IS_VERS(<, AR_EEPROM_VER14_2)) { 841 if (eeprom.ee_Gmode) 842 setmode(headerInfo11G); 843 else 844 skipto(ftemplate, "endmode"); 845 return; 846 } 847 if (IS_VERS(>=, AR_EEPROM_VER14_2)) { 848 if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G) 849 setmode(headerInfo11B); /* NB: 2.4GHz */ 850 else 851 skipto(ftemplate, "endmode"); 852 return; 853 } 854 } else if (strcasecmp(mode, "11b") == 0) { 855 if (IS_VERS(<, AR_EEPROM_VER14_2)) { 856 if (eeprom.ee_Bmode) 857 setmode(headerInfo11B); 858 else 859 skipto(ftemplate, "endmode"); 860 return; 861 } 862 } 863 warnx("line %d, unknown/unexpected mode \"%s\" ignored", 864 lineno, mode); 865 skipto(ftemplate, "endmode"); 866} 867 868static void 869parseTemplate(FILE *ftemplate, FILE *fd) 870{ 871 int c, i; 872 char id[MAXID]; 873 long forchan, forpdgain, forctl, forpcdac; 874 875 lineno = 1; 876 bol = 1; 877 while ((c = getc(ftemplate)) != EOF) { 878 if (c == '#') { /* comment */ 879 skiptoeol: 880 while ((c = getc(ftemplate)) != EOF && c != '\n') 881 ; 882 if (c == EOF) 883 return; 884 lineno++; 885 bol = 1; 886 continue; 887 } 888 if (c == '.' && bol) { /* .directive */ 889 if (token(ftemplate, id, MAXID, ".directive") == EOF) 890 return; 891 /* process directive */ 892 if (strcasecmp(id, "ifmode") == 0) { 893 skipws(ftemplate); 894 if (token(ftemplate, id, MAXID, "id") == EOF) 895 return; 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"); 902 if (curchan == -1) 903 curchan = 0; 904 } else if (strcasecmp(id, "endforchan") == 0) { 905 if (++curchan < numChannels) 906 fseek(ftemplate, forchan, SEEK_SET); 907 else 908 curchan = -1; 909 } else if (strcasecmp(id, "ifpdgain") == 0) { 910 skipws(ftemplate); 911 if (token(ftemplate, id, MAXID, "pdgain") == EOF) 912 return; 913 curlpdgain = strtoul(id, NULL, 0); 914 if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) { 915 skipto(ftemplate, "endpdgain"); 916 curlpdgain = -1; 917 } else 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) { 924 skipws(ftemplate); 925 if (token(ftemplate, id, MAXID, "pdgain") == EOF) 926 return; 927 curlpdgain = strtoul(id, NULL, 0); 928 if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) { 929 skipto(ftemplate, "endforpdgain"); 930 curlpdgain = -1; 931 } else 932 curpdgain = pdgain(curlpdgain); 933 } 934 } else if (strcasecmp(id, "endforpdgain") == 0) { 935 if (++curpdgain < pRaw->pDataPerChannel[curchan].numPdGains) 936 fseek(ftemplate, forpdgain, SEEK_SET); 937 else 938 curpdgain = -1; 939 } else if (strcasecmp(id, "forpcdac") == 0) { 940 forpcdac = ftell(ftemplate) - sizeof("forpcdac"); 941 if (curpcdac == -1) 942 curpcdac = 0; 943 } else if (strcasecmp(id, "endforpcdac") == 0) { 944 if (++curpcdac < pDataPerChannel[0].numPcdacValues) 945 fseek(ftemplate, forpcdac, SEEK_SET); 946 else 947 curpcdac = -1; 948 } else if (strcasecmp(id, "forctl") == 0) { 949 forctl = ftell(ftemplate) - sizeof("forchan"); 950 if (curctl == -1) 951 curctl = nextctl(0); 952 } else if (strcasecmp(id, "endforctl") == 0) { 953 curctl = nextctl(curctl+1); 954 if (curctl != -1) 955 fseek(ftemplate, forctl, SEEK_SET); 956 } else { 957 warnx("line %d, unknown directive %s ignored", 958 lineno, id); 959 } 960 goto skiptoeol; 961 } 962 if (c == '$') { /* $variable reference */ 963 if (token(ftemplate, id, MAXID, "$var") == EOF) 964 return; 965 /* XXX not valid if variable depends on curmode */ 966 eevar(fd, id); 967 continue; 968 } 969 if (c == '\\') { /* escape next character */ 970 c = getc(ftemplate); 971 if (c == EOF) 972 return; 973 } 974 fputc(c, fd); 975 bol = (c == '\n'); 976 if (bol) 977 lineno++; 978 } 979} 980