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: 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 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 * 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 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 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 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 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 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 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 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 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 378 printAntennaControl(FILE *fd, int ant) 379 { 380 fprintf(fd, "0x%02X", eeprom.ee_antennaControl[ant][curmode]); 381 } 382 383 static void 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 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 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 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 436 printQuarterDbmPower(FILE *fd, int16_t power25dBm) 437 { 438 fprintf(fd, "%2d.%02d", power25dBm / 4, (power25dBm % 4) * 25); 439 } 440 441 static void 442 printHalfDbmPower(FILE *fd, int16_t power5dBm) 443 { 444 fprintf(fd, "%2d.%d", power5dBm / 2, (power5dBm % 2) * 5); 445 } 446 447 static void 448 printVpd(FILE *fd, int vpd) 449 { 450 fprintf(fd, "[%3d]", vpd); 451 } 452 453 static void 454 printPcdacValue(FILE *fd, int v) 455 { 456 fprintf(fd, "%2d.%02d", v / EEP_SCALE, v % EEP_SCALE); 457 } 458 459 static void 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 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 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 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 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