svn commit: r185743 - in head/tools/tools/ath: . athdebug athkey athpow athprom athregs athstats common

Sam Leffler sam at FreeBSD.org
Sun Dec 7 11:17:35 PST 2008


Author: sam
Date: Sun Dec  7 19:17:33 2008
New Revision: 185743
URL: http://svn.freebsd.org/changeset/base/185743

Log:
  bring in diagnostic tools that are useful now that we have hal source code

Added:
  head/tools/tools/ath/Makefile.inc   (contents, props changed)
  head/tools/tools/ath/athkey/
  head/tools/tools/ath/athkey/Makefile   (contents, props changed)
  head/tools/tools/ath/athkey/athkey.c   (contents, props changed)
  head/tools/tools/ath/athpow/
  head/tools/tools/ath/athpow/Makefile   (contents, props changed)
  head/tools/tools/ath/athpow/athpow.c   (contents, props changed)
  head/tools/tools/ath/athprom/
  head/tools/tools/ath/athprom/Makefile   (contents, props changed)
  head/tools/tools/ath/athprom/athprom.c   (contents, props changed)
  head/tools/tools/ath/athprom/eeprom-14   (contents, props changed)
  head/tools/tools/ath/athprom/eeprom-3   (contents, props changed)
  head/tools/tools/ath/athprom/eeprom-4   (contents, props changed)
  head/tools/tools/ath/athprom/eeprom-5   (contents, props changed)
  head/tools/tools/ath/athregs/
  head/tools/tools/ath/athregs/Makefile   (contents, props changed)
  head/tools/tools/ath/athregs/dumpregs.c   (contents, props changed)
  head/tools/tools/ath/athregs/dumpregs.h   (contents, props changed)
  head/tools/tools/ath/athregs/dumpregs_5210.c   (contents, props changed)
  head/tools/tools/ath/athregs/dumpregs_5211.c   (contents, props changed)
  head/tools/tools/ath/athregs/dumpregs_5212.c   (contents, props changed)
  head/tools/tools/ath/athregs/dumpregs_5416.c   (contents, props changed)
  head/tools/tools/ath/common/
  head/tools/tools/ath/common/ah_osdep.h   (contents, props changed)
  head/tools/tools/ath/common/diag.h   (contents, props changed)
Modified:
  head/tools/tools/ath/Makefile
  head/tools/tools/ath/athdebug/Makefile
  head/tools/tools/ath/athstats/Makefile

Modified: head/tools/tools/ath/Makefile
==============================================================================
--- head/tools/tools/ath/Makefile	Sun Dec  7 18:45:30 2008	(r185742)
+++ head/tools/tools/ath/Makefile	Sun Dec  7 19:17:33 2008	(r185743)
@@ -1,5 +1,5 @@
 #	$FreeBSD$
 
-SUBDIR=	athstats athdebug
+SUBDIR=	athdebug athkey athprom athregs athstats
 
 .include <bsd.subdir.mk>

Added: head/tools/tools/ath/Makefile.inc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/tools/ath/Makefile.inc	Sun Dec  7 19:17:33 2008	(r185743)
@@ -0,0 +1,11 @@
+#	$FreeBSD$
+
+BINDIR=	/usr/local/bin
+NO_MAN=
+
+ATH_DEFAULT=	ath0
+
+CFLAGS+=-DATH_DEFAULT='"${ATH_DEFAULT}"'
+CFLAGS+=-I../common
+CFLAGS+=-I../../../../sys/dev/ath
+CFLAGS+=-I../../../../sys/dev/ath/ath_hal

Modified: head/tools/tools/ath/athdebug/Makefile
==============================================================================
--- head/tools/tools/ath/athdebug/Makefile	Sun Dec  7 18:45:30 2008	(r185742)
+++ head/tools/tools/ath/athdebug/Makefile	Sun Dec  7 19:17:33 2008	(r185743)
@@ -1,7 +1,7 @@
 # $FreeBSD$
 
 PROG=	athdebug
-BINDIR=	/usr/local/bin
-NO_MAN=
+
+.include <../Makefile.inc>
 
 .include <bsd.prog.mk>

