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

📄 ar5212_misc.c

📁 最新之atheros芯片driver source code, 基于linux操作系统,內含atheros芯片HAL全部代码
💻 C
📖 第 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: ar5212_misc.c,v 1.12 2008/11/27 22:30:00 sam Exp $ */#include "opt_ah.h"#include "ah.h"#include "ah_internal.h"#include "ah_devid.h"#ifdef AH_DEBUG#include "ah_desc.h"			/* NB: for HAL_PHYERR* */#endif#include "ar5212/ar5212.h"#include "ar5212/ar5212reg.h"#include "ar5212/ar5212phy.h"#include "ah_eeprom_v3.h"#define	AR_NUM_GPIO	6		/* 6 GPIO pins */#define	AR_GPIOD_MASK	0x0000002F	/* GPIO data reg r/w mask */extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *);voidar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac){	struct ath_hal_5212 *ahp = AH5212(ah);	OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN);}HAL_BOOLar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac){	struct ath_hal_5212 *ahp = AH5212(ah);	OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN);	return AH_TRUE;}voidar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask){	struct ath_hal_5212 *ahp = AH5212(ah);	OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN);}HAL_BOOLar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask){	struct ath_hal_5212 *ahp = AH5212(ah);	/* save it since it must be rewritten on reset */	OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN);	OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));	OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));	return AH_TRUE;}/* * Attempt to change the cards operating regulatory domain to the given value */HAL_BOOLar5212SetRegulatoryDomain(struct ath_hal *ah,	uint16_t regDomain, HAL_STATUS *status){	HAL_STATUS ecode;	if (AH_PRIVATE(ah)->ah_currentRD == regDomain) {		ecode = HAL_EINVAL;		goto bad;	}	if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) {		ecode = HAL_EEWRITE;		goto bad;	}#ifdef AH_SUPPORT_WRITE_REGDOMAIN	if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) {		HALDEBUG(ah, HAL_DEBUG_ANY,		    "%s: set regulatory domain to %u (0x%x)\n",		    __func__, regDomain, regDomain);		AH_PRIVATE(ah)->ah_currentRD = regDomain;		return AH_TRUE;	}#endif	ecode = HAL_EIO;bad:	if (status)		*status = ecode;	return AH_FALSE;}/* * Return the wireless modes (a,b,g,t) supported by hardware. * * This value is what is actually supported by the hardware * and is unaffected by regulatory/country code settings. */u_intar5212GetWirelessModes(struct ath_hal *ah){	u_int mode = 0;	if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {		mode = HAL_MODE_11A;		if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))			mode |= HAL_MODE_TURBO | HAL_MODE_108A;		if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate)			mode |= HAL_MODE_11A_HALF_RATE;		if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate)			mode |= HAL_MODE_11A_QUARTER_RATE;	}	if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))		mode |= HAL_MODE_11B;	if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) &&	    AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) {		mode |= HAL_MODE_11G;		if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE))			mode |= HAL_MODE_108G;		if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate)			mode |= HAL_MODE_11G_HALF_RATE;		if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate)			mode |= HAL_MODE_11G_QUARTER_RATE;	}	return mode;}/* * Set the interrupt and GPIO values so the ISR can disable RF * on a switch signal.  Assumes GPIO port and interrupt polarity * are set prior to call. */voidar5212EnableRfKill(struct ath_hal *ah){	uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent;	int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL);	int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY);	/*	 * Configure the desired GPIO port for input	 * and enable baseband rf silence.	 */	ath_hal_gpioCfgInput(ah, select);	OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000);	/*	 * If radio disable switch connection to GPIO bit x is enabled	 * program GPIO interrupt.	 * If rfkill bit on eeprom is 1, setupeeprommap routine has already	 * verified that it is a later version of eeprom, it has a place for	 * rfkill bit and it is set to 1, indicating that GPIO bit x hardware	 * connection is present.	 */	ath_hal_gpioSetIntr(ah, select,	    (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity));}/* * Change the LED blinking pattern to correspond to the connectivity */voidar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state){	static const uint32_t ledbits[8] = {		AR_PCICFG_LEDCTL_NONE,	/* HAL_LED_INIT */		AR_PCICFG_LEDCTL_PEND,	/* HAL_LED_SCAN */		AR_PCICFG_LEDCTL_PEND,	/* HAL_LED_AUTH */		AR_PCICFG_LEDCTL_ASSOC,	/* HAL_LED_ASSOC*/		AR_PCICFG_LEDCTL_ASSOC,	/* HAL_LED_RUN */		AR_PCICFG_LEDCTL_NONE,		AR_PCICFG_LEDCTL_NONE,		AR_PCICFG_LEDCTL_NONE,	};	uint32_t bits;	bits = OS_REG_READ(ah, AR_PCICFG);	if (IS_2417(ah)) {		/*		 * Enable LED for Nala. There is a bit marked reserved		 * that must be set and we also turn on the power led.		 * Because we mark s/w LED control setting the control		 * status bits below is meangless (the driver must flash		 * the LED(s) using the GPIO lines).		 */		bits = (bits &~ AR_PCICFG_LEDMODE)		     | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE)#if 0		     | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE)#endif		     | 0x08000000;	}	bits = (bits &~ AR_PCICFG_LEDCTL)	     | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL);	OS_REG_WRITE(ah, AR_PCICFG, bits);}/* * Change association related fields programmed into the hardware. * Writing a valid BSSID to the hardware effectively enables the hardware * to synchronize its TSF to the correct beacons and receive frames coming * from that BSSID. It is called by the SME JOIN operation. */voidar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId){	struct ath_hal_5212 *ahp = AH5212(ah);	/* XXX save bssid for possible re-use on reset */	OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);	OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));	OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) |				     ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));}/* * Get the current hardware tsf for stamlme */uint64_tar5212GetTsf64(struct ath_hal *ah){	uint32_t low1, low2, u32;	/* sync multi-word read */	low1 = OS_REG_READ(ah, AR_TSF_L32);	u32 = OS_REG_READ(ah, AR_TSF_U32);	low2 = OS_REG_READ(ah, AR_TSF_L32);	if (low2 < low1) {	/* roll over */		/*		 * If we are not preempted this will work.  If we are		 * then we re-reading AR_TSF_U32 does no good as the		 * low bits will be meaningless.  Likewise reading		 * L32, U32, U32, then comparing the last two reads		 * to check for rollover doesn't help if preempted--so		 * we take this approach as it costs one less PCI read		 * which can be noticeable when doing things like		 * timestamping packets in monitor mode.		 */		u32++;	}	return (((uint64_t) u32) << 32) | ((uint64_t) low2);}/* * Get the current hardware tsf for stamlme */uint32_tar5212GetTsf32(struct ath_hal *ah){	return OS_REG_READ(ah, AR_TSF_L32);}/* * Reset the current hardware tsf for stamlme. */voidar5212ResetTsf(struct ath_hal *ah){	uint32_t val = OS_REG_READ(ah, AR_BEACON);	OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);	/*	 * When resetting the TSF, write twice to the	 * corresponding register; each write to the RESET_TSF bit toggles	 * the internal signal to cause a reset of the TSF - but if the signal	 * is left high, it will reset the TSF on the next chip reset also!	 * writing the bit an even number of times fixes this issue	 */	OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);}/* * Set or clear hardware basic rate bit * Set hardware basic rate set if basic rate is found * and basic rate is equal or less than 2Mbps */voidar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs){	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;	uint32_t reg;	uint8_t xset;	int i;	if (chan == AH_NULL || !IS_CHAN_CCK(chan))		return;	xset = 0;	for (i = 0; i < rs->rs_count; i++) {		uint8_t rset = rs->rs_rates[i];		/* Basic rate defined? */		if ((rset & 0x80) && (rset &= 0x7f) >= xset)			xset = rset;	}	/*	 * Set the h/w bit to reflect whether or not the basic	 * rate is found to be equal or less than 2Mbps.	 */	reg = OS_REG_READ(ah, AR_STA_ID1);	if (xset && xset/2 <= 2)		OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B);	else		OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B);}/* * Grab a semi-random value from hardware registers - may not * change often */uint32_tar5212GetRandomSeed(struct ath_hal *ah){	uint32_t nf;	nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;	if (nf & 0x100)		nf = 0 - ((nf ^ 0x1ff) + 1);	return (OS_REG_READ(ah, AR_TSF_U32) ^		OS_REG_READ(ah, AR_TSF_L32) ^ nf);}/* * Detect if our card is present */HAL_BOOLar5212DetectCardPresent(struct ath_hal *ah){	uint16_t macVersion, macRev;	uint32_t v;	/*	 * Read the Silicon Revision register and compare that	 * to what we read at attach time.  If the same, we say	 * a card/device is present.	 */	v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID;	macVersion = v >> AR_SREV_ID_S;	macRev = v & AR_SREV_REVISION;	return (AH_PRIVATE(ah)->ah_macVersion == macVersion &&		AH_PRIVATE(ah)->ah_macRev == macRev);}voidar5212EnableMibCounters(struct ath_hal *ah){	/* NB: this just resets the mib counter machinery */	OS_REG_WRITE(ah, AR_MIBC,	    ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);}void ar5212DisableMibCounters(struct ath_hal *ah){	OS_REG_WRITE(ah, AR_MIBC,  AR_MIBC | AR_MIBC_CMC);}/* * Update MIB Counters */voidar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats){	stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL);	stats->rts_bad	  += OS_REG_READ(ah, AR_RTS_FAIL);	stats->fcs_bad	  += OS_REG_READ(ah, AR_FCS_FAIL);	stats->rts_good	  += OS_REG_READ(ah, AR_RTS_OK);	stats->beacons	  += OS_REG_READ(ah, AR_BEACON_CNT);}/* * Detect if the HW supports spreading a CCK signal on channel 14 */HAL_BOOLar5212IsJapanChannelSpreadSupported(struct ath_hal *ah){	return AH_TRUE;}/* * Get the rssi of frame curently being received. */uint32_tar5212GetCurRssi(struct ath_hal *ah){	return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);}u_intar5212GetDefAntenna(struct ath_hal *ah){   	return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7);}   voidar5212SetDefAntenna(struct ath_hal *ah, u_int antenna){	OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));}HAL_ANT_SETTINGar5212GetAntennaSwitch(struct ath_hal *ah){	return AH5212(ah)->ah_antControl;}HAL_BOOLar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting){	struct ath_hal_5212 *ahp = AH5212(ah);	const HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan;	if (!ahp->ah_phyPowerOn || ichan == AH_NULL) {		/* PHY powered off, just stash settings */		ahp->ah_antControl = setting;		ahp->ah_diversity = (setting == HAL_ANT_VARIABLE);		return AH_TRUE;	}	return ar5212SetAntennaSwitchInternal(ah, setting, ichan);}HAL_BOOLar5212IsSleepAfterBeaconBroken(struct ath_hal *ah){	return AH_TRUE;}HAL_BOOLar5212SetSifsTime(struct ath_hal *ah, u_int us){	struct ath_hal_5212 *ahp = AH5212(ah);	if (us > ath_hal_mac_usec(ah, 0xffff)) {		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n",		    __func__, us);		ahp->ah_sifstime = (u_int) -1;	/* restore default handling */		return AH_FALSE;	} else {		/* convert to system clocks */		OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us));		ahp->ah_slottime = us;		return AH_TRUE;	}}u_intar5212GetSifsTime(struct ath_hal *ah){	u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff;	return ath_hal_mac_usec(ah, clks);	/* convert from system clocks */}HAL_BOOLar5212SetSlotTime(struct ath_hal *ah, u_int us){	struct ath_hal_5212 *ahp = AH5212(ah);	if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) {		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n",		    __func__, us);		ahp->ah_slottime = (u_int) -1;	/* restore default handling */		return AH_FALSE;	} else {		/* convert to system clocks */		OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us));		ahp->ah_slottime = us;		return AH_TRUE;	}}u_intar5212GetSlotTime(struct ath_hal *ah){	u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff;	return ath_hal_mac_usec(ah, clks);	/* convert from system clocks */}HAL_BOOLar5212SetAckTimeout(struct ath_hal *ah, u_int us){	struct ath_hal_5212 *ahp = AH5212(ah);	if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n",		    __func__, us);		ahp->ah_acktimeout = (u_int) -1; /* restore default handling */		return AH_FALSE;	} else {		/* convert to system clocks */		OS_REG_RMW_FIELD(ah, AR_TIME_OUT,			AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us));		ahp->ah_acktimeout = us;		return AH_TRUE;	}}u_intar5212GetAckTimeout(struct ath_hal *ah){	u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK);	return ath_hal_mac_usec(ah, clks);	/* convert from system clocks */}u_intar5212GetAckCTSRate(struct ath_hal *ah){	return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0);}HAL_BOOLar5212SetAckCTSRate(struct ath_hal *ah, u_int high){	struct ath_hal_5212 *ahp = AH5212(ah);	if (high) {		OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);		ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB;	} else {		OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);		ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB;	}	return AH_TRUE;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -