1/*-
2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 *    redistribution must be conditioned upon including a substantially
14 *    similar Disclaimer requirement for further binary redistribution.
15 *
16 * NO WARRANTY
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
28 *
29 * $FreeBSD$
30 */
31#include "diag.h"
32
33#include <getopt.h>
34#include <stdlib.h>
35#include <string.h>
36
37#include "ah.h"
38#include "ah_internal.h"
39#include "ah_eeprom.h"
40#include "ah_eeprom_v1.h"
41#include "ah_eeprom_v3.h"
42#include "ah_eeprom_v14.h"
43#include "ar5212/ar5212reg.h"
44#define	IS_5112(ah) \
45	(((ah)->ah_analog5GhzRev&0xf0) >= AR_RAD5112_SREV_MAJOR \
46	 && ((ah)->ah_analog5GhzRev&0xf0) < AR_RAD2316_SREV_MAJOR )
47#define	IS_2316(ah) \
48	((ah)->ah_macVersion == AR_SREV_2415)
49#define	IS_2413(ah) \
50	((ah)->ah_macVersion == AR_SREV_2413 || IS_2316(ah))
51#define IS_5424(ah) \
52	((ah)->ah_macVersion == AR_SREV_5424 || \
53	((ah)->ah_macVersion == AR_SREV_5413 && \
54	  (ah)->ah_macRev <= AR_SREV_D2PLUS_MS))
55#define IS_5413(ah) \
56	((ah)->ah_macVersion == AR_SREV_5413 || IS_5424(ah))
57
58#ifndef MAX
59#define	MAX(a,b)	((a) > (b) ? (a) : (b))
60#endif
61
62static void printPcdacTable(FILE *fd, u_int16_t pcdac[], u_int n);
63static void printPowerPerRate(FILE *fd, u_int16_t ratesArray[], u_int n);
64static void printRevs(FILE *fd, const HAL_REVS *revs);
65
66static void
67usage(const char *progname)
68{
69	fprintf(stderr, "usage: %s [-v] [-i dev]\n", progname);
70	exit(1);
71}
72
73int
74main(int argc, char *argv[])
75{
76	int s, i, verbose = 0, c;
77	struct ath_diag atd;
78	const char *ifname;
79	HAL_REVS revs;
80	u_int16_t pcdacTable[MAX(PWR_TABLE_SIZE,PWR_TABLE_SIZE_2413)];
81	u_int16_t ratesArray[37];
82	u_int nrates, npcdac;
83
84	s = socket(AF_INET, SOCK_DGRAM, 0);
85	if (s < 0)
86		err(1, "socket");
87	ifname = getenv("ATH");
88	if (!ifname)
89		ifname = ATH_DEFAULT;
90	while ((c = getopt(argc, argv, "i:v")) != -1)
91		switch (c) {
92		case 'i':
93			ifname = optarg;
94			break;
95		case 'v':
96			verbose++;
97			break;
98		default:
99			usage(argv[0]);
100		}
101	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
102
103	atd.ad_id = HAL_DIAG_REVS;
104	atd.ad_out_data = (caddr_t) &revs;
105	atd.ad_out_size = sizeof(revs);
106	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
107		err(1, atd.ad_name);
108
109	if (verbose)
110		printRevs(stdout, &revs);
111
112	atd.ad_id = HAL_DIAG_TXRATES;
113	atd.ad_out_data = (caddr_t) ratesArray;
114	atd.ad_out_size = sizeof(ratesArray);
115	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
116		err(1, atd.ad_name);
117	nrates = sizeof(ratesArray) / sizeof(u_int16_t);
118
119	atd.ad_id = HAL_DIAG_PCDAC;
120	atd.ad_out_data = (caddr_t) pcdacTable;
121	atd.ad_out_size = sizeof(pcdacTable);
122	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
123		err(1, atd.ad_name);
124	if (IS_2413(&revs) || IS_5413(&revs))
125		npcdac = PWR_TABLE_SIZE_2413;
126	else
127		npcdac = PWR_TABLE_SIZE;
128
129	printf("PCDAC table:\n");
130	printPcdacTable(stdout, pcdacTable, npcdac);
131
132	printf("Power per rate table:\n");
133	printPowerPerRate(stdout, ratesArray, nrates);
134
135	return 0;
136}
137
138static void
139printPcdacTable(FILE *fd, u_int16_t pcdac[], u_int n)
140{
141	int i, halfRates = n/2;
142
143	for (i = 0; i < halfRates; i += 2)
144		fprintf(fd, "[%2u] %04x %04x [%2u] %04x %04x\n",
145			i, pcdac[2*i + 1], pcdac[2*i],
146			i+1, pcdac[2*(i+1) + 1], pcdac[2*(i+1)]);
147}
148
149static void
150printPowerPerRate(FILE *fd, u_int16_t ratesArray[], u_int n)
151{
152	const char *rateString[] = {
153		" 6mb OFDM", " 9mb OFDM", "12mb OFDM", "18mb OFDM",
154		"24mb OFDM", "36mb OFDM", "48mb OFDM", "54mb OFDM",
155		"1L   CCK ", "2L   CCK ", "2S   CCK ", "5.5L CCK ",
156		"5.5S CCK ", "11L  CCK ", "11S  CCK ", "XR       "
157	};
158	int i, halfRates = n/2;
159
160	for (i = 0; i < halfRates; i++)
161		fprintf(fd, " %s %3d.%1d dBm | %s %3d.%1d dBm\n",
162			 rateString[i], ratesArray[i]/2,
163			 (ratesArray[i] %2) * 5,
164			 rateString[i + halfRates],
165			 ratesArray[i + halfRates]/2,
166			 (ratesArray[i + halfRates] %2) *5);
167}
168
169static void
170printRevs(FILE *fd, const HAL_REVS *revs)
171{
172	const char *rfbackend;
173
174	fprintf(fd, "PCI device id 0x%x subvendor id 0x%x\n",
175		revs->ah_devid, revs->ah_subvendorid);
176	fprintf(fd, "mac %d.%d phy %d.%d"
177		, revs->ah_macVersion, revs->ah_macRev
178		, revs->ah_phyRev >> 4, revs->ah_phyRev & 0xf
179	);
180	rfbackend = IS_5413(revs) ? "5413" :
181		    IS_2413(revs) ? "2413" :
182		    IS_5112(revs) ? "5112" :
183				    "5111";
184	if (revs->ah_analog5GhzRev && revs->ah_analog2GhzRev)
185		fprintf(fd, " 5ghz radio %d.%d 2ghz radio %d.%d (%s)\n"
186			, revs->ah_analog5GhzRev >> 4
187			, revs->ah_analog5GhzRev & 0xf
188			, revs->ah_analog2GhzRev >> 4
189			, revs->ah_analog2GhzRev & 0xf
190			, rfbackend
191		);
192	else
193		fprintf(fd, " radio %d.%d (%s)\n"
194			, revs->ah_analog5GhzRev >> 4
195			, revs->ah_analog5GhzRev & 0xf
196			, rfbackend
197		);
198}
199