Added: head/tools/tools/ath/athkey/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/tools/ath/athkey/Makefile	Sun Dec  7 19:17:33 2008	(r185743)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+PROG=	athkey
+
+.include <../Makefile.inc>
+
+.include <bsd.prog.mk>

Added: head/tools/tools/ath/athkey/athkey.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/tools/ath/athkey/athkey.c	Sun Dec  7 19:17:33 2008	(r185743)
@@ -0,0 +1,203 @@
+/*-
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+#include "diag.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+#include <ctype.h>
+#include <getopt.h>
+
+const char *progname;
+
+static int
+toint(int c)
+{
+	return isdigit(c) ? c - '0' : isupper(c) ? c - 'A' + 10 : c - 'a' + 10;
+}
+
+static int
+getdata(const char *arg, u_int8_t *data, size_t maxlen)
+{
+	const char *cp = arg;
+	int len;
+
+	if (cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X'))
+		cp += 2;
+	len = 0;
+	while (*cp) {
+		int b0, b1;
+		if (cp[0] == ':' || cp[0] == '-' || cp[0] == '.') {
+			cp++;
+			continue;
+		}
+		if (!isxdigit(cp[0])) {
+			fprintf(stderr, "%s: invalid data value %c (not hex)\n",
+				progname, cp[0]);
+			exit(-1);
+		}
+		b0 = toint(cp[0]);
+		if (cp[1] != '\0') {
+			if (!isxdigit(cp[1])) {
+				fprintf(stderr, "%s: invalid data value %c "
+					"(not hex)\n", progname, cp[1]);
+				exit(-1);
+			}
+			b1 = toint(cp[1]);
+			cp += 2;
+		} else {			/* fake up 0<n> */
+			b1 = b0, b0 = 0;
+			cp += 1;
+		}
+		if (len > maxlen) {
+			fprintf(stderr,
+				"%s: too much data in %s, max %u bytes\n",
+				progname, arg, maxlen);
+		}
+		data[len++] = (b0<<4) | b1;
+	}
+	return len;
+}
+
+/* XXX this assumes 5212 key types are common to 5211 and 5210 */
+
+static int
+getcipher(const char *name)
+{
+#define	streq(a,b)	(strcasecmp(a,b) == 0)
+
+	if (streq(name, "wep"))
+		return HAL_CIPHER_WEP;
+	if (streq(name, "tkip"))
+		return HAL_CIPHER_TKIP;
+	if (streq(name, "aes-ocb") || streq(name, "ocb"))
+		return HAL_CIPHER_AES_OCB;
+	if (streq(name, "aes-ccm") || streq(name, "ccm") ||
+	    streq(name, "aes"))
+		return HAL_CIPHER_AES_CCM;
+	if (streq(name, "ckip"))
+		return HAL_CIPHER_CKIP;
+	if (streq(name, "none") || streq(name, "clr"))
+		return HAL_CIPHER_CLR;
+
+	fprintf(stderr, "%s: unknown cipher %s\n", progname, name);
+	exit(-1);
+#undef streq
+}
+
+static void
+usage(void)
+{
+	fprintf(stderr, "usage: %s [-i device] keyix cipher keyval [mac]\n",
+		progname);
+	exit(-1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	const char *ifname;
+	struct ath_diag atd;
+	HAL_DIAG_KEYVAL setkey;
+	const char *cp;
+	int s, c;
+	u_int16_t keyix;
+	int op = HAL_DIAG_SETKEY;
+	int xor = 0;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0)
+		err(1, "socket");
+	ifname = getenv("ATH");
+	if (!ifname)
+		ifname = ATH_DEFAULT;
+
+	progname = argv[0];
+	while ((c = getopt(argc, argv, "di:x")) != -1)
+		switch (c) {
+		case 'd':
+			op = HAL_DIAG_RESETKEY;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'x':
+			xor = 1;
+			break;
+		default:
+			usage();
+			/*NOTREACHED*/
+		}
+	argc -= optind;
+	argv += optind;
+	if (argc < 1)
+		usage();
+
+	keyix = (u_int16_t) atoi(argv[0]);
+	if (keyix > 127)
+		errx(-1, "%s: invalid key index %s, must be [0..127]",
+			progname, argv[0]);
+	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
+	atd.ad_id = op | ATH_DIAG_IN | ATH_DIAG_DYN;
+	atd.ad_out_data = NULL;
+	atd.ad_out_size = 0;
+	switch (op) {
+	case HAL_DIAG_RESETKEY:
+		atd.ad_in_data = (caddr_t) &keyix;
+		atd.ad_in_size = sizeof(u_int16_t);
+		if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+			err(1, atd.ad_name);
+		return 0;
+	case HAL_DIAG_SETKEY:
+		if (argc != 3 && argc != 4)
+			usage();
+		memset(&setkey, 0, sizeof(setkey));
+		setkey.dk_keyix = keyix;
+		setkey.dk_xor = xor;
+		setkey.dk_keyval.kv_type = getcipher(argv[1]);
+		setkey.dk_keyval.kv_len = getdata(argv[2],
+		    setkey.dk_keyval.kv_val, sizeof(setkey.dk_keyval.kv_val));
+		/* XXX MIC */
+		if (argc == 4)
+			(void) getdata(argv[3], setkey.dk_mac,
+				IEEE80211_ADDR_LEN);
+		atd.ad_in_data = (caddr_t) &setkey;
+		atd.ad_in_size = sizeof(setkey);
+		if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+			err(1, atd.ad_name);
+		return 0;
+	}
+	return -1;
+}

