📄 ah.c.svn-base
字号:
/* * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting * Copyright (c) 2002-2008 Atheros Communications, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: ah.c,v 1.15 2008/11/15 22:15:44 sam Exp $ */#include "opt_ah.h"#include "ah.h"#include "ah_internal.h"#include "ah_devid.h"/* linker set of registered chips */OS_SET_DECLARE(ah_chips, struct ath_hal_chip);/* * Check the set of registered chips to see if any recognize * the device as one they can support. */const char*ath_hal_probe(uint16_t vendorid, uint16_t devid){ struct ath_hal_chip **pchip; OS_SET_FOREACH(pchip, ah_chips) { const char *name = (*pchip)->probe(vendorid, devid); if (name != AH_NULL) return name; } return AH_NULL;}/* * Attach detects device chip revisions, initializes the hwLayer * function list, reads EEPROM information, * selects reset vectors, and performs a short self test. * Any failures will return an error that should cause a hardware * disable. */struct ath_hal*ath_hal_attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *error){ struct ath_hal_chip **pchip; OS_SET_FOREACH(pchip, ah_chips) { struct ath_hal_chip *chip = *pchip; struct ath_hal *ah; /* XXX don't have vendorid, assume atheros one works */ if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) continue; ah = chip->attach(devid, sc, st, sh, error); if (ah != AH_NULL) { /* copy back private state to public area */ ah->ah_devid = AH_PRIVATE(ah)->ah_devid; ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; return ah; } } return AH_NULL;}/* linker set of registered RF backends */OS_SET_DECLARE(ah_rfs, struct ath_hal_rf);/* * Check the set of registered RF backends to see if * any recognize the device as one they can support. */struct ath_hal_rf *ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode){ struct ath_hal_rf **prf; OS_SET_FOREACH(prf, ah_rfs) { struct ath_hal_rf *rf = *prf; if (rf->probe(ah)) return rf; } *ecode = HAL_ENOTSUPP; return AH_NULL;}/* * Poll the register looking for a specific value. */HAL_BOOLath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val){#define AH_TIMEOUT 1000 int i; for (i = 0; i < AH_TIMEOUT; i++) { if ((OS_REG_READ(ah, reg) & mask) == val) return AH_TRUE; OS_DELAY(10); } HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", __func__, reg, OS_REG_READ(ah, reg), mask, val); return AH_FALSE;#undef AH_TIMEOUT}/* * Reverse the bits starting at the low bit for a value of * bit_count in size */uint32_tath_hal_reverseBits(uint32_t val, uint32_t n){ uint32_t retval; int i; for (i = 0, retval = 0; i < n; i++) { retval = (retval << 1) | (val & 1); val >>= 1; } return retval;}/* * Compute the time to transmit a frame of length frameLen bytes * using the specified rate, phy, and short preamble setting. */uint16_tath_hal_computetxtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, HAL_BOOL shortPreamble){ uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; uint32_t kbps; kbps = rates->info[rateix].rateKbps; /* * index can be invalid duting dynamic Turbo transitions. */ if(kbps == 0) return 0; switch (rates->info[rateix].phy) { case IEEE80211_T_CCK:#define CCK_SIFS_TIME 10#define CCK_PREAMBLE_BITS 144#define CCK_PLCP_BITS 48 phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; if (shortPreamble && rates->info[rateix].shortPreamble) phyTime >>= 1; numBits = frameLen << 3; txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000)/kbps); break;#undef CCK_SIFS_TIME#undef CCK_PREAMBLE_BITS#undef CCK_PLCP_BITS case IEEE80211_T_OFDM:#define OFDM_SIFS_TIME 16#define OFDM_PREAMBLE_TIME 20#define OFDM_PLCP_BITS 22#define OFDM_SYMBOL_TIME 4#define OFDM_SIFS_TIME_HALF 32#define OFDM_PREAMBLE_TIME_HALF 40#define OFDM_PLCP_BITS_HALF 22#define OFDM_SYMBOL_TIME_HALF 8#define OFDM_SIFS_TIME_QUARTER 64#define OFDM_PREAMBLE_TIME_QUARTER 80#define OFDM_PLCP_BITS_QUARTER 22#define OFDM_SYMBOL_TIME_QUARTER 16 if (AH_PRIVATE(ah)->ah_curchan && IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; HALASSERT(bitsPerSymbol != 0); numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = howmany(numBits, bitsPerSymbol); txTime = OFDM_SIFS_TIME_QUARTER + OFDM_PREAMBLE_TIME_QUARTER + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); } else if (AH_PRIVATE(ah)->ah_curchan && IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; HALASSERT(bitsPerSymbol != 0); numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = howmany(numBits, bitsPerSymbol); txTime = OFDM_SIFS_TIME_HALF + OFDM_PREAMBLE_TIME_HALF + (numSymbols * OFDM_SYMBOL_TIME_HALF); } else { /* full rate channel */ bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; HALASSERT(bitsPerSymbol != 0); numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = howmany(numBits, bitsPerSymbol); txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME + (numSymbols * OFDM_SYMBOL_TIME); } break;#undef OFDM_SIFS_TIME#undef OFDM_PREAMBLE_TIME#undef OFDM_PLCP_BITS#undef OFDM_SYMBOL_TIME case IEEE80211_T_TURBO:#define TURBO_SIFS_TIME 8#define TURBO_PREAMBLE_TIME 14#define TURBO_PLCP_BITS 22#define TURBO_SYMBOL_TIME 4 /* we still save OFDM rates in kbps - so double them */ bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000; HALASSERT(bitsPerSymbol != 0); numBits = TURBO_PLCP_BITS + (frameLen << 3); numSymbols = howmany(numBits, bitsPerSymbol); txTime = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME + (numSymbols * TURBO_SYMBOL_TIME); break;#undef TURBO_SIFS_TIME#undef TURBO_PREAMBLE_TIME#undef TURBO_PLCP_BITS#undef TURBO_SYMBOL_TIME default: HALDEBUG(ah, HAL_DEBUG_PHYIO, "%s: unknown phy %u (rate ix %u)\n", __func__, rates->info[rateix].phy, rateix); txTime = 0; break; } return txTime;}static __inline intmapgsm(u_int freq, u_int flags){ freq *= 10; if (flags & CHANNEL_QUARTER) freq += 5; else if (flags & CHANNEL_HALF) freq += 10; else freq += 20; return (freq - 24220) / 5;}static __inline intmappsb(u_int freq, u_int flags){ return ((freq * 10) + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;}/* * Convert GHz frequency to IEEE channel number. */intath_hal_mhz2ieee(struct ath_hal *ah, u_int freq, u_int flags){ if (flags & CHANNEL_2GHZ) { /* 2GHz band */ if (freq == 2484) return 14; if (freq < 2484) { if (ath_hal_isgsmsku(ah)) return mapgsm(freq, flags); return ((int)freq - 2407) / 5; } else return 15 + ((freq - 2512) / 20); } else if (flags & CHANNEL_5GHZ) {/* 5Ghz band */ if (ath_hal_ispublicsafetysku(ah) && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { return mappsb(freq, flags); } else if ((flags & CHANNEL_A) && (freq <= 5000)) { return (freq - 4000) / 5; } else { return (freq - 5000) / 5; } } else { /* either, guess */ if (freq == 2484) return 14; if (freq < 2484) { if (ath_hal_isgsmsku(ah)) return mapgsm(freq, flags); return ((int)freq - 2407) / 5; } if (freq < 5000) { if (ath_hal_ispublicsafetysku(ah) && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { return mappsb(freq, flags); } else if (freq > 4900) { return (freq - 4000) / 5; } else { return 15 + ((freq - 2512) / 20); } } return (freq - 5000) / 5; }}typedef enum { WIRELESS_MODE_11a = 0, WIRELESS_MODE_TURBO = 1, WIRELESS_MODE_11b = 2, WIRELESS_MODE_11g = 3, WIRELESS_MODE_108g = 4, WIRELESS_MODE_MAX} WIRELESS_MODE;static WIRELESS_MODEath_hal_chan2wmode(struct ath_hal *ah, const HAL_CHANNEL *chan){ if (IS_CHAN_CCK(chan)) return WIRELESS_MODE_11b; if (IS_CHAN_G(chan)) return WIRELESS_MODE_11g; if (IS_CHAN_108G(chan)) return WIRELESS_MODE_108g; if (IS_CHAN_TURBO(chan)) return WIRELESS_MODE_TURBO; return WIRELESS_MODE_11a;}/* * Convert between microseconds and core system clocks. */ /* 11a Turbo 11b 11g 108g */static const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 };u_intath_hal_mac_clks(struct ath_hal *ah, u_int usecs){ const HAL_CHANNEL *c = (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan; u_int clks; /* NB: ah_curchan may be null when called attach time */ if (c != AH_NULL) { clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; if (IS_CHAN_HT40(c)) clks <<= 1; else if (IS_CHAN_HALF_RATE(c)) clks >>= 1; else if (IS_CHAN_QUARTER_RATE(c)) clks >>= 2; } else clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; return clks;}u_intath_hal_mac_usec(struct ath_hal *ah, u_int clks){ const HAL_CHANNEL *c = (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan; u_int usec; /* NB: ah_curchan may be null when called attach time */ if (c != AH_NULL) { usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; if (IS_CHAN_HT40(c)) usec >>= 1; else if (IS_CHAN_HALF_RATE(c)) usec <<= 1; else if (IS_CHAN_QUARTER_RATE(c)) usec <<= 2; } else usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; return usec;}/* * Setup a h/w rate table's reverse lookup table and * fill in ack durations. This routine is called for * each rate table returned through the ah_getRateTable * method. The reverse lookup tables are assumed to be * initialized to zero (or at least the first entry). * We use this as a key that indicates whether or not * we've previously setup the reverse lookup table. * * XXX not reentrant, but shouldn't matter */voidath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt){#define N(a) (sizeof(a)/sizeof(a[0])) int i; if (rt->rateCodeToIndex[0] != 0) /* already setup */ return; for (i = 0; i < N(rt->rateCodeToIndex); i++) rt->rateCodeToIndex[i] = (uint8_t) -1; for (i = 0; i < rt->rateCount; i++) { uint8_t code = rt->info[i].rateCode; uint8_t cix = rt->info[i].controlRate; HALASSERT(code < N(rt->rateCodeToIndex)); rt->rateCodeToIndex[code] = i; HALASSERT((code | rt->info[i].shortPreamble) < N(rt->rateCodeToIndex)); rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; /* * XXX for 11g the control rate to use for 5.5 and 11 Mb/s * depends on whether they are marked as basic rates; * the static tables are setup with an 11b-compatible * 2Mb/s rate which will work but is suboptimal */ rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); }#undef N}HAL_STATUSath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, uint32_t capability, uint32_t *result){ const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; switch (type) { case HAL_CAP_REG_DMN: /* regulatory domain */ *result = AH_PRIVATE(ah)->ah_currentRD; return HAL_OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -