⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ah.c.svn-base

📁 最新之atheros芯片driver source code, 基于linux操作系统,內含atheros芯片HAL全部代码
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/* * 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 + -