Added: head/tools/tools/ath/athpow/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/tools/ath/athpow/Makefile	Sun Dec  7 19:17:33 2008	(r185743)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+PROG=	athpow
+
+.include <../Makefile.inc>
+
+.include <bsd.prog.mk>

Added: head/tools/tools/ath/athpow/athpow.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/tools/ath/athpow/athpow.c	Sun Dec  7 19:17:33 2008	(r185743)
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+#include "diag.h"
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_eeprom.h"
+#include "ah_eeprom_v1.h"
+#include "ah_eeprom_v3.h"
+#include "ah_eeprom_v14.h"
+#include "ar5212/ar5212reg.h"
+#define	IS_5112(ah) \
+	(((ah)->ah_analog5GhzRev&0xf0) >= AR_RAD5112_SREV_MAJOR \
+	 && ((ah)->ah_analog5GhzRev&0xf0) < AR_RAD2316_SREV_MAJOR )
+#define	IS_2316(ah) \
+	((ah)->ah_macVersion == AR_SREV_2415)
+#define	IS_2413(ah) \
+	((ah)->ah_macVersion == AR_SREV_2413 || IS_2316(ah))
+#define IS_5424(ah) \
+	((ah)->ah_macVersion == AR_SREV_5424 || \
+	((ah)->ah_macVersion == AR_SREV_5413 && \
+	  (ah)->ah_macRev <= AR_SREV_D2PLUS_MS))
+#define IS_5413(ah) \
+	((ah)->ah_macVersion == AR_SREV_5413 || IS_5424(ah))
+
+#ifndef MAX
+#define	MAX(a,b)	((a) > (b) ? (a) : (b))
+#endif
+
+static void printPcdacTable(FILE *fd, u_int16_t pcdac[], u_int n);
+static void printPowerPerRate(FILE *fd, u_int16_t ratesArray[], u_int n);
+static void printRevs(FILE *fd, const HAL_REVS *revs);
+
+static void
+usage(const char *progname)
+{
+	fprintf(stderr, "usage: %s [-v] [-i dev]\n", progname);
+	exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int s, i, verbose = 0, c;
+	struct ath_diag atd;
+	const char *ifname;
+	HAL_REVS revs;
+	u_int16_t pcdacTable[MAX(PWR_TABLE_SIZE,PWR_TABLE_SIZE_2413)];
+	u_int16_t ratesArray[16];
+	u_int nrates, npcdac;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0)
+		err(1, "socket");
+	ifname = getenv("ATH");
+	if (!ifname)
+		ifname = ATH_DEFAULT;
+	while ((c = getopt(argc, argv, "i:v")) != -1)
+		switch (c) {
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
+
+	atd.ad_id = HAL_DIAG_REVS;
+	atd.ad_out_data = (caddr_t) &revs;
+	atd.ad_out_size = sizeof(revs);
+	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+		err(1, atd.ad_name);
+
+	if (verbose)
+		printRevs(stdout, &revs);
+
+	atd.ad_id = HAL_DIAG_TXRATES;
+	atd.ad_out_data = (caddr_t) ratesArray;
+	atd.ad_out_size = sizeof(ratesArray);
+	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+		err(1, atd.ad_name);
+	nrates = sizeof(ratesArray) / sizeof(u_int16_t);
+
+	atd.ad_id = HAL_DIAG_PCDAC;
+	atd.ad_out_data = (caddr_t) pcdacTable;
+	atd.ad_out_size = sizeof(pcdacTable);
+	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+		err(1, atd.ad_name);
+	if (IS_2413(&revs) || IS_5413(&revs))
+		npcdac = PWR_TABLE_SIZE_2413;
+	else
+		npcdac = PWR_TABLE_SIZE;
+
+	printf("PCDAC table:\n");
+	printPcdacTable(stdout, pcdacTable, npcdac);
+
+	printf("Power per rate table:\n");
+	printPowerPerRate(stdout, ratesArray, nrates);
+
+	return 0;
+}
+
+static void
+printPcdacTable(FILE *fd, u_int16_t pcdac[], u_int n)
+{
+	int i, halfRates = n/2;
+
+	for (i = 0; i < halfRates; i += 2)
+		fprintf(fd, "[%2u] %04x %04x [%2u] %04x %04x\n",
+			i, pcdac[2*i + 1], pcdac[2*i],
+			i+1, pcdac[2*(i+1) + 1], pcdac[2*(i+1)]);
+}
+
+static void
+printPowerPerRate(FILE *fd, u_int16_t ratesArray[], u_int n)
+{
+	const char *rateString[] = {
+		" 6mb OFDM", " 9mb OFDM", "12mb OFDM", "18mb OFDM",
+		"24mb OFDM", "36mb OFDM", "48mb OFDM", "54mb OFDM",
+		"1L   CCK ", "2L   CCK ", "2S   CCK ", "5.5L CCK ",
+		"5.5S CCK ", "11L  CCK ", "11S  CCK ", "XR       "
+	};
+	int i, halfRates = n/2;
+
+	for (i = 0; i < halfRates; i++)
+		fprintf(fd, " %s %3d.%1d dBm | %s %3d.%1d dBm\n", 
+			 rateString[i], ratesArray[i]/2,
+			 (ratesArray[i] %2) * 5, 
+			 rateString[i + halfRates],
+			 ratesArray[i + halfRates]/2,
+			 (ratesArray[i + halfRates] %2) *5);
+}
+
+static void
+printRevs(FILE *fd, const HAL_REVS *revs)
+{
+	const char *rfbackend;
+
+	fprintf(fd, "PCI device id 0x%x subvendor id 0x%x\n",
+		revs->ah_devid, revs->ah_subvendorid);
+	fprintf(fd, "mac %d.%d phy %d.%d"
+		, revs->ah_macVersion, revs->ah_macRev
+		, revs->ah_phyRev >> 4, revs->ah_phyRev & 0xf
+	);
+	rfbackend = IS_5413(revs) ? "5413" :
+		    IS_2413(revs) ? "2413" :
+		    IS_5112(revs) ? "5112" :
+				    "5111";
+	if (revs->ah_analog5GhzRev && revs->ah_analog2GhzRev)
+		fprintf(fd, " 5ghz radio %d.%d 2ghz radio %d.%d (%s)\n"
+			, revs->ah_analog5GhzRev >> 4
+			, revs->ah_analog5GhzRev & 0xf
+			, revs->ah_analog2GhzRev >> 4
+			, revs->ah_analog2GhzRev & 0xf
+			, rfbackend
+		);
+	else
+		fprintf(fd, " radio %d.%d (%s)\n"
+			, revs->ah_analog5GhzRev >> 4
+			, revs->ah_analog5GhzRev & 0xf
+			, rfbackend
+		);
+}

