1 | /* |
2 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
3 | * Copyright (c) 2002-2006 Atheros Communications, Inc. |
4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | * |
17 | * $Id: ar5211_misc.c,v 1.2 2011/03/07 11:25:42 cegger Exp $ |
18 | */ |
19 | #include "opt_ah.h" |
20 | |
21 | #include "ah.h" |
22 | #include "ah_internal.h" |
23 | |
24 | #include "ar5211/ar5211.h" |
25 | #include "ar5211/ar5211reg.h" |
26 | #include "ar5211/ar5211phy.h" |
27 | |
28 | #include "ah_eeprom_v3.h" |
29 | |
30 | #define AR_NUM_GPIO 6 /* 6 GPIO bits */ |
31 | #define AR_GPIOD_MASK 0x2f /* 6-bit mask */ |
32 | |
33 | void |
34 | ar5211GetMacAddress(struct ath_hal *ah, uint8_t *mac) |
35 | { |
36 | struct ath_hal_5211 *ahp = AH5211(ah); |
37 | |
38 | OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); |
39 | } |
40 | |
41 | HAL_BOOL |
42 | ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *mac) |
43 | { |
44 | struct ath_hal_5211 *ahp = AH5211(ah); |
45 | |
46 | OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); |
47 | return AH_TRUE; |
48 | } |
49 | |
50 | void |
51 | ar5211GetBssIdMask(struct ath_hal *ah, uint8_t *mask) |
52 | { |
53 | static const uint8_t ones[IEEE80211_ADDR_LEN] = |
54 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
55 | OS_MEMCPY(mask, ones, IEEE80211_ADDR_LEN); |
56 | } |
57 | |
58 | HAL_BOOL |
59 | ar5211SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) |
60 | { |
61 | return AH_FALSE; |
62 | } |
63 | |
64 | /* |
65 | * Read 16 bits of data from the specified EEPROM offset. |
66 | */ |
67 | HAL_BOOL |
68 | ar5211EepromRead(struct ath_hal *ah, u_int off, uint16_t *data) |
69 | { |
70 | OS_REG_WRITE(ah, AR_EEPROM_ADDR, off); |
71 | OS_REG_WRITE(ah, AR_EEPROM_CMD, AR_EEPROM_CMD_READ); |
72 | |
73 | if (!ath_hal_wait(ah, AR_EEPROM_STS, |
74 | AR_EEPROM_STS_READ_COMPLETE | AR_EEPROM_STS_READ_ERROR, |
75 | AR_EEPROM_STS_READ_COMPLETE)) { |
76 | HALDEBUG(ah, HAL_DEBUG_ANY, |
77 | "%s: read failed for entry 0x%x\n" , __func__, off); |
78 | return AH_FALSE; |
79 | } |
80 | *data = OS_REG_READ(ah, AR_EEPROM_DATA) & 0xffff; |
81 | return AH_TRUE; |
82 | } |
83 | |
84 | #ifdef AH_SUPPORT_WRITE_EEPROM |
85 | /* |
86 | * Write 16 bits of data to the specified EEPROM offset. |
87 | */ |
88 | HAL_BOOL |
89 | ar5211EepromWrite(struct ath_hal *ah, u_int off, uint16_t data) |
90 | { |
91 | return AH_FALSE; |
92 | } |
93 | #endif /* AH_SUPPORT_WRITE_EEPROM */ |
94 | |
95 | /* |
96 | * Attempt to change the cards operating regulatory domain to the given value |
97 | */ |
98 | HAL_BOOL |
99 | ar5211SetRegulatoryDomain(struct ath_hal *ah, |
100 | uint16_t regDomain, HAL_STATUS *status) |
101 | { |
102 | HAL_STATUS ecode; |
103 | |
104 | if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { |
105 | ecode = HAL_EINVAL; |
106 | goto bad; |
107 | } |
108 | /* |
109 | * Check if EEPROM is configured to allow this; must |
110 | * be a proper version and the protection bits must |
111 | * permit re-writing that segment of the EEPROM. |
112 | */ |
113 | if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { |
114 | ecode = HAL_EEWRITE; |
115 | goto bad; |
116 | } |
117 | #ifdef AH_SUPPORT_WRITE_REGDOMAIN |
118 | if (ar5211EepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { |
119 | HALDEBUG(ah, HAL_DEBUG_ANY, |
120 | "%s: set regulatory domain to %u (0x%x)\n" , |
121 | __func__, regDomain, regDomain); |
122 | AH_PRIVATE(ah)->ah_currentRD = regDomain; |
123 | return AH_TRUE; |
124 | } |
125 | #endif |
126 | ecode = HAL_EIO; |
127 | bad: |
128 | if (status) |
129 | *status = ecode; |
130 | return AH_FALSE; |
131 | } |
132 | |
133 | /* |
134 | * Return the wireless modes (a,b,g,t) supported by hardware. |
135 | * |
136 | * This value is what is actually supported by the hardware |
137 | * and is unaffected by regulatory/country code settings. |
138 | * |
139 | */ |
140 | u_int |
141 | ar5211GetWirelessModes(struct ath_hal *ah) |
142 | { |
143 | u_int mode = 0; |
144 | |
145 | if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { |
146 | mode = HAL_MODE_11A; |
147 | if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) |
148 | mode |= HAL_MODE_TURBO | HAL_MODE_108A; |
149 | } |
150 | if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) |
151 | mode |= HAL_MODE_11B; |
152 | return mode; |
153 | } |
154 | |
155 | #if 0 |
156 | HAL_BOOL |
157 | ar5211GetTurboDisable(struct ath_hal *ah) |
158 | { |
159 | return (AH5211(ah)->ah_turboDisable != 0); |
160 | } |
161 | #endif |
162 | |
163 | /* |
164 | * Called if RfKill is supported (according to EEPROM). Set the interrupt and |
165 | * GPIO values so the ISR and can disable RF on a switch signal |
166 | */ |
167 | void |
168 | ar5211EnableRfKill(struct ath_hal *ah) |
169 | { |
170 | uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; |
171 | int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); |
172 | int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); |
173 | |
174 | /* |
175 | * Configure the desired GPIO port for input |
176 | * and enable baseband rf silence. |
177 | */ |
178 | ar5211GpioCfgInput(ah, select); |
179 | OS_REG_SET_BIT(ah, AR_PHY_BASE, 0x00002000); |
180 | /* |
181 | * If radio disable switch connection to GPIO bit x is enabled |
182 | * program GPIO interrupt. |
183 | * If rfkill bit on eeprom is 1, setupeeprommap routine has already |
184 | * verified that it is a later version of eeprom, it has a place for |
185 | * rfkill bit and it is set to 1, indicating that GPIO bit x hardware |
186 | * connection is present. |
187 | */ |
188 | ar5211GpioSetIntr(ah, select, (ar5211GpioGet(ah, select) != polarity)); |
189 | } |
190 | |
191 | /* |
192 | * Configure GPIO Output lines |
193 | */ |
194 | HAL_BOOL |
195 | ar5211GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type) |
196 | { |
197 | uint32_t reg; |
198 | |
199 | HALASSERT(gpio < AR_NUM_GPIO); |
200 | |
201 | reg = OS_REG_READ(ah, AR_GPIOCR); |
202 | reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT)); |
203 | reg |= AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT); |
204 | |
205 | OS_REG_WRITE(ah, AR_GPIOCR, reg); |
206 | return AH_TRUE; |
207 | } |
208 | |
209 | /* |
210 | * Configure GPIO Input lines |
211 | */ |
212 | HAL_BOOL |
213 | ar5211GpioCfgInput(struct ath_hal *ah, uint32_t gpio) |
214 | { |
215 | uint32_t reg; |
216 | |
217 | HALASSERT(gpio < AR_NUM_GPIO); |
218 | |
219 | reg = OS_REG_READ(ah, AR_GPIOCR); |
220 | reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT)); |
221 | reg |= AR_GPIOCR_0_CR_N << (gpio * AR_GPIOCR_CR_SHIFT); |
222 | |
223 | OS_REG_WRITE(ah, AR_GPIOCR, reg); |
224 | return AH_TRUE; |
225 | } |
226 | |
227 | /* |
228 | * Once configured for I/O - set output lines |
229 | */ |
230 | HAL_BOOL |
231 | ar5211GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) |
232 | { |
233 | uint32_t reg; |
234 | |
235 | HALASSERT(gpio < AR_NUM_GPIO); |
236 | |
237 | reg = OS_REG_READ(ah, AR_GPIODO); |
238 | reg &= ~(1 << gpio); |
239 | reg |= (val&1) << gpio; |
240 | |
241 | OS_REG_WRITE(ah, AR_GPIODO, reg); |
242 | return AH_TRUE; |
243 | } |
244 | |
245 | /* |
246 | * Once configured for I/O - get input lines |
247 | */ |
248 | uint32_t |
249 | ar5211GpioGet(struct ath_hal *ah, uint32_t gpio) |
250 | { |
251 | if (gpio < AR_NUM_GPIO) { |
252 | uint32_t val = OS_REG_READ(ah, AR_GPIODI); |
253 | val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1; |
254 | return val; |
255 | } else { |
256 | return 0xffffffff; |
257 | } |
258 | } |
259 | |
260 | /* |
261 | * Set the GPIO 0 Interrupt (gpio is ignored) |
262 | */ |
263 | void |
264 | ar5211GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) |
265 | { |
266 | uint32_t val = OS_REG_READ(ah, AR_GPIOCR); |
267 | |
268 | /* Clear the bits that we will modify. */ |
269 | val &= ~(AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA | |
270 | AR_GPIOCR_0_CR_A); |
271 | |
272 | val |= AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_ENA; |
273 | if (ilevel) |
274 | val |= AR_GPIOCR_INT_SELH; |
275 | |
276 | /* Don't need to change anything for low level interrupt. */ |
277 | OS_REG_WRITE(ah, AR_GPIOCR, val); |
278 | |
279 | /* Change the interrupt mask. */ |
280 | ar5211SetInterrupts(ah, AH5211(ah)->ah_maskReg | HAL_INT_GPIO); |
281 | } |
282 | |
283 | /* |
284 | * Change the LED blinking pattern to correspond to the connectivity |
285 | */ |
286 | void |
287 | ar5211SetLedState(struct ath_hal *ah, HAL_LED_STATE state) |
288 | { |
289 | static const uint32_t ledbits[8] = { |
290 | AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_INIT */ |
291 | AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_SCAN */ |
292 | AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_AUTH */ |
293 | AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_ASSOC*/ |
294 | AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_RUN */ |
295 | AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, |
296 | AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, |
297 | AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, |
298 | }; |
299 | OS_REG_WRITE(ah, AR_PCICFG, |
300 | (OS_REG_READ(ah, AR_PCICFG) &~ |
301 | (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE)) |
302 | | ledbits[state & 0x7] |
303 | ); |
304 | } |
305 | |
306 | /* |
307 | * Change association related fields programmed into the hardware. |
308 | * Writing a valid BSSID to the hardware effectively enables the hardware |
309 | * to synchronize its TSF to the correct beacons and receive frames coming |
310 | * from that BSSID. It is called by the SME JOIN operation. |
311 | */ |
312 | void |
313 | ar5211WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) |
314 | { |
315 | struct ath_hal_5211 *ahp = AH5211(ah); |
316 | |
317 | /* XXX save bssid for possible re-use on reset */ |
318 | OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); |
319 | OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); |
320 | OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | |
321 | ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); |
322 | } |
323 | |
324 | /* |
325 | * Get the current hardware tsf for stamlme. |
326 | */ |
327 | uint64_t |
328 | ar5211GetTsf64(struct ath_hal *ah) |
329 | { |
330 | uint32_t low1, low2, u32; |
331 | |
332 | /* sync multi-word read */ |
333 | low1 = OS_REG_READ(ah, AR_TSF_L32); |
334 | u32 = OS_REG_READ(ah, AR_TSF_U32); |
335 | low2 = OS_REG_READ(ah, AR_TSF_L32); |
336 | if (low2 < low1) { /* roll over */ |
337 | /* |
338 | * If we are not preempted this will work. If we are |
339 | * then we re-reading AR_TSF_U32 does no good as the |
340 | * low bits will be meaningless. Likewise reading |
341 | * L32, U32, U32, then comparing the last two reads |
342 | * to check for rollover doesn't help if preempted--so |
343 | * we take this approach as it costs one less PCI |
344 | * read which can be noticeable when doing things |
345 | * like timestamping packets in monitor mode. |
346 | */ |
347 | u32++; |
348 | } |
349 | return (((uint64_t) u32) << 32) | ((uint64_t) low2); |
350 | } |
351 | |
352 | /* |
353 | * Get the current hardware tsf for stamlme. |
354 | */ |
355 | uint32_t |
356 | ar5211GetTsf32(struct ath_hal *ah) |
357 | { |
358 | return OS_REG_READ(ah, AR_TSF_L32); |
359 | } |
360 | |
361 | /* |
362 | * Reset the current hardware tsf for stamlme |
363 | */ |
364 | void |
365 | ar5211ResetTsf(struct ath_hal *ah) |
366 | { |
367 | uint32_t val = OS_REG_READ(ah, AR_BEACON); |
368 | |
369 | OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); |
370 | } |
371 | |
372 | /* |
373 | * Grab a semi-random value from hardware registers - may not |
374 | * change often |
375 | */ |
376 | uint32_t |
377 | ar5211GetRandomSeed(struct ath_hal *ah) |
378 | { |
379 | uint32_t nf; |
380 | |
381 | nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; |
382 | if (nf & 0x100) |
383 | nf = 0 - ((nf ^ 0x1ff) + 1); |
384 | return (OS_REG_READ(ah, AR_TSF_U32) ^ |
385 | OS_REG_READ(ah, AR_TSF_L32) ^ nf); |
386 | } |
387 | |
388 | /* |
389 | * Detect if our card is present |
390 | */ |
391 | HAL_BOOL |
392 | ar5211DetectCardPresent(struct ath_hal *ah) |
393 | { |
394 | uint16_t macVersion, macRev; |
395 | uint32_t v; |
396 | |
397 | /* |
398 | * Read the Silicon Revision register and compare that |
399 | * to what we read at attach time. If the same, we say |
400 | * a card/device is present. |
401 | */ |
402 | v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID_M; |
403 | macVersion = v >> AR_SREV_ID_S; |
404 | macRev = v & AR_SREV_REVISION_M; |
405 | return (AH_PRIVATE(ah)->ah_macVersion == macVersion && |
406 | AH_PRIVATE(ah)->ah_macRev == macRev); |
407 | } |
408 | |
409 | /* |
410 | * Update MIB Counters |
411 | */ |
412 | void |
413 | ar5211UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS *stats) |
414 | { |
415 | stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); |
416 | stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); |
417 | stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); |
418 | stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); |
419 | stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); |
420 | } |
421 | |
422 | HAL_BOOL |
423 | ar5211SetSifsTime(struct ath_hal *ah, u_int us) |
424 | { |
425 | struct ath_hal_5211 *ahp = AH5211(ah); |
426 | |
427 | if (us > ath_hal_mac_usec(ah, 0xffff)) { |
428 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n" , |
429 | __func__, us); |
430 | ahp->ah_sifstime = (u_int) -1; /* restore default handling */ |
431 | return AH_FALSE; |
432 | } else { |
433 | /* convert to system clocks */ |
434 | OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us)); |
435 | ahp->ah_slottime = us; |
436 | return AH_TRUE; |
437 | } |
438 | } |
439 | |
440 | u_int |
441 | ar5211GetSifsTime(struct ath_hal *ah) |
442 | { |
443 | u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; |
444 | return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ |
445 | } |
446 | |
447 | HAL_BOOL |
448 | ar5211SetSlotTime(struct ath_hal *ah, u_int us) |
449 | { |
450 | struct ath_hal_5211 *ahp = AH5211(ah); |
451 | |
452 | if (us < HAL_SLOT_TIME_9 || us > ath_hal_mac_usec(ah, 0xffff)) { |
453 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n" , |
454 | __func__, us); |
455 | ahp->ah_slottime = us; /* restore default handling */ |
456 | return AH_FALSE; |
457 | } else { |
458 | /* convert to system clocks */ |
459 | OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); |
460 | ahp->ah_slottime = us; |
461 | return AH_TRUE; |
462 | } |
463 | } |
464 | |
465 | u_int |
466 | ar5211GetSlotTime(struct ath_hal *ah) |
467 | { |
468 | u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; |
469 | return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ |
470 | } |
471 | |
472 | HAL_BOOL |
473 | ar5211SetAckTimeout(struct ath_hal *ah, u_int us) |
474 | { |
475 | struct ath_hal_5211 *ahp = AH5211(ah); |
476 | |
477 | if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { |
478 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n" , |
479 | __func__, us); |
480 | ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ |
481 | return AH_FALSE; |
482 | } else { |
483 | /* convert to system clocks */ |
484 | OS_REG_RMW_FIELD(ah, AR_TIME_OUT, |
485 | AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); |
486 | ahp->ah_acktimeout = us; |
487 | return AH_TRUE; |
488 | } |
489 | } |
490 | |
491 | u_int |
492 | ar5211GetAckTimeout(struct ath_hal *ah) |
493 | { |
494 | u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); |
495 | return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ |
496 | } |
497 | |
498 | u_int |
499 | ar5211GetAckCTSRate(struct ath_hal *ah) |
500 | { |
501 | return ((AH5211(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); |
502 | } |
503 | |
504 | HAL_BOOL |
505 | ar5211SetAckCTSRate(struct ath_hal *ah, u_int high) |
506 | { |
507 | struct ath_hal_5211 *ahp = AH5211(ah); |
508 | |
509 | if (high) { |
510 | OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); |
511 | ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; |
512 | } else { |
513 | OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); |
514 | ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; |
515 | } |
516 | return AH_TRUE; |
517 | } |
518 | |
519 | HAL_BOOL |
520 | ar5211SetCTSTimeout(struct ath_hal *ah, u_int us) |
521 | { |
522 | struct ath_hal_5211 *ahp = AH5211(ah); |
523 | |
524 | if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { |
525 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n" , |
526 | __func__, us); |
527 | ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ |
528 | return AH_FALSE; |
529 | } else { |
530 | /* convert to system clocks */ |
531 | OS_REG_RMW_FIELD(ah, AR_TIME_OUT, |
532 | AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); |
533 | ahp->ah_ctstimeout = us; |
534 | return AH_TRUE; |
535 | } |
536 | } |
537 | |
538 | u_int |
539 | ar5211GetCTSTimeout(struct ath_hal *ah) |
540 | { |
541 | u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); |
542 | return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ |
543 | } |
544 | |
545 | HAL_BOOL |
546 | ar5211SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) |
547 | { |
548 | /* nothing to do */ |
549 | return AH_TRUE; |
550 | } |
551 | |
552 | void |
553 | ar5211SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) |
554 | { |
555 | } |
556 | |
557 | /* |
558 | * Control Adaptive Noise Immunity Parameters |
559 | */ |
560 | HAL_BOOL |
561 | ar5211AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) |
562 | { |
563 | return AH_FALSE; |
564 | } |
565 | |
566 | void |
567 | ar5211AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats, HAL_CHANNEL *chan) |
568 | { |
569 | } |
570 | |
571 | void |
572 | ar5211MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats) |
573 | { |
574 | } |
575 | |
576 | /* |
577 | * Get the rssi of frame curently being received. |
578 | */ |
579 | uint32_t |
580 | (struct ath_hal *ah) |
581 | { |
582 | return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); |
583 | } |
584 | |
585 | u_int |
586 | ar5211GetDefAntenna(struct ath_hal *ah) |
587 | { |
588 | return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); |
589 | } |
590 | |
591 | void |
592 | ar5211SetDefAntenna(struct ath_hal *ah, u_int antenna) |
593 | { |
594 | OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); |
595 | } |
596 | |
597 | HAL_ANT_SETTING |
598 | ar5211GetAntennaSwitch(struct ath_hal *ah) |
599 | { |
600 | return AH5211(ah)->ah_diversityControl; |
601 | } |
602 | |
603 | HAL_BOOL |
604 | ar5211SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) |
605 | { |
606 | const HAL_CHANNEL *chan = |
607 | (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan; |
608 | |
609 | if (chan == AH_NULL) { |
610 | AH5211(ah)->ah_diversityControl = settings; |
611 | return AH_TRUE; |
612 | } |
613 | return ar5211SetAntennaSwitchInternal(ah, settings, chan); |
614 | } |
615 | |
616 | HAL_STATUS |
617 | ar5211GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, |
618 | uint32_t capability, uint32_t *result) |
619 | { |
620 | |
621 | switch (type) { |
622 | case HAL_CAP_CIPHER: /* cipher handled in hardware */ |
623 | switch (capability) { |
624 | case HAL_CIPHER_AES_OCB: |
625 | case HAL_CIPHER_WEP: |
626 | case HAL_CIPHER_CLR: |
627 | return HAL_OK; |
628 | default: |
629 | return HAL_ENOTSUPP; |
630 | } |
631 | default: |
632 | return ath_hal_getcapability(ah, type, capability, result); |
633 | } |
634 | } |
635 | |
636 | HAL_BOOL |
637 | ar5211SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, |
638 | uint32_t capability, uint32_t setting, HAL_STATUS *status) |
639 | { |
640 | switch (type) { |
641 | case HAL_CAP_DIAG: /* hardware diagnostic support */ |
642 | /* |
643 | * NB: could split this up into virtual capabilities, |
644 | * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly |
645 | * seems worth the additional complexity. |
646 | */ |
647 | #ifdef AH_DEBUG |
648 | AH_PRIVATE(ah)->ah_diagreg = setting; |
649 | #else |
650 | AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */ |
651 | #endif |
652 | OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); |
653 | return AH_TRUE; |
654 | default: |
655 | return ath_hal_setcapability(ah, type, capability, |
656 | setting, status); |
657 | } |
658 | } |
659 | |
660 | HAL_BOOL |
661 | ar5211GetDiagState(struct ath_hal *ah, int request, |
662 | const void *args, uint32_t argsize, |
663 | void **result, uint32_t *resultsize) |
664 | { |
665 | struct ath_hal_5211 *ahp = AH5211(ah); |
666 | |
667 | (void) ahp; |
668 | if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) |
669 | return AH_TRUE; |
670 | switch (request) { |
671 | case HAL_DIAG_EEPROM: |
672 | return ath_hal_eepromDiag(ah, request, |
673 | args, argsize, result, resultsize); |
674 | case HAL_DIAG_RFGAIN: |
675 | *result = &ahp->ah_gainValues; |
676 | *resultsize = sizeof(GAIN_VALUES); |
677 | return AH_TRUE; |
678 | case HAL_DIAG_RFGAIN_CURSTEP: |
679 | *result = __DECONST(void *, ahp->ah_gainValues.currStep); |
680 | *resultsize = (*result == AH_NULL) ? |
681 | 0 : sizeof(GAIN_OPTIMIZATION_STEP); |
682 | return AH_TRUE; |
683 | } |
684 | return AH_FALSE; |
685 | } |
686 | |