athrd.c revision 187904
1/*-
2 * Copyright (c) 2002-2009 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: head/tools/tools/ath/athrd/athrd.c 187904 2009-01-29 23:24:21Z sam $
30 */
31#include "opt_ah.h"
32
33#include "ah.h"
34
35#include <net80211/_ieee80211.h>
36#include <net80211/ieee80211_regdomain.h>
37
38#include "ah_internal.h"
39#include "ah_eeprom_v3.h"		/* XXX */
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <stdarg.h>
44#include <string.h>
45#include <unistd.h>
46
47int		ath_hal_debug = 0;
48HAL_CTRY_CODE	cc = CTRY_DEFAULT;
49HAL_REG_DOMAIN	rd = 169;		/* FCC */
50HAL_BOOL	Amode = 1;
51HAL_BOOL	Bmode = 1;
52HAL_BOOL	Gmode = 1;
53HAL_BOOL	HT20mode = 1;
54HAL_BOOL	HT40mode = 1;
55HAL_BOOL	turbo5Disable = AH_FALSE;
56HAL_BOOL	turbo2Disable = AH_FALSE;
57
58u_int16_t	_numCtls = 8;
59u_int16_t	_ctl[32] =
60	{ 0x10, 0x13, 0x40, 0x30, 0x11, 0x31, 0x12, 0x32 };
61RD_EDGES_POWER	_rdEdgesPower[NUM_EDGES*NUM_CTLS] = {
62	{ 5180, 28, 0 },	/* 0x10 */
63	{ 5240, 60, 0 },
64	{ 5260, 36, 0 },
65	{ 5320, 27, 0 },
66	{ 5745, 36, 0 },
67	{ 5765, 36, 0 },
68	{ 5805, 36, 0 },
69	{ 5825, 36, 0 },
70
71	{ 5210, 28, 0 },	/* 0x13 */
72	{ 5250, 28, 0 },
73	{ 5290, 30, 0 },
74	{ 5760, 36, 0 },
75	{ 5800, 36, 0 },
76	{ 0, 0, 0 },
77	{ 0, 0, 0 },
78	{ 0, 0, 0 },
79
80	{ 5170, 60, 0 },	/* 0x40 */
81	{ 5230, 60, 0 },
82	{ 0, 0, 0 },
83	{ 0, 0, 0 },
84	{ 0, 0, 0 },
85	{ 0, 0, 0 },
86	{ 0, 0, 0 },
87	{ 0, 0, 0 },
88
89	{ 5180, 33, 0 },	/* 0x30 */
90	{ 5320, 33, 0 },
91	{ 5500, 34, 0 },
92	{ 5700, 34, 0 },
93	{ 5745, 35, 0 },
94	{ 5765, 35, 0 },
95	{ 5785, 35, 0 },
96	{ 5825, 35, 0 },
97
98	{ 2412, 36, 0 },	/* 0x11 */
99	{ 2417, 36, 0 },
100	{ 2422, 36, 0 },
101	{ 2432, 36, 0 },
102	{ 2442, 36, 0 },
103	{ 2457, 36, 0 },
104	{ 2467, 36, 0 },
105	{ 2472, 36, 0 },
106
107	{ 2412, 36, 0 },	/* 0x31 */
108	{ 2417, 36, 0 },
109	{ 2422, 36, 0 },
110	{ 2432, 36, 0 },
111	{ 2442, 36, 0 },
112	{ 2457, 36, 0 },
113	{ 2467, 36, 0 },
114	{ 2472, 36, 0 },
115
116	{ 2412, 36, 0 },	/* 0x12 */
117	{ 2417, 36, 0 },
118	{ 2422, 36, 0 },
119	{ 2432, 36, 0 },
120	{ 2442, 36, 0 },
121	{ 2457, 36, 0 },
122	{ 2467, 36, 0 },
123	{ 2472, 36, 0 },
124
125	{ 2412, 28, 0 },	/* 0x32 */
126	{ 2417, 28, 0 },
127	{ 2422, 28, 0 },
128	{ 2432, 28, 0 },
129	{ 2442, 28, 0 },
130	{ 2457, 28, 0 },
131	{ 2467, 28, 0 },
132	{ 2472, 28, 0 },
133};
134
135u_int16_t	turbo2WMaxPower5 = 32;
136u_int16_t	turbo2WMaxPower2;
137int8_t		antennaGainMax[2] = { 0, 0 };	/* XXX */
138int		eeversion = AR_EEPROM_VER3_1;
139TRGT_POWER_ALL_MODES tpow = {
140	8, {
141	    { 22, 24, 28, 32, 5180 },
142	    { 22, 24, 28, 32, 5200 },
143	    { 22, 24, 28, 32, 5320 },
144	    { 26, 30, 34, 34, 5500 },
145	    { 26, 30, 34, 34, 5700 },
146	    { 20, 30, 34, 36, 5745 },
147	    { 20, 30, 34, 36, 5825 },
148	    { 20, 30, 34, 36, 5850 },
149	},
150	2, {
151	    { 23, 27, 31, 34, 2412 },
152	    { 23, 27, 31, 34, 2447 },
153	},
154	2, {
155	    { 36, 36, 36, 36, 2412 },
156	    { 36, 36, 36, 36, 2484 },
157	}
158};
159#define	numTargetPwr_11a	tpow.numTargetPwr_11a
160#define	trgtPwr_11a		tpow.trgtPwr_11a
161#define	numTargetPwr_11g	tpow.numTargetPwr_11g
162#define	trgtPwr_11g		tpow.trgtPwr_11g
163#define	numTargetPwr_11b	tpow.numTargetPwr_11b
164#define	trgtPwr_11b		tpow.trgtPwr_11b
165
166static HAL_BOOL
167getChannelEdges(struct ath_hal *ah, u_int16_t flags, u_int16_t *low, u_int16_t *high)
168{
169	struct ath_hal_private *ahp = AH_PRIVATE(ah);
170	HAL_CAPABILITIES *pCap = &ahp->ah_caps;
171
172	if (flags & IEEE80211_CHAN_5GHZ) {
173		*low = pCap->halLow5GhzChan;
174		*high = pCap->halHigh5GhzChan;
175		return AH_TRUE;
176	}
177	if (flags & IEEE80211_CHAN_2GHZ) {
178		*low = pCap->halLow2GhzChan;
179		*high = pCap->halHigh2GhzChan;
180		return AH_TRUE;
181	}
182	return AH_FALSE;
183}
184
185static u_int
186getWirelessModes(struct ath_hal *ah)
187{
188	u_int mode = 0;
189
190	if (Amode) {
191		mode = HAL_MODE_11A;
192		if (!turbo5Disable)
193			mode |= HAL_MODE_TURBO;
194	}
195	if (Bmode)
196		mode |= HAL_MODE_11B;
197	if (Gmode) {
198		mode |= HAL_MODE_11G;
199		if (!turbo2Disable)
200			mode |= HAL_MODE_108G;
201	}
202	if (HT20mode)
203		mode |= HAL_MODE_11NG_HT20|HAL_MODE_11NA_HT20;
204	if (HT40mode)
205		mode |= HAL_MODE_11NG_HT40PLUS|HAL_MODE_11NA_HT40PLUS
206		     |  HAL_MODE_11NG_HT40MINUS|HAL_MODE_11NA_HT40MINUS
207		     ;
208	return mode;
209}
210
211/* Enumerated Regulatory Domain Information 8 bit values indicate that
212 * the regdomain is really a pair of unitary regdomains.  12 bit values
213 * are the real unitary regdomains and are the only ones which have the
214 * frequency bitmasks and flags set.
215 */
216
217enum EnumRd {
218	/*
219	 * The following regulatory domain definitions are
220	 * found in the EEPROM. Each regulatory domain
221	 * can operate in either a 5GHz or 2.4GHz wireless mode or
222	 * both 5GHz and 2.4GHz wireless modes.
223	 * In general, the value holds no special
224	 * meaning and is used to decode into either specific
225	 * 2.4GHz or 5GHz wireless mode for that particular
226	 * regulatory domain.
227	 */
228	NO_ENUMRD	= 0x00,
229	NULL1_WORLD	= 0x03,		/* For 11b-only countries (no 11a allowed) */
230	NULL1_ETSIB	= 0x07,		/* Israel */
231	NULL1_ETSIC	= 0x08,
232	FCC1_FCCA	= 0x10,		/* USA */
233	FCC1_WORLD	= 0x11,		/* Hong Kong */
234	FCC4_FCCA	= 0x12,		/* USA - Public Safety */
235
236	FCC2_FCCA	= 0x20,		/* Canada */
237	FCC2_WORLD	= 0x21,		/* Australia & HK */
238	FCC2_ETSIC	= 0x22,
239	FRANCE_RES	= 0x31,		/* Legacy France for OEM */
240	FCC3_FCCA	= 0x3A,		/* USA & Canada w/5470 band, 11h, DFS enabled */
241	FCC3_WORLD  = 0x3B,     /* USA & Canada w/5470 band, 11h, DFS enabled */
242
243	ETSI1_WORLD	= 0x37,
244	ETSI3_ETSIA	= 0x32,		/* France (optional) */
245	ETSI2_WORLD	= 0x35,		/* Hungary & others */
246	ETSI3_WORLD	= 0x36,		/* France & others */
247	ETSI4_WORLD	= 0x30,
248	ETSI4_ETSIC	= 0x38,
249	ETSI5_WORLD	= 0x39,
250	ETSI6_WORLD	= 0x34,		/* Bulgaria */
251	ETSI_RESERVED	= 0x33,		/* Reserved (Do not used) */
252
253	MKK1_MKKA	= 0x40,		/* Japan (JP1) */
254	MKK1_MKKB	= 0x41,		/* Japan (JP0) */
255	APL4_WORLD	= 0x42,		/* Singapore */
256	MKK2_MKKA	= 0x43,		/* Japan with 4.9G channels */
257	APL_RESERVED	= 0x44,		/* Reserved (Do not used)  */
258	APL2_WORLD	= 0x45,		/* Korea */
259	APL2_APLC	= 0x46,
260	APL3_WORLD	= 0x47,
261	MKK1_FCCA	= 0x48,		/* Japan (JP1-1) */
262	APL2_APLD	= 0x49,		/* Korea with 2.3G channels */
263	MKK1_MKKA1	= 0x4A,		/* Japan (JE1) */
264	MKK1_MKKA2	= 0x4B,		/* Japan (JE2) */
265	MKK1_MKKC	= 0x4C,		/* Japan (MKK1_MKKA,except Ch14) */
266
267	APL3_FCCA   = 0x50,
268	APL1_WORLD	= 0x52,		/* Latin America */
269	APL1_FCCA	= 0x53,
270	APL1_APLA	= 0x54,
271	APL1_ETSIC	= 0x55,
272	APL2_ETSIC	= 0x56,		/* Venezuela */
273	APL5_WORLD	= 0x58,		/* Chile */
274	APL6_WORLD	= 0x5B,		/* Singapore */
275	APL7_FCCA   = 0x5C,     /* Taiwan 5.47 Band */
276	APL8_WORLD  = 0x5D,     /* Malaysia 5GHz */
277	APL9_WORLD  = 0x5E,     /* Korea 5GHz */
278
279	/*
280	 * World mode SKUs
281	 */
282	WOR0_WORLD	= 0x60,		/* World0 (WO0 SKU) */
283	WOR1_WORLD	= 0x61,		/* World1 (WO1 SKU) */
284	WOR2_WORLD	= 0x62,		/* World2 (WO2 SKU) */
285	WOR3_WORLD	= 0x63,		/* World3 (WO3 SKU) */
286	WOR4_WORLD	= 0x64,		/* World4 (WO4 SKU) */
287	WOR5_ETSIC	= 0x65,		/* World5 (WO5 SKU) */
288
289	WOR01_WORLD	= 0x66,		/* World0-1 (WW0-1 SKU) */
290	WOR02_WORLD	= 0x67,		/* World0-2 (WW0-2 SKU) */
291	EU1_WORLD	= 0x68,		/* Same as World0-2 (WW0-2 SKU), except active scan ch1-13. No ch14 */
292
293	WOR9_WORLD	= 0x69,		/* World9 (WO9 SKU) */
294	WORA_WORLD	= 0x6A,		/* WorldA (WOA SKU) */
295
296	MKK3_MKKB	= 0x80,		/* Japan UNI-1 even + MKKB */
297	MKK3_MKKA2	= 0x81,		/* Japan UNI-1 even + MKKA2 */
298	MKK3_MKKC	= 0x82,		/* Japan UNI-1 even + MKKC */
299
300	MKK4_MKKB	= 0x83,		/* Japan UNI-1 even + UNI-2 + MKKB */
301	MKK4_MKKA2	= 0x84,		/* Japan UNI-1 even + UNI-2 + MKKA2 */
302	MKK4_MKKC	= 0x85,		/* Japan UNI-1 even + UNI-2 + MKKC */
303
304	MKK5_MKKB	= 0x86,		/* Japan UNI-1 even + UNI-2 + mid-band + MKKB */
305	MKK5_MKKA2	= 0x87,		/* Japan UNI-1 even + UNI-2 + mid-band + MKKA2 */
306	MKK5_MKKC	= 0x88,		/* Japan UNI-1 even + UNI-2 + mid-band + MKKC */
307
308	MKK6_MKKB	= 0x89,		/* Japan UNI-1 even + UNI-1 odd MKKB */
309	MKK6_MKKA2	= 0x8A,		/* Japan UNI-1 even + UNI-1 odd + MKKA2 */
310	MKK6_MKKC	= 0x8B,		/* Japan UNI-1 even + UNI-1 odd + MKKC */
311
312	MKK7_MKKB	= 0x8C,		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKB */
313	MKK7_MKKA2	= 0x8D,		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA2 */
314	MKK7_MKKC	= 0x8E,		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKC */
315
316	MKK8_MKKB	= 0x8F,		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKB */
317	MKK8_MKKA2	= 0x90,		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKA2 */
318	MKK8_MKKC	= 0x91,		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKC */
319
320	/* Following definitions are used only by s/w to map old
321 	 * Japan SKUs.
322	 */
323	MKK3_MKKA       = 0xF0,         /* Japan UNI-1 even + MKKA */
324	MKK3_MKKA1      = 0xF1,         /* Japan UNI-1 even + MKKA1 */
325	MKK3_FCCA       = 0xF2,         /* Japan UNI-1 even + FCCA */
326	MKK4_MKKA       = 0xF3,         /* Japan UNI-1 even + UNI-2 + MKKA */
327	MKK4_MKKA1      = 0xF4,         /* Japan UNI-1 even + UNI-2 + MKKA1 */
328	MKK4_FCCA       = 0xF5,         /* Japan UNI-1 even + UNI-2 + FCCA */
329	MKK9_MKKA       = 0xF6,         /* Japan UNI-1 even + 4.9GHz */
330	MKK10_MKKA      = 0xF7,         /* Japan UNI-1 even + UNI-2 + 4.9GHz */
331
332	/*
333	 * Regulator domains ending in a number (e.g. APL1,
334	 * MK1, ETSI4, etc) apply to 5GHz channel and power
335	 * information.  Regulator domains ending in a letter
336	 * (e.g. APLA, FCCA, etc) apply to 2.4GHz channel and
337	 * power information.
338	 */
339	APL1		= 0x0150,	/* LAT & Asia */
340	APL2		= 0x0250,	/* LAT & Asia */
341	APL3		= 0x0350,	/* Taiwan */
342	APL4		= 0x0450,	/* Jordan */
343	APL5		= 0x0550,	/* Chile */
344	APL6		= 0x0650,	/* Singapore */
345	APL8		= 0x0850,	/* Malaysia */
346	APL9		= 0x0950,	/* Korea (South) ROC 3 */
347
348	ETSI1		= 0x0130,	/* Europe & others */
349	ETSI2		= 0x0230,	/* Europe & others */
350	ETSI3		= 0x0330,	/* Europe & others */
351	ETSI4		= 0x0430,	/* Europe & others */
352	ETSI5		= 0x0530,	/* Europe & others */
353	ETSI6		= 0x0630,	/* Europe & others */
354	ETSIA		= 0x0A30,	/* France */
355	ETSIB		= 0x0B30,	/* Israel */
356	ETSIC		= 0x0C30,	/* Latin America */
357
358	FCC1		= 0x0110,	/* US & others */
359	FCC2		= 0x0120,	/* Canada, Australia & New Zealand */
360	FCC3		= 0x0160,	/* US w/new middle band & DFS */
361	FCC4          	= 0x0165,     	/* US Public Safety */
362	FCCA		= 0x0A10,
363
364	APLD		= 0x0D50,	/* South Korea */
365
366	MKK1		= 0x0140,	/* Japan (UNI-1 odd)*/
367	MKK2		= 0x0240,	/* Japan (4.9 GHz + UNI-1 odd) */
368	MKK3		= 0x0340,	/* Japan (UNI-1 even) */
369	MKK4		= 0x0440,	/* Japan (UNI-1 even + UNI-2) */
370	MKK5		= 0x0540,	/* Japan (UNI-1 even + UNI-2 + mid-band) */
371	MKK6		= 0x0640,	/* Japan (UNI-1 odd + UNI-1 even) */
372	MKK7		= 0x0740,	/* Japan (UNI-1 odd + UNI-1 even + UNI-2 */
373	MKK8		= 0x0840,	/* Japan (UNI-1 odd + UNI-1 even + UNI-2 + mid-band) */
374	MKK9            = 0x0940,       /* Japan (UNI-1 even + 4.9 GHZ) */
375	MKK10           = 0x0B40,       /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */
376	MKKA		= 0x0A40,	/* Japan */
377	MKKC		= 0x0A50,
378
379	NULL1		= 0x0198,
380	WORLD		= 0x0199,
381	DEBUG_REG_DMN	= 0x01ff,
382};
383#define DEF_REGDMN		FCC1_FCCA
384
385static struct {
386	const char *name;
387	HAL_REG_DOMAIN rd;
388} domains[] = {
389#define	D(_x)	{ #_x, _x }
390	D(NO_ENUMRD),
391	D(NULL1_WORLD),		/* For 11b-only countries (no 11a allowed) */
392	D(NULL1_ETSIB),		/* Israel */
393	D(NULL1_ETSIC),
394	D(FCC1_FCCA),		/* USA */
395	D(FCC1_WORLD),		/* Hong Kong */
396	D(FCC4_FCCA),		/* USA - Public Safety */
397
398	D(FCC2_FCCA),		/* Canada */
399	D(FCC2_WORLD),		/* Australia & HK */
400	D(FCC2_ETSIC),
401	D(FRANCE_RES),		/* Legacy France for OEM */
402	D(FCC3_FCCA),
403	D(FCC3_WORLD),
404
405	D(ETSI1_WORLD),
406	D(ETSI3_ETSIA),		/* France (optional) */
407	D(ETSI2_WORLD),		/* Hungary & others */
408	D(ETSI3_WORLD),		/* France & others */
409	D(ETSI4_WORLD),
410	D(ETSI4_ETSIC),
411	D(ETSI5_WORLD),
412	D(ETSI6_WORLD),		/* Bulgaria */
413	D(ETSI_RESERVED),		/* Reserved (Do not used) */
414
415	D(MKK1_MKKA),		/* Japan (JP1) */
416	D(MKK1_MKKB),		/* Japan (JP0) */
417	D(APL4_WORLD),		/* Singapore */
418	D(MKK2_MKKA),		/* Japan with 4.9G channels */
419	D(APL_RESERVED),		/* Reserved (Do not used)  */
420	D(APL2_WORLD),		/* Korea */
421	D(APL2_APLC),
422	D(APL3_WORLD),
423	D(MKK1_FCCA),		/* Japan (JP1-1) */
424	D(APL2_APLD),		/* Korea with 2.3G channels */
425	D(MKK1_MKKA1),		/* Japan (JE1) */
426	D(MKK1_MKKA2),		/* Japan (JE2) */
427	D(MKK1_MKKC),
428
429	D(APL3_FCCA),
430	D(APL1_WORLD),		/* Latin America */
431	D(APL1_FCCA),
432	D(APL1_APLA),
433	D(APL1_ETSIC),
434	D(APL2_ETSIC),		/* Venezuela */
435	D(APL5_WORLD),		/* Chile */
436	D(APL6_WORLD),		/* Singapore */
437	D(APL7_FCCA),     /* Taiwan 5.47 Band */
438	D(APL8_WORLD),     /* Malaysia 5GHz */
439	D(APL9_WORLD),     /* Korea 5GHz */
440
441	D(WOR0_WORLD),		/* World0 (WO0 SKU) */
442	D(WOR1_WORLD),		/* World1 (WO1 SKU) */
443	D(WOR2_WORLD),		/* World2 (WO2 SKU) */
444	D(WOR3_WORLD),		/* World3 (WO3 SKU) */
445	D(WOR4_WORLD),		/* World4 (WO4 SKU) */
446	D(WOR5_ETSIC),		/* World5 (WO5 SKU) */
447
448	D(WOR01_WORLD),		/* World0-1 (WW0-1 SKU) */
449	D(WOR02_WORLD),		/* World0-2 (WW0-2 SKU) */
450	D(EU1_WORLD),
451
452	D(WOR9_WORLD),		/* World9 (WO9 SKU) */
453	D(WORA_WORLD),		/* WorldA (WOA SKU) */
454
455	D(MKK3_MKKB),		/* Japan UNI-1 even + MKKB */
456	D(MKK3_MKKA2),		/* Japan UNI-1 even + MKKA2 */
457	D(MKK3_MKKC),		/* Japan UNI-1 even + MKKC */
458
459	D(MKK4_MKKB),		/* Japan UNI-1 even + UNI-2 + MKKB */
460	D(MKK4_MKKA2),		/* Japan UNI-1 even + UNI-2 + MKKA2 */
461	D(MKK4_MKKC),		/* Japan UNI-1 even + UNI-2 + MKKC */
462
463	D(MKK5_MKKB),		/* Japan UNI-1 even + UNI-2 + mid-band + MKKB */
464	D(MKK5_MKKA2),		/* Japan UNI-1 even + UNI-2 + mid-band + MKKA2 */
465	D(MKK5_MKKC),		/* Japan UNI-1 even + UNI-2 + mid-band + MKKC */
466
467	D(MKK6_MKKB),		/* Japan UNI-1 even + UNI-1 odd MKKB */
468	D(MKK6_MKKA2),		/* Japan UNI-1 even + UNI-1 odd + MKKA2 */
469	D(MKK6_MKKC),		/* Japan UNI-1 even + UNI-1 odd + MKKC */
470
471	D(MKK7_MKKB),		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKB */
472	D(MKK7_MKKA2),		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA2 */
473	D(MKK7_MKKC),		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKC */
474
475	D(MKK8_MKKB),		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKB */
476	D(MKK8_MKKA2),		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKA2 */
477	D(MKK8_MKKC),		/* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKC */
478
479	D(MKK3_MKKA),         /* Japan UNI-1 even + MKKA */
480	D(MKK3_MKKA1),         /* Japan UNI-1 even + MKKA1 */
481	D(MKK3_FCCA),         /* Japan UNI-1 even + FCCA */
482	D(MKK4_MKKA),         /* Japan UNI-1 even + UNI-2 + MKKA */
483	D(MKK4_MKKA1),         /* Japan UNI-1 even + UNI-2 + MKKA1 */
484	D(MKK4_FCCA),         /* Japan UNI-1 even + UNI-2 + FCCA */
485	D(MKK9_MKKA),         /* Japan UNI-1 even + 4.9GHz */
486	D(MKK10_MKKA),         /* Japan UNI-1 even + UNI-2 + 4.9GHz */
487
488	D(APL1),	/* LAT & Asia */
489	D(APL2),	/* LAT & Asia */
490	D(APL3),	/* Taiwan */
491	D(APL4),	/* Jordan */
492	D(APL5),	/* Chile */
493	D(APL6),	/* Singapore */
494	D(APL8),	/* Malaysia */
495	D(APL9),	/* Korea (South) ROC 3 */
496
497	D(ETSI1),	/* Europe & others */
498	D(ETSI2),	/* Europe & others */
499	D(ETSI3),	/* Europe & others */
500	D(ETSI4),	/* Europe & others */
501	D(ETSI5),	/* Europe & others */
502	D(ETSI6),	/* Europe & others */
503	D(ETSIA),	/* France */
504	D(ETSIB),	/* Israel */
505	D(ETSIC),	/* Latin America */
506
507	D(FCC1),	/* US & others */
508	D(FCC2),
509	D(FCC3),	/* US w/new middle band & DFS */
510	D(FCC4),     	/* US Public Safety */
511	D(FCCA),
512
513	D(APLD),	/* South Korea */
514
515	D(MKK1),	/* Japan (UNI-1 odd)*/
516	D(MKK2),	/* Japan (4.9 GHz + UNI-1 odd) */
517	D(MKK3),	/* Japan (UNI-1 even) */
518	D(MKK4),	/* Japan (UNI-1 even + UNI-2) */
519	D(MKK5),	/* Japan (UNI-1 even + UNI-2 + mid-band) */
520	D(MKK6),	/* Japan (UNI-1 odd + UNI-1 even) */
521	D(MKK7),	/* Japan (UNI-1 odd + UNI-1 even + UNI-2 */
522	D(MKK8),	/* Japan (UNI-1 odd + UNI-1 even + UNI-2 + mid-band) */
523	D(MKK9),       /* Japan (UNI-1 even + 4.9 GHZ) */
524	D(MKK10),       /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */
525	D(MKKA),	/* Japan */
526	D(MKKC),
527
528	D(NULL1),
529	D(WORLD),
530	D(DEBUG_REG_DMN),
531#undef D
532};
533
534static HAL_BOOL
535rdlookup(const char *name, HAL_REG_DOMAIN *rd)
536{
537#define	N(a)	(sizeof(a)/sizeof(a[0]))
538	int i;
539
540	for (i = 0; i < N(domains); i++)
541		if (strcasecmp(domains[i].name, name) == 0) {
542			*rd = domains[i].rd;
543			return AH_TRUE;
544		}
545	return AH_FALSE;
546#undef N
547}
548
549static const char *
550getrdname(HAL_REG_DOMAIN rd)
551{
552#define	N(a)	(sizeof(a)/sizeof(a[0]))
553	int i;
554
555	for (i = 0; i < N(domains); i++)
556		if (domains[i].rd == rd)
557			return domains[i].name;
558	return NULL;
559#undef N
560}
561
562static void
563rdlist()
564{
565#define	N(a)	(sizeof(a)/sizeof(a[0]))
566	int i;
567
568	printf("\nRegulatory domains:\n\n");
569	for (i = 0; i < N(domains); i++)
570		printf("%-15s%s", domains[i].name,
571			((i+1)%5) == 0 ? "\n" : "");
572	printf("\n");
573#undef N
574}
575
576typedef struct {
577	HAL_CTRY_CODE	countryCode;
578	HAL_REG_DOMAIN	regDmnEnum;
579	const char*	isoName;
580	const char*	name;
581} COUNTRY_CODE_TO_ENUM_RD;
582
583/*
584 * Country Code Table to Enumerated RD
585 */
586static COUNTRY_CODE_TO_ENUM_RD allCountries[] = {
587    {CTRY_DEBUG,       NO_ENUMRD,     "DB", "DEBUG" },
588    {CTRY_DEFAULT,     DEF_REGDMN,    "NA", "NO_COUNTRY_SET" },
589    {CTRY_ALBANIA,     NULL1_WORLD,   "AL", "ALBANIA" },
590    {CTRY_ALGERIA,     NULL1_WORLD,   "DZ", "ALGERIA" },
591    {CTRY_ARGENTINA,   APL3_WORLD,    "AR", "ARGENTINA" },
592    {CTRY_ARMENIA,     ETSI4_WORLD,   "AM", "ARMENIA" },
593    {CTRY_AUSTRALIA,   FCC2_WORLD,    "AU", "AUSTRALIA" },
594    {CTRY_AUSTRIA,     ETSI1_WORLD,   "AT", "AUSTRIA" },
595    {CTRY_AZERBAIJAN,  ETSI4_WORLD,   "AZ", "AZERBAIJAN" },
596    {CTRY_BAHRAIN,     APL6_WORLD,   "BH", "BAHRAIN" },
597    {CTRY_BELARUS,     NULL1_WORLD,   "BY", "BELARUS" },
598    {CTRY_BELGIUM,     ETSI1_WORLD,   "BE", "BELGIUM" },
599    {CTRY_BELIZE,      APL1_ETSIC,    "BZ", "BELIZE" },
600    {CTRY_BOLIVIA,     APL1_ETSIC,    "BO", "BOLVIA" },
601    {CTRY_BRAZIL,      FCC3_WORLD,    "BR", "BRAZIL" },
602    {CTRY_BRUNEI_DARUSSALAM,APL1_WORLD,"BN", "BRUNEI DARUSSALAM" },
603    {CTRY_BULGARIA,    ETSI6_WORLD,   "BG", "BULGARIA" },
604    {CTRY_CANADA,      FCC2_FCCA,     "CA", "CANADA" },
605    {CTRY_CHILE,       APL6_WORLD,    "CL", "CHILE" },
606    {CTRY_CHINA,       APL1_WORLD,    "CN", "CHINA" },
607    {CTRY_COLOMBIA,    FCC1_FCCA,     "CO", "COLOMBIA" },
608    {CTRY_COSTA_RICA,  NULL1_WORLD,   "CR", "COSTA RICA" },
609    {CTRY_CROATIA,     ETSI3_WORLD,   "HR", "CROATIA" },
610    {CTRY_CYPRUS,      ETSI1_WORLD,   "CY", "CYPRUS" },
611    {CTRY_CZECH,       ETSI3_WORLD,   "CZ", "CZECH REPUBLIC" },
612    {CTRY_DENMARK,     ETSI1_WORLD,   "DK", "DENMARK" },
613    {CTRY_DOMINICAN_REPUBLIC,FCC1_FCCA,"DO", "DOMINICAN REPUBLIC" },
614    {CTRY_ECUADOR,     NULL1_WORLD,   "EC", "ECUADOR" },
615    {CTRY_EGYPT,       ETSI3_WORLD,   "EG", "EGYPT" },
616    {CTRY_EL_SALVADOR, NULL1_WORLD,   "SV", "EL SALVADOR" },
617    {CTRY_ESTONIA,     ETSI1_WORLD,   "EE", "ESTONIA" },
618    {CTRY_FINLAND,     ETSI1_WORLD,   "FI", "FINLAND" },
619    {CTRY_FRANCE,      ETSI3_WORLD,   "FR", "FRANCE" },
620    {CTRY_FRANCE2,     ETSI3_WORLD,   "F2", "FRANCE_RES" },
621    {CTRY_GEORGIA,     ETSI4_WORLD,   "GE", "GEORGIA" },
622    {CTRY_GERMANY,     ETSI1_WORLD,   "DE", "GERMANY" },
623    {CTRY_GREECE,      ETSI1_WORLD,   "GR", "GREECE" },
624    {CTRY_GUATEMALA,   FCC1_FCCA,     "GT", "GUATEMALA" },
625    {CTRY_HONDURAS,    NULL1_WORLD,   "HN", "HONDURAS" },
626    {CTRY_HONG_KONG,   FCC2_WORLD,    "HK", "HONG KONG" },
627    {CTRY_HUNGARY,     ETSI1_WORLD,   "HU", "HUNGARY" },
628    {CTRY_ICELAND,     ETSI1_WORLD,   "IS", "ICELAND" },
629    {CTRY_INDIA,       APL6_WORLD,    "IN", "INDIA" },
630    {CTRY_INDONESIA,   APL1_WORLD,    "ID", "INDONESIA" },
631    {CTRY_IRAN,        APL1_WORLD,    "IR", "IRAN" },
632    {CTRY_IRELAND,     ETSI1_WORLD,   "IE", "IRELAND" },
633    {CTRY_ISRAEL,      NULL1_WORLD,   "IL", "ISRAEL" },
634    {CTRY_ITALY,       ETSI1_WORLD,   "IT", "ITALY" },
635    {CTRY_JAPAN,       MKK1_MKKA,     "JP", "JAPAN" },
636    {CTRY_JAPAN1,      MKK1_MKKB,     "JP", "JAPAN1" },
637    {CTRY_JAPAN2,      MKK1_FCCA,     "JP", "JAPAN2" },
638    {CTRY_JAPAN3,      MKK2_MKKA,     "JP", "JAPAN3" },
639    {CTRY_JAPAN4,      MKK1_MKKA1,    "JP", "JAPAN4" },
640    {CTRY_JAPAN5,      MKK1_MKKA2,    "JP", "JAPAN5" },
641    {CTRY_JAPAN6,      MKK1_MKKC,     "JP", "JAPAN6" },
642
643    {CTRY_JAPAN7,      MKK3_MKKB,     "JP", "JAPAN7" },
644    {CTRY_JAPAN8,      MKK3_MKKA2,    "JP", "JAPAN8" },
645    {CTRY_JAPAN9,      MKK3_MKKC,     "JP", "JAPAN9" },
646
647    {CTRY_JAPAN10,      MKK4_MKKB,     "JP", "JAPAN10" },
648    {CTRY_JAPAN11,      MKK4_MKKA2,    "JP", "JAPAN11" },
649    {CTRY_JAPAN12,      MKK4_MKKC,     "JP", "JAPAN12" },
650
651    {CTRY_JAPAN13,      MKK5_MKKB,     "JP", "JAPAN13" },
652    {CTRY_JAPAN14,      MKK5_MKKA2,    "JP", "JAPAN14" },
653    {CTRY_JAPAN15,      MKK5_MKKC,     "JP", "JAPAN15" },
654
655    {CTRY_JAPAN16,      MKK6_MKKB,     "JP", "JAPAN16" },
656    {CTRY_JAPAN17,      MKK6_MKKA2,    "JP", "JAPAN17" },
657    {CTRY_JAPAN18,      MKK6_MKKC,     "JP", "JAPAN18" },
658
659    {CTRY_JAPAN19,      MKK7_MKKB,     "JP", "JAPAN19" },
660    {CTRY_JAPAN20,      MKK7_MKKA2,    "JP", "JAPAN20" },
661    {CTRY_JAPAN21,      MKK7_MKKC,     "JP", "JAPAN21" },
662
663    {CTRY_JAPAN22,      MKK8_MKKB,     "JP", "JAPAN22" },
664    {CTRY_JAPAN23,      MKK8_MKKA2,    "JP", "JAPAN23" },
665    {CTRY_JAPAN24,      MKK8_MKKC,     "JP", "JAPAN24" },
666
667    {CTRY_JORDAN,      APL4_WORLD,    "JO", "JORDAN" },
668    {CTRY_KAZAKHSTAN,  NULL1_WORLD,   "KZ", "KAZAKHSTAN" },
669    {CTRY_KOREA_NORTH, APL2_WORLD,    "KP", "NORTH KOREA" },
670    {CTRY_KOREA_ROC,   APL2_WORLD,    "KR", "KOREA REPUBLIC" },
671    {CTRY_KOREA_ROC2,  APL2_WORLD,    "K2", "KOREA REPUBLIC2" },
672    {CTRY_KOREA_ROC3,  APL9_WORLD,    "K3", "KOREA REPUBLIC3" },
673    {CTRY_KUWAIT,      NULL1_WORLD,   "KW", "KUWAIT" },
674    {CTRY_LATVIA,      ETSI1_WORLD,   "LV", "LATVIA" },
675    {CTRY_LEBANON,     NULL1_WORLD,   "LB", "LEBANON" },
676    {CTRY_LIECHTENSTEIN,ETSI1_WORLD,  "LI", "LIECHTENSTEIN" },
677    {CTRY_LITHUANIA,   ETSI1_WORLD,   "LT", "LITHUANIA" },
678    {CTRY_LUXEMBOURG,  ETSI1_WORLD,   "LU", "LUXEMBOURG" },
679    {CTRY_MACAU,       FCC2_WORLD,    "MO", "MACAU" },
680    {CTRY_MACEDONIA,   NULL1_WORLD,   "MK", "MACEDONIA" },
681    {CTRY_MALAYSIA,    APL8_WORLD,    "MY", "MALAYSIA" },
682    {CTRY_MALTA,       ETSI1_WORLD,   "MT", "MALTA" },
683    {CTRY_MEXICO,      FCC1_FCCA,     "MX", "MEXICO" },
684    {CTRY_MONACO,      ETSI4_WORLD,   "MC", "MONACO" },
685    {CTRY_MOROCCO,     NULL1_WORLD,   "MA", "MOROCCO" },
686    {CTRY_NETHERLANDS, ETSI1_WORLD,   "NL", "NETHERLANDS" },
687    {CTRY_NEW_ZEALAND, FCC2_ETSIC,    "NZ", "NEW ZEALAND" },
688    {CTRY_NORWAY,      ETSI1_WORLD,   "NO", "NORWAY" },
689    {CTRY_OMAN,        APL6_WORLD,    "OM", "OMAN" },
690    {CTRY_PAKISTAN,    NULL1_WORLD,   "PK", "PAKISTAN" },
691    {CTRY_PANAMA,      FCC1_FCCA,     "PA", "PANAMA" },
692    {CTRY_PERU,        APL1_WORLD,    "PE", "PERU" },
693    {CTRY_PHILIPPINES, APL1_WORLD,    "PH", "PHILIPPINES" },
694    {CTRY_POLAND,      ETSI1_WORLD,   "PL", "POLAND" },
695    {CTRY_PORTUGAL,    ETSI1_WORLD,   "PT", "PORTUGAL" },
696    {CTRY_PUERTO_RICO, FCC1_FCCA,     "PR", "PUERTO RICO" },
697    {CTRY_QATAR,       NULL1_WORLD,   "QA", "QATAR" },
698    {CTRY_ROMANIA,     NULL1_WORLD,   "RO", "ROMANIA" },
699    {CTRY_RUSSIA,      NULL1_WORLD,   "RU", "RUSSIA" },
700    {CTRY_SAUDI_ARABIA,NULL1_WORLD,   "SA", "SAUDI ARABIA" },
701    {CTRY_SINGAPORE,   APL6_WORLD,    "SG", "SINGAPORE" },
702    {CTRY_SLOVAKIA,    ETSI1_WORLD,   "SK", "SLOVAK REPUBLIC" },
703    {CTRY_SLOVENIA,    ETSI1_WORLD,   "SI", "SLOVENIA" },
704    {CTRY_SOUTH_AFRICA,FCC3_WORLD,    "ZA", "SOUTH AFRICA" },
705    {CTRY_SPAIN,       ETSI1_WORLD,   "ES", "SPAIN" },
706    {CTRY_SWEDEN,      ETSI1_WORLD,   "SE", "SWEDEN" },
707    {CTRY_SWITZERLAND, ETSI1_WORLD,   "CH", "SWITZERLAND" },
708    {CTRY_SYRIA,       NULL1_WORLD,   "SY", "SYRIA" },
709    {CTRY_TAIWAN,      APL3_FCCA,    "TW", "TAIWAN" },
710    {CTRY_THAILAND,    NULL1_WORLD,   "TH", "THAILAND" },
711    {CTRY_TRINIDAD_Y_TOBAGO,ETSI4_WORLD,"TT", "TRINIDAD & TOBAGO" },
712    {CTRY_TUNISIA,     ETSI3_WORLD,   "TN", "TUNISIA" },
713    {CTRY_TURKEY,      ETSI3_WORLD,   "TR", "TURKEY" },
714    {CTRY_UKRAINE,     NULL1_WORLD,   "UA", "UKRAINE" },
715    {CTRY_UAE,         NULL1_WORLD,   "AE", "UNITED ARAB EMIRATES" },
716    {CTRY_UNITED_KINGDOM, ETSI1_WORLD,"GB", "UNITED KINGDOM" },
717    {CTRY_UNITED_STATES, FCC1_FCCA,   "US", "UNITED STATES" },
718    {CTRY_UNITED_STATES_FCC49, FCC4_FCCA,   "PS", "UNITED STATES (PUBLIC SAFETY)" },
719    {CTRY_URUGUAY,     APL2_WORLD,    "UY", "URUGUAY" },
720    {CTRY_UZBEKISTAN,  FCC3_FCCA,     "UZ", "UZBEKISTAN" },
721    {CTRY_VENEZUELA,   APL2_ETSIC,    "VE", "VENEZUELA" },
722    {CTRY_VIET_NAM,    NULL1_WORLD,   "VN", "VIET NAM" },
723    {CTRY_YEMEN,       NULL1_WORLD,   "YE", "YEMEN" },
724    {CTRY_ZIMBABWE,    NULL1_WORLD,   "ZW", "ZIMBABWE" }
725};
726
727static HAL_BOOL
728cclookup(const char *name, HAL_REG_DOMAIN *rd, HAL_CTRY_CODE *cc)
729{
730#define	N(a)	(sizeof(a)/sizeof(a[0]))
731	int i;
732
733	for (i = 0; i < N(allCountries); i++)
734		if (strcasecmp(allCountries[i].isoName, name) == 0 ||
735		    strcasecmp(allCountries[i].name, name) == 0) {
736			*rd = allCountries[i].regDmnEnum;
737			*cc = allCountries[i].countryCode;
738			return AH_TRUE;
739		}
740	return AH_FALSE;
741#undef N
742}
743
744static const char *
745getccname(HAL_CTRY_CODE cc)
746{
747#define	N(a)	(sizeof(a)/sizeof(a[0]))
748	int i;
749
750	for (i = 0; i < N(allCountries); i++)
751		if (allCountries[i].countryCode == cc)
752			return allCountries[i].name;
753	return NULL;
754#undef N
755}
756
757static const char *
758getccisoname(HAL_CTRY_CODE cc)
759{
760#define	N(a)	(sizeof(a)/sizeof(a[0]))
761	int i;
762
763	for (i = 0; i < N(allCountries); i++)
764		if (allCountries[i].countryCode == cc)
765			return allCountries[i].isoName;
766	return NULL;
767#undef N
768}
769
770static void
771cclist()
772{
773#define	N(a)	(sizeof(a)/sizeof(a[0]))
774	int i;
775
776	printf("\nCountry codes:\n");
777	for (i = 0; i < N(allCountries); i++)
778		printf("%2s %-15.15s%s",
779			allCountries[i].isoName,
780			allCountries[i].name,
781			((i+1)%4) == 0 ? "\n" : " ");
782	printf("\n");
783#undef N
784}
785
786static HAL_BOOL
787setRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan,
788		   int16_t tpcScaleReduction, int16_t powerLimit,
789                   int16_t *pMinPower, int16_t *pMaxPower);
790
791static void
792calctxpower(struct ath_hal *ah,
793	int nchan, const struct ieee80211_channel *chans,
794	int16_t tpcScaleReduction, int16_t powerLimit, int16_t *txpow)
795{
796	int16_t minpow;
797	int i;
798
799	for (i = 0; i < nchan; i++)
800		if (!setRateTable(ah, &chans[i],
801		    tpcScaleReduction, powerLimit, &minpow, &txpow[i])) {
802			printf("unable to set rate table\n");
803			exit(-1);
804		}
805}
806
807int	n = 1;
808const char *sep = "";
809int	dopassive = 0;
810int	showchannels = 0;
811int	isdfs = 0;
812int	is4ms = 0;
813
814static int
815anychan(const struct ieee80211_channel *chans, int nc, int flag)
816{
817	int i;
818
819	for (i = 0; i < nc; i++)
820		if ((chans[i].ic_flags & flag) != 0)
821			return 1;
822	return 0;
823}
824
825static __inline int
826mapgsm(u_int freq, u_int flags)
827{
828	freq *= 10;
829	if (flags & IEEE80211_CHAN_QUARTER)
830		freq += 5;
831	else if (flags & IEEE80211_CHAN_HALF)
832		freq += 10;
833	else
834		freq += 20;
835	return (freq - 24220) / 5;
836}
837
838static __inline int
839mappsb(u_int freq, u_int flags)
840{
841	return ((freq * 10) + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
842}
843
844/*
845 * Convert GHz frequency to IEEE channel number.
846 */
847int
848ath_hal_mhz2ieee(struct ath_hal *ah, u_int freq, u_int flags)
849{
850	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
851		if (freq == 2484)
852			return 14;
853		if (freq < 2484)
854			return ((int)freq - 2407) / 5;
855		else
856			return 15 + ((freq - 2512) / 20);
857	} else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
858		if (IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq))
859			return mappsb(freq, flags);
860		else if ((flags & IEEE80211_CHAN_A) && (freq <= 5000))
861			return (freq - 4000) / 5;
862		else
863			return (freq - 5000) / 5;
864	} else {			/* either, guess */
865		if (freq == 2484)
866			return 14;
867		if (freq < 2484)
868			return ((int)freq - 2407) / 5;
869		if (freq < 5000) {
870			if (IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq))
871				return mappsb(freq, flags);
872			else if (freq > 4900)
873				return (freq - 4000) / 5;
874			else
875				return 15 + ((freq - 2512) / 20);
876		}
877		return (freq - 5000) / 5;
878	}
879}
880
881#define	IEEE80211_IS_CHAN_4MS(_c) \
882	(((_c)->ic_flags & IEEE80211_CHAN_4MSXMIT) != 0)
883
884static void
885dumpchannels(struct ath_hal *ah, int nc,
886	const struct ieee80211_channel *chans, int16_t *txpow)
887{
888	int i;
889
890	for (i = 0; i < nc; i++) {
891		const struct ieee80211_channel *c = &chans[i];
892		int type;
893
894		if (showchannels)
895			printf("%s%3d", sep,
896			    ath_hal_mhz2ieee(ah, c->ic_freq, c->ic_flags));
897		else
898			printf("%s%u", sep, c->ic_freq);
899		if (IEEE80211_IS_CHAN_HALF(c))
900			type = 'H';
901		else if (IEEE80211_IS_CHAN_QUARTER(c))
902			type = 'Q';
903		else if (IEEE80211_IS_CHAN_TURBO(c))
904			type = 'T';
905		else if (IEEE80211_IS_CHAN_HT(c))
906			type = 'N';
907		else if (IEEE80211_IS_CHAN_A(c))
908			type = 'A';
909		else if (IEEE80211_IS_CHAN_108G(c))
910			type = 'T';
911		else if (IEEE80211_IS_CHAN_G(c))
912			type = 'G';
913		else
914			type = 'B';
915		if (dopassive && IEEE80211_IS_CHAN_PASSIVE(c))
916			type = tolower(type);
917		if (isdfs && is4ms)
918			printf("%c%c%c %d.%d", type,
919			    IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ',
920			    IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ',
921			    txpow[i]/2, (txpow[i]%2)*5);
922		else if (isdfs)
923			printf("%c%c %d.%d", type,
924			    IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ',
925			    txpow[i]/2, (txpow[i]%2)*5);
926		else if (is4ms)
927			printf("%c%c %d.%d", type,
928			    IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ',
929			    txpow[i]/2, (txpow[i]%2)*5);
930		else
931			printf("%c %d.%d", type, txpow[i]/2, (txpow[i]%2)*5);
932		if ((n++ % (showchannels ? 7 : 6)) == 0)
933			sep = "\n";
934		else
935			sep = " ";
936	}
937}
938
939static void
940intersect(struct ieee80211_channel *dst, int16_t *dtxpow, int *nd,
941    const struct ieee80211_channel *src, int16_t *stxpow, int ns)
942{
943	int i = 0, j, k, l;
944	while (i < *nd) {
945		for (j = 0; j < ns && dst[i].ic_freq != src[j].ic_freq; j++)
946			;
947		if (j < ns && dtxpow[i] == stxpow[j]) {
948			for (k = i+1, l = i; k < *nd; k++, l++)
949				dst[l] = dst[k];
950			(*nd)--;
951		} else
952			i++;
953	}
954}
955
956static void
957usage(const char *progname)
958{
959	printf("usage: %s [-acdefoilpr4ABGT] [-m opmode] [cc | rd]\n", progname);
960	exit(-1);
961}
962
963static HAL_BOOL
964getChipPowerLimits(struct ath_hal *ah, struct ieee80211_channel *chan)
965{
966}
967
968static HAL_BOOL
969eepromRead(struct ath_hal *ah, u_int off, u_int16_t *data)
970{
971	/* emulate enough stuff to handle japan channel shift */
972	switch (off) {
973	case AR_EEPROM_VERSION:
974		*data = eeversion;
975		return AH_TRUE;
976	case AR_EEPROM_REG_CAPABILITIES_OFFSET:
977		*data = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A;
978		return AH_TRUE;
979	case AR_EEPROM_REG_CAPABILITIES_OFFSET_PRE4_0:
980		*data = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0;
981		return AH_TRUE;
982	}
983	return AH_FALSE;
984}
985
986HAL_STATUS
987getCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
988	uint32_t capability, uint32_t *result)
989{
990	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
991
992	switch (type) {
993	case HAL_CAP_REG_DMN:		/* regulatory domain */
994		*result = AH_PRIVATE(ah)->ah_currentRD;
995		return HAL_OK;
996	default:
997		return HAL_EINVAL;
998	}
999}
1000
1001#define HAL_MODE_HT20 \
1002	(HAL_MODE_11NG_HT20 |  HAL_MODE_11NA_HT20)
1003#define	HAL_MODE_HT40 \
1004	(HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \
1005	 HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS)
1006#define	HAL_MODE_HT	(HAL_MODE_HT20 | HAL_MODE_HT40)
1007
1008int
1009main(int argc, char *argv[])
1010{
1011	static const u_int16_t tpcScaleReductionTable[5] =
1012		{ 0, 3, 6, 9, MAX_RATE_POWER };
1013	struct ath_hal_private ahp;
1014	struct ieee80211_channel achans[IEEE80211_CHAN_MAX];
1015	int16_t atxpow[IEEE80211_CHAN_MAX];
1016	struct ieee80211_channel bchans[IEEE80211_CHAN_MAX];
1017	int16_t btxpow[IEEE80211_CHAN_MAX];
1018	struct ieee80211_channel gchans[IEEE80211_CHAN_MAX];
1019	int16_t gtxpow[IEEE80211_CHAN_MAX];
1020	struct ieee80211_channel tchans[IEEE80211_CHAN_MAX];
1021	int16_t ttxpow[IEEE80211_CHAN_MAX];
1022	struct ieee80211_channel tgchans[IEEE80211_CHAN_MAX];
1023	int16_t tgtxpow[IEEE80211_CHAN_MAX];
1024	struct ieee80211_channel nchans[IEEE80211_CHAN_MAX];
1025	int16_t ntxpow[IEEE80211_CHAN_MAX];
1026	int i, na, nb, ng, nt, ntg, nn;
1027	HAL_BOOL showall = AH_FALSE;
1028	HAL_BOOL extendedChanMode = AH_TRUE;
1029	int modes = 0;
1030	int16_t tpcReduction, powerLimit;
1031	int showdfs = 0;
1032	int show4ms = 0;
1033
1034	memset(&ahp, 0, sizeof(ahp));
1035	ahp.ah_getChannelEdges = getChannelEdges;
1036	ahp.ah_getWirelessModes = getWirelessModes;
1037	ahp.ah_eepromRead = eepromRead;
1038	ahp.ah_getChipPowerLimits = getChipPowerLimits;
1039	ahp.ah_caps.halWirelessModes = HAL_MODE_ALL;
1040	ahp.ah_caps.halLow5GhzChan = 4920;
1041	ahp.ah_caps.halHigh5GhzChan = 6100;
1042	ahp.ah_caps.halLow2GhzChan = 2312;
1043	ahp.ah_caps.halHigh2GhzChan = 2732;
1044	ahp.ah_caps.halChanHalfRate = AH_TRUE;
1045	ahp.ah_caps.halChanQuarterRate = AH_TRUE;
1046	ahp.h.ah_getCapability = getCapability;
1047	ahp.ah_opmode = HAL_M_STA;
1048
1049	tpcReduction = tpcScaleReductionTable[0];
1050	powerLimit =  MAX_RATE_POWER;
1051
1052	while ((i = getopt(argc, argv, "acdeflm:pr4ABGhHNT")) != -1)
1053		switch (i) {
1054		case 'a':
1055			showall = AH_TRUE;
1056			break;
1057		case 'c':
1058			showchannels = AH_TRUE;
1059			break;
1060		case 'd':
1061			ath_hal_debug = HAL_DEBUG_ANY;
1062			break;
1063		case 'e':
1064			extendedChanMode = AH_FALSE;
1065			break;
1066		case 'f':
1067			showchannels = AH_FALSE;
1068			break;
1069		case 'l':
1070			cclist();
1071			rdlist();
1072			exit(0);
1073		case 'm':
1074			if (strncasecmp(optarg, "sta", 2) == 0)
1075				ahp.ah_opmode = HAL_M_STA;
1076			else if (strncasecmp(optarg, "ibss", 2) == 0)
1077				ahp.ah_opmode = HAL_M_IBSS;
1078			else if (strncasecmp(optarg, "adhoc", 2) == 0)
1079				ahp.ah_opmode = HAL_M_IBSS;
1080			else if (strncasecmp(optarg, "ap", 2) == 0)
1081				ahp.ah_opmode = HAL_M_HOSTAP;
1082			else if (strncasecmp(optarg, "hostap", 2) == 0)
1083				ahp.ah_opmode = HAL_M_HOSTAP;
1084			else if (strncasecmp(optarg, "monitor", 2) == 0)
1085				ahp.ah_opmode = HAL_M_MONITOR;
1086			else
1087				usage(argv[0]);
1088			break;
1089		case 'p':
1090			dopassive = 1;
1091			break;
1092		case 'A':
1093			modes |= HAL_MODE_11A;
1094			break;
1095		case 'B':
1096			modes |= HAL_MODE_11B;
1097			break;
1098		case 'G':
1099			modes |= HAL_MODE_11G;
1100			break;
1101		case 'h':
1102			modes |= HAL_MODE_HT20;
1103			break;
1104		case 'H':
1105			modes |= HAL_MODE_HT40;
1106			break;
1107		case 'N':
1108			modes |= HAL_MODE_HT;
1109			break;
1110		case 'T':
1111			modes |= HAL_MODE_TURBO | HAL_MODE_108G;
1112			break;
1113		case 'r':
1114			showdfs = 1;
1115			break;
1116		case '4':
1117			show4ms = 1;
1118			break;
1119		default:
1120			usage(argv[0]);
1121		}
1122	switch (argc - optind)  {
1123	case 0:
1124		if (!cclookup("US", &rd, &cc)) {
1125			printf("%s: unknown country code\n", "US");
1126			exit(-1);
1127		}
1128		break;
1129	case 1:			/* cc/regdomain */
1130		if (!cclookup(argv[optind], &rd, &cc)) {
1131			if (!rdlookup(argv[optind], &rd)) {
1132				const char* rdname;
1133
1134				rd = strtoul(argv[optind], NULL, 0);
1135				rdname = getrdname(rd);
1136				if (rdname == NULL) {
1137					printf("%s: unknown country/regulatory "
1138						"domain code\n", argv[optind]);
1139					exit(-1);
1140				}
1141			}
1142			cc = CTRY_DEFAULT;
1143		}
1144		break;
1145	default:		/* regdomain cc */
1146		if (!rdlookup(argv[optind], &rd)) {
1147			const char* rdname;
1148
1149			rd = strtoul(argv[optind], NULL, 0);
1150			rdname = getrdname(rd);
1151			if (rdname == NULL) {
1152				printf("%s: unknown country/regulatory "
1153					"domain code\n", argv[optind]);
1154				exit(-1);
1155			}
1156		}
1157		if (!cclookup(argv[optind+1], &rd, &cc))
1158			cc = strtoul(argv[optind+1], NULL, 0);
1159		break;
1160	}
1161	if (cc != CTRY_DEFAULT)
1162		printf("\n%s (%s, 0x%x, %u) %s (0x%x, %u)\n",
1163			getccname(cc), getccisoname(cc), cc, cc,
1164			getrdname(rd), rd, rd);
1165	else
1166		printf("\n%s (0x%x, %u)\n",
1167			getrdname(rd), rd, rd);
1168
1169	if (modes == 0) {
1170		/* NB: no HAL_MODE_HT */
1171		modes = HAL_MODE_11A | HAL_MODE_11B |
1172			HAL_MODE_11G | HAL_MODE_TURBO | HAL_MODE_108G;
1173	}
1174	na = nb = ng = nt = ntg = nn = 0;
1175	if (modes & HAL_MODE_11G) {
1176		ahp.ah_currentRD = rd;
1177		if (ath_hal_getchannels(&ahp.h, gchans, IEEE80211_CHAN_MAX, &ng,
1178		    HAL_MODE_11G, cc, rd, extendedChanMode) == HAL_OK) {
1179			calctxpower(&ahp.h, ng, gchans, tpcReduction, powerLimit, gtxpow);
1180			if (showdfs)
1181				isdfs |= anychan(gchans, ng, IEEE80211_CHAN_DFS);
1182			if (show4ms)
1183				is4ms |= anychan(gchans, ng, IEEE80211_CHAN_4MSXMIT);
1184		}
1185	}
1186	if (modes & HAL_MODE_11B) {
1187		ahp.ah_currentRD = rd;
1188		if (ath_hal_getchannels(&ahp.h, bchans, IEEE80211_CHAN_MAX, &nb,
1189		    HAL_MODE_11B, cc, rd, extendedChanMode) == HAL_OK) {
1190			calctxpower(&ahp.h, nb, bchans, tpcReduction, powerLimit, btxpow);
1191			if (showdfs)
1192				isdfs |= anychan(bchans, nb, IEEE80211_CHAN_DFS);
1193			if (show4ms)
1194				is4ms |= anychan(bchans, nb, IEEE80211_CHAN_4MSXMIT);
1195		}
1196	}
1197	if (modes & HAL_MODE_11A) {
1198		ahp.ah_currentRD = rd;
1199		if (ath_hal_getchannels(&ahp.h, achans, IEEE80211_CHAN_MAX, &na,
1200		    HAL_MODE_11A, cc, rd, extendedChanMode) == HAL_OK) {
1201			calctxpower(&ahp.h, na, achans, tpcReduction, powerLimit, atxpow);
1202			if (showdfs)
1203				isdfs |= anychan(achans, na, IEEE80211_CHAN_DFS);
1204			if (show4ms)
1205				is4ms |= anychan(achans, na, IEEE80211_CHAN_4MSXMIT);
1206		}
1207	}
1208	if (modes & HAL_MODE_TURBO) {
1209		ahp.ah_currentRD = rd;
1210		if (ath_hal_getchannels(&ahp.h, tchans, IEEE80211_CHAN_MAX, &nt,
1211		    HAL_MODE_TURBO, cc, rd, extendedChanMode) == HAL_OK) {
1212			calctxpower(&ahp.h, nt, tchans, tpcReduction, powerLimit, ttxpow);
1213			if (showdfs)
1214				isdfs |= anychan(tchans, nt, IEEE80211_CHAN_DFS);
1215			if (show4ms)
1216				is4ms |= anychan(tchans, nt, IEEE80211_CHAN_4MSXMIT);
1217		}
1218	}
1219	if (modes & HAL_MODE_108G) {
1220		ahp.ah_currentRD = rd;
1221		if (ath_hal_getchannels(&ahp.h, tgchans, IEEE80211_CHAN_MAX, &ntg,
1222		    HAL_MODE_108G, cc, rd, extendedChanMode) == HAL_OK) {
1223			calctxpower(&ahp.h, ntg, tgchans, tpcReduction, powerLimit, tgtxpow);
1224			if (showdfs)
1225				isdfs |= anychan(tgchans, ntg, IEEE80211_CHAN_DFS);
1226			if (show4ms)
1227				is4ms |= anychan(tgchans, ntg, IEEE80211_CHAN_4MSXMIT);
1228		}
1229	}
1230	if (modes & HAL_MODE_HT) {
1231		ahp.ah_currentRD = rd;
1232		if (ath_hal_getchannels(&ahp.h, nchans, IEEE80211_CHAN_MAX, &nn,
1233		    modes & HAL_MODE_HT, cc, rd, extendedChanMode) == HAL_OK) {
1234			calctxpower(&ahp.h, nn, nchans, tpcReduction, powerLimit, ntxpow);
1235			if (showdfs)
1236				isdfs |= anychan(nchans, nn, IEEE80211_CHAN_DFS);
1237			if (show4ms)
1238				is4ms |= anychan(nchans, nn, IEEE80211_CHAN_4MSXMIT);
1239		}
1240	}
1241
1242	if (!showall) {
1243#define	CHECKMODES(_modes, _m)	((_modes & (_m)) == (_m))
1244		if (CHECKMODES(modes, HAL_MODE_11B|HAL_MODE_11G)) {
1245			/* b ^= g */
1246			intersect(bchans, btxpow, &nb, gchans, gtxpow, ng);
1247		}
1248		if (CHECKMODES(modes, HAL_MODE_11A|HAL_MODE_TURBO)) {
1249			/* t ^= a */
1250			intersect(tchans, ttxpow, &nt, achans, atxpow, na);
1251		}
1252		if (CHECKMODES(modes, HAL_MODE_11G|HAL_MODE_108G)) {
1253			/* tg ^= g */
1254			intersect(tgchans, tgtxpow, &ntg, gchans, gtxpow, ng);
1255		}
1256		if (CHECKMODES(modes, HAL_MODE_11G|HAL_MODE_HT)) {
1257			/* g ^= n */
1258			intersect(gchans, gtxpow, &ng, nchans, ntxpow, nn);
1259		}
1260		if (CHECKMODES(modes, HAL_MODE_11A|HAL_MODE_HT)) {
1261			/* a ^= n */
1262			intersect(achans, atxpow, &na, nchans, ntxpow, nn);
1263		}
1264#undef CHECKMODES
1265	}
1266
1267	if (modes & HAL_MODE_11G)
1268		dumpchannels(&ahp.h, ng, gchans, gtxpow);
1269	if (modes & HAL_MODE_11B)
1270		dumpchannels(&ahp.h, nb, bchans, btxpow);
1271	if (modes & HAL_MODE_11A)
1272		dumpchannels(&ahp.h, na, achans, atxpow);
1273	if (modes & HAL_MODE_108G)
1274		dumpchannels(&ahp.h, ntg, tgchans, tgtxpow);
1275	if (modes & HAL_MODE_TURBO)
1276		dumpchannels(&ahp.h, nt, tchans, ttxpow);
1277	if (modes & HAL_MODE_HT)
1278		dumpchannels(&ahp.h, nn, nchans, ntxpow);
1279	printf("\n");
1280	return (0);
1281}
1282
1283/*
1284 * Search a list for a specified value v that is within
1285 * EEP_DELTA of the search values.  Return the closest
1286 * values in the list above and below the desired value.
1287 * EEP_DELTA is a factional value; everything is scaled
1288 * so only integer arithmetic is used.
1289 *
1290 * NB: the input list is assumed to be sorted in ascending order
1291 */
1292static void
1293ar5212GetLowerUpperValues(u_int16_t v, u_int16_t *lp, u_int16_t listSize,
1294                          u_int16_t *vlo, u_int16_t *vhi)
1295{
1296	u_int32_t target = v * EEP_SCALE;
1297	u_int16_t *ep = lp+listSize;
1298
1299	/*
1300	 * Check first and last elements for out-of-bounds conditions.
1301	 */
1302	if (target < (u_int32_t)(lp[0] * EEP_SCALE - EEP_DELTA)) {
1303		*vlo = *vhi = lp[0];
1304		return;
1305	}
1306	if (target > (u_int32_t)(ep[-1] * EEP_SCALE + EEP_DELTA)) {
1307		*vlo = *vhi = ep[-1];
1308		return;
1309	}
1310
1311	/* look for value being near or between 2 values in list */
1312	for (; lp < ep; lp++) {
1313		/*
1314		 * If value is close to the current value of the list
1315		 * then target is not between values, it is one of the values
1316		 */
1317		if (abs(lp[0] * EEP_SCALE - target) < EEP_DELTA) {
1318			*vlo = *vhi = lp[0];
1319			return;
1320		}
1321		/*
1322		 * Look for value being between current value and next value
1323		 * if so return these 2 values
1324		 */
1325		if (target < (u_int32_t)(lp[1] * EEP_SCALE - EEP_DELTA)) {
1326			*vlo = lp[0];
1327			*vhi = lp[1];
1328			return;
1329		}
1330	}
1331}
1332
1333/*
1334 * Find the maximum conformance test limit for the given channel and CTL info
1335 */
1336static u_int16_t
1337ar5212GetMaxEdgePower(u_int16_t channel, RD_EDGES_POWER *pRdEdgesPower)
1338{
1339	/* temp array for holding edge channels */
1340	u_int16_t tempChannelList[NUM_EDGES];
1341	u_int16_t clo, chi, twiceMaxEdgePower;
1342	int i, numEdges;
1343
1344	/* Get the edge power */
1345	for (i = 0; i < NUM_EDGES; i++) {
1346		if (pRdEdgesPower[i].rdEdge == 0)
1347			break;
1348		tempChannelList[i] = pRdEdgesPower[i].rdEdge;
1349	}
1350	numEdges = i;
1351
1352	ar5212GetLowerUpperValues(channel, tempChannelList,
1353		numEdges, &clo, &chi);
1354	/* Get the index for the lower channel */
1355	for (i = 0; i < numEdges && clo != tempChannelList[i]; i++)
1356		;
1357	/* Is lower channel ever outside the rdEdge? */
1358	HALASSERT(i != numEdges);
1359
1360	if ((clo == chi && clo == channel) || (pRdEdgesPower[i].flag)) {
1361		/*
1362		 * If there's an exact channel match or an inband flag set
1363		 * on the lower channel use the given rdEdgePower
1364		 */
1365		twiceMaxEdgePower = pRdEdgesPower[i].twice_rdEdgePower;
1366		HALASSERT(twiceMaxEdgePower > 0);
1367	} else
1368		twiceMaxEdgePower = MAX_RATE_POWER;
1369	return twiceMaxEdgePower;
1370}
1371
1372/*
1373 * Returns interpolated or the scaled up interpolated value
1374 */
1375static u_int16_t
1376interpolate(u_int16_t target, u_int16_t srcLeft, u_int16_t srcRight,
1377	u_int16_t targetLeft, u_int16_t targetRight)
1378{
1379	u_int16_t rv;
1380	int16_t lRatio;
1381
1382	/* to get an accurate ratio, always scale, if want to scale, then don't scale back down */
1383	if ((targetLeft * targetRight) == 0)
1384		return 0;
1385
1386	if (srcRight != srcLeft) {
1387		/*
1388		 * Note the ratio always need to be scaled,
1389		 * since it will be a fraction.
1390		 */
1391		lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft);
1392		if (lRatio < 0) {
1393		    /* Return as Left target if value would be negative */
1394		    rv = targetLeft;
1395		} else if (lRatio > EEP_SCALE) {
1396		    /* Return as Right target if Ratio is greater than 100% (SCALE) */
1397		    rv = targetRight;
1398		} else {
1399			rv = (lRatio * targetRight + (EEP_SCALE - lRatio) *
1400					targetLeft) / EEP_SCALE;
1401		}
1402	} else {
1403		rv = targetLeft;
1404	}
1405	return rv;
1406}
1407
1408/*
1409 * Return the four rates of target power for the given target power table
1410 * channel, and number of channels
1411 */
1412static void
1413ar5212GetTargetPowers(struct ath_hal *ah, const struct ieee80211_channel *chan,
1414	TRGT_POWER_INFO *powInfo,
1415	u_int16_t numChannels, TRGT_POWER_INFO *pNewPower)
1416{
1417	/* temp array for holding target power channels */
1418	u_int16_t tempChannelList[NUM_TEST_FREQUENCIES];
1419	u_int16_t clo, chi, ixlo, ixhi;
1420	int i;
1421
1422	/* Copy the target powers into the temp channel list */
1423	for (i = 0; i < numChannels; i++)
1424		tempChannelList[i] = powInfo[i].testChannel;
1425
1426	ar5212GetLowerUpperValues(chan->ic_freq, tempChannelList,
1427		numChannels, &clo, &chi);
1428
1429	/* Get the indices for the channel */
1430	ixlo = ixhi = 0;
1431	for (i = 0; i < numChannels; i++) {
1432		if (clo == tempChannelList[i]) {
1433			ixlo = i;
1434		}
1435		if (chi == tempChannelList[i]) {
1436			ixhi = i;
1437			break;
1438		}
1439	}
1440
1441	/*
1442	 * Get the lower and upper channels, target powers,
1443	 * and interpolate between them.
1444	 */
1445	pNewPower->twicePwr6_24 = interpolate(chan->ic_freq, clo, chi,
1446		powInfo[ixlo].twicePwr6_24, powInfo[ixhi].twicePwr6_24);
1447	pNewPower->twicePwr36 = interpolate(chan->ic_freq, clo, chi,
1448		powInfo[ixlo].twicePwr36, powInfo[ixhi].twicePwr36);
1449	pNewPower->twicePwr48 = interpolate(chan->ic_freq, clo, chi,
1450		powInfo[ixlo].twicePwr48, powInfo[ixhi].twicePwr48);
1451	pNewPower->twicePwr54 = interpolate(chan->ic_freq, clo, chi,
1452		powInfo[ixlo].twicePwr54, powInfo[ixhi].twicePwr54);
1453}
1454
1455static RD_EDGES_POWER*
1456findEdgePower(struct ath_hal *ah, u_int ctl)
1457{
1458	int i;
1459
1460	for (i = 0; i < _numCtls; i++)
1461		if (_ctl[i] == ctl)
1462			return &_rdEdgesPower[i * NUM_EDGES];
1463	return AH_NULL;
1464}
1465
1466/*
1467 * Sets the transmit power in the baseband for the given
1468 * operating channel and mode.
1469 */
1470static HAL_BOOL
1471setRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan,
1472		   int16_t tpcScaleReduction, int16_t powerLimit,
1473                   int16_t *pMinPower, int16_t *pMaxPower)
1474{
1475	u_int16_t ratesArray[16];
1476	u_int16_t *rpow = ratesArray;
1477	u_int16_t twiceMaxRDPower, twiceMaxEdgePower, twiceMaxEdgePowerCck;
1478	int8_t twiceAntennaGain, twiceAntennaReduction;
1479	TRGT_POWER_INFO targetPowerOfdm, targetPowerCck;
1480	RD_EDGES_POWER *rep;
1481	int16_t scaledPower;
1482	u_int8_t cfgCtl;
1483
1484	twiceMaxRDPower = chan->ic_maxregpower * 2;
1485	*pMaxPower = -MAX_RATE_POWER;
1486	*pMinPower = MAX_RATE_POWER;
1487
1488	/* Get conformance test limit maximum for this channel */
1489	cfgCtl = ath_hal_getctl(ah, chan);
1490	rep = findEdgePower(ah, cfgCtl);
1491	if (rep != AH_NULL)
1492		twiceMaxEdgePower = ar5212GetMaxEdgePower(chan->ic_freq, rep);
1493	else
1494		twiceMaxEdgePower = MAX_RATE_POWER;
1495
1496	if (IEEE80211_IS_CHAN_G(chan)) {
1497		/* Check for a CCK CTL for 11G CCK powers */
1498		cfgCtl = (cfgCtl & 0xFC) | 0x01;
1499		rep = findEdgePower(ah, cfgCtl);
1500		if (rep != AH_NULL)
1501			twiceMaxEdgePowerCck = ar5212GetMaxEdgePower(chan->ic_freq, rep);
1502		else
1503			twiceMaxEdgePowerCck = MAX_RATE_POWER;
1504	} else {
1505		/* Set the 11B cck edge power to the one found before */
1506		twiceMaxEdgePowerCck = twiceMaxEdgePower;
1507	}
1508
1509	/* Get Antenna Gain reduction */
1510	if (IEEE80211_IS_CHAN_5GHZ(chan)) {
1511		twiceAntennaGain = antennaGainMax[0];
1512	} else {
1513		twiceAntennaGain = antennaGainMax[1];
1514	}
1515	twiceAntennaReduction =
1516		ath_hal_getantennareduction(ah, chan, twiceAntennaGain);
1517
1518	if (IEEE80211_IS_CHAN_OFDM(chan)) {
1519		/* Get final OFDM target powers */
1520		if (IEEE80211_IS_CHAN_G(chan)) {
1521			/* TODO - add Turbo 2.4 to this mode check */
1522			ar5212GetTargetPowers(ah, chan, trgtPwr_11g,
1523				numTargetPwr_11g, &targetPowerOfdm);
1524		} else {
1525			ar5212GetTargetPowers(ah, chan, trgtPwr_11a,
1526				numTargetPwr_11a, &targetPowerOfdm);
1527		}
1528
1529		/* Get Maximum OFDM power */
1530		/* Minimum of target and edge powers */
1531		scaledPower = AH_MIN(twiceMaxEdgePower,
1532				twiceMaxRDPower - twiceAntennaReduction);
1533
1534		/*
1535		 * If turbo is set, reduce power to keep power
1536		 * consumption under 2 Watts.  Note that we always do
1537		 * this unless specially configured.  Then we limit
1538		 * power only for non-AP operation.
1539		 */
1540		if (IEEE80211_IS_CHAN_TURBO(chan)
1541#ifdef AH_ENABLE_AP_SUPPORT
1542		    && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP
1543#endif
1544		) {
1545			/*
1546			 * If turbo is set, reduce power to keep power
1547			 * consumption under 2 Watts
1548			 */
1549			if (eeversion >= AR_EEPROM_VER3_1)
1550				scaledPower = AH_MIN(scaledPower,
1551					turbo2WMaxPower5);
1552			/*
1553			 * EEPROM version 4.0 added an additional
1554			 * constraint on 2.4GHz channels.
1555			 */
1556			if (eeversion >= AR_EEPROM_VER4_0 &&
1557			    IEEE80211_IS_CHAN_2GHZ(chan))
1558				scaledPower = AH_MIN(scaledPower,
1559					turbo2WMaxPower2);
1560		}
1561		/* Reduce power by max regulatory domain allowed restrictions */
1562		scaledPower -= (tpcScaleReduction * 2);
1563		scaledPower = (scaledPower < 0) ? 0 : scaledPower;
1564		scaledPower = AH_MIN(scaledPower, powerLimit);
1565
1566		scaledPower = AH_MIN(scaledPower, targetPowerOfdm.twicePwr6_24);
1567
1568		/* Set OFDM rates 9, 12, 18, 24, 36, 48, 54, XR */
1569		rpow[0] = rpow[1] = rpow[2] = rpow[3] = rpow[4] = scaledPower;
1570		rpow[5] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr36);
1571		rpow[6] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr48);
1572		rpow[7] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr54);
1573
1574#ifdef notyet
1575		if (eeversion >= AR_EEPROM_VER4_0) {
1576			/* Setup XR target power from EEPROM */
1577			rpow[15] = AH_MIN(scaledPower, IS_CHAN_2GHZ(chan) ?
1578				xrTargetPower2 : xrTargetPower5);
1579		} else {
1580			/* XR uses 6mb power */
1581			rpow[15] = rpow[0];
1582		}
1583#else
1584		rpow[15] = rpow[0];
1585#endif
1586
1587		*pMinPower = rpow[7];
1588		*pMaxPower = rpow[0];
1589
1590#if 0
1591		ahp->ah_ofdmTxPower = rpow[0];
1592#endif
1593
1594		HALDEBUG(ah, HAL_DEBUG_ANY,
1595		    "%s: MaxRD: %d TurboMax: %d MaxCTL: %d "
1596		    "TPC_Reduction %d\n", __func__,
1597		    twiceMaxRDPower, turbo2WMaxPower5,
1598		    twiceMaxEdgePower, tpcScaleReduction * 2);
1599	}
1600
1601	if (IEEE80211_IS_CHAN_CCK(chan)) {
1602		/* Get final CCK target powers */
1603		ar5212GetTargetPowers(ah, chan, trgtPwr_11b,
1604			numTargetPwr_11b, &targetPowerCck);
1605
1606		/* Reduce power by max regulatory domain allowed restrictions */
1607		scaledPower = AH_MIN(twiceMaxEdgePowerCck,
1608			twiceMaxRDPower - twiceAntennaReduction);
1609
1610		scaledPower -= (tpcScaleReduction * 2);
1611		scaledPower = (scaledPower < 0) ? 0 : scaledPower;
1612		scaledPower = AH_MIN(scaledPower, powerLimit);
1613
1614		rpow[8] = (scaledPower < 1) ? 1 : scaledPower;
1615
1616		/* Set CCK rates 2L, 2S, 5.5L, 5.5S, 11L, 11S */
1617		rpow[8]  = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24);
1618		rpow[9]  = AH_MIN(scaledPower, targetPowerCck.twicePwr36);
1619		rpow[10] = rpow[9];
1620		rpow[11] = AH_MIN(scaledPower, targetPowerCck.twicePwr48);
1621		rpow[12] = rpow[11];
1622		rpow[13] = AH_MIN(scaledPower, targetPowerCck.twicePwr54);
1623		rpow[14] = rpow[13];
1624
1625		/* Set min/max power based off OFDM values or initialization */
1626		if (rpow[13] < *pMinPower)
1627		    *pMinPower = rpow[13];
1628		if (rpow[9] > *pMaxPower)
1629		    *pMaxPower = rpow[9];
1630
1631	}
1632#if 0
1633	ahp->ah_tx6PowerInHalfDbm = *pMaxPower;
1634#endif
1635	return AH_TRUE;
1636}
1637
1638void*
1639ath_hal_malloc(size_t size)
1640{
1641	return calloc(1, size);
1642}
1643
1644void
1645ath_hal_free(void* p)
1646{
1647	return free(p);
1648}
1649
1650void
1651ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap)
1652{
1653	vprintf(fmt, ap);
1654}
1655
1656void
1657ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
1658{
1659	va_list ap;
1660	va_start(ap, fmt);
1661	ath_hal_vprintf(ah, fmt, ap);
1662	va_end(ap);
1663}
1664
1665void
1666HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
1667{
1668	if (ath_hal_debug & mask) {
1669		__va_list ap;
1670		va_start(ap, fmt);
1671		ath_hal_vprintf(ah, fmt, ap);
1672		va_end(ap);
1673	}
1674}
1675