Added: head/tools/tools/ath/athprom/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/tools/ath/athprom/Makefile	Sun Dec  7 19:17:33 2008	(r185743)
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+PROG=	athprom
+
+.include <../Makefile.inc>
+
+TEMPLATEDIR=	/usr/local/libdata/athprom
+TEXTMODE?=	444
+
+CFLAGS+=-DDIR_TEMPLATE='"${TEMPLATEDIR}"'
+
+beforeinstall:
+	mkdir -p ${DESTDIR}${TEMPLATEDIR}
+	${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${TEXTMODE} \
+	    ${.CURDIR}/eeprom-* ${DESTDIR}${TEMPLATEDIR}/
+
+.include <bsd.prog.mk>

Added: head/tools/tools/ath/athprom/athprom.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/tools/ath/athprom/athprom.c	Sun Dec  7 19:17:33 2008	(r185743)
@@ -0,0 +1,978 @@
+/*-
+ * Copyright (c) 2008 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+#include "diag.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_eeprom_v1.h"
+#include "ah_eeprom_v3.h"
+#include "ah_eeprom_v14.h"
+
+#define	IS_VERS(op, v)		(eeprom.ee_version op (v))
+
+#include <getopt.h>
+#include <errno.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef DIR_TEMPLATE
+#define	DIR_TEMPLATE	"/usr/local/libdata/athprom"
+#endif
+
+struct	ath_diag atd;
+int	s;
+const char *progname;
+union {
+	HAL_EEPROM legacy;		/* format v3.x ... v5.x */
+	struct ar5416eeprom v14;	/* 11n format v14.x ... */
+} eep;
+#define	eeprom	eep.legacy
+#define	eepromN	eep.v14
+
+static void parseTemplate(FILE *ftemplate, FILE *fd);
+static uint16_t eeread(uint16_t);
+static void eewrite(uint16_t, uint16_t);
+
+static void
+usage()
+{
+	fprintf(stderr, "usage: %s [-i ifname] [-t pathname] [offset | offset=value]\n", progname);
+	exit(-1);
+}
+
+static FILE *
+opentemplate(const char *dir)
+{
+	char filename[PATH_MAX];
+	FILE *fd;
+
+	/* find the template using the eeprom version */
+	snprintf(filename, sizeof(filename), "%s/eeprom-%d.%d",
+	    dir, eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
+	fd = fopen(filename, "r");
+	if (fd == NULL && errno == ENOENT) {
+		/* retry with just the major version */
+		snprintf(filename, sizeof(filename), "%s/eeprom-%d",
+		    dir, eeprom.ee_version >> 12);
+		fd = fopen(filename, "r");
+		if (fd != NULL)		/* XXX verbose */
+			warnx("Using template file %s", filename);
+	}
+	return fd;
+}
+
+int
+main(int argc, char *argv[])
+{
+	FILE *fd = NULL;
+	const char *ifname;
+	int c;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0)
+		err(1, "socket");
+	ifname = getenv("ATH");
+	if (!ifname)
+		ifname = ATH_DEFAULT;
+
+	progname = argv[0];
+	while ((c = getopt(argc, argv, "i:t:")) != -1)
+		switch (c) {
+		case 'i':
+			ifname = optarg;
+			break;
+		case 't':
+			fd = fopen(optarg, "r");
+			if (fd == NULL)
+				err(-1, "Cannot open %s", optarg);
+			break;
+		default:
+			usage();
+			/*NOTREACHED*/
+		}
+	argc -= optind;
+	argv += optind;
+
+	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
+
+	if (argc != 0) {
+		for (; argc > 0; argc--, argv++) {
+			uint16_t off, val, oval;
+			char line[256];
+			char *cp;
+
+			cp = strchr(argv[0], '=');
+			if (cp != NULL)
+				*cp = '\0';
+			off = (uint16_t) strtoul(argv[0], NULL, 0);
+			if (off == 0 && errno == EINVAL)
+				errx(1, "%s: invalid eeprom offset %s",
+					progname, argv[0]);
+			if (cp == NULL) {
+				printf("%04x: %04x\n", off, eeread(off));
+			} else {
+				val = (uint16_t) strtoul(cp+1, NULL, 0);
+				if (val == 0 && errno == EINVAL)
+				errx(1, "%s: invalid eeprom value %s",
+					progname, cp+1);
+				oval = eeread(off);
+				printf("Write %04x: %04x = %04x? ",
+					off, oval, val);
+				fflush(stdout);
+				if (fgets(line, sizeof(line), stdin) != NULL &&
+				    line[0] == 'y')
+					eewrite(off, val);
+			}
+		}
+	} else {
+		atd.ad_id = HAL_DIAG_EEPROM;
+		atd.ad_out_data = (caddr_t) &eep;
+		atd.ad_out_size = sizeof(eep);
+		if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+			err(1, atd.ad_name);
+		if (fd == NULL) {
+			fd = opentemplate(DIR_TEMPLATE);
+			if (fd == NULL)
+				fd = opentemplate(".");
+			if (fd == NULL)
+				errx(-1, "Cannot locate template file for "
+				    "v%d.%d EEPROM", eeprom.ee_version >> 12,
+				    eeprom.ee_version & 0xfff);
+		}
+		parseTemplate(fd, stdout);
+		fclose(fd);
+	}
+	return 0;
+}
+
+static u_int16_t
+eeread(u_int16_t off)
+{
+	u_int16_t eedata;
+
+	atd.ad_id = HAL_DIAG_EEREAD | ATH_DIAG_IN | ATH_DIAG_DYN;
+	atd.ad_in_size = sizeof(off);
+	atd.ad_in_data = (caddr_t) &off;
+	atd.ad_out_size = sizeof(eedata);
+	atd.ad_out_data = (caddr_t) &eedata;
+	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+		err(1, atd.ad_name);
+	return eedata;
+}
+
+static void
+eewrite(uint16_t off, uint16_t value)
+{
+	HAL_DIAG_EEVAL eeval;
+
+	eeval.ee_off = off;
+	eeval.ee_data = value;
+
+	atd.ad_id = HAL_DIAG_EEWRITE | ATH_DIAG_IN;
+	atd.ad_in_size = sizeof(eeval);
+	atd.ad_in_data = (caddr_t) &eeval;
+	atd.ad_out_size = 0;
+	atd.ad_out_data = NULL;
+	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+		err(1, atd.ad_name);
+}
+
+#define	MAXID	128
+int	lineno;
+int	bol;
+int	curmode = -1;
+int	curchan;
+int	curpdgain;	/* raw pdgain index */
+int	curlpdgain;	/* logical pdgain index */
+int	curpcdac;
+int	curctl;
+int	numChannels;
+const RAW_DATA_STRUCT_2413 *pRaw;
+const TRGT_POWER_INFO *pPowerInfo;
+const DATA_PER_CHANNEL *pDataPerChannel;
+const EEPROM_POWER_EXPN_5112 *pExpnPower;
+int	singleXpd;
+
+static int
+token(FILE *fd, char id[], int maxid, const char *what)
+{
+	int c, i;
+
+	i = 0;
+	for (;;) {
+		c = getc(fd);
+		if (c == EOF)
+			return EOF;
+		if (!isalnum(c) && c != '_') {
+			ungetc(c, fd);
+			break;
+		}
+		if (i == maxid-1) {
+			warnx("line %d, %s too long", lineno, what);
+			break;
+		}
+		id[i++] = c;
+	}
+	id[i] = '\0';
+	if (i != 0)
+		bol = 0;
+	return i;
+}
+
+static int
+skipto(FILE *fd, const char *what)
+{
+	char id[MAXID];
+	int c;
+
+	for (;;) {
+		c = getc(fd);
+		if (c == EOF)
+			goto bad;
+		if (c == '.' && bol) {		/* .directive */
+			if (token(fd, id, MAXID, ".directive") == EOF)
+				goto bad;
+			if (strcasecmp(id, what) == 0)
+				break;
+			continue;
+		}
+		if (c == '\\') {		/* escape next character */
+			c = getc(fd);
+			if (c == EOF)
+				goto bad;
+		}
+		bol = (c == '\n');
+		if (bol)
+			lineno++;
+	}
+	return 0;
+bad:
+	warnx("EOF with no matching .%s", what);
+	return EOF;
+}
+
+static int
+skipws(FILE *fd)
+{
+	int c, i;
+
+	i = 0;
+	while ((c = getc(fd)) != EOF && isblank(c))
+		i++;
+	if (c != EOF)
+		ungetc(c, fd);
+	if (i != 0)
+		bol = 0;
+	return 0;
+}
+
+static void
+setmode(int mode)
+{
+	EEPROM_POWER_EXPN_5112 *exp;
+
+	curmode = mode;
+	curchan = -1;
+	curctl = -1;
+	curpdgain = -1;
+	curlpdgain = -1;
+	curpcdac = -1;
+	switch (curmode) {
+	case headerInfo11A:
+		pPowerInfo = eeprom.ee_trgtPwr_11a;
+		pDataPerChannel = eeprom.ee_dataPerChannel11a;
+		break;
+	case headerInfo11B:
+		pPowerInfo = eeprom.ee_trgtPwr_11b;
+		pDataPerChannel = eeprom.ee_dataPerChannel11b;
+		break;
+	case headerInfo11G:
+		pPowerInfo = eeprom.ee_trgtPwr_11g;
+		pDataPerChannel = eeprom.ee_dataPerChannel11g;
+		break;
+	}
+	if (IS_VERS(<, AR_EEPROM_VER4_0))		/* nothing to do */
+		return;
+	if (IS_VERS(<, AR_EEPROM_VER5_0)) {
+		exp = &eeprom.ee_modePowerArray5112[curmode];
+		/* fetch indirect data*/
+		atd.ad_id = HAL_DIAG_EEPROM_EXP_11A+curmode;
+		atd.ad_out_size = roundup(
+			sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t))
+		    + sizeof(EXPN_DATA_PER_CHANNEL_5112) * exp->numChannels;
+		atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size);
+		if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
+			err(1, atd.ad_name);
+		exp->pChannels = (void *) atd.ad_out_data;
+		exp->pDataPerChannel = (void *)((char *)atd.ad_out_data +
+		   roundup(sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t)));
+		pExpnPower = exp;
+		numChannels = pExpnPower->numChannels;
+		if (exp->xpdMask != 0x9) {
+			for (singleXpd = 0; singleXpd < NUM_XPD_PER_CHANNEL; singleXpd++)
+				if (exp->xpdMask == (1<<singleXpd))
+					break;
+		} else
+			singleXpd = 0;
+	} else if (IS_VERS(<, AR_EEPROM_VER14_2)) {
+		pRaw = &eeprom.ee_rawDataset2413[curmode];
+		numChannels = pRaw->numChannels;
+	}
+}
+
+int
+nextctl(int start)
+{
+	int i;
+
+	for (i = start; i < eeprom.ee_numCtls && eeprom.ee_ctl[i]; i++) {
+		switch (eeprom.ee_ctl[i] & 3) {
+		case 0: case 3:
+			if (curmode != headerInfo11A)
+				continue;
+			break;
+		case 1:
+			if (curmode != headerInfo11B)
+				continue;
+			break;
+		case 2:
+			if (curmode != headerInfo11G)
+				continue;
+			break;
+		}
+		return i;
+	}
+	return -1;
+}
+
+static void
+printAntennaControl(FILE *fd, int ant)
+{
+	fprintf(fd, "0x%02X", eeprom.ee_antennaControl[ant][curmode]);
+}
+
+static void
+printEdge(FILE *fd, int edge)
+{
+	const RD_EDGES_POWER *pRdEdgePwrInfo =
+	    &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
+
+	if (pRdEdgePwrInfo[edge].rdEdge == 0)
+		fprintf(fd, " -- ");
+	else
+		fprintf(fd, "%04d", pRdEdgePwrInfo[edge].rdEdge);
+}
+
+static void
+printEdgePower(FILE *fd, int edge)
+{
+	const RD_EDGES_POWER *pRdEdgePwrInfo =
+	    &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
+
+	if (pRdEdgePwrInfo[edge].rdEdge == 0)
+		fprintf(fd, " -- ");
+	else
+                fprintf(fd, "%2d.%d",
+		    pRdEdgePwrInfo[edge].twice_rdEdgePower / 2,
+                    (pRdEdgePwrInfo[edge].twice_rdEdgePower % 2) * 5);
+}
+
+static void
+printEdgeFlag(FILE *fd, int edge)
+{
+	const RD_EDGES_POWER *pRdEdgePwrInfo =
+	    &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES];
+
+	if (pRdEdgePwrInfo[edge].rdEdge == 0)
+		fprintf(fd, "--");
+	else
+                fprintf(fd, " %1d", pRdEdgePwrInfo[edge].flag);
+}
+
+static int16_t
+getMaxPowerV5(const RAW_DATA_PER_CHANNEL_2413 *data)
+{
+	uint32_t i;
+	uint16_t numVpd;
+
+	for (i = 0; i < MAX_NUM_PDGAINS_PER_CHANNEL; i++) {
+		numVpd = data->pDataPerPDGain[i].numVpd;
+		if (numVpd > 0)
+			return data->pDataPerPDGain[i].pwr_t4[numVpd-1];
+	}
+	return 0;
+}
+
+static void
+printQuarterDbmPower(FILE *fd, int16_t power25dBm)
+{
+	fprintf(fd, "%2d.%02d", power25dBm / 4, (power25dBm % 4) * 25);
+}
+
+static void
+printHalfDbmPower(FILE *fd, int16_t power5dBm)
+{
+	fprintf(fd, "%2d.%d", power5dBm / 2, (power5dBm % 2) * 5);
+}
+
+static void
+printVpd(FILE *fd, int vpd)
+{
+	fprintf(fd, "[%3d]", vpd);
+}
+
+static void
+printPcdacValue(FILE *fd, int v)
+{
+	fprintf(fd, "%2d.%02d", v / EEP_SCALE, v % EEP_SCALE);
+}
+
+static void
+undef(const char *what)
+{
+	warnx("%s undefined for version %d.%d format EEPROM", what,
+	    eeprom.ee_version >> 12, eeprom.ee_version & 0xfff);
+}
+
+static int
+pdgain(int lpdgain)
+{
+	uint32_t mask;
+	int i, l = lpdgain;
+
+	if (IS_VERS(<, AR_EEPROM_VER5_0))
+		mask = pExpnPower->xpdMask;
+	else
+		mask = pRaw->xpd_mask;
+	for (i = 0; mask != 0; mask >>= 1, i++)
+		if ((mask & 1) && l-- == 0)
+			return i;
+	warnx("can't find logical pdgain %d", lpdgain);
+	return -1;
+}
+
+#define	COUNTRY_ERD_FLAG        0x8000
+#define WORLDWIDE_ROAMING_FLAG  0x4000
+
+void
+eevar(FILE *fd, const char *var)
+{
+#define	streq(a,b)	(strcasecmp(a,b) == 0)
+#define	strneq(a,b,n)	(strncasecmp(a,b,n) == 0)
+	if (streq(var, "mode")) {
+		fprintf(fd, "%s",
+		    curmode == headerInfo11A ? "11a" :
+		    curmode == headerInfo11B ? "11b" :
+		    curmode == headerInfo11G ? "11g" : "???");
+	} else if (streq(var, "version")) {
+		fprintf(fd, "%04x", eeprom.ee_version);
+	} else if (streq(var, "V_major")) {
+		fprintf(fd, "%2d", eeprom.ee_version >> 12);
+	} else if (streq(var, "V_minor")) {
+		fprintf(fd, "%2d", eeprom.ee_version & 0xfff);
+	} else if (streq(var, "earStart")) {
+		fprintf(fd, "%03x", eeprom.ee_earStart);
+	} else if (streq(var, "tpStart")) {
+		fprintf(fd, "%03x", eeprom.ee_targetPowersStart);
+	} else if (streq(var, "eepMap")) {
+		fprintf(fd, "%3d", eeprom.ee_eepMap);
+	} else if (streq(var, "exist32KHzCrystal")) {
+		fprintf(fd, "%3d", eeprom.ee_exist32kHzCrystal);
+	} else if (streq(var, "eepMap2PowerCalStart")) {
+		fprintf(fd , "%3d", eeprom.ee_eepMap2PowerCalStart);
+	} else if (streq(var, "Amode")) {
+		fprintf(fd , "%1d", eeprom.ee_Amode);
+	} else if (streq(var, "Bmode")) {
+		fprintf(fd , "%1d", eeprom.ee_Bmode);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list