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, MERCHANTABILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
28 *
29 * $FreeBSD: src/tools/tools/ath/athrd/athrd.c,v 1.2 2009/01/29 23:24:21 sam Exp $
30 */
31 #include "opt_ah.h"
32
33 #include "ah.h"
34
35 #include <netproto/802_11/_ieee80211.h>
36 #include <netproto/802_11/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
47 int ath_hal_debug = 0;
48 HAL_CTRY_CODE cc = CTRY_DEFAULT;
49 HAL_REG_DOMAIN rd = 169; /* FCC */
50 HAL_BOOL Amode = 1;
51 HAL_BOOL Bmode = 1;
52 HAL_BOOL Gmode = 1;
53 HAL_BOOL HT20mode = 1;
54 HAL_BOOL HT40mode = 1;
55 HAL_BOOL turbo5Disable = AH_FALSE;
56 HAL_BOOL turbo2Disable = AH_FALSE;
57
58 u_int16_t _numCtls = 8;
59 u_int16_t _ctl[32] =
60 { 0x10, 0x13, 0x40, 0x30, 0x11, 0x31, 0x12, 0x32 };
61 RD_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
135 u_int16_t turbo2WMaxPower5 = 32;
136 u_int16_t turbo2WMaxPower2;
137 int8_t antennaGainMax[2] = { 0, 0 }; /* XXX */
138 int eeversion = AR_EEPROM_VER3_1;
139 TRGT_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
166 static HAL_BOOL
getChannelEdges(struct ath_hal * ah,u_int16_t flags,u_int16_t * low,u_int16_t * high)167 getChannelEdges(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
185 static u_int
getWirelessModes(struct ath_hal * ah)186 getWirelessModes(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
217 enum 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
385 static 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
534 static HAL_BOOL
rdlookup(const char * name,HAL_REG_DOMAIN * rd)535 rdlookup(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
549 static const char *
getrdname(HAL_REG_DOMAIN rd)550 getrdname(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
562 static void
rdlist()563 rdlist()
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
576 typedef 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 */
586 static 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
727 static HAL_BOOL
cclookup(const char * name,HAL_REG_DOMAIN * rd,HAL_CTRY_CODE * cc)728 cclookup(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
744 static const char *
getccname(HAL_CTRY_CODE cc)745 getccname(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
757 static const char *
getccisoname(HAL_CTRY_CODE cc)758 getccisoname(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
770 static void
cclist()771 cclist()
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
786 static HAL_BOOL
787 setRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan,
788 int16_t tpcScaleReduction, int16_t powerLimit,
789 int16_t *pMinPower, int16_t *pMaxPower);
790
791 static void
calctxpower(struct ath_hal * ah,int nchan,const struct ieee80211_channel * chans,int16_t tpcScaleReduction,int16_t powerLimit,int16_t * txpow)792 calctxpower(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
807 int n = 1;
808 const char *sep = "";
809 int dopassive = 0;
810 int showchannels = 0;
811 int isdfs = 0;
812 int is4ms = 0;
813
814 static int
anychan(const struct ieee80211_channel * chans,int nc,int flag)815 anychan(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
825 static __inline int
mapgsm(u_int freq,u_int flags)826 mapgsm(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
838 static __inline int
mappsb(u_int freq,u_int flags)839 mappsb(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 */
847 int
ath_hal_mhz2ieee(struct ath_hal * ah,u_int freq,u_int flags)848 ath_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
884 static void
dumpchannels(struct ath_hal * ah,int nc,const struct ieee80211_channel * chans,int16_t * txpow)885 dumpchannels(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
939 static void
intersect(struct ieee80211_channel * dst,int16_t * dtxpow,int * nd,const struct ieee80211_channel * src,int16_t * stxpow,int ns)940 intersect(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
956 static void
usage(const char * progname)957 usage(const char *progname)
958 {
959 printf("usage: %s [-acdefoilpr4ABGT] [-m opmode] [cc | rd]\n", progname);
960 exit(-1);
961 }
962
963 static HAL_BOOL
getChipPowerLimits(struct ath_hal * ah,struct ieee80211_channel * chan)964 getChipPowerLimits(struct ath_hal *ah, struct ieee80211_channel *chan)
965 {
966 }
967
968 static HAL_BOOL
eepromRead(struct ath_hal * ah,u_int off,u_int16_t * data)969 eepromRead(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
986 HAL_STATUS
getCapability(struct ath_hal * ah,HAL_CAPABILITY_TYPE type,uint32_t capability,uint32_t * result)987 getCapability(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
1008 int
main(int argc,char * argv[])1009 main(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 */
1292 static void
ar5212GetLowerUpperValues(u_int16_t v,u_int16_t * lp,u_int16_t listSize,u_int16_t * vlo,u_int16_t * vhi)1293 ar5212GetLowerUpperValues(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 */
1336 static u_int16_t
ar5212GetMaxEdgePower(u_int16_t channel,RD_EDGES_POWER * pRdEdgesPower)1337 ar5212GetMaxEdgePower(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 */
1375 static u_int16_t
interpolate(u_int16_t target,u_int16_t srcLeft,u_int16_t srcRight,u_int16_t targetLeft,u_int16_t targetRight)1376 interpolate(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 */
1412 static void
ar5212GetTargetPowers(struct ath_hal * ah,const struct ieee80211_channel * chan,TRGT_POWER_INFO * powInfo,u_int16_t numChannels,TRGT_POWER_INFO * pNewPower)1413 ar5212GetTargetPowers(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
1455 static RD_EDGES_POWER*
findEdgePower(struct ath_hal * ah,u_int ctl)1456 findEdgePower(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 */
1470 static HAL_BOOL
setRateTable(struct ath_hal * ah,const struct ieee80211_channel * chan,int16_t tpcScaleReduction,int16_t powerLimit,int16_t * pMinPower,int16_t * pMaxPower)1471 setRateTable(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
1638 void*
ath_hal_malloc(size_t size)1639 ath_hal_malloc(size_t size)
1640 {
1641 return calloc(1, size);
1642 }
1643
1644 void
ath_hal_free(void * p)1645 ath_hal_free(void* p)
1646 {
1647 return free(p);
1648 }
1649
1650 void
ath_hal_vprintf(struct ath_hal * ah,const char * fmt,va_list ap)1651 ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap)
1652 {
1653 vprintf(fmt, ap);
1654 }
1655
1656 void
ath_hal_printf(struct ath_hal * ah,const char * fmt,...)1657 ath_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
1665 void
HALDEBUG(struct ath_hal * ah,u_int mask,const char * fmt,...)1666 HALDEBUG(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