1185743Ssam/*-
2185743Ssam * Copyright (c) 2008 Sam Leffler, Errno Consulting
3185743Ssam * All rights reserved.
4185743Ssam *
5185743Ssam * Redistribution and use in source and binary forms, with or without
6185743Ssam * modification, are permitted provided that the following conditions
7185743Ssam * are met:
8185743Ssam * 1. Redistributions of source code must retain the above copyright
9185743Ssam *    notice, this list of conditions and the following disclaimer,
10185743Ssam *    without modification.
11185743Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12185743Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13185743Ssam *    redistribution must be conditioned upon including a substantially
14185743Ssam *    similar Disclaimer requirement for further binary redistribution.
15185743Ssam *
16185743Ssam * NO WARRANTY
17185743Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18185743Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19185743Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20185743Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21185743Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22185743Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23185743Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24185743Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25185743Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26185743Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27185743Ssam * THE POSSIBILITY OF SUCH DAMAGES.
28185743Ssam *
29185743Ssam * $FreeBSD$
30185743Ssam */
31185743Ssam#include "diag.h"
32185743Ssam
33185743Ssam#include "ah.h"
34185743Ssam#include "ah_internal.h"
35185743Ssam#include "ah_eeprom_v1.h"
36185743Ssam#include "ah_eeprom_v3.h"
37185743Ssam#include "ah_eeprom_v14.h"
38185743Ssam
39185743Ssam#define	IS_VERS(op, v)		(eeprom.ee_version op (v))
40185743Ssam
41185743Ssam#include <getopt.h>
42185743Ssam#include <errno.h>
43185743Ssam#include <err.h>
44185743Ssam#include <stdlib.h>
45185743Ssam#include <string.h>
46217680Sadrian#include <ctype.h>
47185743Ssam
48185743Ssam#ifndef DIR_TEMPLATE
49185743Ssam#define	DIR_TEMPLATE	"/usr/local/libdata/athprom"
50185743Ssam#endif
51185743Ssam
52185743Ssamstruct	ath_diag atd;
53185743Ssamint	s;
54185743Ssamconst char *progname;
55185743Ssamunion {
56185743Ssam	HAL_EEPROM legacy;		/* format v3.x ... v5.x */
57185743Ssam	struct ar5416eeprom v14;	/* 11n format v14.x ... */
58185743Ssam} eep;
59185743Ssam#define	eeprom	eep.legacy
60185743Ssam#define	eepromN	eep.v14
61185743Ssam
62185743Ssamstatic void parseTemplate(FILE *ftemplate, FILE *fd);
63185743Ssamstatic uint16_t eeread(uint16_t);
64185743Ssamstatic void eewrite(uint16_t, uint16_t);
65185743Ssam
66185743Ssamstatic void
67185743Ssamusage()
68185743Ssam{
69185743Ssam	fprintf(stderr, "usage: %s [-i ifname] [-t pathname] [offset | offset=value]\n", progname);
70185743Ssam	exit(-1);
71185743Ssam}
72185743Ssam
73185743Ssamstatic FILE *
74185743Ssamopentemplate(const char *dir)
75185743Ssam{
76185743Ssam	char filename[PATH_MAX];
77185743Ssam	FILE *fd;
78185743Ssam
79185743Ssam	/* find the template using the eeprom version */
80185743Ssam	snprintf(filename, sizeof(filename), "%s/eeprom-%d.%d",
81185743Ssam	    dir, eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
82185743Ssam	fd = fopen(filename, "r");
83185743Ssam	if (fd == NULL && errno == ENOENT) {
84185743Ssam		/* retry with just the major version */
85185743Ssam		snprintf(filename, sizeof(filename), "%s/eeprom-%d",
86185743Ssam		    dir, eeprom.ee_version >> 12);
87185743Ssam		fd = fopen(filename, "r");
88185743Ssam		if (fd != NULL)		/* XXX verbose */
89185743Ssam			warnx("Using template file %s", filename);
90185743Ssam	}
91185743Ssam	return fd;
92185743Ssam}
93185743Ssam
94185743Ssamint
95185743Ssammain(int argc, char *argv[])
96185743Ssam{
97185743Ssam	FILE *fd = NULL;
98185743Ssam	const char *ifname;
99185743Ssam	int c;
100185743Ssam
101185743Ssam	s = socket(AF_INET, SOCK_DGRAM, 0);
102185743Ssam	if (s < 0)
103185743Ssam		err(1, "socket");
104185743Ssam	ifname = getenv("ATH");
105185743Ssam	if (!ifname)
106185743Ssam		ifname = ATH_DEFAULT;
107185743Ssam
108185743Ssam	progname = argv[0];
109185743Ssam	while ((c = getopt(argc, argv, "i:t:")) != -1)
110185743Ssam		switch (c) {
111185743Ssam		case 'i':
112185743Ssam			ifname = optarg;
113185743Ssam			break;
114185743Ssam		case 't':
115185743Ssam			fd = fopen(optarg, "r");
116185743Ssam			if (fd == NULL)
117185743Ssam				err(-1, "Cannot open %s", optarg);
118185743Ssam			break;
119185743Ssam		default:
120185743Ssam			usage();
121185743Ssam			/*NOTREACHED*/
122185743Ssam		}
123185743Ssam	argc -= optind;
124185743Ssam	argv += optind;
125185743Ssam
126185743Ssam	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
127185743Ssam
128185743Ssam	if (argc != 0) {
129185743Ssam		for (; argc > 0; argc--, argv++) {
130185743Ssam			uint16_t off, val, oval;
131185743Ssam			char line[256];
132185743Ssam			char *cp;
133185743Ssam
134185743Ssam			cp = strchr(argv[0], '=');
135185743Ssam			if (cp != NULL)
136185743Ssam				*cp = '\0';
137185743Ssam			off = (uint16_t) strtoul(argv[0], NULL, 0);
138185743Ssam			if (off == 0 && errno == EINVAL)
139185743Ssam				errx(1, "%s: invalid eeprom offset %s",
140185743Ssam					progname, argv[0]);
141185743Ssam			if (cp == NULL) {
142185743Ssam				printf("%04x: %04x\n", off, eeread(off));
143185743Ssam			} else {
144185743Ssam				val = (uint16_t) strtoul(cp+1, NULL, 0);
145185743Ssam				if (val == 0 && errno == EINVAL)
146185743Ssam				errx(1, "%s: invalid eeprom value %s",
147185743Ssam					progname, cp+1);
148185743Ssam				oval = eeread(off);
149185743Ssam				printf("Write %04x: %04x = %04x? ",
150185743Ssam					off, oval, val);
151185743Ssam				fflush(stdout);
152185743Ssam				if (fgets(line, sizeof(line), stdin) != NULL &&
153185743Ssam				    line[0] == 'y')
154185743Ssam					eewrite(off, val);
155185743Ssam			}
156185743Ssam		}
157185743Ssam	} else {
158185743Ssam		atd.ad_id = HAL_DIAG_EEPROM;
159185743Ssam		atd.ad_out_data = (caddr_t) &eep;
160185743Ssam		atd.ad_out_size = sizeof(eep);
161185743Ssam		if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
162244964Sadrian			err(1, "ioctl: %s", atd.ad_name);
163185743Ssam		if (fd == NULL) {
164185743Ssam			fd = opentemplate(DIR_TEMPLATE);
165185743Ssam			if (fd == NULL)
166185743Ssam				fd = opentemplate(".");
167185743Ssam			if (fd == NULL)
168185743Ssam				errx(-1, "Cannot locate template file for "
169185743Ssam				    "v%d.%d EEPROM", eeprom.ee_version >> 12,
170185743Ssam				    eeprom.ee_version & 0xfff);
171185743Ssam		}
172185743Ssam		parseTemplate(fd, stdout);
173185743Ssam		fclose(fd);
174185743Ssam	}
175185743Ssam	return 0;
176185743Ssam}
177185743Ssam
178185743Ssamstatic u_int16_t
179185743Ssameeread(u_int16_t off)
180185743Ssam{
181185743Ssam	u_int16_t eedata;
182185743Ssam
183185743Ssam	atd.ad_id = HAL_DIAG_EEREAD | ATH_DIAG_IN | ATH_DIAG_DYN;
184185743Ssam	atd.ad_in_size = sizeof(off);
185185743Ssam	atd.ad_in_data = (caddr_t) &off;
186185743Ssam	atd.ad_out_size = sizeof(eedata);
187185743Ssam	atd.ad_out_data = (caddr_t) &eedata;
188185743Ssam	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
189244964Sadrian		err(1, "ioctl: %s", atd.ad_name);
190185743Ssam	return eedata;
191185743Ssam}
192185743Ssam
193185743Ssamstatic void
194185743Ssameewrite(uint16_t off, uint16_t value)
195185743Ssam{
196185743Ssam	HAL_DIAG_EEVAL eeval;
197185743Ssam
198185743Ssam	eeval.ee_off = off;
199185743Ssam	eeval.ee_data = value;
200185743Ssam
201185743Ssam	atd.ad_id = HAL_DIAG_EEWRITE | ATH_DIAG_IN;
202185743Ssam	atd.ad_in_size = sizeof(eeval);
203185743Ssam	atd.ad_in_data = (caddr_t) &eeval;
204185743Ssam	atd.ad_out_size = 0;
205185743Ssam	atd.ad_out_data = NULL;
206185743Ssam	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
207244964Sadrian		err(1, "ioctl: %s", atd.ad_name);
208185743Ssam}
209185743Ssam
210185743Ssam#define	MAXID	128
211185743Ssamint	lineno;
212185743Ssamint	bol;
213185743Ssamint	curmode = -1;
214185743Ssamint	curchan;
215185743Ssamint	curpdgain;	/* raw pdgain index */
216185743Ssamint	curlpdgain;	/* logical pdgain index */
217185743Ssamint	curpcdac;
218185743Ssamint	curctl;
219185743Ssamint	numChannels;
220185743Ssamconst RAW_DATA_STRUCT_2413 *pRaw;
221185743Ssamconst TRGT_POWER_INFO *pPowerInfo;
222185743Ssamconst DATA_PER_CHANNEL *pDataPerChannel;
223185743Ssamconst EEPROM_POWER_EXPN_5112 *pExpnPower;
224185743Ssamint	singleXpd;
225185743Ssam
226185743Ssamstatic int
227185743Ssamtoken(FILE *fd, char id[], int maxid, const char *what)
228185743Ssam{
229185743Ssam	int c, i;
230185743Ssam
231185743Ssam	i = 0;
232185743Ssam	for (;;) {
233185743Ssam		c = getc(fd);
234185743Ssam		if (c == EOF)
235185743Ssam			return EOF;
236185743Ssam		if (!isalnum(c) && c != '_') {
237185743Ssam			ungetc(c, fd);
238185743Ssam			break;
239185743Ssam		}
240185743Ssam		if (i == maxid-1) {
241185743Ssam			warnx("line %d, %s too long", lineno, what);
242185743Ssam			break;
243185743Ssam		}
244185743Ssam		id[i++] = c;
245185743Ssam	}
246185743Ssam	id[i] = '\0';
247185743Ssam	if (i != 0)
248185743Ssam		bol = 0;
249185743Ssam	return i;
250185743Ssam}
251185743Ssam
252185743Ssamstatic int
253185743Ssamskipto(FILE *fd, const char *what)
254185743Ssam{
255185743Ssam	char id[MAXID];
256185743Ssam	int c;
257185743Ssam
258185743Ssam	for (;;) {
259185743Ssam		c = getc(fd);
260185743Ssam		if (c == EOF)
261185743Ssam			goto bad;
262185743Ssam		if (c == '.' && bol) {		/* .directive */
263185743Ssam			if (token(fd, id, MAXID, ".directive") == EOF)
264185743Ssam				goto bad;
265185743Ssam			if (strcasecmp(id, what) == 0)
266185743Ssam				break;
267185743Ssam			continue;
268185743Ssam		}
269185743Ssam		if (c == '\\') {		/* escape next character */
270185743Ssam			c = getc(fd);
271185743Ssam			if (c == EOF)
272185743Ssam				goto bad;
273185743Ssam		}
274185743Ssam		bol = (c == '\n');
275185743Ssam		if (bol)
276185743Ssam			lineno++;
277185743Ssam	}
278185743Ssam	return 0;
279185743Ssambad:
280185743Ssam	warnx("EOF with no matching .%s", what);
281185743Ssam	return EOF;
282185743Ssam}
283185743Ssam
284185743Ssamstatic int
285185743Ssamskipws(FILE *fd)
286185743Ssam{
287185743Ssam	int c, i;
288185743Ssam
289185743Ssam	i = 0;
290185743Ssam	while ((c = getc(fd)) != EOF && isblank(c))
291185743Ssam		i++;
292185743Ssam	if (c != EOF)
293185743Ssam		ungetc(c, fd);
294185743Ssam	if (i != 0)
295185743Ssam		bol = 0;
296185743Ssam	return 0;
297185743Ssam}
298185743Ssam
299185743Ssamstatic void
300185743Ssamsetmode(int mode)
301185743Ssam{
302185743Ssam	EEPROM_POWER_EXPN_5112 *exp;
303185743Ssam
304185743Ssam	curmode = mode;
305185743Ssam	curchan = -1;
306185743Ssam	curctl = -1;
307185743Ssam	curpdgain = -1;
308185743Ssam	curlpdgain = -1;
309185743Ssam	curpcdac = -1;
310185743Ssam	switch (curmode) {
311185743Ssam	case headerInfo11A:
312185743Ssam		pPowerInfo = eeprom.ee_trgtPwr_11a;
313185743Ssam		pDataPerChannel = eeprom.ee_dataPerChannel11a;
314185743Ssam		break;
315185743Ssam	case headerInfo11B:
316185743Ssam		pPowerInfo = eeprom.ee_trgtPwr_11b;
317185743Ssam		pDataPerChannel = eeprom.ee_dataPerChannel11b;
318185743Ssam		break;
319185743Ssam	case headerInfo11G:
320185743Ssam		pPowerInfo = eeprom.ee_trgtPwr_11g;
321185743Ssam		pDataPerChannel = eeprom.ee_dataPerChannel11g;
322185743Ssam		break;
323185743Ssam	}
324185743Ssam	if (IS_VERS(<, AR_EEPROM_VER4_0))		/* nothing to do */
325185743Ssam		return;
326185743Ssam	if (IS_VERS(<, AR_EEPROM_VER5_0)) {
327185743Ssam		exp = &eeprom.ee_modePowerArray5112[curmode];
328185743Ssam		/* fetch indirect data*/
329185743Ssam		atd.ad_id = HAL_DIAG_EEPROM_EXP_11A+curmode;
330185743Ssam		atd.ad_out_size = roundup(
331185743Ssam			sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t))
332185743Ssam		    + sizeof(EXPN_DATA_PER_CHANNEL_5112) * exp->numChannels;
333185743Ssam		atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size);
334185743Ssam		if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
335244964Sadrian			err(1, "ioctl: %s", atd.ad_name);
336185743Ssam		exp->pChannels = (void *) atd.ad_out_data;
337185743Ssam		exp->pDataPerChannel = (void *)((char *)atd.ad_out_data +
338185743Ssam		   roundup(sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t)));
339185743Ssam		pExpnPower = exp;
340185743Ssam		numChannels = pExpnPower->numChannels;
341185743Ssam		if (exp->xpdMask != 0x9) {
342185743Ssam			for (singleXpd = 0; singleXpd < NUM_XPD_PER_CHANNEL; singleXpd++)
343185743Ssam				if (exp->xpdMask == (1<<singleXpd))
344185743Ssam					break;
345185743Ssam		} else
346185743Ssam			singleXpd = 0;
347185743Ssam	} else if (IS_VERS(<, AR_EEPROM_VER14_2)) {
348185743Ssam		pRaw = &eeprom.ee_rawDataset2413[curmode];
349185743Ssam		numChannels = pRaw->numChannels;
350185743Ssam	}
351185743Ssam}
352185743Ssam
353185743Ssamint
354185743Ssamnextctl(int start)
355185743Ssam{
356185743Ssam	int i;
357185743Ssam
358185743Ssam	for (i = start; i < eeprom.ee_numCtls && eeprom.ee_ctl[i]; i++) {
359185743Ssam		switch (eeprom.ee_ctl[i] & 3) {
360185743Ssam		case 0: case 3:
361185743Ssam			if (curmode != headerInfo11A)
362185743Ssam				continue;
363185743Ssam			break;
364185743Ssam		case 1:
365185743Ssam			if (curmode != headerInfo11B)
366185743Ssam				continue;
367185743Ssam			break;
368185743Ssam		case 2:
369185743Ssam			if (curmode != headerInfo11G)
370185743Ssam				continue;
371185743Ssam			break;
372185743Ssam		}
373185743Ssam		return i;
374185743Ssam	}
375185743Ssam	return -1;
376185743Ssam}
377185743Ssam
378185743Ssamstatic void
379185743SsamprintAntennaControl(FILE *fd, int ant)
380185743Ssam{
381185743Ssam	fprintf(fd, "0x%02X", eeprom.ee_antennaControl[ant][curmode]);
382185743Ssam}
383185743Ssam
384185743Ssamstatic void
385185743SsamprintEdge(FILE *fd, int edge)
386185743Ssam{
387185743Ssam	const RD_EDGES_POWER *pRdEdgePwrInfo =
388185743Ssam	    &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
389185743Ssam
390185743Ssam	if (pRdEdgePwrInfo[edge].rdEdge == 0)
391185743Ssam		fprintf(fd, " -- ");
392185743Ssam	else
393185743Ssam		fprintf(fd, "%04d", pRdEdgePwrInfo[edge].rdEdge);
394185743Ssam}
395185743Ssam
396185743Ssamstatic void
397185743SsamprintEdgePower(FILE *fd, int edge)
398185743Ssam{
399185743Ssam	const RD_EDGES_POWER *pRdEdgePwrInfo =
400185743Ssam	    &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
401185743Ssam
402185743Ssam	if (pRdEdgePwrInfo[edge].rdEdge == 0)
403185743Ssam		fprintf(fd, " -- ");
404185743Ssam	else
405185743Ssam                fprintf(fd, "%2d.%d",
406185743Ssam		    pRdEdgePwrInfo[edge].twice_rdEdgePower / 2,
407185743Ssam                    (pRdEdgePwrInfo[edge].twice_rdEdgePower % 2) * 5);
408185743Ssam}
409185743Ssam
410185743Ssamstatic void
411185743SsamprintEdgeFlag(FILE *fd, int edge)
412185743Ssam{
413185743Ssam	const RD_EDGES_POWER *pRdEdgePwrInfo =
414185743Ssam	    &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
415185743Ssam
416185743Ssam	if (pRdEdgePwrInfo[edge].rdEdge == 0)
417185743Ssam		fprintf(fd, "--");
418185743Ssam	else
419185743Ssam                fprintf(fd, " %1d", pRdEdgePwrInfo[edge].flag);
420185743Ssam}
421185743Ssam
422185743Ssamstatic int16_t
423185743SsamgetMaxPowerV5(const RAW_DATA_PER_CHANNEL_2413 *data)
424185743Ssam{
425185743Ssam	uint32_t i;
426185743Ssam	uint16_t numVpd;
427185743Ssam
428185743Ssam	for (i = 0; i < MAX_NUM_PDGAINS_PER_CHANNEL; i++) {
429185743Ssam		numVpd = data->pDataPerPDGain[i].numVpd;
430185743Ssam		if (numVpd > 0)
431185743Ssam			return data->pDataPerPDGain[i].pwr_t4[numVpd-1];
432185743Ssam	}
433185743Ssam	return 0;
434185743Ssam}
435185743Ssam
436185743Ssamstatic void
437185743SsamprintQuarterDbmPower(FILE *fd, int16_t power25dBm)
438185743Ssam{
439185743Ssam	fprintf(fd, "%2d.%02d", power25dBm / 4, (power25dBm % 4) * 25);
440185743Ssam}
441185743Ssam
442185743Ssamstatic void
443185743SsamprintHalfDbmPower(FILE *fd, int16_t power5dBm)
444185743Ssam{
445185743Ssam	fprintf(fd, "%2d.%d", power5dBm / 2, (power5dBm % 2) * 5);
446185743Ssam}
447185743Ssam
448185743Ssamstatic void
449185743SsamprintVpd(FILE *fd, int vpd)
450185743Ssam{
451185743Ssam	fprintf(fd, "[%3d]", vpd);
452185743Ssam}
453185743Ssam
454185743Ssamstatic void
455185743SsamprintPcdacValue(FILE *fd, int v)
456185743Ssam{
457185743Ssam	fprintf(fd, "%2d.%02d", v / EEP_SCALE, v % EEP_SCALE);
458185743Ssam}
459185743Ssam
460185743Ssamstatic void
461185743Ssamundef(const char *what)
462185743Ssam{
463185743Ssam	warnx("%s undefined for version %d.%d format EEPROM", what,
464185743Ssam	    eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
465185743Ssam}
466185743Ssam
467185743Ssamstatic int
468185743Ssampdgain(int lpdgain)
469185743Ssam{
470185743Ssam	uint32_t mask;
471185743Ssam	int i, l = lpdgain;
472185743Ssam
473185743Ssam	if (IS_VERS(<, AR_EEPROM_VER5_0))
474185743Ssam		mask = pExpnPower->xpdMask;
475185743Ssam	else
476185743Ssam		mask = pRaw->xpd_mask;
477185743Ssam	for (i = 0; mask != 0; mask >>= 1, i++)
478185743Ssam		if ((mask & 1) && l-- == 0)
479185743Ssam			return i;
480185743Ssam	warnx("can't find logical pdgain %d", lpdgain);
481185743Ssam	return -1;
482185743Ssam}
483185743Ssam
484185743Ssam#define	COUNTRY_ERD_FLAG        0x8000
485185743Ssam#define WORLDWIDE_ROAMING_FLAG  0x4000
486185743Ssam
487185743Ssamvoid
488185743Ssameevar(FILE *fd, const char *var)
489185743Ssam{
490185743Ssam#define	streq(a,b)	(strcasecmp(a,b) == 0)
491185743Ssam#define	strneq(a,b,n)	(strncasecmp(a,b,n) == 0)
492185743Ssam	if (streq(var, "mode")) {
493185743Ssam		fprintf(fd, "%s",
494185743Ssam		    curmode == headerInfo11A ? "11a" :
495185743Ssam		    curmode == headerInfo11B ? "11b" :
496185743Ssam		    curmode == headerInfo11G ? "11g" : "???");
497185743Ssam	} else if (streq(var, "version")) {
498185743Ssam		fprintf(fd, "%04x", eeprom.ee_version);
499185743Ssam	} else if (streq(var, "V_major")) {
500185743Ssam		fprintf(fd, "%2d", eeprom.ee_version >> 12);
501185743Ssam	} else if (streq(var, "V_minor")) {
502185743Ssam		fprintf(fd, "%2d", eeprom.ee_version & 0xfff);
503185743Ssam	} else if (streq(var, "earStart")) {
504185743Ssam		fprintf(fd, "%03x", eeprom.ee_earStart);
505185743Ssam	} else if (streq(var, "tpStart")) {
506185743Ssam		fprintf(fd, "%03x", eeprom.ee_targetPowersStart);
507185743Ssam	} else if (streq(var, "eepMap")) {
508185743Ssam		fprintf(fd, "%3d", eeprom.ee_eepMap);
509185743Ssam	} else if (streq(var, "exist32KHzCrystal")) {
510185743Ssam		fprintf(fd, "%3d", eeprom.ee_exist32kHzCrystal);
511185743Ssam	} else if (streq(var, "eepMap2PowerCalStart")) {
512185743Ssam		fprintf(fd , "%3d", eeprom.ee_eepMap2PowerCalStart);
513185743Ssam	} else if (streq(var, "Amode")) {
514185743Ssam		fprintf(fd , "%1d", eeprom.ee_Amode);
515185743Ssam	} else if (streq(var, "Bmode")) {
516185743Ssam		fprintf(fd , "%1d", eeprom.ee_Bmode);
517185743Ssam	} else if (streq(var, "Gmode")) {
518185743Ssam		fprintf(fd , "%1d", eeprom.ee_Gmode);
519185743Ssam	} else if (streq(var, "regdomain")) {
520185743Ssam		if ((eeprom.ee_regdomain & COUNTRY_ERD_FLAG) == 0)
521185743Ssam			fprintf(fd, "%03X ", eeprom.ee_regdomain >> 15);
522185743Ssam		else
523185743Ssam			fprintf(fd, "%-3dC", eeprom.ee_regdomain & 0xfff);
524185743Ssam	} else if (streq(var, "turbo2Disable")) {
525185743Ssam		fprintf(fd, "%1d", eeprom.ee_turbo2Disable);
526185743Ssam	} else if (streq(var, "turbo5Disable")) {
527185743Ssam		fprintf(fd, "%1d", eeprom.ee_turbo5Disable);
528185743Ssam	} else if (streq(var, "rfKill")) {
529185743Ssam		fprintf(fd, "%1d", eeprom.ee_rfKill);
530185743Ssam	} else if (streq(var, "disableXr5")) {
531185743Ssam		fprintf(fd, "%1d", eeprom.ee_disableXr5);
532185743Ssam	} else if (streq(var, "disableXr2")) {
533185743Ssam		fprintf(fd, "%1d", eeprom.ee_disableXr2);
534185743Ssam	} else if (streq(var, "turbo2WMaxPower5")) {
535185743Ssam		fprintf(fd, "%2d", eeprom.ee_turbo2WMaxPower5);
536185743Ssam	} else if (streq(var, "cckOfdmDelta")) {
537185743Ssam		fprintf(fd, "%2d", eeprom.ee_cckOfdmPwrDelta);
538185743Ssam	} else if (streq(var, "gainI")) {
539185743Ssam		fprintf(fd, "%2d", eeprom.ee_gainI[curmode]);
540185743Ssam	} else if (streq(var, "WWR")) {
541185743Ssam		fprintf(fd, "%1x",
542185743Ssam		    (eeprom.ee_regdomain & WORLDWIDE_ROAMING_FLAG) != 0);
543185743Ssam	} else if (streq(var, "falseDetectBackoff")) {
544185743Ssam		fprintf(fd, "0x%02x", eeprom.ee_falseDetectBackoff[curmode]);
545185743Ssam	} else if (streq(var, "deviceType")) {
546185743Ssam		fprintf(fd, "%1x", eeprom.ee_deviceType);
547185743Ssam	} else if (streq(var, "switchSettling")) {
548185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2))
549185743Ssam			fprintf(fd, "0x%02x", eeprom.ee_switchSettling[curmode]);
550185743Ssam		else
551185743Ssam			fprintf(fd, "%3d", eepromN.modalHeader[curmode].switchSettling);
552185743Ssam	} else if (streq(var, "adcDesiredSize")) {
553185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2))
554185743Ssam			fprintf(fd, "%2d", eeprom.ee_adcDesiredSize[curmode]);
555185743Ssam		else
556185743Ssam			fprintf(fd, "%3d", eepromN.modalHeader[curmode].adcDesiredSize);
557185743Ssam	} else if (streq(var, "xlnaGain")) {
558185743Ssam		fprintf(fd, "0x%02x", eeprom.ee_xlnaGain[curmode]);
559185743Ssam	} else if (streq(var, "txEndToXLNAOn")) {
560185743Ssam		fprintf(fd, "0x%02x", eeprom.ee_txEndToXLNAOn[curmode]);
561185743Ssam	} else if (streq(var, "thresh62")) {
562185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2))
563185743Ssam			fprintf(fd, "0x%02x", eeprom.ee_thresh62[curmode]);
564185743Ssam		else
565185743Ssam			fprintf(fd, "%3d", eepromN.modalHeader[curmode].thresh62);
566185743Ssam	} else if (streq(var, "txEndToRxOn")) {
567185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn);
568185743Ssam	} else if (streq(var, "txEndToXPAOff")) {
569185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2))
570185743Ssam			fprintf(fd, "0x%02x", eeprom.ee_txEndToXPAOff[curmode]);
571185743Ssam		else
572185743Ssam			fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToXpaOff);
573185743Ssam	} else if (streq(var, "txFrameToXPAOn")) {
574185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2))
575185743Ssam			fprintf(fd, "0x%02x", eeprom.ee_txFrameToXPAOn[curmode]);
576185743Ssam		else
577185743Ssam			fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn);
578185743Ssam	} else if (streq(var, "pgaDesiredSize")) {
579185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2))
580185743Ssam			fprintf(fd, "%2d", eeprom.ee_pgaDesiredSize[curmode]);
581185743Ssam		else
582185743Ssam			fprintf(fd, "%3d", eepromN.modalHeader[curmode].pgaDesiredSize);
583185743Ssam	} else if (streq(var, "noiseFloorThresh")) {
584185743Ssam		fprintf(fd, "%3d", eeprom.ee_noiseFloorThresh[curmode]);
585185743Ssam	} else if (strneq(var, "noiseFloorThreshCh", 18)) {
586185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].noiseFloorThreshCh[atoi(var+18)]);
587185743Ssam	} else if (strneq(var, "xlnaGainCh", 10)) {
588185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].xlnaGainCh[atoi(var+10)]);
589185743Ssam	} else if (streq(var, "xgain")) {
590185743Ssam		fprintf(fd, "0x%02x", eeprom.ee_xgain[curmode]);
591185743Ssam	} else if (streq(var, "xpd")) {
592185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2))
593185743Ssam			fprintf(fd, "%1d", eeprom.ee_xpd[curmode]);
594185743Ssam		else
595185743Ssam			fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpd);
596185743Ssam	} else if (streq(var, "txrxAtten")) {
597185743Ssam		fprintf(fd, "0x%02x", eeprom.ee_txrxAtten[curmode]);
598185743Ssam	} else if (streq(var, "capField")) {
599185743Ssam		fprintf(fd, "0x%04X", eeprom.ee_capField);
600185743Ssam	} else if (streq(var, "txrxAttenTurbo")) {
601185743Ssam		fprintf(fd, "0x%02x",
602185743Ssam		    eeprom.ee_txrxAtten[curmode != headerInfo11A]);
603185743Ssam	} else if (streq(var, "switchSettlingTurbo")) {
604185743Ssam		fprintf(fd, "0x%02X",
605185743Ssam		    eeprom.ee_switchSettlingTurbo[curmode != headerInfo11A]);
606185743Ssam	} else if (streq(var, "adcDesiredSizeTurbo")) {
607185743Ssam		fprintf(fd, "%2d",
608185743Ssam		    eeprom.ee_adcDesiredSizeTurbo[curmode != headerInfo11A]);
609185743Ssam	} else if (streq(var, "pgaDesiredSizeTurbo")) {
610185743Ssam		fprintf(fd, "%2d",
611185743Ssam		    eeprom.ee_pgaDesiredSizeTurbo[curmode != headerInfo11A]);
612185743Ssam	} else if (streq(var, "rxtxMarginTurbo")) {
613185743Ssam		fprintf(fd, "0x%02x",
614185743Ssam		    eeprom.ee_rxtxMarginTurbo[curmode != headerInfo11A]);
615185743Ssam	} else if (strneq(var, "antennaControl", 14)) {
616185743Ssam		printAntennaControl(fd, atoi(var+14));
617185743Ssam	} else if (strneq(var, "antCtrlChain", 12)) {
618185743Ssam		fprintf(fd, "0x%08X",
619185743Ssam		    eepromN.modalHeader[curmode].antCtrlChain[atoi(var+12)]);
620185743Ssam	} else if (strneq(var, "antGainCh", 9)) {
621185743Ssam		fprintf(fd, "%3d",
622185743Ssam		    eepromN.modalHeader[curmode].antennaGainCh[atoi(var+9)]);
623185743Ssam	} else if (strneq(var, "txRxAttenCh", 11)) {
624185743Ssam		fprintf(fd, "%3d",
625185743Ssam		    eepromN.modalHeader[curmode].txRxAttenCh[atoi(var+11)]);
626185743Ssam	} else if (strneq(var, "rxTxMarginCh", 12)) {
627185743Ssam		fprintf(fd, "%3d",
628185743Ssam		    eepromN.modalHeader[curmode].rxTxMarginCh[atoi(var+12)]);
629185743Ssam	} else if (streq(var, "xpdGain")) {
630185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpdGain);
631185743Ssam	} else if (strneq(var, "iqCalICh", 8)) {
632185743Ssam		fprintf(fd, "%3d",
633185743Ssam		    eepromN.modalHeader[curmode].iqCalICh[atoi(var+8)]);
634185743Ssam	} else if (strneq(var, "iqCalQCh", 8)) {
635185743Ssam		fprintf(fd, "%3d",
636185743Ssam		    eepromN.modalHeader[curmode].iqCalQCh[atoi(var+8)]);
637185743Ssam	} else if (streq(var, "pdGainOverlap")) {
638185743Ssam		printHalfDbmPower(fd, eepromN.modalHeader[curmode].pdGainOverlap);
639185743Ssam	} else if (streq(var, "ob1")) {
640185743Ssam		fprintf(fd, "%1d", eeprom.ee_ob1);
641185743Ssam	} else if (streq(var, "ob2")) {
642185743Ssam		fprintf(fd, "%1d", eeprom.ee_ob2);
643185743Ssam	} else if (streq(var, "ob3")) {
644185743Ssam		fprintf(fd, "%1d", eeprom.ee_ob3);
645185743Ssam	} else if (streq(var, "ob4")) {
646185743Ssam		fprintf(fd, "%1d", eeprom.ee_ob4);
647185743Ssam	} else if (streq(var, "db1")) {
648185743Ssam		fprintf(fd, "%1d", eeprom.ee_db1);
649185743Ssam	} else if (streq(var, "db2")) {
650185743Ssam		fprintf(fd, "%1d", eeprom.ee_db2);
651185743Ssam	} else if (streq(var, "db3")) {
652185743Ssam		fprintf(fd, "%1d", eeprom.ee_db3);
653185743Ssam	} else if (streq(var, "db4")) {
654185743Ssam		fprintf(fd, "%1d", eeprom.ee_db4);
655185743Ssam	} else if (streq(var, "obFor24")) {
656185743Ssam                fprintf(fd, "%1d", eeprom.ee_obFor24);
657185743Ssam	} else if (streq(var, "ob2GHz0")) {
658185743Ssam                fprintf(fd, "%1d", eeprom.ee_ob2GHz[0]);
659185743Ssam	} else if (streq(var, "dbFor24")) {
660185743Ssam                fprintf(fd, "%1d", eeprom.ee_dbFor24);
661185743Ssam	} else if (streq(var, "db2GHz0")) {
662185743Ssam                fprintf(fd, "%1d", eeprom.ee_db2GHz[0]);
663185743Ssam	} else if (streq(var, "obFor24g")) {
664185743Ssam                fprintf(fd, "%1d", eeprom.ee_obFor24g);
665185743Ssam	} else if (streq(var, "ob2GHz1")) {
666185743Ssam                fprintf(fd, "%1d", eeprom.ee_ob2GHz[1]);
667185743Ssam	} else if (streq(var, "dbFor24g")) {
668185743Ssam                fprintf(fd, "%1d", eeprom.ee_dbFor24g);
669185743Ssam	} else if (streq(var, "db2GHz1")) {
670185743Ssam                fprintf(fd, "%1d", eeprom.ee_db2GHz[1]);
671185743Ssam	} else if (streq(var, "ob")) {
672185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].ob);
673185743Ssam	} else if (streq(var, "db")) {
674185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].db);
675185743Ssam	} else if (streq(var, "xpaBiasLvl")) {
676185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpaBiasLvl);
677185743Ssam	} else if (streq(var, "pwrDecreaseFor2Chain")) {
678185743Ssam		printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor2Chain);
679185743Ssam	} else if (streq(var, "pwrDecreaseFor3Chain")) {
680185743Ssam		printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor3Chain);
681185743Ssam	} else if (streq(var, "txFrameToDataStart")) {
682185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToDataStart);
683185743Ssam	} else if (streq(var, "txFrameToPaOn")) {
684185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToPaOn);
685185743Ssam	} else if (streq(var, "ht40PowerIncForPdadc")) {
686185743Ssam		fprintf(fd, "%3d", eepromN.modalHeader[curmode].ht40PowerIncForPdadc);
687185743Ssam	} else if (streq(var, "checksum")) {
688185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.checksum);
689185743Ssam	} else if (streq(var, "length")) {
690185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.length);
691185743Ssam	} else if (streq(var, "regDmn0")) {
692185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[0]);
693185743Ssam	} else if (streq(var, "regDmn1")) {
694185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[1]);
695185743Ssam	} else if (streq(var, "txMask")) {
696185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.txMask);
697185743Ssam	} else if (streq(var, "rxMask")) {
698185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.rxMask);
699185743Ssam	} else if (streq(var, "rfSilent")) {
700185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.rfSilent);
701185743Ssam	} else if (streq(var, "btOptions")) {
702185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.blueToothOptions);
703185743Ssam	} else if (streq(var, "deviceCap")) {
704185743Ssam                fprintf(fd, "0x%04X", eepromN.baseEepHeader.deviceCap);
705185743Ssam	} else if (strneq(var, "macaddr", 7)) {
706185743Ssam                fprintf(fd, "%02X",
707185743Ssam		    eepromN.baseEepHeader.macAddr[atoi(var+7)]);
708185743Ssam	} else if (streq(var, "opCapFlags")) {
709185743Ssam                fprintf(fd, "0x%02X", eepromN.baseEepHeader.opCapFlags);
710185743Ssam	} else if (streq(var, "eepMisc")) {
711185743Ssam                fprintf(fd, "0x%02X", eepromN.baseEepHeader.eepMisc);
712185743Ssam	} else if (strneq(var, "binBuildNumber", 14)) {
713185743Ssam                fprintf(fd, "%3d",
714185743Ssam		    (eepromN.baseEepHeader.binBuildNumber >> (8*atoi(var+14)))
715185743Ssam		    & 0xff);
716185743Ssam	} else if (strneq(var, "custData", 8)) {
717185743Ssam		fprintf(fd, "%2.2X", eepromN.custData[atoi(var+8)]);
718185743Ssam	} else if (streq(var, "xpd_mask")) {
719185743Ssam		if (IS_VERS(<, AR_EEPROM_VER5_0))
720185743Ssam			fprintf(fd, "0x%02x", pExpnPower->xpdMask);
721185743Ssam		else
722185743Ssam			fprintf(fd, "0x%02x", pRaw->xpd_mask);
723185743Ssam	} else if (streq(var, "numChannels")) {
724185743Ssam		if (IS_VERS(<, AR_EEPROM_VER5_0))
725185743Ssam			fprintf(fd, "%2d", pExpnPower->numChannels);
726185743Ssam		else
727185743Ssam			fprintf(fd, "%2d", pRaw->numChannels);
728185743Ssam	} else if (streq(var, "freq")) {
729185743Ssam		if (IS_VERS(<, AR_EEPROM_VER5_0))
730185743Ssam			fprintf(fd, "%4d", pExpnPower->pChannels[curchan]);
731185743Ssam		else
732185743Ssam			fprintf(fd, "%4d", pRaw->pChannels[curchan]);
733185743Ssam	} else if (streq(var, "maxpow")) {
734185743Ssam		int16_t maxPower_t4;
735185743Ssam		if (IS_VERS(<, AR_EEPROM_VER5_0)) {
736185743Ssam			maxPower_t4 = pExpnPower->pDataPerChannel[curchan].maxPower_t4;
737185743Ssam		} else {
738185743Ssam			maxPower_t4 = pRaw->pDataPerChannel[curchan].maxPower_t4;
739185743Ssam			if (maxPower_t4 == 0)
740185743Ssam				maxPower_t4 = getMaxPowerV5(&pRaw->pDataPerChannel[curchan]);
741185743Ssam		}
742185743Ssam		printQuarterDbmPower(fd, maxPower_t4);
743185743Ssam	} else if (streq(var, "pd_gain")) {
744185743Ssam		fprintf(fd, "%4d", pRaw->pDataPerChannel[curchan].
745185743Ssam		    pDataPerPDGain[curpdgain].pd_gain);
746185743Ssam	} else if (strneq(var, "maxpwr", 6)) {
747185743Ssam		int vpd = atoi(var+6);
748185743Ssam		if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd)
749185743Ssam			printQuarterDbmPower(fd, pRaw->pDataPerChannel[curchan].
750185743Ssam			    pDataPerPDGain[curpdgain].pwr_t4[vpd]);
751185743Ssam		else
752185743Ssam			fprintf(fd, "     ");
753185743Ssam	} else if (strneq(var, "pwr_t4_", 7)) {
754185743Ssam		printQuarterDbmPower(fd, pExpnPower->pDataPerChannel[curchan].
755185743Ssam		    pDataPerXPD[singleXpd].pwr_t4[atoi(var+7)]);
756185743Ssam	} else if (strneq(var, "Vpd", 3)) {
757185743Ssam		int vpd = atoi(var+3);
758185743Ssam		if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd)
759185743Ssam			printVpd(fd, pRaw->pDataPerChannel[curchan].
760185743Ssam			    pDataPerPDGain[curpdgain].Vpd[vpd]);
761185743Ssam		else
762185743Ssam			fprintf(fd, "     ");
763185743Ssam	} else if (streq(var, "CTL")) {
764185743Ssam		fprintf(fd, "0x%2x", eeprom.ee_ctl[curctl] & 0xff);
765185743Ssam	} else if (streq(var, "ctlType")) {
766185743Ssam		static const char *ctlType[16] = {
767185743Ssam		    "11a base", "11b", "11g", "11a TURBO", "108g",
768185743Ssam		    "2GHT20", "5GHT20", "2GHT40", "5GHT40",
769185743Ssam		    "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf",
770185743Ssam		};
771185743Ssam		fprintf(fd, "%8s", ctlType[eeprom.ee_ctl[curctl] & CTL_MODE_M]);
772185743Ssam	} else if (streq(var, "ctlRD")) {
773185743Ssam		static const char *ctlRD[8] = {
774185743Ssam		    "0x00", " FCC", "0x20", "ETSI",
775185743Ssam		    " MKK", "0x50", "0x60", "0x70"
776185743Ssam		};
777185743Ssam		fprintf(fd, "%s", ctlRD[(eeprom.ee_ctl[curctl] >> 4) & 7]);
778185743Ssam	} else if (strneq(var, "rdEdgePower", 11)) {
779185743Ssam		printEdgePower(fd, atoi(var+11));
780185743Ssam	} else if (strneq(var, "rdEdgeFlag", 10)) {
781185743Ssam		printEdgeFlag(fd, atoi(var+10));
782185743Ssam	} else if (strneq(var, "rdEdge", 6)) {
783185743Ssam		printEdge(fd, atoi(var+6));
784185743Ssam	} else if (strneq(var, "testChannel", 11)) {
785185743Ssam		fprintf(fd, "%4d", pPowerInfo[atoi(var+11)].testChannel);
786185743Ssam	} else if (strneq(var, "pwr6_24_", 8)) {
787185743Ssam		printHalfDbmPower(fd, pPowerInfo[atoi(var+8)].twicePwr6_24);
788185743Ssam	} else if (strneq(var, "pwr36_", 6)) {
789185743Ssam		printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr36);
790185743Ssam	} else if (strneq(var, "pwr48_", 6)) {
791185743Ssam		printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr48);
792185743Ssam	} else if (strneq(var, "pwr54_", 6)) {
793185743Ssam		printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr54);
794185743Ssam	} else if (strneq(var, "channelValue", 12)) {
795185743Ssam		fprintf(fd, "%4d", pDataPerChannel[atoi(var+12)].channelValue);
796185743Ssam	} else if (strneq(var, "pcdacMin", 8)) {
797185743Ssam		fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMin);
798185743Ssam	} else if (strneq(var, "pcdacMax", 8)) {
799185743Ssam		fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMax);
800185743Ssam	} else if (strneq(var, "pcdac", 5)) {
801185743Ssam		if (IS_VERS(<, AR_EEPROM_VER4_0)) {
802185743Ssam			fprintf(fd, "%02d", pDataPerChannel[atoi(var+5)].
803185743Ssam			    PcdacValues[curpcdac]);
804185743Ssam		} else if (IS_VERS(<, AR_EEPROM_VER5_0)) {
805185743Ssam			fprintf(fd, "%02d",
806185743Ssam			    pExpnPower->pDataPerChannel[curchan].
807185743Ssam				pDataPerXPD[singleXpd].pcdac[atoi(var+5)]);
808185743Ssam		} else
809185743Ssam			undef("pcdac");
810185743Ssam	} else if (strneq(var, "pwrValue", 8)) {
811185743Ssam		printPcdacValue(fd,
812185743Ssam		    pDataPerChannel[atoi(var+8)].PwrValues[curpcdac]);
813185743Ssam	} else if (streq(var, "singleXpd")) {
814185743Ssam		fprintf(fd, "%2d", singleXpd);
815185743Ssam	} else
816185743Ssam		warnx("line %u, unknown EEPROM variable \"%s\"", lineno, var);
817185743Ssam#undef strneq
818185743Ssam#undef streq
819185743Ssam}
820185743Ssam
821185743Ssamstatic void
822185743Ssamifmode(FILE *ftemplate, const char *mode)
823185743Ssam{
824185743Ssam	if (strcasecmp(mode, "11a") == 0) {
825185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2)) {
826185743Ssam			if (eeprom.ee_Amode)
827185743Ssam				setmode(headerInfo11A);
828185743Ssam			else
829185743Ssam				skipto(ftemplate, "endmode");
830185743Ssam			return;
831185743Ssam		}
832185743Ssam		if (IS_VERS(>=, AR_EEPROM_VER14_2)) {
833185743Ssam			if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A)
834185743Ssam				setmode(headerInfo11A);
835185743Ssam			else
836185743Ssam				skipto(ftemplate, "endmode");
837185743Ssam			return;
838185743Ssam		}
839185743Ssam	} else if (strcasecmp(mode, "11g") == 0) {
840185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2)) {
841185743Ssam			if (eeprom.ee_Gmode)
842185743Ssam				setmode(headerInfo11G);
843185743Ssam			else
844185743Ssam				skipto(ftemplate, "endmode");
845185743Ssam			return;
846185743Ssam		}
847185743Ssam		if (IS_VERS(>=, AR_EEPROM_VER14_2)) {
848185743Ssam			if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G)
849185743Ssam				setmode(headerInfo11B);		/* NB: 2.4GHz */
850185743Ssam			else
851185743Ssam				skipto(ftemplate, "endmode");
852185743Ssam			return;
853185743Ssam		}
854185743Ssam	} else if (strcasecmp(mode, "11b") == 0) {
855185743Ssam		if (IS_VERS(<, AR_EEPROM_VER14_2)) {
856185743Ssam			if (eeprom.ee_Bmode)
857185743Ssam				setmode(headerInfo11B);
858185743Ssam			else
859185743Ssam				skipto(ftemplate, "endmode");
860185743Ssam			return;
861185743Ssam		}
862185743Ssam	}
863185743Ssam	warnx("line %d, unknown/unexpected mode \"%s\" ignored",
864185743Ssam	    lineno, mode);
865185743Ssam	skipto(ftemplate, "endmode");
866185743Ssam}
867185743Ssam
868185743Ssamstatic void
869185743SsamparseTemplate(FILE *ftemplate, FILE *fd)
870185743Ssam{
871185743Ssam	int c, i;
872185743Ssam	char id[MAXID];
873185743Ssam	long forchan, forpdgain, forctl, forpcdac;
874185743Ssam
875185743Ssam	lineno = 1;
876185743Ssam	bol = 1;
877185743Ssam	while ((c = getc(ftemplate)) != EOF) {
878185743Ssam		if (c == '#') {			/* comment */
879185743Ssam	skiptoeol:
880185743Ssam			while ((c = getc(ftemplate)) != EOF && c != '\n')
881185743Ssam				;
882185743Ssam			if (c == EOF)
883185743Ssam				return;
884185743Ssam			lineno++;
885185743Ssam			bol = 1;
886185743Ssam			continue;
887185743Ssam		}
888185743Ssam		if (c == '.' && bol) {		/* .directive */
889185743Ssam			if (token(ftemplate, id, MAXID, ".directive") == EOF)
890185743Ssam				return;
891185743Ssam			/* process directive */
892185743Ssam			if (strcasecmp(id, "ifmode") == 0) {
893185743Ssam				skipws(ftemplate);
894185743Ssam				if (token(ftemplate, id, MAXID, "id") == EOF)
895185743Ssam					return;
896185743Ssam				ifmode(ftemplate, id);
897185743Ssam			} else if (strcasecmp(id, "endmode") == 0) {
898185743Ssam				/* XXX free malloc'd indirect data */
899185743Ssam				curmode = -1;	/* NB: undefined */
900185743Ssam			} else if (strcasecmp(id, "forchan") == 0) {
901185743Ssam				forchan = ftell(ftemplate) - sizeof("forchan");
902185743Ssam				if (curchan == -1)
903185743Ssam					curchan = 0;
904185743Ssam			} else if (strcasecmp(id, "endforchan") == 0) {
905185743Ssam				if (++curchan < numChannels)
906185743Ssam					fseek(ftemplate, forchan, SEEK_SET);
907185743Ssam				else
908185743Ssam					curchan = -1;
909185743Ssam			} else if (strcasecmp(id, "ifpdgain") == 0) {
910185743Ssam				skipws(ftemplate);
911185743Ssam				if (token(ftemplate, id, MAXID, "pdgain") == EOF)
912185743Ssam					return;
913185743Ssam				curlpdgain = strtoul(id, NULL, 0);
914185743Ssam				if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) {
915185743Ssam					skipto(ftemplate, "endpdgain");
916185743Ssam					curlpdgain = -1;
917185743Ssam				} else
918185743Ssam					curpdgain = pdgain(curlpdgain);
919185743Ssam			} else if (strcasecmp(id, "endpdgain") == 0) {
920185743Ssam				curlpdgain = curpdgain = -1;
921185743Ssam			} else if (strcasecmp(id, "forpdgain") == 0) {
922185743Ssam				forpdgain = ftell(ftemplate) - sizeof("forpdgain");
923185743Ssam				if (curlpdgain == -1) {
924185743Ssam					skipws(ftemplate);
925185743Ssam					if (token(ftemplate, id, MAXID, "pdgain") == EOF)
926185743Ssam						return;
927185743Ssam					curlpdgain = strtoul(id, NULL, 0);
928185743Ssam					if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) {
929185743Ssam						skipto(ftemplate, "endforpdgain");
930185743Ssam						curlpdgain = -1;
931185743Ssam					} else
932185743Ssam						curpdgain = pdgain(curlpdgain);
933185743Ssam				}
934185743Ssam			} else if (strcasecmp(id, "endforpdgain") == 0) {
935185743Ssam				if (++curpdgain < pRaw->pDataPerChannel[curchan].numPdGains)
936185743Ssam					fseek(ftemplate, forpdgain, SEEK_SET);
937185743Ssam				else
938185743Ssam					curpdgain = -1;
939185743Ssam			} else if (strcasecmp(id, "forpcdac") == 0) {
940185743Ssam				forpcdac = ftell(ftemplate) - sizeof("forpcdac");
941185743Ssam				if (curpcdac == -1)
942185743Ssam					curpcdac = 0;
943185743Ssam			} else if (strcasecmp(id, "endforpcdac") == 0) {
944185743Ssam				if (++curpcdac < pDataPerChannel[0].numPcdacValues)
945185743Ssam					fseek(ftemplate, forpcdac, SEEK_SET);
946185743Ssam				else
947185743Ssam					curpcdac = -1;
948185743Ssam			} else if (strcasecmp(id, "forctl") == 0) {
949185743Ssam				forctl = ftell(ftemplate) - sizeof("forchan");
950185743Ssam				if (curctl == -1)
951185743Ssam					curctl = nextctl(0);
952185743Ssam			} else if (strcasecmp(id, "endforctl") == 0) {
953185743Ssam				curctl = nextctl(curctl+1);
954185743Ssam				if (curctl != -1)
955185743Ssam					fseek(ftemplate, forctl, SEEK_SET);
956185743Ssam			} else {
957185743Ssam				warnx("line %d, unknown directive %s ignored",
958185743Ssam				    lineno, id);
959185743Ssam			}
960185743Ssam			goto skiptoeol;
961185743Ssam		}
962185743Ssam		if (c == '$') {			/* $variable reference */
963185743Ssam			if (token(ftemplate, id, MAXID, "$var") == EOF)
964185743Ssam				return;
965185743Ssam			/* XXX not valid if variable depends on curmode */
966185743Ssam			eevar(fd, id);
967185743Ssam			continue;
968185743Ssam		}
969185743Ssam		if (c == '\\') {		/* escape next character */
970185743Ssam			c = getc(ftemplate);
971185743Ssam			if (c == EOF)
972185743Ssam				return;
973185743Ssam		}
974185743Ssam		fputc(c, fd);
975185743Ssam		bol = (c == '\n');
976185743Ssam		if (bol)
977185743Ssam			lineno++;
978185743Ssam	}
979185743Ssam}
980