diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2004-11-02 03:01:17 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2004-11-02 03:01:17 +0000 |
commit | 6f310ee239544802e42e2a984bac432479b1a8ba (patch) | |
tree | 358dd508a47f8cb4c1cef09b798a9236c1cb6c3c /sys/dev | |
parent | 811904472e873a7a84e99ef1b66849f83cbc0f3b (diff) |
import of a free hal part for the ath driver as a replacement for the
binary-only hal module found in FreeBSD and NetBSD. OpenBSD's approach
is based on reverse engineering because it is _not_ possible to
include a non-free and binary-only piece of software in a 100% free
operating system. it still lacks some features found in the "official" hal
module but this will be done very soon with a help by a lot of
contributors - because it's free.
ok deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/ar5210.c | 2514 | ||||
-rw-r--r-- | sys/dev/ic/ar5210reg.h | 687 | ||||
-rw-r--r-- | sys/dev/ic/ar5210var.h | 440 | ||||
-rw-r--r-- | sys/dev/ic/ar5xxx.c | 548 | ||||
-rw-r--r-- | sys/dev/ic/ar5xxx.h | 962 |
5 files changed, 5151 insertions, 0 deletions
diff --git a/sys/dev/ic/ar5210.c b/sys/dev/ic/ar5210.c new file mode 100644 index 00000000000..220eb9d44d4 --- /dev/null +++ b/sys/dev/ic/ar5210.c @@ -0,0 +1,2514 @@ +/* $OpenBSD: ar5210.c,v 1.1 2004/11/02 03:01:16 reyk Exp $ */ + +/* + * Copyright (c) 2004 Reyk Floeter <reyk@vantronix.net>. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY + * SPECIAL 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. + */ + +/* + * HAL interface for the Atheros AR5000 Wireless LAN chipset + * (AR5210 + AR5110). + */ + +#include <dev/ic/ar5xxx.h> + +#ifdef AR5K_SUPPORT_AR5210 + +#include <dev/ic/ar5210reg.h> +#include <dev/ic/ar5210var.h> + +HAL_BOOL ar5k_ar5210_nic_reset(struct ath_hal *, u_int32_t); +HAL_BOOL ar5k_ar5210_nic_wakeup(struct ath_hal *, HAL_BOOL, HAL_BOOL); +u_int32_t ar5k_ar5210_chan2athchan(HAL_CHANNEL *); +HAL_BOOL ar5k_ar5210_set_channel(struct ath_hal *, HAL_CHANNEL *); +void ar5k_ar5210_init_tx_queue(struct ath_hal *, u_int, HAL_BOOL); +const void ar5k_ar5210_fill(struct ath_hal *); + +AR5K_HAL_FUNCTIONS(extern, ar5k_ar5210,); + +const void +ar5k_ar5210_fill(hal) + struct ath_hal *hal; +{ + hal->ah_magic = AR5K_AR5210_MAGIC; + + /* + * Init/Exit functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, getRateTable); + AR5K_HAL_FUNCTION(hal, ar5210, detach); + + /* + * Reset functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, reset); + AR5K_HAL_FUNCTION(hal, ar5210, setPCUConfig); + AR5K_HAL_FUNCTION(hal, ar5210, perCalibration); + + /* + * TX functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, updateTxTrigLevel); + AR5K_HAL_FUNCTION(hal, ar5210, setupTxQueue); + AR5K_HAL_FUNCTION(hal, ar5210, setTxQueueProps); + AR5K_HAL_FUNCTION(hal, ar5210, releaseTxQueue); + AR5K_HAL_FUNCTION(hal, ar5210, resetTxQueue); + AR5K_HAL_FUNCTION(hal, ar5210, getTxDP); + AR5K_HAL_FUNCTION(hal, ar5210, setTxDP); + AR5K_HAL_FUNCTION(hal, ar5210, startTxDma); + AR5K_HAL_FUNCTION(hal, ar5210, stopTxDma); + AR5K_HAL_FUNCTION(hal, ar5210, setupTxDesc); + AR5K_HAL_FUNCTION(hal, ar5210, setupXTxDesc); + AR5K_HAL_FUNCTION(hal, ar5210, fillTxDesc); + AR5K_HAL_FUNCTION(hal, ar5210, procTxDesc); + AR5K_HAL_FUNCTION(hal, ar5210, hasVEOL); + + /* + * RX functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, getRxDP); + AR5K_HAL_FUNCTION(hal, ar5210, setRxDP); + AR5K_HAL_FUNCTION(hal, ar5210, enableReceive); + AR5K_HAL_FUNCTION(hal, ar5210, stopDmaReceive); + AR5K_HAL_FUNCTION(hal, ar5210, startPcuReceive); + AR5K_HAL_FUNCTION(hal, ar5210, stopPcuReceive); + AR5K_HAL_FUNCTION(hal, ar5210, setMulticastFilter); + AR5K_HAL_FUNCTION(hal, ar5210, setMulticastFilterIndex); + AR5K_HAL_FUNCTION(hal, ar5210, clrMulticastFilterIndex); + AR5K_HAL_FUNCTION(hal, ar5210, getRxFilter); + AR5K_HAL_FUNCTION(hal, ar5210, setRxFilter); + AR5K_HAL_FUNCTION(hal, ar5210, setupRxDesc); + AR5K_HAL_FUNCTION(hal, ar5210, procRxDesc); + AR5K_HAL_FUNCTION(hal, ar5210, rxMonitor); + + /* + * Misc functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, dumpState); + AR5K_HAL_FUNCTION(hal, ar5210, getDiagState); + AR5K_HAL_FUNCTION(hal, ar5210, getMacAddress); + AR5K_HAL_FUNCTION(hal, ar5210, setMacAddress); + AR5K_HAL_FUNCTION(hal, ar5210, setRegulatoryDomain); + AR5K_HAL_FUNCTION(hal, ar5210, setLedState); + AR5K_HAL_FUNCTION(hal, ar5210, writeAssocid); + AR5K_HAL_FUNCTION(hal, ar5210, gpioCfgInput); + AR5K_HAL_FUNCTION(hal, ar5210, gpioCfgOutput); + AR5K_HAL_FUNCTION(hal, ar5210, gpioGet); + AR5K_HAL_FUNCTION(hal, ar5210, gpioSet); + AR5K_HAL_FUNCTION(hal, ar5210, gpioSetIntr); + AR5K_HAL_FUNCTION(hal, ar5210, getTsf32); + AR5K_HAL_FUNCTION(hal, ar5210, getTsf64); + AR5K_HAL_FUNCTION(hal, ar5210, resetTsf); + AR5K_HAL_FUNCTION(hal, ar5210, getRegDomain); + AR5K_HAL_FUNCTION(hal, ar5210, detectCardPresent); + AR5K_HAL_FUNCTION(hal, ar5210, updateMibCounters); + AR5K_HAL_FUNCTION(hal, ar5210, getRfGain); + AR5K_HAL_FUNCTION(hal, ar5210, setSlotTime); + AR5K_HAL_FUNCTION(hal, ar5210, getSlotTime); + AR5K_HAL_FUNCTION(hal, ar5210, setAckTimeout); + AR5K_HAL_FUNCTION(hal, ar5210, getAckTimeout); + AR5K_HAL_FUNCTION(hal, ar5210, setCTSTimeout); + AR5K_HAL_FUNCTION(hal, ar5210, getCTSTimeout); + + /* + * Key table (WEP) functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, isHwCipherSupported); + AR5K_HAL_FUNCTION(hal, ar5210, getKeyCacheSize); + AR5K_HAL_FUNCTION(hal, ar5210, resetKeyCacheEntry); + AR5K_HAL_FUNCTION(hal, ar5210, isKeyCacheEntryValid); + AR5K_HAL_FUNCTION(hal, ar5210, setKeyCacheEntry); + AR5K_HAL_FUNCTION(hal, ar5210, setKeyCacheEntryMac); + + /* + * Power management functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, setPowerMode); + AR5K_HAL_FUNCTION(hal, ar5210, getPowerMode); + AR5K_HAL_FUNCTION(hal, ar5210, queryPSPollSupport); + AR5K_HAL_FUNCTION(hal, ar5210, initPSPoll); + AR5K_HAL_FUNCTION(hal, ar5210, enablePSPoll); + AR5K_HAL_FUNCTION(hal, ar5210, disablePSPoll); + + /* + * Beacon functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, beaconInit); + AR5K_HAL_FUNCTION(hal, ar5210, setStationBeaconTimers); + AR5K_HAL_FUNCTION(hal, ar5210, resetStationBeaconTimers); + AR5K_HAL_FUNCTION(hal, ar5210, waitForBeaconDone); + + /* + * Interrupt functions + */ + AR5K_HAL_FUNCTION(hal, ar5210, isInterruptPending); + AR5K_HAL_FUNCTION(hal, ar5210, getPendingInterrupts); + AR5K_HAL_FUNCTION(hal, ar5210, getInterrupts); + AR5K_HAL_FUNCTION(hal, ar5210, setInterrupts); + + /* + * Chipset functions (ar5k-specific, non-HAL) + */ + AR5K_HAL_FUNCTION(hal, ar5210, get_capabilities); + AR5K_HAL_FUNCTION(hal, ar5210, radar_alert); + AR5K_HAL_FUNCTION(hal, ar5210, regulation_domain); + + /* + * EEPROM access + */ + AR5K_HAL_FUNCTION(hal, ar5210, eeprom_init); + AR5K_HAL_FUNCTION(hal, ar5210, eeprom_is_busy); + AR5K_HAL_FUNCTION(hal, ar5210, eeprom_read); + AR5K_HAL_FUNCTION(hal, ar5210, eeprom_write); +} + +struct ath_hal * +ar5k_ar5210_attach(device, sc, st, sh, status) + u_int16_t device; + void *sc; + bus_space_tag_t st; + bus_space_handle_t sh; + int *status; +{ + int i; + struct ath_hal *hal = (struct ath_hal*) sc; + u_int8_t mac[IEEE80211_ADDR_LEN]; + + ar5k_ar5210_fill(hal); + + /* Bring device out of sleep and reset it's units */ + if(ar5k_ar5210_nic_wakeup(hal, AH_FALSE, AH_TRUE) != AH_TRUE) + return(NULL); + + /* Get MAC, PHY and RADIO revisions */ + hal->ah_mac_version = 1; + hal->ah_mac_revision = (AR5K_REG_READ(AR5K_AR5210_SREV) & + AR5K_AR5210_SREV_ID_M); + hal->ah_phy_revision = AR5K_REG_READ(AR5K_AR5210_PHY_CHIP_ID) & + 0x00ffffffff; + + /* ...wait until PHY is ready and read RADIO revision */ + AR5K_REG_WRITE(AR5K_AR5210_PHY(0x34), 0x00001c16); + for(i = 0; i < 4; i++) + AR5K_REG_WRITE(AR5K_AR5210_PHY(0x20), 0x00010000); + hal->ah_radio_5ghz_revision = (u_int16_t) + (ar5k_bitswap((AR5K_REG_READ(AR5K_AR5210_PHY(256) >> 28) & + 0xf), 4) + 1); + hal->ah_radio_2ghz_revision = 0; + + memset(&mac, 0xff, sizeof(mac)); + ar5k_ar5210_writeAssocid(hal, mac, 0, 0); + ar5k_ar5210_getMacAddress(hal, mac); + ar5k_ar5210_setPCUConfig(hal); + + return(hal); +} + +HAL_BOOL +ar5k_ar5210_nic_reset(hal, val) + struct ath_hal *hal; + u_int32_t val; +{ + HAL_BOOL ret = AH_FALSE; + u_int32_t mask = val ? val : ~0; + + /* + * Reset the device and wait until success + */ + AR5K_REG_WRITE(AR5K_AR5210_RC, val); + + /* Wait at least 128 PCI clocks */ + AR5K_DELAY(15); + + val &= + AR5K_AR5210_RC_PCU | AR5K_AR5210_RC_MAC | + AR5K_AR5210_RC_PHY | AR5K_AR5210_RC_DMA; + + mask &= + AR5K_AR5210_RC_PCU | AR5K_AR5210_RC_MAC | + AR5K_AR5210_RC_PHY | AR5K_AR5210_RC_DMA; + + ret = ar5k_register_timeout(hal, AR5K_AR5210_RC, mask, val, AH_FALSE); + + /* + * Reset configuration register + */ + if((val & AR5K_AR5210_RC_MAC) == 0) + AR5K_REG_WRITE(AR5K_AR5210_CFG, AR5K_AR5210_INIT_CFG); + + return(ret); +} + +HAL_BOOL +ar5k_ar5210_nic_wakeup(hal, turbo, initial) + struct ath_hal *hal; + HAL_BOOL turbo; + HAL_BOOL initial; +{ + /* + * Reset and wakeup the device + */ + + if(initial == AH_TRUE) { + /* ...reset hardware */ + if(ar5k_ar5210_nic_reset(hal, AR5K_AR5210_RC_PCI) == AH_FALSE) { + AR5K_PRINTF("failed to reset the PCI chipset\n"); + return(AH_FALSE); + } + + AR5K_DELAY(1000); + } + + /* ...wakeup the device */ + if(ar5k_ar5210_setPowerMode(hal, HAL_PM_AWAKE, AH_TRUE, 0) == AH_FALSE) { + AR5K_PRINTF("failed to resume the AR5210 chipset\n"); + return(AH_FALSE); + } + + /* ...enable Atheros turbo mode if requested */ + AR5K_REG_WRITE(AR5K_AR5210_PHY_FC, + turbo == AH_TRUE ? AR5K_AR5210_PHY_FC_TURBO_MODE : 0); + + /* ...reset chipset */ + if(ar5k_ar5210_nic_reset(hal, AR5K_AR5210_RC_CHIP) == AH_FALSE) { + AR5K_PRINTF("failed to reset the AR5210 chipset\n"); + return(AH_FALSE); + } + + AR5K_DELAY(1000); + + /* ...reset chipset and PCI device */ + if(ar5k_ar5210_nic_reset(hal, AR5K_AR5210_RC_CHIP | + AR5K_AR5210_RC_PCI) == AH_FALSE) { + AR5K_PRINTF("failed to reset the AR5210 + PCI chipset\n"); + return(AH_FALSE); + } + + AR5K_DELAY(2300); + + /* ...wakeup (again) */ + if(ar5k_ar5210_setPowerMode(hal, HAL_PM_AWAKE, AH_TRUE, 0) == AH_FALSE) { + AR5K_PRINTF("failed to resume the AR5210 (again)\n"); + return(AH_FALSE); + } + + /* ...final warm reset */ + if(ar5k_ar5210_nic_reset(hal, 0) == AH_FALSE) { + AR5K_PRINTF("failed to warm reset the AR5210\n"); + return(AH_FALSE); + } + + return(AH_TRUE); +} + +u_int32_t +ar5k_ar5210_chan2athchan(channel) + HAL_CHANNEL *channel; +{ + u_int32_t athchan; + + /* + * Convert IEEE channel/MHz to an internal channel value used + * by the AR5210 chipset. This has not been verified with + * newer chipsets like the AR5212A who have a completely + * different RF/PHY part. + */ + athchan = (ar5k_bitswap((ieee80211_mhz2ieee(channel->channel, + channel->channelFlags) - 24) + / 2, 5) << 1) | (1 << 6) | 0x1; + + return(athchan); +} + +HAL_BOOL +ar5k_ar5210_set_channel(hal, channel) + struct ath_hal *hal; + HAL_CHANNEL *channel; +{ + u_int32_t data; + + /* Disable phy and wait */ + AR5K_REG_WRITE(AR5K_AR5210_PHY_ACTIVE, AR5K_AR5210_PHY_DISABLE); + AR5K_DELAY(1000); + + /* + * Check bounds supported by the PHY + * (don't care about regulation restrictions at this point) + */ + if(channel->channel < hal->ah_capabilities.cap_range.range_5ghz_min || + channel->channel > hal->ah_capabilities.cap_range.range_5ghz_max) { + AR5K_PRINTF("channel out of supported range (%u MHz)\n", + channel->channel); + return(AH_FALSE); + } + + /* + * Set the channel and wait + */ + data = ar5k_ar5210_chan2athchan(channel); + AR5K_REG_WRITE(AR5K_AR5210_PHY(0x27), data); + AR5K_REG_WRITE(AR5K_AR5210_PHY(0x30), 0); + AR5K_DELAY(1000); + + /* + * Activate phy and wait + */ + AR5K_REG_WRITE(AR5K_AR5210_PHY_ACTIVE, AR5K_AR5210_PHY_ENABLE); + AR5K_DELAY(1000); + + hal->ah_current_channel.channel = channel->channel; + hal->ah_current_channel.channelFlags = channel->channelFlags; + hal->ah_turbo = channel->channelFlags == CHANNEL_T ? AH_TRUE : AH_FALSE; + + return(AH_TRUE); +} + +const HAL_RATE_TABLE * +ar5k_ar5210_getRateTable(hal, mode) + struct ath_hal *hal; + u_int mode; +{ + switch(mode) { + case HAL_MODE_11A: + return(&hal->ah_rt_11a); + case HAL_MODE_TURBO: + return(&hal->ah_rt_turbo); + case HAL_MODE_11B: + case HAL_MODE_11G: + default: + return(NULL); + } + + return(NULL); +} + +void +ar5k_ar5210_detach(hal) + struct ath_hal *hal; +{ + /* + * Free HAL structure, assume interrupts are down + */ + free(hal, M_DEVBUF); +} + +HAL_BOOL +ar5k_ar5210_reset(hal, op_mode, channel, change_channel, status) + struct ath_hal *hal; + HAL_OPMODE op_mode; + HAL_CHANNEL *channel; + HAL_BOOL change_channel; + HAL_STATUS *status; +{ + int i; + struct ar5k_ini initial[] = AR5K_AR5210_INI; + + if(ar5k_ar5210_nic_wakeup(hal, + channel->channelFlags & IEEE80211_CHAN_T ? + AH_TRUE : AH_FALSE, AH_FALSE) == AH_FALSE) + return(AH_FALSE); + + /* + * Initialize operating mode + */ + hal->ah_op_mode = op_mode; + ar5k_ar5210_setPCUConfig(hal); + + /* + * Write initial mode register settings + */ + for(i = 0; i < AR5K_ELEMENTS(initial); i++) { + if(change_channel == AH_TRUE && + initial[i].ini_register >= AR5K_AR5210_PCU_MIN && + initial[i].ini_register <= AR5K_AR5210_PCU_MAX) + continue; + + switch(initial[i].ini_mode) { + case INI_READ: + /* Cleared on read */ + AR5K_REG_READ(initial[i].ini_register); + break; + + case INI_WRITE: + default: + AR5K_REG_WRITE(initial[i].ini_register, + initial[i].ini_value); + } + } + + AR5K_DELAY(1000); + + /* + * Set channel and calibrate the PHY + */ + if(ar5k_ar5210_perCalibration(hal, channel) == AH_FALSE) + return(AH_FALSE); + + /* + * Set RF kill flags if supported by the device (read from the EEPROM) + */ + if(hal->ah_capabilities.cap_eeprom.ee_rfkill != 0) { + if ((hal->ah_gpio[0] = ar5k_ar5210_gpioGet(hal, 0)) == 0) + ar5k_ar5210_gpioSetIntr(hal, 0, 1); + else + ar5k_ar5210_gpioSetIntr(hal, 0, 0); + } + + /* + * Reset queues and start beacon timers at the end of the reset routine + */ + for(i = 0; i < hal->ah_capabilities.cap_queues.q_tx_num; i++) { + if(ar5k_ar5210_resetTxQueue(hal, i) == AH_FALSE) { + AR5K_PRINTF("failed to reset TX queue #%d\n", i); + return(AH_FALSE); + } + } + + AR5K_REG_ENABLE_BITS(AR5K_AR5210_BEACON, + AR5K_AR5210_BEACON_EN | AR5K_AR5210_BEACON_RESET_TSF); + + return(AH_TRUE); +} + +void +ar5k_ar5210_setPCUConfig(hal) + struct ath_hal *hal; +{ + u_int32_t pcu_reg, beacon_reg, low_id, high_id; + + beacon_reg = 0; + pcu_reg = 0; + + switch(hal->ah_op_mode) { + case IEEE80211_M_STA: + pcu_reg |= AR5K_AR5210_STA_ID1_NO_PSPOLL | + AR5K_AR5210_STA_ID1_DESC_ANTENNA | + AR5K_AR5210_STA_ID1_PWR_SV; + break; + + case IEEE80211_M_IBSS: + pcu_reg |= AR5K_AR5210_STA_ID1_ADHOC | + AR5K_AR5210_STA_ID1_NO_PSPOLL | + AR5K_AR5210_STA_ID1_DESC_ANTENNA; + beacon_reg |= AR5K_AR5210_BCR_ADHOC; + break; + + case IEEE80211_M_HOSTAP: + pcu_reg |= AR5K_AR5210_STA_ID1_AP | + AR5K_AR5210_STA_ID1_NO_PSPOLL | + AR5K_AR5210_STA_ID1_DESC_ANTENNA; + beacon_reg |= AR5K_AR5210_BCR_AP; + break; + + case IEEE80211_M_MONITOR: + pcu_reg |= AR5K_AR5210_STA_ID1_NO_PSPOLL; + break; + + default: + return; + } + + /* + * Set PCU and BCR registers + */ + memcpy(&low_id, &(hal->ah_sta_id[0]), 4); + memcpy(&high_id, &(hal->ah_sta_id[4]), 2); + AR5K_REG_WRITE(AR5K_AR5210_STA_ID0, low_id); + AR5K_REG_WRITE(AR5K_AR5210_STA_ID1, pcu_reg | high_id); + AR5K_REG_WRITE(AR5K_AR5210_BCR, beacon_reg); + + return; +} + +HAL_BOOL +ar5k_ar5210_perCalibration(hal, channel) + struct ath_hal *hal; + HAL_CHANNEL *channel; +{ + /* + * Disable beacons and RX/TX queues, wait + */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_DIAG_SW, + AR5K_AR5210_DIAG_SW_DIS_TX | AR5K_AR5210_DIAG_SW_DIS_RX); + AR5K_REG_DISABLE_BITS(AR5K_AR5210_BEACON, AR5K_AR5210_BEACON_EN); + + AR5K_DELAY(2300); + + /* + * Set the channel (with AGC turned off) + */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_PHY_AGC, AR5K_AR5210_PHY_AGC_DISABLE); + + if(ar5k_ar5210_set_channel(hal, channel) != AH_TRUE) + return(AH_FALSE); + + AR5K_REG_DISABLE_BITS(AR5K_AR5210_PHY_AGC, AR5K_AR5210_PHY_AGC_DISABLE); + + /* + * Enable noise floor calibration and wait until completion + */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_PHY_AGCCTL, + AR5K_AR5210_PHY_AGC_CAL); + + if(ar5k_register_timeout(hal, AR5K_AR5210_PHY_AGCCTL, + AR5K_AR5210_PHY_AGC_CAL, 0, AH_FALSE) == AH_FALSE) { + AR5K_PRINTF("calibration timeout\n"); + return(AH_FALSE); + } + + /* + * XXX Check the current noise floor? + */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_PHY_AGCCTL, + AR5K_AR5210_PHY_AGC_NF); + + /* + * Re-enable RX/TX and beacons + */ + AR5K_REG_DISABLE_BITS(AR5K_AR5210_DIAG_SW, + AR5K_AR5210_DIAG_SW_DIS_TX | AR5K_AR5210_DIAG_SW_DIS_RX); + AR5K_REG_ENABLE_BITS(AR5K_AR5210_BEACON, AR5K_AR5210_BEACON_EN); + + return(AH_TRUE); +} + +/* + * Transmit functions + */ + +HAL_BOOL +ar5k_ar5210_updateTxTrigLevel(hal, increase) + struct ath_hal *hal; + HAL_BOOL increase; +{ + u_int32_t trigger_level; + HAL_BOOL status = AH_FALSE; + + /* + * Disable interrupts by setting the mask + */ + AR5K_REG_DISABLE_BITS(AR5K_AR5210_IMR, HAL_INT_GLOBAL); + + trigger_level = AR5K_REG_READ(AR5K_AR5210_TRIG_LVL); + + if(increase == AH_FALSE) { + if(--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) + goto done; + } else + trigger_level += + ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); + + /* + * Update trigger level on success + */ + AR5K_REG_WRITE(AR5K_AR5210_TRIG_LVL, trigger_level); + status = AH_TRUE; + + done: + /* + * Restore interrupt mask + */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_IMR, HAL_INT_GLOBAL); + + return(status); +} + +int +ar5k_ar5210_setupTxQueue(hal, queue_type, queue_info) + struct ath_hal *hal; + HAL_TX_QUEUE queue_type; + const HAL_TXQ_INFO *queue_info; +{ + u_int queue; + + /* + * Get queue by type + */ + switch(queue_type) { + case HAL_TX_QUEUE_DATA: + queue = 0; + break; + case HAL_TX_QUEUE_BEACON: + case HAL_TX_QUEUE_CAB: + queue = 1; + break; + default: + return(-EINVAL); + } + + /* + * Setup internal queue structure + */ + bzero(&hal->ah_txq[queue], sizeof(HAL_TXQ_INFO)); + hal->ah_txq[queue].tqi_type = queue_type; + + if(queue_info != NULL) { + if(ar5k_ar5210_setTxQueueProps(hal, queue, queue_info) != AH_TRUE) + return(AH_FALSE); + } + + return(0); +} + +HAL_BOOL +ar5k_ar5210_setTxQueueProps(hal, queue, queue_info) + struct ath_hal *hal; + int queue; + const HAL_TXQ_INFO *queue_info; +{ + AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); + + if(hal->ah_txq[queue].tqi_type == HAL_TX_QUEUE_INACTIVE) + return(AH_FALSE); + + hal->ah_txq[queue].tqi_aifs = queue_info->tqi_aifs; + hal->ah_txq[queue].tqi_cw_max = queue_info->tqi_cw_max; + hal->ah_txq[queue].tqi_cw_min = queue_info->tqi_cw_min; + hal->ah_txq[queue].tqi_flags = queue_info->tqi_flags; + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_releaseTxQueue(hal, queue) + struct ath_hal *hal; + u_int queue; +{ + AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); + + /* This queue will be skipped in further operations */ + hal->ah_txq[queue].tqi_type = HAL_TX_QUEUE_INACTIVE; + + return(AH_FALSE); +} + +void +ar5k_ar5210_init_tx_queue(hal, aifs, turbo) + struct ath_hal *hal; + u_int aifs; + HAL_BOOL turbo; +{ + int i; + struct { + u_int16_t mode_register; + u_int32_t mode_base, mode_turbo; + } initial[] = AR5K_AR5210_INI_MODE(aifs); + + /* + * Write initial mode register settings + */ + for(i = 0; i < AR5K_ELEMENTS(initial); i++) + AR5K_REG_WRITE(initial[i].mode_register, turbo == AH_TRUE ? + initial[i].mode_turbo : initial[i].mode_base); +} + +HAL_BOOL +ar5k_ar5210_resetTxQueue(hal, queue) + struct ath_hal *hal; + u_int queue; +{ + u_int32_t cw_min, retry_lg, retry_sh; + HAL_TXQ_INFO *tq; + + AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); + + tq = &hal->ah_txq[queue]; + + /* Only handle data queues, others will be ignored */ + if(tq->tqi_type != HAL_TX_QUEUE_DATA) + return(AH_TRUE); + + /* Set turbo/base mode parameters */ + ar5k_ar5210_init_tx_queue(hal, hal->ah_aifs + tq->tqi_aifs, + hal->ah_turbo == AH_TRUE ? AH_TRUE : AH_FALSE); + + /* + * Set retry limits + */ + if(hal->ah_software_retry == AH_TRUE) { + /* XXX Need to test this */ + retry_lg = hal->ah_limit_tx_retries; + retry_sh = retry_lg = retry_lg > AR5K_AR5210_RETRY_LMT_SH_RETRY ? + AR5K_AR5210_RETRY_LMT_SH_RETRY : retry_lg; + } else { + retry_lg = AR5K_INIT_LG_RETRY; + retry_sh = AR5K_INIT_SH_RETRY; + } + + /* + * Set initial content window (cw_min/cw_max) + */ + cw_min = 1; + while(cw_min < hal->ah_cw_min) + cw_min = (cw_min << 1) | 1; + + cw_min = tq->tqi_cw_min < 0 ? + (cw_min >> (-tq->tqi_cw_min)) : + ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); + + /* Commit values */ + AR5K_REG_WRITE(AR5K_AR5210_RETRY_LMT, + (cw_min << AR5K_AR5210_RETRY_LMT_CW_MIN_S) + | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, AR5K_AR5210_RETRY_LMT_SLG_RETRY) + | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, AR5K_AR5210_RETRY_LMT_SSH_RETRY) + | AR5K_REG_SM(retry_lg, AR5K_AR5210_RETRY_LMT_LG_RETRY) + | AR5K_REG_SM(retry_sh, AR5K_AR5210_RETRY_LMT_SH_RETRY)); + + return(AH_TRUE); +} + +u_int32_t +ar5k_ar5210_getTxDP(hal, queue) + struct ath_hal *hal; + u_int queue; +{ + u_int16_t tx_reg; + + AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); + + /* + * Get the transmit queue descriptor pointer register by type + */ + switch(hal->ah_txq[queue].tqi_type) { + case HAL_TX_QUEUE_DATA: + tx_reg = AR5K_AR5210_TXDP0; + break; + case HAL_TX_QUEUE_BEACON: + case HAL_TX_QUEUE_CAB: + tx_reg = AR5K_AR5210_TXDP1; + break; + default: + return(0xffffffff); + } + + return(AR5K_REG_READ(tx_reg)); +} + +HAL_BOOL +ar5k_ar5210_setTxDP(hal, queue, phys_addr) + struct ath_hal *hal; + u_int queue; + u_int32_t phys_addr; +{ + u_int16_t tx_reg; + + AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); + + /* + * Get the transmit queue descriptor pointer register by type + */ + switch(hal->ah_txq[queue].tqi_type) { + case HAL_TX_QUEUE_DATA: + tx_reg = AR5K_AR5210_TXDP0; + break; + case HAL_TX_QUEUE_BEACON: + case HAL_TX_QUEUE_CAB: + tx_reg = AR5K_AR5210_TXDP1; + break; + default: + return(AH_FALSE); + } + + /* Set descriptor pointer */ + AR5K_REG_WRITE(tx_reg, phys_addr); + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_startTxDma(hal, queue) + struct ath_hal *hal; + u_int queue; +{ + u_int32_t tx_queue; + + AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); + + tx_queue = AR5K_REG_READ(AR5K_AR5210_CR); + + /* + * Set the queue type + */ + switch(hal->ah_txq[queue].tqi_type) { + case HAL_TX_QUEUE_DATA: + tx_queue |= AR5K_AR5210_CR_TXE0 & ~AR5K_AR5210_CR_TXD0; + break; + + case HAL_TX_QUEUE_BEACON: + tx_queue |= AR5K_AR5210_CR_TXE1 & ~AR5K_AR5210_CR_TXD1; + AR5K_REG_WRITE(AR5K_AR5210_BSR, + AR5K_AR5210_BCR_TQ1V | AR5K_AR5210_BCR_BDMAE); + break; + + case HAL_TX_QUEUE_CAB: + tx_queue |= AR5K_AR5210_CR_TXE1 & ~AR5K_AR5210_CR_TXD1; + AR5K_REG_WRITE(AR5K_AR5210_BSR, + AR5K_AR5210_BCR_TQ1FV | AR5K_AR5210_BCR_TQ1V | AR5K_AR5210_BCR_BDMAE); + break; + + default: + return(AH_FALSE); + } + + /* Start queue */ + AR5K_REG_WRITE(AR5K_AR5210_CR, tx_queue); + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_stopTxDma(hal, queue) + struct ath_hal *hal; + u_int queue; +{ + u_int32_t tx_queue; + + AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); + + tx_queue = AR5K_REG_READ(AR5K_AR5210_CR); + + /* + * Set by queue type + */ + switch(hal->ah_txq[queue].tqi_type) { + case HAL_TX_QUEUE_DATA: + tx_queue |= AR5K_AR5210_CR_TXD0 & ~AR5K_AR5210_CR_TXE0; + break; + + case HAL_TX_QUEUE_BEACON: + case HAL_TX_QUEUE_CAB: + /* XXX Fix me... */ + tx_queue |= AR5K_AR5210_CR_TXD1 & ~AR5K_AR5210_CR_TXD1; + AR5K_REG_WRITE(AR5K_AR5210_BSR, 0); + break; + + default: + return(AH_FALSE); + } + + /* Stop queue */ + AR5K_REG_WRITE(AR5K_AR5210_CR, tx_queue); + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_setupTxDesc(hal, desc, packet_length, header_length, type, tx_power, + tx_rate0, tx_tries0, key_index, antenna_mode, flags, rtscts_rate, + rtscts_duration) + struct ath_hal *hal; + struct ath_desc *desc; + u_int packet_length; + u_int header_length; + HAL_PKT_TYPE type; + u_int tx_power; + u_int tx_rate0; + u_int tx_tries0; + u_int key_index; + u_int antenna_mode; + u_int flags; + u_int rtscts_rate; + u_int rtscts_duration; +{ + struct ar5k_ar5210_tx_desc *tx_desc; + + tx_desc = (struct ar5k_ar5210_tx_desc*)&desc->ds_ctl0; + + /* Clear descriptor */ + bzero(tx_desc, sizeof(struct ar5k_ar5210_tx_desc)); + + /* + * Validate input + */ + if(tx_tries0 == 0) + return(AH_FALSE); + + switch(type) { + case HAL_PKT_TYPE_NORMAL: + tx_desc->frame_type = AR5K_AR5210_DESC_TX_FRAME_TYPE_NORMAL; + break; + + case HAL_PKT_TYPE_ATIM: + tx_desc->frame_type = AR5K_AR5210_DESC_TX_FRAME_TYPE_ATIM; + break; + + case HAL_PKT_TYPE_PSPOLL: + tx_desc->frame_type = AR5K_AR5210_DESC_TX_FRAME_TYPE_PSPOLL; + break; + + case HAL_PKT_TYPE_BEACON: + case HAL_PKT_TYPE_PROBE_RESP: + tx_desc->frame_type = AR5K_AR5210_DESC_TX_FRAME_TYPE_NO_DELAY; + break; + + case HAL_PKT_TYPE_PIFS: + tx_desc->frame_type = AR5K_AR5210_DESC_TX_FRAME_TYPE_PIFS; + break; + + default: + /* Invalid packet type (possibly not supported) */ + return(AH_FALSE); + } + + if((tx_desc->frame_len = packet_length) != packet_length) + return(AH_FALSE); + + if((tx_desc->header_len = header_length) != header_length) + return(AH_FALSE); + + tx_desc->xmit_rate = tx_rate0; + tx_desc->ant_mode_xmit = antenna_mode ? 1 : 0; + tx_desc->clear_dest_mask = flags & HAL_TXDESC_CLRDMASK ? 1 : 0; + + /* + * WEP crap + */ + if(key_index != HAL_TXKEYIX_INVALID) { + tx_desc->encrypt_key_valid = 1; + tx_desc->encrypt_key_index = key_index; + } + + /* + * RTS/CTS + */ + if(flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) { + tx_desc->rts_cts_enable = 1; + tx_desc->rts_duration = rtscts_duration; + } + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_fillTxDesc(hal, desc, segment_length, first_segment, last_segment) + struct ath_hal *hal; + struct ath_desc *desc; + u_int segment_length; + HAL_BOOL first_segment; + HAL_BOOL last_segment; +{ + struct ar5k_ar5210_tx_desc *tx_desc; + + tx_desc = (struct ar5k_ar5210_tx_desc*)&desc->ds_ctl0; + + /* Clear status descriptor */ + desc->ds_hw[0] = desc->ds_hw[1] = 0; + + /* Validate segment length and initialize the descriptor */ + if((tx_desc->buf_len = segment_length) != segment_length) + return(AH_FALSE); + + if(first_segment != AH_TRUE) + tx_desc->frame_len = 0; + + tx_desc->more = last_segment == AH_TRUE ? 0 : 1; + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_setupXTxDesc(hal, desc, tx_rate1, tx_tries1, tx_rate2, tx_tries2, + tx_rate3, tx_tries3) + struct ath_hal *hal; + struct ath_desc *desc; + u_int tx_rate1; + u_int tx_tries1; + u_int tx_rate2; + u_int tx_tries2; + u_int tx_rate3; + u_int tx_tries3; +{ + /* + * Does this function is for setting up XR? Not sure... + * Nevertheless, I didn't find any information about XR support + * by the AR5210. This seems to be a slightly new feature. + */ + return(AH_FALSE); +} + +HAL_STATUS +ar5k_ar5210_procTxDesc(hal, desc) + struct ath_hal *hal; + struct ath_desc *desc; +{ + struct ar5k_ar5210_tx_status *tx_status; + struct ar5k_ar5210_tx_desc *tx_desc; + + tx_desc = (struct ar5k_ar5210_tx_desc*)&desc->ds_ctl0; + tx_status = (struct ar5k_ar5210_tx_status*)&desc->ds_hw[0]; + + /* No frame has been send or error */ + if(tx_status->done == 0) + return(HAL_EINPROGRESS); + + /* + * Get descriptor status + */ + desc->ds_us.tx.ts_seqnum = tx_status->seq_num; + desc->ds_us.tx.ts_tstamp = tx_status->send_timestamp; + desc->ds_us.tx.ts_shortretry = tx_status->short_retry_count; + desc->ds_us.tx.ts_longretry = tx_status->long_retry_count; + desc->ds_us.tx.ts_rssi = tx_status->ack_sig_strength; + desc->ds_us.tx.ts_rate = tx_desc->xmit_rate; + desc->ds_us.tx.ts_antenna = 0; + desc->ds_us.tx.ts_status = 0; + + if(tx_status->frame_xmit_ok == 0) { + if(tx_status->excessive_retries) + desc->ds_us.tx.ts_status |= HAL_TXERR_XRETRY; + + if(tx_status->fifo_underrun) + desc->ds_us.tx.ts_status |= HAL_TXERR_FIFO; + + if(tx_status->filtered) + desc->ds_us.tx.ts_status |= HAL_TXERR_FILT; + } + +#if 0 + /* + * Reset descriptor + */ + bzero(tx_desc, sizeof(struct ar5k_ar5210_tx_desc)); + bzero(tx_status, sizeof(struct ar5k_ar5210_tx_status)); +#endif + + return(HAL_OK); +} + +HAL_BOOL +ar5k_ar5210_hasVEOL(hal) + struct ath_hal *hal; +{ + return(AH_FALSE); +} + +/* + * Receive functions + */ + +u_int32_t +ar5k_ar5210_getRxDP(hal) + struct ath_hal *hal; +{ + return(AR5K_REG_READ(AR5K_AR5210_RXDP)); +} + +void +ar5k_ar5210_setRxDP(hal, phys_addr) + struct ath_hal *hal; + u_int32_t phys_addr; +{ + AR5K_REG_WRITE(AR5K_AR5210_RXDP, phys_addr); +} + +void +ar5k_ar5210_enableReceive(hal) + struct ath_hal *hal; +{ + AR5K_REG_WRITE(AR5K_AR5210_CR, AR5K_AR5210_CR_RXE); +} + +HAL_BOOL +ar5k_ar5210_stopDmaReceive(hal) + struct ath_hal *hal; +{ + int i; + + AR5K_REG_WRITE(AR5K_AR5210_CR, AR5K_AR5210_CR_RXD); + + /* + * It may take some time to disable the DMA receive unit + */ + for(i = 2000; + i > 0 && (AR5K_REG_READ(AR5K_AR5210_CR) & AR5K_AR5210_CR_RXE) != 0; + i--) + AR5K_DELAY(10); + + return(i > 0 ? AH_TRUE : AH_FALSE); +} + +void +ar5k_ar5210_startPcuReceive(hal) + struct ath_hal *hal; +{ + AR5K_REG_DISABLE_BITS(AR5K_AR5210_DIAG_SW, AR5K_AR5210_DIAG_SW_DIS_RX); +} + +void +ar5k_ar5210_stopPcuReceive(hal) + struct ath_hal *hal; +{ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_DIAG_SW, AR5K_AR5210_DIAG_SW_DIS_RX); +} + +void +ar5k_ar5210_setMulticastFilter(hal, filter0, filter1) + struct ath_hal *hal; + u_int32_t filter0; + u_int32_t filter1; +{ + /* Set the multicat filter */ + AR5K_REG_WRITE(AR5K_AR5210_MCAST_FIL0, filter0); + AR5K_REG_WRITE(AR5K_AR5210_MCAST_FIL1, filter1); +} + +HAL_BOOL +ar5k_ar5210_setMulticastFilterIndex(hal, index) + struct ath_hal *hal; + u_int32_t index; +{ + if(index >= 64) + return(AH_FALSE); + else if(index >= 32) + AR5K_REG_ENABLE_BITS(AR5K_AR5210_MCAST_FIL1, + (1 << (index - 32))); + else + AR5K_REG_ENABLE_BITS(AR5K_AR5210_MCAST_FIL0, + (1 << index)); + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_clrMulticastFilterIndex(hal, index) + struct ath_hal *hal; + u_int32_t index; +{ + if(index >= 64) + return(AH_FALSE); + else if(index >= 32) + AR5K_REG_DISABLE_BITS(AR5K_AR5210_MCAST_FIL1, + (1 << (index - 32))); + else + AR5K_REG_DISABLE_BITS(AR5K_AR5210_MCAST_FIL0, + (1 << index)); + + return(AH_TRUE); +} + +u_int32_t +ar5k_ar5210_getRxFilter(hal) + struct ath_hal *hal; +{ + return(AR5K_REG_READ(AR5K_AR5210_RX_FILTER)); +} + +void +ar5k_ar5210_setRxFilter(hal, filter) + struct ath_hal *hal; + u_int32_t filter; +{ + /* + * The AR5210 uses promiscous mode to detect radar activity + */ + if(filter & HAL_RX_FILTER_PHYRADAR) { + filter &= ~HAL_RX_FILTER_PHYRADAR; + filter |= AR5K_AR5210_RX_FILTER_PROMISC; + } + + AR5K_REG_WRITE(AR5K_AR5210_RX_FILTER, filter); +} + +HAL_BOOL +ar5k_ar5210_setupRxDesc(hal, desc, size, flags) + struct ath_hal *hal; + struct ath_desc *desc; + u_int32_t size; + u_int flags; +{ + struct ar5k_ar5210_rx_desc *rx_desc; + + /* Reset descriptor */ + desc->ds_ctl0 = 0; + desc->ds_ctl1 = 0; + bzero(&desc->ds_hw[0], sizeof(struct ar5k_ar5210_rx_status)); + + rx_desc = (struct ar5k_ar5210_rx_desc*)&desc->ds_ctl0; + + if((rx_desc->buf_len = size) != size) + return(AH_FALSE); + + if(flags & HAL_RXDESC_INTREQ) + rx_desc->inter_req = 1; + + return(AH_TRUE); +} + +HAL_STATUS +ar5k_ar5210_procRxDesc(hal, desc, phys_addr, next) + struct ath_hal *hal; + struct ath_desc *desc; + u_int32_t phys_addr; + struct ath_desc *next; +{ + u_int32_t now, tstamp; + struct ar5k_ar5210_rx_status *rx_status; + + rx_status = (struct ar5k_ar5210_rx_status*)&desc->ds_hw[0]; + + /* No frame received / not ready */ + if(!rx_status->done) + return(HAL_EINPROGRESS); + + /* + * Frame receive status + */ + now = (AR5K_REG_READ(AR5K_AR5210_TSF_L32) >> 10) & 0xffff; + tstamp = ((now & 0x1fff) < rx_status->receive_timestamp) ? + (((now - 0x2000) & 0xffff) | (u_int32_t) rx_status->receive_timestamp) : + (now | (u_int32_t) rx_status->receive_timestamp); + desc->ds_us.rx.rs_tstamp = rx_status->receive_timestamp & 0x7fff; + desc->ds_us.rx.rs_datalen = rx_status->data_len; + desc->ds_us.rx.rs_rssi = rx_status->receive_sig_strength; + desc->ds_us.rx.rs_rate = rx_status->receive_rate; + desc->ds_us.rx.rs_antenna = rx_status->receive_antenna ? 1 : 0; + desc->ds_us.rx.rs_more = rx_status->more ? 1 : 0; + desc->ds_us.rx.rs_status = 0; + + /* + * Key table status + */ + if(!rx_status->key_index_valid) + desc->ds_us.rx.rs_keyix = HAL_RXKEYIX_INVALID; + else + desc->ds_us.rx.rs_keyix = rx_status->key_index; + + /* + * Receive/descriptor errors + */ + if(!rx_status->frame_receive_ok) { + if(rx_status->crc_error) + desc->ds_us.rx.rs_status |= HAL_RXERR_CRC; + + if(rx_status->phy_error) { + desc->ds_us.rx.rs_status |= HAL_RXERR_PHY; + desc->ds_us.rx.rs_phyerr = rx_status->phy_error; + } + + if(rx_status->fifo_overrun) + desc->ds_us.rx.rs_status |= HAL_RXERR_FIFO; + + if(rx_status->decrypt_crc_error) + desc->ds_us.rx.rs_status |= HAL_RXERR_DECRYPT; + } + + return(HAL_OK); +} + +void +ar5k_ar5210_rxMonitor(hal) + struct ath_hal *hal; +{ + /* + * XXX Not sure, if this works correctly. + */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_RX_FILTER, + AR5K_AR5210_RX_FILTER_PROMISC); +} + +/* + * Misc functions + */ + +void +ar5k_ar5210_dumpState(hal) + struct ath_hal *hal; +{ +#define AR5K_PRINT_REGISTER(_x) \ + printf("(%s: %08x) ", #_x, AR5K_REG_READ(AR5K_AR5210_##_x)); + + printf("DMA registers:\n"); + AR5K_PRINT_REGISTER(TXDP0); + AR5K_PRINT_REGISTER(TXDP1); + AR5K_PRINT_REGISTER(CR); + AR5K_PRINT_REGISTER(RXDP); + AR5K_PRINT_REGISTER(CFG); + AR5K_PRINT_REGISTER(ISR); + AR5K_PRINT_REGISTER(IMR); + AR5K_PRINT_REGISTER(IER); + AR5K_PRINT_REGISTER(BCR); + AR5K_PRINT_REGISTER(BSR); + AR5K_PRINT_REGISTER(TXCFG); + AR5K_PRINT_REGISTER(RXCFG); + AR5K_PRINT_REGISTER(MIBC); + AR5K_PRINT_REGISTER(TOPS); + AR5K_PRINT_REGISTER(RXNOFRM); + AR5K_PRINT_REGISTER(TXNOFRM); + AR5K_PRINT_REGISTER(RPGTO); + AR5K_PRINT_REGISTER(RFCNT); + AR5K_PRINT_REGISTER(MISC); + AR5K_PRINT_REGISTER(RC); + AR5K_PRINT_REGISTER(SCR); + AR5K_PRINT_REGISTER(INTPEND); + AR5K_PRINT_REGISTER(SFR); + AR5K_PRINT_REGISTER(PCICFG); + AR5K_PRINT_REGISTER(GPIOCR); + AR5K_PRINT_REGISTER(GPIODO); + AR5K_PRINT_REGISTER(GPIODI); + AR5K_PRINT_REGISTER(SREV); + printf("\n"); + + printf("PCU registers:\n"); + AR5K_PRINT_REGISTER(STA_ID0); + AR5K_PRINT_REGISTER(STA_ID1); + AR5K_PRINT_REGISTER(BSS_ID0); + AR5K_PRINT_REGISTER(BSS_ID1); + AR5K_PRINT_REGISTER(SLOT_TIME); + AR5K_PRINT_REGISTER(TIME_OUT); + AR5K_PRINT_REGISTER(RSSI_THR); + AR5K_PRINT_REGISTER(RETRY_LMT); + AR5K_PRINT_REGISTER(USEC); + AR5K_PRINT_REGISTER(BEACON); + AR5K_PRINT_REGISTER(CFP_PERIOD); + AR5K_PRINT_REGISTER(TIMER0); + AR5K_PRINT_REGISTER(TIMER1); + AR5K_PRINT_REGISTER(TIMER2); + AR5K_PRINT_REGISTER(TIMER3); + AR5K_PRINT_REGISTER(IFS0); + AR5K_PRINT_REGISTER(IFS1); + AR5K_PRINT_REGISTER(CFP_DUR); + AR5K_PRINT_REGISTER(RX_FILTER); + AR5K_PRINT_REGISTER(MCAST_FIL0); + AR5K_PRINT_REGISTER(MCAST_FIL1); + AR5K_PRINT_REGISTER(TX_MASK0); + AR5K_PRINT_REGISTER(TX_MASK1); + AR5K_PRINT_REGISTER(CLR_TMASK); + AR5K_PRINT_REGISTER(TRIG_LVL); + AR5K_PRINT_REGISTER(DIAG_SW); + AR5K_PRINT_REGISTER(TSF_L32); + AR5K_PRINT_REGISTER(TSF_U32); + AR5K_PRINT_REGISTER(LAST_TSTP); + AR5K_PRINT_REGISTER(RETRY_CNT); + AR5K_PRINT_REGISTER(BACKOFF); + AR5K_PRINT_REGISTER(NAV); + AR5K_PRINT_REGISTER(RTS_OK); + AR5K_PRINT_REGISTER(RTS_FAIL); + AR5K_PRINT_REGISTER(ACK_FAIL); + AR5K_PRINT_REGISTER(FCS_FAIL); + AR5K_PRINT_REGISTER(BEACON_CNT); + AR5K_PRINT_REGISTER(KEYTABLE_0); + printf("\n"); + + printf("PHY registers:\n"); + AR5K_PRINT_REGISTER(PHY(0)); + AR5K_PRINT_REGISTER(PHY_FC); + AR5K_PRINT_REGISTER(PHY_AGC); + AR5K_PRINT_REGISTER(PHY_CHIP_ID); + AR5K_PRINT_REGISTER(PHY_ACTIVE); + AR5K_PRINT_REGISTER(PHY_AGCCTL); + printf("\n"); +} + +HAL_BOOL +ar5k_ar5210_getDiagState(hal, id, device, size) + struct ath_hal *hal; + int id; + void **device; + u_int *size; + +{ + /* + * We'll ignore this right now. This seems to be some kind of an obscure + * debugging interface for the binary-only HAL. + */ + return(AH_FALSE); +} + +void +ar5k_ar5210_getMacAddress(hal, mac) + struct ath_hal *hal; + u_int8_t *mac; +{ + memcpy(mac, hal->ah_sta_id, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5k_ar5210_setMacAddress(hal, mac) + struct ath_hal *hal; + const u_int8_t *mac; +{ + u_int32_t low_id, high_id; + + /* Set new station ID */ + memcpy(hal->ah_sta_id, mac, IEEE80211_ADDR_LEN); + + memcpy(&low_id, mac, 4); + memcpy(&high_id, mac + 4, 2); + high_id = 0x0000ffff & htole32(high_id); + + AR5K_REG_WRITE(AR5K_AR5210_STA_ID0, htole32(low_id)); + AR5K_REG_WRITE(AR5K_AR5210_STA_ID1, high_id); + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_setRegulatoryDomain(hal, regdomain, status) + struct ath_hal *hal; + u_int16_t regdomain; + HAL_STATUS *status; + +{ + if(ar5k_ar5210_regulation_domain(hal, AH_TRUE, + ar5k_regdomain_to_ieee((u_int8_t)regdomain)) == AH_TRUE) { + *status = HAL_OK; + return(AH_TRUE); + } + + *status = -EIO; + + return(AH_FALSE); +} + +void +ar5k_ar5210_setLedState(hal, state) + struct ath_hal *hal; + HAL_LED_STATE state; +{ + u_int32_t led; + + led = AR5K_REG_READ(AR5K_AR5210_PCICFG); + + /* + * Some blinking values, define at your wish + */ + switch(state) { + case IEEE80211_S_SCAN: + case IEEE80211_S_INIT: + led |= + AR5K_AR5210_PCICFG_LED_PEND | + AR5K_AR5210_PCICFG_LED_BCTL; + break; + case IEEE80211_S_RUN: + led |= + AR5K_AR5210_PCICFG_LED_ACT; + break; + default: + led |= + AR5K_AR5210_PCICFG_LED_ACT | + AR5K_AR5210_PCICFG_LED_BCTL; + break; + } + + AR5K_REG_WRITE(AR5K_AR5210_PCICFG, led); +} + +void +ar5k_ar5210_writeAssocid(hal, bssid, assoc_id, tim_offset) + struct ath_hal *hal; + const u_int8_t *bssid; + u_int16_t assoc_id; + u_int16_t tim_offset; +{ + u_int32_t low_id, high_id; + + /* + * Set BSSID which triggers the "SME Join" operation + */ + memcpy(&low_id, bssid, 4); + memcpy(&high_id, bssid + 4, 2); + AR5K_REG_WRITE(AR5K_AR5210_BSS_ID0, htole32(low_id)); + AR5K_REG_WRITE(AR5K_AR5210_BSS_ID1, htole32(high_id) | + ((assoc_id & 0x3fff) << AR5K_AR5210_BSS_ID1_AID_S)); + memcpy(&hal->ah_bssid, bssid, IEEE80211_ADDR_LEN); + + if(assoc_id == 0) { + ar5k_ar5210_disablePSPoll(hal); + return; + } + + AR5K_REG_WRITE(AR5K_AR5210_BEACON, + (AR5K_REG_READ(AR5K_AR5210_BEACON) & + ~AR5K_AR5210_BEACON_TIM) | + (((tim_offset ? tim_offset + 4 : 0) << + AR5K_AR5210_BEACON_TIM_S) & + AR5K_AR5210_BEACON_TIM)); + + ar5k_ar5210_enablePSPoll(hal, NULL, 0); +} + +HAL_BOOL +ar5k_ar5210_gpioCfgOutput(hal, gpio) + struct ath_hal *hal; + u_int32_t gpio; +{ + if(gpio > AR5K_AR5210_NUM_GPIO) + return(AH_FALSE); + + AR5K_REG_WRITE(AR5K_AR5210_GPIOCR, + (AR5K_REG_READ(AR5K_AR5210_GPIOCR) &~ AR5K_AR5210_GPIOCR_ALL(gpio)) + | AR5K_AR5210_GPIOCR_OUT1(gpio)); + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_gpioCfgInput(hal, gpio) + struct ath_hal *hal; + u_int32_t gpio; +{ + if(gpio > AR5K_AR5210_NUM_GPIO) + return(AH_FALSE); + + AR5K_REG_WRITE(AR5K_AR5210_GPIOCR, + (AR5K_REG_READ(AR5K_AR5210_GPIOCR) &~ AR5K_AR5210_GPIOCR_ALL(gpio)) + | AR5K_AR5210_GPIOCR_IN(gpio)); + + return(AH_TRUE); +} + +u_int32_t +ar5k_ar5210_gpioGet(hal, gpio) + struct ath_hal *hal; + u_int32_t gpio; +{ + if(gpio > AR5K_AR5210_NUM_GPIO) + return(0xffffffff); + + /* GPIO input magic */ + return(((AR5K_REG_READ(AR5K_AR5210_GPIODI) & + AR5K_AR5210_GPIOD_MASK) >> gpio) & 0x1); +} + +HAL_BOOL +ar5k_ar5210_gpioSet(hal, gpio, val) + struct ath_hal *hal; + u_int32_t gpio; + u_int32_t val; +{ + u_int32_t data; + + if(gpio > AR5K_AR5210_NUM_GPIO) + return(0xffffffff); + + /* GPIO output magic */ + data = AR5K_REG_READ(AR5K_AR5210_GPIODO); + + data &= ~(1 << gpio); + data |= (val&1) << gpio; + + AR5K_REG_WRITE(AR5K_AR5210_GPIODO, data); + + return(AH_TRUE); +} + +void +ar5k_ar5210_gpioSetIntr(hal, gpio, interrupt_level) + struct ath_hal *hal; + u_int gpio; + u_int32_t interrupt_level; +{ + u_int32_t data; + + if(gpio > AR5K_AR5210_NUM_GPIO) + return; + + /* + * Set the GPIO interrupt + */ + data = (AR5K_REG_READ(AR5K_AR5210_GPIOCR) & + ~(AR5K_AR5210_GPIOCR_INT_SEL(gpio) | AR5K_AR5210_GPIOCR_INT_SELH | + AR5K_AR5210_GPIOCR_INT_ENA | AR5K_AR5210_GPIOCR_ALL(gpio))) | + (AR5K_AR5210_GPIOCR_INT_SEL(gpio) | AR5K_AR5210_GPIOCR_INT_ENA); + + AR5K_REG_WRITE(AR5K_AR5210_GPIOCR, + interrupt_level ? data : (data | AR5K_AR5210_GPIOCR_INT_SELH)); + + hal->ah_imr |= AR5K_AR5210_IMR_GPIO; + + /* Enable GPIO interrupts */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_IMR, AR5K_AR5210_IMR_GPIO); +} + +u_int32_t +ar5k_ar5210_getTsf32(hal) + struct ath_hal *hal; +{ + return(AR5K_REG_READ(AR5K_AR5210_TSF_L32)); +} + +u_int64_t +ar5k_ar5210_getTsf64(hal) + struct ath_hal *hal; +{ + u_int64_t tsf = AR5K_REG_READ(AR5K_AR5210_TSF_U32); + return(AR5K_REG_READ(AR5K_AR5210_TSF_L32) | (tsf << 32)); +} + +void +ar5k_ar5210_resetTsf(hal) + struct ath_hal *hal; +{ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_BEACON, + AR5K_AR5210_BEACON_RESET_TSF); +} + +u_int16_t +ar5k_ar5210_getRegDomain(hal) + struct ath_hal *hal; +{ + u_int16_t regdomain; + ieee80211_regdomain_t ieee_regdomain; + + if(ar5k_ar5210_regulation_domain(hal, AH_FALSE, &ieee_regdomain) == AH_TRUE) { + regdomain = ar5k_regdomain_from_ieee(&ieee_regdomain); + return(regdomain > 0 ? regdomain : hal->ah_regdomain); + } + + return(0); +} + +HAL_BOOL +ar5k_ar5210_detectCardPresent(hal) + struct ath_hal *hal; +{ + u_int16_t magic; + + /* + * Checking the EEPROM's magic value could be an indication + * if the card is still present. I didn't find another suitable + * way to do this. + */ + if(ar5k_ar5210_eeprom_read(hal, AR5K_AR5210_EEPROM_MAGIC, &magic) != 0) + return(AH_FALSE); + + return(magic == AR5K_AR5210_EEPROM_MAGIC_VALUE ? AH_TRUE : AH_FALSE); +} + +void +ar5k_ar5210_updateMibCounters(hal, statistics) + struct ath_hal *hal; + HAL_MIB_STATS *statistics; +{ + statistics->ackrcv_bad += AR5K_REG_READ(AR5K_AR5210_ACK_FAIL); + statistics->rts_bad += AR5K_REG_READ(AR5K_AR5210_RTS_FAIL); + statistics->rts_good += AR5K_REG_READ(AR5K_AR5210_RTS_OK); + statistics->fcs_bad += AR5K_REG_READ(AR5K_AR5210_FCS_FAIL); + statistics->beacons += AR5K_REG_READ(AR5K_AR5210_BEACON_CNT); +} + +HAL_RFGAIN +ar5k_ar5210_getRfGain(hal) + struct ath_hal *hal; +{ + return(HAL_RFGAIN_INACTIVE); +} + +HAL_BOOL +ar5k_ar5210_setSlotTime(hal, slot_time) + struct ath_hal *hal; + u_int slot_time; + +{ + if(slot_time < HAL_SLOT_TIME_9 || slot_time > HAL_SLOT_TIME_MAX) + return(AH_FALSE); + + AR5K_REG_WRITE(AR5K_AR5210_SLOT_TIME, + ar5k_htoclock(slot_time, hal->ah_turbo)); + + return(AH_TRUE); +} + +u_int +ar5k_ar5210_getSlotTime(hal) + struct ath_hal *hal; +{ + return(ar5k_clocktoh(AR5K_REG_READ(AR5K_AR5210_SLOT_TIME) & 0xffff, + hal->ah_turbo)); +} + +HAL_BOOL +ar5k_ar5210_setAckTimeout(hal, timeout) + struct ath_hal *hal; + u_int timeout; +{ + if(ar5k_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_AR5210_TIME_OUT_ACK), + hal->ah_turbo) <= timeout) + return(AH_FALSE); + + AR5K_REG_WRITE_BITS(AR5K_AR5210_TIME_OUT, AR5K_AR5210_TIME_OUT_ACK, + ar5k_htoclock(timeout, hal->ah_turbo)); + + return(AH_TRUE); +} + +u_int +ar5k_ar5210_getAckTimeout(hal) + struct ath_hal *hal; +{ + return(ar5k_clocktoh(AR5K_REG_MS(AR5K_REG_READ(AR5K_AR5210_TIME_OUT), + AR5K_AR5210_TIME_OUT_ACK), hal->ah_turbo)); +} + +HAL_BOOL +ar5k_ar5210_setCTSTimeout(hal, timeout) + struct ath_hal *hal; + u_int timeout; +{ + if(ar5k_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_AR5210_TIME_OUT_CTS), + hal->ah_turbo) <= timeout) + return(AH_FALSE); + + AR5K_REG_WRITE_BITS(AR5K_AR5210_TIME_OUT, AR5K_AR5210_TIME_OUT_CTS, + ar5k_htoclock(timeout, hal->ah_turbo)); + + return(AH_TRUE); +} + +u_int +ar5k_ar5210_getCTSTimeout(hal) + struct ath_hal *hal; +{ + return(ar5k_clocktoh(AR5K_REG_MS(AR5K_REG_READ(AR5K_AR5210_TIME_OUT), + AR5K_AR5210_TIME_OUT_CTS), hal->ah_turbo)); +} + +/* + * Key table (WEP) functions + */ + +HAL_BOOL +ar5k_ar5210_isHwCipherSupported(hal, cipher) + struct ath_hal *hal; + HAL_CIPHER cipher; +{ + /* + * The AR5210 only supports WEP + */ + if(cipher == HAL_CIPHER_WEP) + return(AH_TRUE); + + return(AH_FALSE); +} + +u_int32_t +ar5k_ar5210_getKeyCacheSize(hal) + struct ath_hal *hal; +{ + return(AR5K_AR5210_KEYTABLE_SIZE); +} + +HAL_BOOL +ar5k_ar5210_resetKeyCacheEntry(hal, entry) + struct ath_hal *hal; + u_int16_t entry; +{ + int i; + + AR5K_ASSERT_ENTRY(entry, AR5K_AR5210_KEYTABLE_SIZE); + + for(i = 0; i < AR5K_AR5210_KEYCACHE_SIZE; i++) + AR5K_REG_WRITE(AR5K_AR5210_KEYTABLE(entry) + (i * 4), 0); + + return(AH_FALSE); +} + +HAL_BOOL +ar5k_ar5210_isKeyCacheEntryValid(hal, entry) + struct ath_hal *hal; + u_int16_t entry; +{ + int offset; + + AR5K_ASSERT_ENTRY(entry, AR5K_AR5210_KEYTABLE_SIZE); + + /* + * Check the validation flag at the end of the entry + */ + offset = (AR5K_AR5210_KEYCACHE_SIZE - 1) * 4; + if(AR5K_REG_READ(AR5K_AR5210_KEYTABLE(entry) + offset) & + AR5K_AR5210_KEYTABLE_VALID) + return AH_TRUE; + + return(AH_FALSE); +} + +HAL_BOOL +ar5k_ar5210_setKeyCacheEntry(hal, entry, keyval, mac, xor_notused) + struct ath_hal *hal; + u_int16_t entry; + const HAL_KEYVAL *keyval; + const u_int8_t *mac; + int xor_notused; +{ + int elements = AR5K_AR5210_KEYCACHE_SIZE - 2; + u_int32_t key_v[elements]; + int i, offset = 0; + + AR5K_ASSERT_ENTRY(entry, AR5K_AR5210_KEYTABLE_SIZE); + + /* + * Store the key type in the last field + */ + switch(keyval->wk_len) { + case 5: + key_v[elements - 1] = AR5K_AR5210_KEYTABLE_TYPE_40; + break; + + case 13: + key_v[elements - 1] = AR5K_AR5210_KEYTABLE_TYPE_104; + break; + + case 16: + key_v[elements - 1] = AR5K_AR5210_KEYTABLE_TYPE_128; + break; + + default: + /* Unsupported key length (not WEP40/104/128) */ + return(AH_FALSE); + } + + /* + * Write key cache entry + */ + for(i = 0; i < elements; i++) { + if(elements < 5) { + if(i % 2) { + key_v[i] = AR5K_LE_READ_2(keyval->wk_key + + offset) & 0xffff; + offset += 2; + } else { + key_v[i] = AR5K_LE_READ_4(keyval->wk_key + + offset); + offset += 4; + } + + if(i == 4 && keyval->wk_len <= 13) + key_v[i] &= 0xff; + } + + /* Write value */ + AR5K_REG_WRITE(AR5K_AR5210_KEYTABLE(entry) + (i * 4), key_v[i]); + } + + return(ar5k_ar5210_setKeyCacheEntryMac(hal, entry, mac)); +} + +HAL_BOOL +ar5k_ar5210_setKeyCacheEntryMac(hal, entry, mac) + struct ath_hal *hal; + u_int16_t entry; + const u_int8_t *mac; +{ + u_int32_t low_id, high_id; + int offset; + + /* + * Invalid entry (key table overflow) + */ + AR5K_TRACE; + + AR5K_ASSERT_ENTRY(entry, AR5K_AR5210_KEYTABLE_SIZE); + + AR5K_TRACE; + + offset = AR5K_AR5210_KEYCACHE_SIZE - 2; + + AR5K_TRACE; + + /* XXX big endian problems? */ + bcopy(mac, &low_id, 4); + + AR5K_TRACE; + + bcopy(mac + 4, &high_id, 2); + + AR5K_TRACE; + + high_id = 0x0000ffff & htole32(high_id); + + AR5K_TRACE; + + AR5K_REG_WRITE(AR5K_AR5210_KEYTABLE(entry) + (offset++ * 4), htole32(low_id)); + + AR5K_TRACE; + + AR5K_REG_WRITE(AR5K_AR5210_KEYTABLE(entry) + (offset * 4), high_id); + + AR5K_TRACE; + + return(AH_TRUE); +} + +/* + * Power management functions + */ + +HAL_BOOL +ar5k_ar5210_setPowerMode(hal, mode, set_chip, sleep_duration) + struct ath_hal *hal; + HAL_POWER_MODE mode; + int set_chip; + u_int16_t sleep_duration; +{ + int i; + + switch(mode) { + case HAL_PM_AUTO: + if(set_chip) + AR5K_REG_WRITE(AR5K_AR5210_SCR, + AR5K_AR5210_SCR_SLE | sleep_duration); + break; + + case HAL_PM_FULL_SLEEP: + if(set_chip) + AR5K_REG_WRITE(AR5K_AR5210_SCR, AR5K_AR5210_SCR_SLE_SLP); + break; + + case HAL_PM_AWAKE: + if(!set_chip) + goto commit; + + AR5K_REG_WRITE(AR5K_AR5210_SCR, AR5K_AR5210_SCR_SLE_WAKE); + + for(i = 5000; i > 0; i--) { + /* Check if the AR5210 did wake up */ + if((AR5K_REG_READ(AR5K_AR5210_PCICFG) & + AR5K_AR5210_PCICFG_SPWR_DN) == 0) + break; + + /* Wait a bit and retry */ + AR5K_DELAY(200); + AR5K_REG_WRITE(AR5K_AR5210_SCR, + AR5K_AR5210_SCR_SLE_WAKE); + } + + /* Fail if the AR5210 didn't wake up */ + if(i <= 0) + return(AH_FALSE); + break; + + case HAL_PM_NETWORK_SLEEP: + case HAL_PM_UNDEFINED: + default: + return(AH_FALSE); + } + + commit: + hal->ah_power_mode = mode; + + AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, + AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA); + AR5K_REG_ENABLE_BITS(AR5K_AR5210_STA_ID1, + AR5K_AR5210_STA_ID1_PWR_SV); + + return(AH_TRUE); +} + +HAL_POWER_MODE +ar5k_ar5210_getPowerMode(hal) + struct ath_hal *hal; +{ + return(hal->ah_power_mode); +} + +HAL_BOOL +ar5k_ar5210_queryPSPollSupport(hal) + struct ath_hal *hal; +{ + /* I think so, why not? */ + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_initPSPoll(hal) + struct ath_hal *hal; +{ + /* + * Not used on the AR5210 + */ + return(AH_FALSE); +} + +HAL_BOOL +ar5k_ar5210_enablePSPoll(hal, bssid, assoc_id) + struct ath_hal *hal; + u_int8_t *bssid; + u_int16_t assoc_id; +{ + AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, + AR5K_AR5210_STA_ID1_NO_PSPOLL | + AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA); + + return(AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_disablePSPoll(hal) + struct ath_hal *hal; +{ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_STA_ID1, + AR5K_AR5210_STA_ID1_NO_PSPOLL | + AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA); + + return(AH_TRUE); +} + +/* + * Beacon functions + */ + +void +ar5k_ar5210_beaconInit(hal, next_beacon, interval) + struct ath_hal *hal; + u_int32_t next_beacon; + u_int32_t interval; +{ + u_int32_t timer1, timer2, timer3; + + /* + * Set the additional timers by mode + */ + switch(hal->ah_op_mode) { + case HAL_M_STA: + timer1 = 0xffffffff; + timer2 = 0xffffffff; + timer3 = 1; + break; + + default: + timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << + 0x00000003; + timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << + 0x00000003; + timer3 = next_beacon + hal->ah_atim_window; + } + + /* + * Enable all timers and set the beacon register + * (next beacon, DMA beacon, software beacon, ATIM window time) + */ + AR5K_REG_WRITE(AR5K_AR5210_TIMER0, next_beacon); + AR5K_REG_WRITE(AR5K_AR5210_TIMER1, timer1); + AR5K_REG_WRITE(AR5K_AR5210_TIMER2, timer2); + AR5K_REG_WRITE(AR5K_AR5210_TIMER3, timer3); + + AR5K_REG_WRITE(AR5K_AR5210_BEACON, interval & + (AR5K_AR5210_BEACON_PERIOD | AR5K_AR5210_BEACON_RESET_TSF | + AR5K_AR5210_BEACON_EN)); +} + +void +ar5k_ar5210_setStationBeaconTimers(hal, state, tsf, dtim_count, cfp_count) + struct ath_hal *hal; + const HAL_BEACON_STATE *state; + u_int32_t tsf; + u_int32_t dtim_count; + u_int32_t cfp_count; + +{ + u_int32_t cfp_period, next_cfp; + + /* Return on an invalid beacon state */ + if(state->bs_interval > 0) + return; + + /* + * PCF support? + */ + if(state->bs_cfp_period > 0) { + /* Enable CFP mode and set the CFP and timer registers */ + cfp_period = state->bs_cfp_period * state->bs_dtim_period * + state->bs_interval; + next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * + state->bs_interval; + + AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, + AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA | + AR5K_AR5210_STA_ID1_PCF); + AR5K_REG_WRITE(AR5K_AR5210_CFP_PERIOD, cfp_period); + AR5K_REG_WRITE(AR5K_AR5210_CFP_DUR, state->bs_cfp_max_duration); + AR5K_REG_WRITE(AR5K_AR5210_TIMER2, + (tsf + (next_cfp == 0 ? cfp_period : next_cfp)) << 3); + } else { + /* Disable PCF mode */ + AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, + AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA | + AR5K_AR5210_STA_ID1_PCF); + } + + /* + * Enable the beacon timer register + */ + AR5K_REG_WRITE(AR5K_AR5210_TIMER0, state->bs_next_beacon); + + /* + * Start the beacon timers + */ + AR5K_REG_WRITE(AR5K_AR5210_BEACON, (AR5K_REG_READ(AR5K_AR5210_BEACON) &~ + (AR5K_AR5210_BEACON_PERIOD | AR5K_AR5210_BEACON_TIM)) | + AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, + AR5K_AR5210_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, + AR5K_AR5210_BEACON_PERIOD)); + + /* + * Write new beacon miss threshold, if it appears to be valid + */ + if((state->bs_bmiss_threshold > + (AR5K_AR5210_RSSI_THR_BM_THR >> AR5K_AR5210_RSSI_THR_BM_THR_S)) && + (state->bs_bmiss_threshold & 0x00007) != 0) + AR5K_REG_WRITE_BITS(AR5K_AR5210_RSSI_THR, + AR5K_AR5210_RSSI_THR_BM_THR, state->bs_bmiss_threshold); +} + +void +ar5k_ar5210_resetStationBeaconTimers(hal) + struct ath_hal *hal; +{ + /* + * Disable beacon timer + */ + AR5K_REG_WRITE(AR5K_AR5210_TIMER0, 0); + + /* + * Disable some beacon register values + */ + AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, + AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA | AR5K_AR5210_STA_ID1_PCF); + AR5K_REG_WRITE(AR5K_AR5210_BEACON, AR5K_AR5210_BEACON_PERIOD); +} + +HAL_BOOL +ar5k_ar5210_waitForBeaconDone(hal, phys_addr) + struct ath_hal *hal; + bus_addr_t phys_addr; +{ + int i; + + /* + * Wait for beaconn queue to be done + */ + for(i = (AR5K_TUNE_BEACON_INTERVAL / 2); i > 0 && + (AR5K_REG_READ(AR5K_AR5210_BSR) & + AR5K_AR5210_BSR_TXQ1F) != 0 && + (AR5K_REG_READ(AR5K_AR5210_CR) & + AR5K_AR5210_CR_TXE1) != 0; i--); + + /* Timeout... */ + if(i <= 0) { + /* + * Re-schedule the beacon queue + */ + AR5K_REG_WRITE(AR5K_AR5210_TXDP1, (u_int32_t)phys_addr); + AR5K_REG_WRITE(AR5K_AR5210_BCR, + AR5K_AR5210_BCR_TQ1V | AR5K_AR5210_BCR_BDMAE); + + return(AH_FALSE); + } + + return(AH_TRUE); +} + +/* + * Interrupt handling + */ + +HAL_BOOL +ar5k_ar5210_isInterruptPending(hal) + struct ath_hal *hal; +{ + return(AR5K_REG_READ(AR5K_AR5210_INTPEND) == 0 ? AH_FALSE : AH_TRUE); +} + +HAL_BOOL +ar5k_ar5210_getPendingInterrupts(hal, interrupt_mask) + struct ath_hal *hal; + u_int32_t *interrupt_mask; +{ + u_int32_t data; + + if((data = AR5K_REG_READ(AR5K_AR5210_ISR)) == HAL_INT_NOCARD) { + *interrupt_mask = data; + return(AH_FALSE); + } + + /* + * Get abstract interrupt mask (HAL-compatible) + */ + *interrupt_mask = (data & HAL_INT_COMMON) & hal->ah_imr; + + if(data & (AR5K_AR5210_ISR_RXOK | AR5K_AR5210_ISR_RXERR)) + *interrupt_mask |= HAL_INT_RX; + if(data & (AR5K_AR5210_ISR_TXOK | AR5K_AR5210_ISR_TXERR)) + *interrupt_mask |= HAL_INT_TX; + if(data & AR5K_AR5210_ISR_FATAL) + *interrupt_mask |= HAL_INT_FATAL; + + /* + * Special interrupt handling (not catched by the driver) + */ + if(((*interrupt_mask) & AR5K_AR5210_ISR_RXPHY) && + hal->ah_radar.r_enabled == AH_TRUE) + ar5k_radar_alert(hal); + + return(AH_TRUE); +} + +u_int32_t +ar5k_ar5210_getInterrupts(hal) + struct ath_hal *hal; +{ + /* Return the interrupt mask stored previously */ + return(hal->ah_imr); +} + +HAL_INT +ar5k_ar5210_setInterrupts(hal, new_mask) + struct ath_hal *hal; + HAL_INT new_mask; +{ + HAL_INT old_mask, int_mask; + + /* + * Disable card interrupts to prevent any race conditions + * (they will be re-enabled afterwards). + */ + AR5K_REG_WRITE(AR5K_AR5210_IER, AR5K_AR5210_IER_DISABLE); + + old_mask = hal->ah_imr; + + /* + * Add additional, chipset-dependent interrupt mask flags + * and write them to the IMR (interrupt mask register). + */ + int_mask = new_mask & HAL_INT_COMMON; + + if(new_mask & HAL_INT_RX) + int_mask |= + AR5K_AR5210_IMR_RXOK | + AR5K_AR5210_IMR_RXERR | + AR5K_AR5210_IMR_RXORN; + + if(new_mask & HAL_INT_TX) + int_mask |= + AR5K_AR5210_IMR_TXOK | + AR5K_AR5210_IMR_TXERR | + AR5K_AR5210_IMR_TXURN; + + AR5K_REG_WRITE(AR5K_AR5210_IMR, int_mask); + + /* Store new interrupt mask */ + hal->ah_imr = new_mask; + + /* ..re-enable interrupts */ + AR5K_REG_WRITE(AR5K_AR5210_IER, AR5K_AR5210_IER_ENABLE); + + return(old_mask); +} + +/* + * Misc internal functions + */ + +HAL_BOOL +ar5k_ar5210_get_capabilities(hal) + struct ath_hal *hal; +{ + /* + * Get the value stored in the EEPROM + */ + if(ar5k_ar5210_eeprom_init(hal) != 0) + return(AH_FALSE); + + /* Set number of supported TX queues */ + hal->ah_capabilities.cap_queues.q_tx_num = AR5K_AR5210_TX_NUM_QUEUES; + + /* + * Set radio capabilities + * (The AR5210 only supports the middle 5GHz band) + */ + hal->ah_capabilities.cap_range.range_5ghz_min = 5120; + hal->ah_capabilities.cap_range.range_5ghz_max = 5430; + hal->ah_capabilities.cap_range.range_2ghz_min = 0; + hal->ah_capabilities.cap_range.range_2ghz_max = 0; + + /* Set supported modes */ + hal->ah_capabilities.cap_mode = HAL_MODE_11A | HAL_MODE_TURBO; + + return(AH_TRUE); +} + +void +ar5k_ar5210_radar_alert(hal, enable) + struct ath_hal *hal; + HAL_BOOL enable; +{ + /* + * Set the RXPHY interrupt to be able to detect + * possible radar activity. + */ + AR5K_REG_WRITE(AR5K_AR5210_IER, AR5K_AR5210_IER_DISABLE); + + if(enable == AH_TRUE) + AR5K_REG_ENABLE_BITS(AR5K_AR5210_IMR, + AR5K_AR5210_IMR_RXPHY); + else + AR5K_REG_DISABLE_BITS(AR5K_AR5210_IMR, + AR5K_AR5210_IMR_RXPHY); + + AR5K_REG_WRITE(AR5K_AR5210_IER, AR5K_AR5210_IER_ENABLE); +} + +HAL_BOOL +ar5k_ar5210_regulation_domain(hal, write, regdomain) + struct ath_hal *hal; + HAL_BOOL write; + ieee80211_regdomain_t *regdomain; +{ + /* Read current value */ + if(write != AH_TRUE) { + memcpy(regdomain, &hal->ah_capabilities.cap_regdomain.reg_current, + sizeof(ieee80211_regdomain_t)); + return(AH_TRUE); + } + + /* Try to write a new value */ + memcpy(&hal->ah_capabilities.cap_regdomain.reg_current, regdomain, + sizeof(ieee80211_regdomain_t)); + + if(hal->ah_capabilities.cap_eeprom.ee_protect & + AR5K_AR5210_EEPROM_PROTECT_128_191) + return(AH_FALSE); + + hal->ah_capabilities.cap_eeprom.ee_regdomain = + ar5k_regdomain_from_ieee(regdomain); + + AR5K_PRINTF("writing new regulation domain to EEPROM: 0x%04x\n", + hal->ah_capabilities.cap_eeprom.ee_regdomain); + + if(ar5k_ar5210_eeprom_write(hal, AR5K_AR5210_EEPROM_REG_DOMAIN, + hal->ah_capabilities.cap_eeprom.ee_regdomain) != 0) + return(AH_FALSE); + + return(AH_TRUE); +} + +/* + * EEPROM access functions + */ + +int +ar5k_ar5210_eeprom_init(hal) + struct ath_hal *hal; +{ + int ret; + + /* Check if EEPROM is busy */ + if(ar5k_ar5210_eeprom_is_busy(hal) == AH_TRUE) + return(-EBUSY); + + /* + * Read values from EEPROM and store them in the capability structure + */ + if((ret = ar5k_ar5210_eeprom_read(hal, AR5K_AR5210_EEPROM_MAGIC, + &hal->ah_capabilities.cap_eeprom.ee_magic)) != 0) + return(ret); + + if(hal->ah_capabilities.cap_eeprom.ee_magic != + AR5K_AR5210_EEPROM_MAGIC_VALUE) + return(-EFTYPE); + + if((ret = ar5k_ar5210_eeprom_read(hal, AR5K_AR5210_EEPROM_INFO_VERSION, + &hal->ah_capabilities.cap_eeprom.ee_version)) != 0) + return(ret); + + if((ret = ar5k_ar5210_eeprom_read(hal, AR5K_AR5210_EEPROM_PROTECT, + &hal->ah_capabilities.cap_eeprom.ee_protect)) != 0) + return(ret); + + if((ret = ar5k_ar5210_eeprom_read(hal, AR5K_AR5210_EEPROM_REG_DOMAIN, + &hal->ah_capabilities.cap_eeprom.ee_regdomain)) != 0) + return(ret); + + return(0); +} + +HAL_BOOL +ar5k_ar5210_eeprom_is_busy(hal) + struct ath_hal *hal; +{ + return(AR5K_REG_READ(AR5K_AR5210_CFG) & AR5K_AR5210_CFG_EEBS ? + AH_TRUE : AH_FALSE); +} + +int +ar5k_ar5210_eeprom_read(hal, offset, data) + struct ath_hal *hal; + u_int32_t offset; + u_int16_t *data; +{ + u_int32_t status, timeout; + + /* Enable eeprom access */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_PCICFG, AR5K_AR5210_PCICFG_EEAE); + + /* + * Prime read pump + */ + (void)AR5K_REG_READ(AR5K_AR5210_EEPROM_BASE + (4 * offset)); + + for(timeout = 10000; timeout > 0; timeout--) { + AR5K_DELAY(1); + status = AR5K_REG_READ(AR5K_AR5210_EEPROM_STATUS); + if(status & AR5K_AR5210_EEPROM_STAT_RDDONE) { + if(status & AR5K_AR5210_EEPROM_STAT_RDERR) + return(-EIO); + *data = (u_int16_t) + (AR5K_REG_READ(AR5K_AR5210_EEPROM_RDATA) & 0xffff); + return(0); + } + } + + return(-ETIMEDOUT); +} + +int +ar5k_ar5210_eeprom_write(hal, offset, data) + struct ath_hal *hal; + u_int32_t offset; + u_int16_t data; +{ + u_int32_t status, timeout; + + /* Enable eeprom access */ + AR5K_REG_ENABLE_BITS(AR5K_AR5210_PCICFG, AR5K_AR5210_PCICFG_EEAE); + + /* + * Prime write pump + */ + AR5K_REG_WRITE(AR5K_AR5210_EEPROM_BASE + (4 * offset), data); + + for(timeout = 10000; timeout > 0; timeout--) { + AR5K_DELAY(1); + status = AR5K_REG_READ(AR5K_AR5210_EEPROM_STATUS); + if(status & AR5K_AR5210_EEPROM_STAT_WRDONE) { + if(status & AR5K_AR5210_EEPROM_STAT_WRERR) + return(-EIO); + return(0); + } + } + + return(-ETIMEDOUT); +} + +#endif /* AR5K_SUPPORT_AR5210 */ diff --git a/sys/dev/ic/ar5210reg.h b/sys/dev/ic/ar5210reg.h new file mode 100644 index 00000000000..79e67105360 --- /dev/null +++ b/sys/dev/ic/ar5210reg.h @@ -0,0 +1,687 @@ +/* $OpenBSD: ar5210reg.h,v 1.1 2004/11/02 03:01:16 reyk Exp $ */ + +/* + * Copyright (c) 2004 Reyk Floeter <reyk@vantronix.net>. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY + * SPECIAL 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. + */ + +/* + * Known registers of the Atheros AR5000 Wireless LAN chipset + * (AR5210 + AR5110). + */ + +#ifndef _AR5K_AR5210_REG_H +#define _AR5K_AR5210_REG_H + +/* + * First tansmit queue descriptor pointer register ("data queue") + */ +#define AR5K_AR5210_TXDP0 0x0000 + +/* + * Second transmit queue descriptor pointer register ("beacon queue") + */ +#define AR5K_AR5210_TXDP1 0x0004 + +/* + * Command register + */ +#define AR5K_AR5210_CR 0x0008 +#define AR5K_AR5210_CR_TXE0 0x00000001 +#define AR5K_AR5210_CR_TXE1 0x00000002 +#define AR5K_AR5210_CR_RXE 0x00000004 +#define AR5K_AR5210_CR_TXD0 0x00000008 +#define AR5K_AR5210_CR_TXD1 0x00000010 +#define AR5K_AR5210_CR_RXD 0x00000020 +#define AR5K_AR5210_CR_SWI 0x00000040 + +/* + * Receive queue descriptor pointer register + */ +#define AR5K_AR5210_RXDP 0x000c + +/* + * Configuration and status register + */ +#define AR5K_AR5210_CFG 0x0014 +#define AR5K_AR5210_CFG_SWTD 0x00000001 +#define AR5K_AR5210_CFG_SWTB 0x00000002 +#define AR5K_AR5210_CFG_SWRD 0x00000004 +#define AR5K_AR5210_CFG_SWRB 0x00000008 +#define AR5K_AR5210_CFG_SWRG 0x00000010 +#define AR5K_AR5210_CFG_EEBS 0x00000200 +#define AR5K_AR5210_CFG_TXCNT 0x00007800 +#define AR5K_AR5210_CFG_TXCNT_S 11 +#define AR5K_AR5210_CFG_TXFSTAT 0x00008000 +#define AR5K_AR5210_CFG_TXFSTRT 0x00010000 + +/* + * Interrupt service register + */ +#define AR5K_AR5210_ISR 0x001c +#define AR5K_AR5210_ISR_RXOK 0x00000001 +#define AR5K_AR5210_ISR_RXDESC 0x00000002 +#define AR5K_AR5210_ISR_RXERR 0x00000004 +#define AR5K_AR5210_ISR_RXNOFRM 0x00000008 +#define AR5K_AR5210_ISR_RXEOL 0x00000120 +#define AR5K_AR5210_ISR_RXORN 0x00000020 +#define AR5K_AR5210_ISR_TXOK 0x00000040 +#define AR5K_AR5210_ISR_TXDESC 0x00000080 +#define AR5K_AR5210_ISR_TXERR 0x00000100 +#define AR5K_AR5210_ISR_TXNOFRM 0x00000200 +#define AR5K_AR5210_ISR_TXEOL 0x00000400 +#define AR5K_AR5210_ISR_TXURN 0x00000800 +#define AR5K_AR5210_ISR_MIB 0x00001000 +#define AR5K_AR5210_ISR_SWI 0x00002000 +#define AR5K_AR5210_ISR_RXPHY 0x00004000 +#define AR5K_AR5210_ISR_RXKCM 0x00008000 +#define AR5K_AR5210_ISR_SWBA 0x00010000 +#define AR5K_AR5210_ISR_BRSSI 0x00020000 +#define AR5K_AR5210_ISR_BMISS 0x00040000 +#define AR5K_AR5210_ISR_MCABT 0x00100000 +#define AR5K_AR5210_ISR_SSERR 0x00200000 +#define AR5K_AR5210_ISR_DPERR 0x00400000 +#define AR5K_AR5210_ISR_GPIO 0x01000000 +#define AR5K_AR5210_ISR_FATAL ( \ + AR5K_AR5210_ISR_MCABT | AR5K_AR5210_ISR_SSERR | \ + AR5K_AR5210_ISR_DPERR | AR5K_AR5210_ISR_RXORN \ +) + +/* + * Interrupt mask register + */ +#define AR5K_AR5210_IMR 0x0020 +#define AR5K_AR5210_IMR_RXOK 0x00000001 +#define AR5K_AR5210_IMR_RXDESC 0x00000002 +#define AR5K_AR5210_IMR_RXERR 0x00000004 +#define AR5K_AR5210_IMR_RXNOFRM 0x00000008 +#define AR5K_AR5210_IMR_RXEOL 0x00000010 +#define AR5K_AR5210_IMR_RXORN 0x00000020 +#define AR5K_AR5210_IMR_TXOK 0x00000040 +#define AR5K_AR5210_IMR_TXDESC 0x00000080 +#define AR5K_AR5210_IMR_TXERR 0x00000100 +#define AR5K_AR5210_IMR_TXNOFRM 0x00000200 +#define AR5K_AR5210_IMR_TXEOL 0x00000400 +#define AR5K_AR5210_IMR_TXURN 0x00000800 +#define AR5K_AR5210_IMR_MIB 0x00001000 +#define AR5K_AR5210_IMR_SWI 0x00002000 +#define AR5K_AR5210_IMR_RXPHY 0x00004000 +#define AR5K_AR5210_IMR_RXKCM 0x00008000 +#define AR5K_AR5210_IMR_SWBA 0x00010000 +#define AR5K_AR5210_IMR_BRSSI 0x00020000 +#define AR5K_AR5210_IMR_BMISS 0x00040000 +#define AR5K_AR5210_IMR_MCABT 0x00100000 +#define AR5K_AR5210_IMR_SSERR 0x00200000 +#define AR5K_AR5210_IMR_DPERR 0x00400000 +#define AR5K_AR5210_IMR_GPIO 0x01000000 + +/* + * Interrupt enable register + */ +#define AR5K_AR5210_IER 0x0024 +#define AR5K_AR5210_IER_DISABLE 0x00000000 +#define AR5K_AR5210_IER_ENABLE 0x00000001 + +/* + * Beacon control register + */ +#define AR5K_AR5210_BCR 0x0028 +#define AR5K_AR5210_BCR_AP 0x00000000 +#define AR5K_AR5210_BCR_ADHOC 0x00000001 +#define AR5K_AR5210_BCR_BDMAE 0x00000002 +#define AR5K_AR5210_BCR_TQ1FV 0x00000004 +#define AR5K_AR5210_BCR_TQ1V 0x00000008 +#define AR5K_AR5210_BCR_BCGET 0x00000010 + +/* + * Beacon status register + */ +#define AR5K_AR5210_BSR 0x002c +#define AR5K_AR5210_BSR_BDLYSW 0x00000001 +#define AR5K_AR5210_BSR_BDLYDMA 0x00000002 +#define AR5K_AR5210_BSR_TXQ1F 0x00000004 +#define AR5K_AR5210_BSR_ATIMDLY 0x00000008 +#define AR5K_AR5210_BSR_SNPBCMD 0x00000100 +#define AR5K_AR5210_BSR_SNPBDMAE 0x00000200 +#define AR5K_AR5210_BSR_SNPTQ1FV 0x00000400 +#define AR5K_AR5210_BSR_SNPTQ1V 0x00000800 +#define AR5K_AR5210_BSR_SNAPPEDBCRVALID 0x00001000 +#define AR5K_AR5210_BSR_SWBA_CNT 0x00ff0000 + +/* + * DMA size definitions + */ +typedef enum { + AR5K_AR5210_DMASIZE_4B = 0, + AR5K_AR5210_DMASIZE_8B, + AR5K_AR5210_DMASIZE_16B, + AR5K_AR5210_DMASIZE_32B, + AR5K_AR5210_DMASIZE_64B, + AR5K_AR5210_DMASIZE_128B, + AR5K_AR5210_DMASIZE_256B, + AR5K_AR5210_DMASIZE_512B +} ar5k_ar5210_dmasize_t; + +/* + * Transmit configuration register + */ +#define AR5K_AR5210_TXCFG 0x0030 +#define AR5K_AR5210_TXCFG_SDMAMR 0x00000007 +#define AR5K_AR5210_TXCFG_TXFSTP 0x00000008 +#define AR5K_AR5210_TXCFG_TXFULL 0x00000070 +#define AR5K_AR5210_TXCFG_TXCONT_EN 0x00000080 + +/* + * Receive configuration register + */ +#define AR5K_AR5210_RXCFG 0x0034 +#define AR5K_AR5210_RXCFG_SDMAMW 0x00000007 +#define AR5K_AR5210_RXCFG_ZLFDMA 0x00000010 + +/* + * MIB control register + */ +#define AR5K_AR5210_MIBC 0x0040 +#define AR5K_AR5210_MIBC_COW 0x00000001 +#define AR5K_AR5210_MIBC_FMC 0x00000002 +#define AR5K_AR5210_MIBC_CMC 0x00000004 +#define AR5K_AR5210_MIBC_MCS 0x00000008 + +/* + * Timeout prescale register + */ +#define AR5K_AR5210_TOPS 0x0044 + +/* + * Receive timeout register (no frame received) + */ +#define AR5K_AR5210_RXNOFRM 0x0048 + +/* + * Transmit timeout register (no frame sent) + */ +#define AR5K_AR5210_TXNOFRM 0x004c + +/* + * Receive frame gap timeout register + */ +#define AR5K_AR5210_RPGTO 0x0050 + +/* + * Receive frame count limit register + */ +#define AR5K_AR5210_RFCNT 0x0054 +#define AR5K_AR5210_RFCNT_RFCL 0x0000000f + +/* + * Misc settings/status register + */ +#define AR5K_AR5210_MISC 0x0058 +#define AR5K_AR5210_MISC_LED_DECAY 0x001c0000 +#define AR5K_AR5210_MISC_LED_BLINK 0x00e00000 + +/* + * Reset control register + */ +#define AR5K_AR5210_RC 0x4000 +#define AR5K_AR5210_RC_PCU 0x00000001 +#define AR5K_AR5210_RC_DMA 0x00000002 +#define AR5K_AR5210_RC_MAC 0x00000004 +#define AR5K_AR5210_RC_PHY 0x00000008 +#define AR5K_AR5210_RC_PCI 0x00000010 +#define AR5K_AR5210_RC_CHIP ( \ + AR5K_AR5210_RC_PCU | AR5K_AR5210_RC_DMA | \ + AR5K_AR5210_RC_MAC | AR5K_AR5210_RC_PHY \ +) + +/* + * Sleep control register + */ +#define AR5K_AR5210_SCR 0x4004 +#define AR5K_AR5210_SCR_SLDUR 0x0000ffff +#define AR5K_AR5210_SCR_SLE 0x00030000 +#define AR5K_AR5210_SCR_SLE_WAKE 0x00000000 +#define AR5K_AR5210_SCR_SLE_SLP 0x00010000 +#define AR5K_AR5210_SCR_SLE_ALLOW 0x00020000 + +/* + * Interrupt pending register + */ +#define AR5K_AR5210_INTPEND 0x4008 +#define AR5K_AR5210_INTPEND_IP 0x00000001 + +/* + * Sleep force register + */ +#define AR5K_AR5210_SFR 0x400c +#define AR5K_AR5210_SFR_SF 0x00000001 + +/* + * PCI configuration register + */ +#define AR5K_AR5210_PCICFG 0x4010 +#define AR5K_AR5210_PCICFG_EEAE 0x00000001 +#define AR5K_AR5210_PCICFG_CLKRUNEN 0x00000004 +#define AR5K_AR5210_PCICFG_LED_PEND 0x00000020 +#define AR5K_AR5210_PCICFG_LED_ACT 0x00000040 +#define AR5K_AR5210_PCICFG_SL_INTEN 0x00000800 +#define AR5K_AR5210_PCICFG_LED_BCTL 0x00001000 +#define AR5K_AR5210_PCICFG_SL_INPEN 0x00002800 +#define AR5K_AR5210_PCICFG_SPWR_DN 0x00010000 + +/* + * "General Purpose Input/Output" (GPIO) control register + */ +#define AR5K_AR5210_GPIOCR 0x4014 +#define AR5K_AR5210_GPIOCR_INT_ENA 0x00008000 +#define AR5K_AR5210_GPIOCR_INT_SELL 0x00000000 +#define AR5K_AR5210_GPIOCR_INT_SELH 0x00010000 +#define AR5K_AR5210_GPIOCR_IN(n) (0 << ((n) * 2)) +#define AR5K_AR5210_GPIOCR_OUT0(n) (1 << ((n) * 2)) +#define AR5K_AR5210_GPIOCR_OUT1(n) (2 << ((n) * 2)) +#define AR5K_AR5210_GPIOCR_OUT(n) (3 << ((n) * 2)) +#define AR5K_AR5210_GPIOCR_ALL(n) (3<< ((n) * 2)) +#define AR5K_AR5210_GPIOCR_INT_SEL(n) ((n) << 12) + +#define AR5K_AR5210_NUM_GPIO 6 + +/* + * "General Purpose Input/Output" (GPIO) data output register + */ +#define AR5K_AR5210_GPIODO 0x4018 + +/* + * "General Purpose Input/Output" (GPIO) data input register + */ +#define AR5K_AR5210_GPIODI 0x401c +#define AR5K_AR5210_GPIOD_MASK 0x0000002f + +/* + * Silicon revision register + */ +#define AR5K_AR5210_SREV 0x4020 +#define AR5K_AR5210_SREV_ID_M 0x000000ff +#define AR5K_AR5210_SREV_FPGA 1 +#define AR5K_AR5210_SREV_PHYPLUS 2 +#define AR5K_AR5210_SREV_PHYPLUS_MS 3 +#define AR5K_AR5210_SREV_CRETE 4 +#define AR5K_AR5210_SREV_CRETE_MS 5 +#define AR5K_AR5210_SREV_CRETE_MS23 7 +#define AR5K_AR5210_SREV_CRETE_23 8 + +/* + * EEPROM access registers + */ +#define AR5K_AR5210_EEPROM_BASE 0x6000 +#define AR5K_AR5210_EEPROM_RDATA 0x6800 +#define AR5K_AR5210_EEPROM_STATUS 0x6c00 +#define AR5K_AR5210_EEPROM_STAT_RDERR 0x0001 +#define AR5K_AR5210_EEPROM_STAT_RDDONE 0x0002 +#define AR5K_AR5210_EEPROM_STAT_WRERR 0x0004 +#define AR5K_AR5210_EEPROM_STAT_WRDONE 0x0008 + +/* + * AR5210 EEPROM data registers + */ +#define AR5K_AR5210_EEPROM_MAGIC 0x3d +#define AR5K_AR5210_EEPROM_MAGIC_VALUE 0x5aa5 +#define AR5K_AR5210_EEPROM_PROTECT 0x3f +#define AR5K_AR5210_EEPROM_PROTECT_128_191 0x80 +#define AR5K_AR5210_EEPROM_REG_DOMAIN 0xbf +#define AR5K_AR5210_EEPROM_INFO_BASE 0xc0 +#define AR5K_AR5210_EEPROM_INFO_VERSION \ + (AR5K_AR5210_EEPROM_INFO_BASE + 1) +#define AR5K_AR5210_EEPROM_INFO_MAX \ + (0x400 - AR5K_AR5210_EEPROM_INFO_BASE) + +/* + * PCU registers + */ + +#define AR5K_AR5210_PCU_MIN 0x8000 +#define AR5K_AR5210_PCU_MAX 0x8fff + +/* + * First station id register (MAC address in lower 32 bits) + */ +#define AR5K_AR5210_STA_ID0 0x8000 + +/* + * Second station id register (MAC address in upper 16 bits) + */ +#define AR5K_AR5210_STA_ID1 0x8004 +#define AR5K_AR5210_STA_ID1_AP 0x00010000 +#define AR5K_AR5210_STA_ID1_ADHOC 0x00020000 +#define AR5K_AR5210_STA_ID1_PWR_SV 0x00040000 +#define AR5K_AR5210_STA_ID1_NO_KEYSRCH 0x00080000 +#define AR5K_AR5210_STA_ID1_NO_PSPOLL 0x00100000 +#define AR5K_AR5210_STA_ID1_PCF 0x00200000 +#define AR5K_AR5210_STA_ID1_DESC_ANTENNA 0x00400000 +#define AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA 0x00800000 +#define AR5K_AR5210_STA_ID1_ACKCTS_6MB 0x01000000 + +/* + * First BSSID register (MAC address, lower 32bits) + */ +#define AR5K_AR5210_BSS_ID0 0x8008 + +/* + * Second BSSID register (MAC address in upper 16 bits) + * + * AID: Association ID + */ +#define AR5K_AR5210_BSS_ID1 0x800c +#define AR5K_AR5210_BSS_ID1_AID 0xffff0000 +#define AR5K_AR5210_BSS_ID1_AID_S 16 + +/* + * Backoff slot time register + */ +#define AR5K_AR5210_SLOT_TIME 0x8010 + +/* + * ACK/CTS timeout register + */ +#define AR5K_AR5210_TIME_OUT 0x8014 +#define AR5K_AR5210_TIME_OUT_ACK 0x00001fff +#define AR5K_AR5210_TIME_OUT_ACK_S 0 +#define AR5K_AR5210_TIME_OUT_CTS 0x1fff0000 +#define AR5K_AR5210_TIME_OUT_CTS_S 16 + +/* + * RSSI threshold register + */ +#define AR5K_AR5210_RSSI_THR 0x8018 +#define AR5K_AR5210_RSSI_THR_BM_THR 0x00000700 +#define AR5K_AR5210_RSSI_THR_BM_THR_S 8 + +/* + * Retry limit register + */ +#define AR5K_AR5210_RETRY_LMT 0x801c +#define AR5K_AR5210_RETRY_LMT_SH_RETRY 0x0000000f +#define AR5K_AR5210_RETRY_LMT_SH_RETRY_S 0 +#define AR5K_AR5210_RETRY_LMT_LG_RETRY 0x000000f0 +#define AR5K_AR5210_RETRY_LMT_LG_RETRY_S 4 +#define AR5K_AR5210_RETRY_LMT_SSH_RETRY 0x00003f00 +#define AR5K_AR5210_RETRY_LMT_SSH_RETRY_S 8 +#define AR5K_AR5210_RETRY_LMT_SLG_RETRY 0x000fc000 +#define AR5K_AR5210_RETRY_LMT_SLG_RETRY_S 14 +#define AR5K_AR5210_RETRY_LMT_CW_MIN 0x3ff00000 +#define AR5K_AR5210_RETRY_LMT_CW_MIN_S 20 + +/* + * Transmit latency register + */ +#define AR5K_AR5210_USEC 0x8020 +#define AR5K_AR5210_USEC_1 0x0000007f +#define AR5K_AR5210_USEC_1_S 0 +#define AR5K_AR5210_USEC_32 0x00003f80 +#define AR5K_AR5210_USEC_32_S 7 +#define AR5K_AR5210_USEC_TX_LATENCY 0x000fc000 +#define AR5K_AR5210_USEC_TX_LATENCY_S 14 +#define AR5K_AR5210_USEC_RX_LATENCY 0x03f00000 +#define AR5K_AR5210_USEC_RX_LATENCY_S 20 + +/* + * PCU beacon control register + */ +#define AR5K_AR5210_BEACON 0x8024 +#define AR5K_AR5210_BEACON_PERIOD 0x0000ffff +#define AR5K_AR5210_BEACON_PERIOD_S 0 +#define AR5K_AR5210_BEACON_TIM 0x007f0000 +#define AR5K_AR5210_BEACON_TIM_S 16 +#define AR5K_AR5210_BEACON_EN 0x00800000 +#define AR5K_AR5210_BEACON_RESET_TSF 0x01000000 + +/* + * CFP period register + */ +#define AR5K_AR5210_CFP_PERIOD 0x8028 + +/* + * Next beacon time register + */ +#define AR5K_AR5210_TIMER0 0x802c + +/* + * Next DMA beacon alert register + */ +#define AR5K_AR5210_TIMER1 0x8030 + +/* + * Next software beacon alert register + */ +#define AR5K_AR5210_TIMER2 0x8034 + +/* + * Next ATIM window time register + */ +#define AR5K_AR5210_TIMER3 0x8038 + +/* + * First inter frame spacing register (IFS) + */ +#define AR5K_AR5210_IFS0 0x8040 +#define AR5K_AR5210_IFS0_SIFS 0x000007ff +#define AR5K_AR5210_IFS0_SIFS_S 0 +#define AR5K_AR5210_IFS0_DIFS 0x007ff800 +#define AR5K_AR5210_IFS0_DIFS_S 11 + +/* + * Second inter frame spacing register (IFS) + */ +#define AR5K_AR5210_IFS1 0x8044 +#define AR5K_AR5210_IFS1_PIFS 0x00000fff +#define AR5K_AR5210_IFS1_PIFS_S 0 +#define AR5K_AR5210_IFS1_EIFS 0x03fff000 +#define AR5K_AR5210_IFS1_EIFS_S 12 +#define AR5K_AR5210_IFS1_CS_EN 0x04000000 + +/* + * CFP duration register + */ +#define AR5K_AR5210_CFP_DUR 0x8048 + +/* + * Receive filter register + */ +#define AR5K_AR5210_RX_FILTER 0x804c +#define AR5K_AR5210_RX_FILTER_UNICAST 0x00000001 +#define AR5K_AR5210_RX_FILTER_MULTICAST 0x00000002 +#define AR5K_AR5210_RX_FILTER_BROADCAST 0x00000004 +#define AR5K_AR5210_RX_FILTER_CONTROL 0x00000008 +#define AR5K_AR5210_RX_FILTER_BEACON 0x00000010 +#define AR5K_AR5210_RX_FILTER_PROMISC 0x00000020 + +/* + * Multicast filter register (lower 32 bits) + */ +#define AR5K_AR5210_MCAST_FIL0 0x8050 + +/* + * Multicast filter register (higher 16 bits) + */ +#define AR5K_AR5210_MCAST_FIL1 0x8054 + +/* + * Transmit mask register (lower 32 bits) + */ +#define AR5K_AR5210_TX_MASK0 0x8058 + +/* + * Transmit mask register (higher 16 bits) + */ +#define AR5K_AR5210_TX_MASK1 0x805c + +/* + * Clear transmit mask + */ +#define AR5K_AR5210_CLR_TMASK 0x8060 + +/* + * Trigger level register (before transmission) + */ +#define AR5K_AR5210_TRIG_LVL 0x8064 + +/* + * PCU control register + */ +#define AR5K_AR5210_DIAG_SW 0x8068 +#define AR5K_AR5210_DIAG_SW_DIS_WEP_ACK 0x00000001 +#define AR5K_AR5210_DIAG_SW_DIS_ACK 0x00000002 +#define AR5K_AR5210_DIAG_SW_DIS_CTS 0x00000004 +#define AR5K_AR5210_DIAG_SW_DIS_ENC 0x00000008 +#define AR5K_AR5210_DIAG_SW_DIS_DEC 0x00000010 +#define AR5K_AR5210_DIAG_SW_DIS_TX 0x00000020 +#define AR5K_AR5210_DIAG_SW_DIS_RX 0x00000040 +#define AR5K_AR5210_DIAG_SW_LOOP_BACK 0x00000080 +#define AR5K_AR5210_DIAG_SW_CORR_FCS 0x00000100 +#define AR5K_AR5210_DIAG_SW_CHAN_INFO 0x00000200 +#define AR5K_AR5210_DIAG_SW_EN_SCRAM_SEED 0x00000400 +#define AR5K_AR5210_DIAG_SW_SCVRAM_SEED 0x0003f800 +#define AR5K_AR5210_DIAG_SW_DIS_SEQ_INC 0x00040000 +#define AR5K_AR5210_DIAG_SW_FRAME_NV0 0x00080000 + +/* + * TSF (clock) register (lower 32 bits) + */ +#define AR5K_AR5210_TSF_L32 0x806c + +/* + * TSF (clock) register (higher 32 bits) + */ +#define AR5K_AR5210_TSF_U32 0x8070 + +/* + * Last beacon timestamp register + */ +#define AR5K_AR5210_LAST_TSTP 0x8080 + +/* + * Retry count register + */ +#define AR5K_AR5210_RETRY_CNT 0x8084 +#define AR5K_AR5210_RETRY_CNT_SSH 0x0000003f +#define AR5K_AR5210_RETRY_CNT_SLG 0x00000fc0 + +/* + * Back-off status register + */ +#define AR5K_AR5210_BACKOFF 0x8088 +#define AR5K_AR5210_BACKOFF_CW 0x000003ff +#define AR5K_AR5210_BACKOFF_CNT 0x03ff0000 + +/* + * NAV register (current) + */ +#define AR5K_AR5210_NAV 0x808c + +/* + * RTS success register + */ +#define AR5K_AR5210_RTS_OK 0x8090 + +/* + * RTS failure register + */ +#define AR5K_AR5210_RTS_FAIL 0x8094 + +/* + * ACK failure register + */ +#define AR5K_AR5210_ACK_FAIL 0x8098 + +/* + * FCS failure register + */ +#define AR5K_AR5210_FCS_FAIL 0x809c + +/* + * Beacon count register + */ +#define AR5K_AR5210_BEACON_CNT 0x80a0 + +/* + * Key table (WEP) register + */ +#define AR5K_AR5210_KEYTABLE_0 0x9000 +#define AR5K_AR5210_KEYTABLE(n) (AR5K_AR5210_KEYTABLE_0 + ((n) * 32)) +#define AR5K_AR5210_KEYTABLE_TYPE_40 0x00000000 +#define AR5K_AR5210_KEYTABLE_TYPE_104 0x00000001 +#define AR5K_AR5210_KEYTABLE_TYPE_128 0x00000003 +#define AR5K_AR5210_KEYTABLE_VALID 0x00008000 + +#define AR5K_AR5210_KEYTABLE_SIZE 64 +#define AR5K_AR5210_KEYCACHE_SIZE 8 + +/* + * PHY register + */ +#define AR5K_AR5210_PHY(_n) (0x9800 + ((_n) << 2)) + +/* + * PHY frame control register + */ +#define AR5K_AR5210_PHY_FC 0x9804 +#define AR5K_AR5210_PHY_FC_TURBO_MODE 0x00000001 +#define AR5K_AR5210_PHY_FC_TURBO_SHORT 0x00000002 +#define AR5K_AR5210_PHY_FC_TIMING_ERR 0x01000000 +#define AR5K_AR5210_PHY_FC_PARITY_ERR 0x02000000 +#define AR5K_AR5210_PHY_FC_ILLRATE_ERR 0x04000000 +#define AR5K_AR5210_PHY_FC_ILLLEN_ERR 0x08000000 +#define AR5K_AR5210_PHY_FC_SERVICE_ERR 0x20000000 +#define AR5K_AR5210_PHY_FC_TXURN_ERR 0x40000000 + +/* + * PHY agility command register + */ +#define AR5K_AR5210_PHY_AGC 0x9808 +#define AR5K_AR5210_PHY_AGC_DISABLE 0x08000000 + +/* + * PHY chip revision register + */ +#define AR5K_AR5210_PHY_CHIP_ID 0x9818 + +/* + * PHY activation register + */ +#define AR5K_AR5210_PHY_ACTIVE 0x981c +#define AR5K_AR5210_PHY_ENABLE 0x00000001 +#define AR5K_AR5210_PHY_DISABLE 0x00000002 + +/* + * PHY agility control register + */ +#define AR5K_AR5210_PHY_AGCCTL 0x9860 +#define AR5K_AR5210_PHY_AGC_CAL 0x00000001 +#define AR5K_AR5210_PHY_AGC_NF 0x00000002 + +/* + * Misc PHY/radio registers + */ +#define AR5K_AR5210_BB_GAIN(_n) (0x9b00 + ((_n) << 2)) +#define AR5K_AR5210_RF_GAIN(_n) (0x9a00 + ((_n) << 2)) + +#endif diff --git a/sys/dev/ic/ar5210var.h b/sys/dev/ic/ar5210var.h new file mode 100644 index 00000000000..2339d316fdc --- /dev/null +++ b/sys/dev/ic/ar5210var.h @@ -0,0 +1,440 @@ +/* $OpenBSD: ar5210var.h,v 1.1 2004/11/02 03:01:16 reyk Exp $ */ + +/* + * Copyright (c) 2004 Reyk Floeter <reyk@vantronix.net>. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY + * SPECIAL 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. + */ + +/* + * Specific definitions for the Atheros AR5000 Wireless LAN chipset + * (AR5210 + AR5110). + */ + +#ifndef _AR5K_AR5210_VAR_H +#define _AR5K_AR5210_VAR_H + +#include <dev/ic/ar5xxx.h> + +/* + * Define a "magic" code for the AR5210 (the HAL layer wants it) + */ + +#define AR5K_AR5210_MAGIC 0x0000145a /* 5210 */ +#define AR5K_AR5210_TX_NUM_QUEUES 2 + +#if BYTE_ORDER == BIG_ENDIAN +#define AR5K_AR5210_INIT_CFG ( \ + AR5K_AR5210_CFG_SWTD | AR5K_AR5210_CFG_SWTB | \ + AR5K_AR5210_CFG_SWRD | AR5K_AR5210_CFG_SWRB | \ + AR5K_AR5210_CFG_SWRG \ +) +#else +#define AR5K_AR5210_INIT_CFG 0x00000000 +#endif + + +/* + * Internal RX/TX descriptor structures + * (rX: reserved fields possibily used by future versions of the ar5k chipset) + */ + +struct ar5k_ar5210_rx_desc { + /* + * First word + */ + u_int32_t r1; + + /* + * Second word + */ + u_int32_t buf_len:12; + u_int32_t r2:1; + u_int32_t inter_req:1; + u_int32_t r3:18; +} __attribute__ ((__packed__)); + +struct ar5k_ar5210_rx_status { + /* + * First word + */ + u_int32_t data_len:12; + u_int32_t more:1; + u_int32_t r1:1; + u_int32_t receive_antenna:1; + u_int32_t receive_rate:4; + u_int32_t receive_sig_strength:8; + u_int32_t r2:5; + + /* + * Second word + */ + u_int32_t done:1; + u_int32_t frame_receive_ok:1; + u_int32_t crc_error:1; + u_int32_t fifo_overrun:1; + u_int32_t decrypt_crc_error:1; + u_int32_t phy_error:3; + u_int32_t key_index_valid:1; + u_int32_t key_index:6; + u_int32_t receive_timestamp:13; + u_int32_t key_cache_miss:1; + u_int32_t r3:3; +} __attribute__ ((__packed__)); + +#define AR5K_AR5210_DESC_RX_PHY_ERROR_NONE 0x00 +#define AR5K_AR5210_DESC_RX_PHY_ERROR_TIMING 0x20 +#define AR5K_AR5210_DESC_RX_PHY_ERROR_PARITY 0x40 +#define AR5K_AR5210_DESC_RX_PHY_ERROR_RATE 0x60 +#define AR5K_AR5210_DESC_RX_PHY_ERROR_LENGTH 0x80 +#define AR5K_AR5210_DESC_RX_PHY_ERROR_64QAM 0xa0 +#define AR5K_AR5210_DESC_RX_PHY_ERROR_SERVICE 0xc0 +#define AR5K_AR5210_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 + +struct ar5k_ar5210_tx_desc { + /* + * First word + */ + u_int32_t frame_len:12; + u_int32_t header_len:6; + u_int32_t xmit_rate:4; + u_int32_t rts_cts_enable:1; + u_int32_t long_packet:1; + u_int32_t clear_dest_mask:1; + u_int32_t ant_mode_xmit:1; + u_int32_t frame_type:3; + u_int32_t inter_req:1; + u_int32_t encrypt_key_valid:1; + u_int32_t r1:1; + + /* + * Second word + */ + u_int32_t buf_len:12; + u_int32_t more:1; + u_int32_t encrypt_key_index:6; + u_int32_t rts_duration:13; +} __attribute__ ((__packed__)); + +#define AR5K_AR5210_DESC_TX_XMIT_RATE_6 0xb +#define AR5K_AR5210_DESC_TX_XMIT_RATE_9 0xf +#define AR5K_AR5210_DESC_TX_XMIT_RATE_12 0xa +#define AR5K_AR5210_DESC_TX_XMIT_RATE_18 0xe +#define AR5K_AR5210_DESC_TX_XMIT_RATE_24 0x9 +#define AR5K_AR5210_DESC_TX_XMIT_RATE_36 0xd +#define AR5K_AR5210_DESC_TX_XMIT_RATE_48 0x8 +#define AR5K_AR5210_DESC_TX_XMIT_RATE_54 0xc + +#define AR5K_AR5210_DESC_TX_FRAME_TYPE_NORMAL 0x00 +#define AR5K_AR5210_DESC_TX_FRAME_TYPE_ATIM 0x04 +#define AR5K_AR5210_DESC_TX_FRAME_TYPE_PSPOLL 0x08 +#define AR5K_AR5210_DESC_TX_FRAME_TYPE_NO_DELAY 0x0c +#define AR5K_AR5210_DESC_TX_FRAME_TYPE_PIFS 0x10 + +struct ar5k_ar5210_tx_status { + /* + * First word + */ + u_int32_t frame_xmit_ok:1; + u_int32_t excessive_retries:1; + u_int32_t fifo_underrun:1; + u_int32_t filtered:1; + u_int32_t short_retry_count:4; + u_int32_t long_retry_count:4; + u_int32_t r1:4; + u_int32_t send_timestamp:16; + + /* + * Second word + */ + u_int32_t done:1; + u_int32_t seq_num:12; + u_int32_t ack_sig_strength:8; + u_int32_t r2:11; +} __attribute__ ((__packed__)); + +/* + * Public function prototypes + */ +extern ar5k_attach_t ar5k_ar5210_attach; + +/* + * Initial mode settings ("Base Mode" or "Turbo Mode") + */ + +#define AR5K_AR5210_INI_MODE(_aifs) { \ + { AR5K_AR5210_SLOT_TIME, \ + AR5K_INIT_SLOT_TIME, \ + AR5K_INIT_SLOT_TIME_TURBO }, \ + { AR5K_AR5210_SLOT_TIME, \ + AR5K_INIT_ACK_CTS_TIMEOUT, \ + AR5K_INIT_ACK_CTS_TIMEOUT_TURBO }, \ + { AR5K_AR5210_USEC, \ + AR5K_INIT_TRANSMIT_LATENCY, \ + AR5K_INIT_TRANSMIT_LATENCY_TURBO}, \ + { AR5K_AR5210_IFS0, \ + ((AR5K_INIT_SIFS + (_aifs) * AR5K_INIT_SLOT_TIME) \ + << AR5K_AR5210_IFS0_DIFS_S) | AR5K_INIT_SIFS, \ + ((AR5K_INIT_SIFS_TURBO + (_aifs) * AR5K_INIT_SLOT_TIME_TURBO) \ + << AR5K_AR5210_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO }, \ + { AR5K_AR5210_IFS1, \ + AR5K_INIT_PROTO_TIME_CNTRL, \ + AR5K_INIT_PROTO_TIME_CNTRL_TURBO }, \ + { AR5K_AR5210_PHY(17), \ + (AR5K_REG_READ(AR5K_AR5210_PHY(17)) & ~0x7F) | 0x1C, \ + (AR5K_REG_READ(AR5K_AR5210_PHY(17)) & ~0x7F) | 0x38 }, \ + { AR5K_AR5210_PHY_FC, \ + \ + AR5K_AR5210_PHY_FC_SERVICE_ERR | \ + AR5K_AR5210_PHY_FC_TXURN_ERR | \ + AR5K_AR5210_PHY_FC_ILLLEN_ERR | \ + AR5K_AR5210_PHY_FC_ILLRATE_ERR | \ + AR5K_AR5210_PHY_FC_PARITY_ERR | \ + AR5K_AR5210_PHY_FC_TIMING_ERR | 0x1020, \ + \ + AR5K_AR5210_PHY_FC_SERVICE_ERR | \ + AR5K_AR5210_PHY_FC_TXURN_ERR | \ + AR5K_AR5210_PHY_FC_ILLLEN_ERR | \ + AR5K_AR5210_PHY_FC_ILLRATE_ERR | \ + AR5K_AR5210_PHY_FC_PARITY_ERR | \ + AR5K_AR5210_PHY_FC_TURBO_MODE | \ + AR5K_AR5210_PHY_FC_TURBO_SHORT | \ + AR5K_AR5210_PHY_FC_TIMING_ERR | 0x2020 }, \ +} + +/* + * Initial register values which have to be loaded into the + * card at boot time and after each reset. + */ + +#define AR5K_AR5210_INI { \ + /* PCU and MAC registers */ \ + { AR5K_AR5210_TXDP0, 0 }, \ + { AR5K_AR5210_TXDP1, 0 }, \ + { AR5K_AR5210_RXDP, 0 }, \ + { AR5K_AR5210_CR, 0 }, \ + { AR5K_AR5210_ISR, 0, INI_READ }, \ + { AR5K_AR5210_IMR, 0 }, \ + { AR5K_AR5210_IER, AR5K_AR5210_IER_DISABLE }, \ + { AR5K_AR5210_BSR, 0, INI_READ }, \ + { AR5K_AR5210_TXCFG, AR5K_AR5210_DMASIZE_128B }, \ + { AR5K_AR5210_RXCFG, AR5K_AR5210_DMASIZE_128B }, \ + { AR5K_AR5210_CFG, AR5K_AR5210_INIT_CFG }, \ + { AR5K_AR5210_TOPS, AR5K_INIT_TOPS }, \ + { AR5K_AR5210_RXNOFRM, AR5K_INIT_RXNOFRM }, \ + { AR5K_AR5210_RPGTO, AR5K_INIT_RPGTO }, \ + { AR5K_AR5210_TXNOFRM, AR5K_INIT_TXNOFRM }, \ + { AR5K_AR5210_SFR, 0 }, \ + { AR5K_AR5210_MIBC, 0 }, \ + { AR5K_AR5210_MISC, 0 }, \ + { AR5K_AR5210_RX_FILTER, 0 }, \ + { AR5K_AR5210_MCAST_FIL0, 0 }, \ + { AR5K_AR5210_MCAST_FIL1, 0 }, \ + { AR5K_AR5210_TX_MASK0, 0 }, \ + { AR5K_AR5210_TX_MASK1, 0 }, \ + { AR5K_AR5210_CLR_TMASK, 0 }, \ + { AR5K_AR5210_TRIG_LVL, AR5K_TUNE_MIN_TX_FIFO_THRES }, \ + { AR5K_AR5210_DIAG_SW, 0 }, \ + { AR5K_AR5210_RSSI_THR, AR5K_TUNE_RSSI_THRES }, \ + { AR5K_AR5210_TSF_L32, 0 }, \ + { AR5K_AR5210_TIMER0, 0 }, \ + { AR5K_AR5210_TIMER1, 0xffffffff }, \ + { AR5K_AR5210_TIMER2, 0xffffffff }, \ + { AR5K_AR5210_TIMER3, 1 }, \ + { AR5K_AR5210_CFP_DUR, 0 }, \ + { AR5K_AR5210_CFP_PERIOD, 0 }, \ + /* PHY registers */ \ + { AR5K_AR5210_PHY(0), 0x00000047 }, \ + { AR5K_AR5210_PHY_AGC, 0x00000000 }, \ + { AR5K_AR5210_PHY(3), 0x09848ea6 }, \ + { AR5K_AR5210_PHY(4), 0x3d32e000 }, \ + { AR5K_AR5210_PHY(5), 0x0000076b }, \ + { AR5K_AR5210_PHY_ACTIVE, AR5K_AR5210_PHY_DISABLE }, \ + { AR5K_AR5210_PHY(8), 0x02020200 }, \ + { AR5K_AR5210_PHY(9), 0x00000e0e }, \ + { AR5K_AR5210_PHY(10), 0x0a020201 }, \ + { AR5K_AR5210_PHY(11), 0x00036ffc }, \ + { AR5K_AR5210_PHY(12), 0x00000000 }, \ + { AR5K_AR5210_PHY(13), 0x00000e0e }, \ + { AR5K_AR5210_PHY(14), 0x00000007 }, \ + { AR5K_AR5210_PHY(15), 0x00020100 }, \ + { AR5K_AR5210_PHY(16), 0x89630000 }, \ + { AR5K_AR5210_PHY(17), 0x1372169c }, \ + { AR5K_AR5210_PHY(18), 0x0018b633 }, \ + { AR5K_AR5210_PHY(19), 0x1284613c }, \ + { AR5K_AR5210_PHY(20), 0x0de8b8e0 }, \ + { AR5K_AR5210_PHY(21), 0x00074859 }, \ + { AR5K_AR5210_PHY(22), 0x7e80beba }, \ + { AR5K_AR5210_PHY(23), 0x313a665e }, \ + { AR5K_AR5210_PHY_AGCCTL, 0x00001d08 }, \ + { AR5K_AR5210_PHY(25), 0x0001ce00 }, \ + { AR5K_AR5210_PHY(26), 0x409a4190 }, \ + { AR5K_AR5210_PHY(28), 0x0000000f }, \ + { AR5K_AR5210_PHY(29), 0x00000080 }, \ + { AR5K_AR5210_PHY(30), 0x00000004 }, \ + { AR5K_AR5210_PHY(31), 0x00000018 }, /* 0x987c */ \ + { AR5K_AR5210_PHY(64), 0x00000000 }, /* 0x9900 */ \ + { AR5K_AR5210_PHY(65), 0x00000000 }, \ + { AR5K_AR5210_PHY(66), 0x00000000 }, \ + { AR5K_AR5210_PHY(67), 0x00800000 }, \ + { AR5K_AR5210_PHY(68), 0x00000003 }, \ + /* BB gain table (64bytes) */ \ + { AR5K_AR5210_BB_GAIN(0), 0x00000000 }, \ + { AR5K_AR5210_BB_GAIN(0x01), 0x00000020 }, \ + { AR5K_AR5210_BB_GAIN(0x02), 0x00000010 }, \ + { AR5K_AR5210_BB_GAIN(0x03), 0x00000030 }, \ + { AR5K_AR5210_BB_GAIN(0x04), 0x00000008 }, \ + { AR5K_AR5210_BB_GAIN(0x05), 0x00000028 }, \ + { AR5K_AR5210_BB_GAIN(0x06), 0x00000028 }, \ + { AR5K_AR5210_BB_GAIN(0x07), 0x00000004 }, \ + { AR5K_AR5210_BB_GAIN(0x08), 0x00000024 }, \ + { AR5K_AR5210_BB_GAIN(0x09), 0x00000014 }, \ + { AR5K_AR5210_BB_GAIN(0x0a), 0x00000034 }, \ + { AR5K_AR5210_BB_GAIN(0x0b), 0x0000000c }, \ + { AR5K_AR5210_BB_GAIN(0x0c), 0x0000002c }, \ + { AR5K_AR5210_BB_GAIN(0x0d), 0x00000002 }, \ + { AR5K_AR5210_BB_GAIN(0x0e), 0x00000022 }, \ + { AR5K_AR5210_BB_GAIN(0x0f), 0x00000012 }, \ + { AR5K_AR5210_BB_GAIN(0x10), 0x00000032 }, \ + { AR5K_AR5210_BB_GAIN(0x11), 0x0000000a }, \ + { AR5K_AR5210_BB_GAIN(0x12), 0x0000002a }, \ + { AR5K_AR5210_BB_GAIN(0x13), 0x00000001 }, \ + { AR5K_AR5210_BB_GAIN(0x14), 0x00000021 }, \ + { AR5K_AR5210_BB_GAIN(0x15), 0x00000011 }, \ + { AR5K_AR5210_BB_GAIN(0x16), 0x00000031 }, \ + { AR5K_AR5210_BB_GAIN(0x17), 0x00000009 }, \ + { AR5K_AR5210_BB_GAIN(0x18), 0x00000029 }, \ + { AR5K_AR5210_BB_GAIN(0x19), 0x00000005 }, \ + { AR5K_AR5210_BB_GAIN(0x1a), 0x00000025 }, \ + { AR5K_AR5210_BB_GAIN(0x1b), 0x00000015 }, \ + { AR5K_AR5210_BB_GAIN(0x1c), 0x00000035 }, \ + { AR5K_AR5210_BB_GAIN(0x1d), 0x0000000d }, \ + { AR5K_AR5210_BB_GAIN(0x1e), 0x0000002d }, \ + { AR5K_AR5210_BB_GAIN(0x1f), 0x00000003 }, \ + { AR5K_AR5210_BB_GAIN(0x20), 0x00000023 }, \ + { AR5K_AR5210_BB_GAIN(0x21), 0x00000013 }, \ + { AR5K_AR5210_BB_GAIN(0x22), 0x00000033 }, \ + { AR5K_AR5210_BB_GAIN(0x23), 0x0000000b }, \ + { AR5K_AR5210_BB_GAIN(0x24), 0x0000002b }, \ + { AR5K_AR5210_BB_GAIN(0x25), 0x00000007 }, \ + { AR5K_AR5210_BB_GAIN(0x26), 0x00000027 }, \ + { AR5K_AR5210_BB_GAIN(0x27), 0x00000017 }, \ + { AR5K_AR5210_BB_GAIN(0x28), 0x00000037 }, \ + { AR5K_AR5210_BB_GAIN(0x29), 0x0000000f }, \ + { AR5K_AR5210_BB_GAIN(0x2a), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x2b), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x2c), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x2d), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x2e), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x2f), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x30), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x31), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x32), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x33), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x34), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x35), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x36), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x37), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x38), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x39), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x3a), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x3b), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x3c), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x3d), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x3e), 0x0000002f }, \ + { AR5K_AR5210_BB_GAIN(0x3f), 0x0000002f }, \ + /* RF gain table (64bytes) */ \ + { AR5K_AR5210_RF_GAIN(0), 0x0000001d }, \ + { AR5K_AR5210_RF_GAIN(0x01), 0x0000005d }, \ + { AR5K_AR5210_RF_GAIN(0x02), 0x0000009d }, \ + { AR5K_AR5210_RF_GAIN(0x03), 0x000000dd }, \ + { AR5K_AR5210_RF_GAIN(0x04), 0x0000011d }, \ + { AR5K_AR5210_RF_GAIN(0x05), 0x00000021 }, \ + { AR5K_AR5210_RF_GAIN(0x06), 0x00000061 }, \ + { AR5K_AR5210_RF_GAIN(0x07), 0x000000a1 }, \ + { AR5K_AR5210_RF_GAIN(0x08), 0x000000e1 }, \ + { AR5K_AR5210_RF_GAIN(0x09), 0x00000031 }, \ + { AR5K_AR5210_RF_GAIN(0x0a), 0x00000071 }, \ + { AR5K_AR5210_RF_GAIN(0x0b), 0x000000b1 }, \ + { AR5K_AR5210_RF_GAIN(0x0c), 0x0000001c }, \ + { AR5K_AR5210_RF_GAIN(0x0d), 0x0000005c }, \ + { AR5K_AR5210_RF_GAIN(0x0e), 0x00000029 }, \ + { AR5K_AR5210_RF_GAIN(0x0f), 0x00000069 }, \ + { AR5K_AR5210_RF_GAIN(0x10), 0x000000a9 }, \ + { AR5K_AR5210_RF_GAIN(0x11), 0x00000020 }, \ + { AR5K_AR5210_RF_GAIN(0x12), 0x00000019 }, \ + { AR5K_AR5210_RF_GAIN(0x13), 0x00000059 }, \ + { AR5K_AR5210_RF_GAIN(0x14), 0x00000099 }, \ + { AR5K_AR5210_RF_GAIN(0x15), 0x00000030 }, \ + { AR5K_AR5210_RF_GAIN(0x16), 0x00000005 }, \ + { AR5K_AR5210_RF_GAIN(0x17), 0x00000025 }, \ + { AR5K_AR5210_RF_GAIN(0x18), 0x00000065 }, \ + { AR5K_AR5210_RF_GAIN(0x19), 0x000000a5 }, \ + { AR5K_AR5210_RF_GAIN(0x1a), 0x00000028 }, \ + { AR5K_AR5210_RF_GAIN(0x1b), 0x00000068 }, \ + { AR5K_AR5210_RF_GAIN(0x1c), 0x0000001f }, \ + { AR5K_AR5210_RF_GAIN(0x1d), 0x0000001e }, \ + { AR5K_AR5210_RF_GAIN(0x1e), 0x00000018 }, \ + { AR5K_AR5210_RF_GAIN(0x1f), 0x00000058 }, \ + { AR5K_AR5210_RF_GAIN(0x20), 0x00000098 }, \ + { AR5K_AR5210_RF_GAIN(0x21), 0x00000003 }, \ + { AR5K_AR5210_RF_GAIN(0x22), 0x00000004 }, \ + { AR5K_AR5210_RF_GAIN(0x23), 0x00000044 }, \ + { AR5K_AR5210_RF_GAIN(0x24), 0x00000084 }, \ + { AR5K_AR5210_RF_GAIN(0x25), 0x00000013 }, \ + { AR5K_AR5210_RF_GAIN(0x26), 0x00000012 }, \ + { AR5K_AR5210_RF_GAIN(0x27), 0x00000052 }, \ + { AR5K_AR5210_RF_GAIN(0x28), 0x00000092 }, \ + { AR5K_AR5210_RF_GAIN(0x29), 0x000000d2 }, \ + { AR5K_AR5210_RF_GAIN(0x2a), 0x0000002b }, \ + { AR5K_AR5210_RF_GAIN(0x2b), 0x0000002a }, \ + { AR5K_AR5210_RF_GAIN(0x2c), 0x0000006a }, \ + { AR5K_AR5210_RF_GAIN(0x2d), 0x000000aa }, \ + { AR5K_AR5210_RF_GAIN(0x2e), 0x0000001b }, \ + { AR5K_AR5210_RF_GAIN(0x2f), 0x0000001a }, \ + { AR5K_AR5210_RF_GAIN(0x30), 0x0000005a }, \ + { AR5K_AR5210_RF_GAIN(0x31), 0x0000009a }, \ + { AR5K_AR5210_RF_GAIN(0x32), 0x000000da }, \ + { AR5K_AR5210_RF_GAIN(0x33), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x34), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x35), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x36), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x37), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x38), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x39), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x3a), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x3b), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x3c), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x3d), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x3e), 0x00000006 }, \ + { AR5K_AR5210_RF_GAIN(0x3f), 0x00000006 }, \ + /* PHY activation */ \ + { AR5K_AR5210_PHY(53), 0x00000020 }, \ + { AR5K_AR5210_PHY(51), 0x00000004 }, \ + { AR5K_AR5210_PHY(50), 0x00060106 }, \ + { AR5K_AR5210_PHY(39), 0x0000006d }, \ + { AR5K_AR5210_PHY(48), 0x00000000 }, \ + { AR5K_AR5210_PHY(52), 0x00000014 }, \ + { AR5K_AR5210_PHY_ACTIVE, AR5K_AR5210_PHY_ENABLE }, \ +} + +#endif /* _AR5K_AR5210_VAR_H */ diff --git a/sys/dev/ic/ar5xxx.c b/sys/dev/ic/ar5xxx.c new file mode 100644 index 00000000000..33b1f834864 --- /dev/null +++ b/sys/dev/ic/ar5xxx.c @@ -0,0 +1,548 @@ +/* $OpenBSD: ar5xxx.c,v 1.1 2004/11/02 03:01:16 reyk Exp $ */ + +/* + * Copyright (c) 2004 Reyk Floeter <reyk@vantronix.net>. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY + * SPECIAL 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. + */ + +/* + * HAL interface for Atheros Wireless LAN devices. + * (Please have a look at ar5k.h for further information) + */ + +#include <dev/pci/pcidevs.h> + +#include <dev/ic/ar5xxx.h> + +#ifdef AR5K_SUPPORT_AR5210 +extern ar5k_attach_t ar5k_ar5210_attach; +#endif + +#ifdef notyet +#ifdef AR5K_SUPPORT_AR5211 +extern ar5k_attach_t ar5k_ar5211_attach; +#endif +#ifdef AR5K_SUPPORT_AR5212 +extern ar5k_attach_t ar5k_ar5212_attach; +#endif +#endif + +static const struct +ieee80211_regchannel ar5k_5ghz_channels[] = IEEE80211_CHANNELS_5GHZ; + +static const struct +ieee80211_regchannel ar5k_2ghz_channels[] = IEEE80211_CHANNELS_2GHZ; + +static const struct { + u_int16_t vendor; + u_int16_t device; + const char * name; + ar5k_attach_t (*attach); +} ar5k_known_products[] = { + /* + * From pcidevs_data.h + */ +#ifdef AR5K_SUPPORT_AR5210 + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210, + "AR5210 Wireless LAN", ar5k_ar5210_attach }, + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210_AP, + "AR5210 Wireless LAN (AP11)", ar5k_ar5210_attach }, + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210_DEFAULT, + "AR5210 Wireless LAN (no eeprom)", ar5k_ar5210_attach }, +#endif +#ifdef notyet +#ifdef AR5K_SUPPORT_AR5211 + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5211, + "AR5211 Wireless LAN", ar5k_ar5211_attach }, + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5211_DEFAULT, + "AR5211 Wireless LAN (no eeprom)", ar5k_ar5211_attach }, + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5311, + "AR5211 Wireless LAN", ar5k_ar5211_attach }, + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5211_FPGA11B, + "AR5211 Wireless LAN Reference Card", ar5k_ar5211_attach }, + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5211_LEGACY, + "AR5211 Wireless LAN Reference Card", ar5k_ar5211_attach }, +#endif +#ifdef AR5K_SUPPORT_AR5212 + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5212, + "AR5212 Wireless LAN", ar5k_ar5212_attach }, + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5212_DEFAULT, + "AR5212 Wireless LAN (no eeprom)", ar5k_ar5212_attach }, + { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5212_FPGA, + "AR5212 Wireless LAN Reference Card", ar5k_ar5212_attach }, +#endif +#endif +}; + +/* + * Perform a lookup if the device is supported by the HAL + */ +const char * +ath_hal_probe(vendor, device) + u_int16_t vendor; + u_int16_t device; +{ + int i; + + /* + * Perform a linear search on the table of supported devices + */ + for(i = 0; i < AR5K_ELEMENTS(ar5k_known_products); i++) { + if(vendor == ar5k_known_products[i].vendor && + device == ar5k_known_products[i].device) + return(ar5k_known_products[i].name); + } + + return(NULL); +} + +/* + * Fills in the HAL structure and initialises the device + */ +struct ath_hal * +ath_hal_attach(device, sc, st, sh, status) + u_int16_t device; + void *sc; + bus_space_tag_t st; + bus_space_handle_t sh; + int *status; +{ + HAL_RATE_TABLE rt_11a = AR5K_RATES_11A; + HAL_RATE_TABLE rt_11b = AR5K_RATES_11B; + HAL_RATE_TABLE rt_11g = AR5K_RATES_11G; + HAL_RATE_TABLE rt_turbo = AR5K_RATES_TURBO; + struct ath_hal *hal = NULL; + ar5k_attach_t *attach; + u_int8_t mac[IEEE80211_ADDR_LEN]; + int i; + + *status = -EINVAL; + + /* + * Call the chipset-dependent attach routine by device id + */ + for(i = 0; i < AR5K_ELEMENTS(ar5k_known_products); i++) { + if(device == ar5k_known_products[i].device && + ar5k_known_products[i].attach != NULL) + attach = ar5k_known_products[i].attach; + } + + if(attach == NULL) { + *status = -ENXIO; + AR5K_PRINTF("device not supported\n"); + return(NULL); + } + + if((hal = malloc(sizeof(struct ath_hal), M_DEVBUF, M_NOWAIT)) == NULL) { + *status = -ENOMEM; + AR5K_PRINTF("out of memory\n"); + return(NULL); + } + + bzero(hal, sizeof(struct ath_hal)); + + hal->ah_sc = sc; + hal->ah_st = st; + hal->ah_sh = sh; + hal->ah_device = device; + hal->ah_sub_vendor = 0; /* XXX unknown?! */ + + /* + * HAL information + */ + hal->ah_abi = HAL_ABI_VERSION; + hal->ah_country_code = CTRY_DEFAULT; + hal->ah_op_mode = HAL_M_STA; + hal->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; + hal->ah_capabilities.cap_eeprom.ee_regdomain = DMN_DEFAULT; + hal->ah_turbo = AH_FALSE; + hal->ah_imr = 0; + hal->ah_atim_window = 0; + hal->ah_aifs = AR5K_TUNE_AIFS; + hal->ah_cw_min = AR5K_TUNE_CWMIN; + hal->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; + hal->ah_software_retry = AH_FALSE; + + if(attach(device, hal, st, sh, status) == NULL) + goto failed; + + /* + * Get card capabilities, values, ... + */ + + if(hal->ah_get_capabilities(hal) != AH_TRUE) { + AR5K_PRINTF("unable to get device capabilities\n"); + goto failed; + } + + if((*status = ar5k_eeprom_read_mac(hal, mac)) != HAL_OK) { + AR5K_PRINTF("unable to read address from EEPROM\n"); + goto failed; + } + + hal->ah_setMacAddress(hal, mac); + + if(hal->ah_capabilities.cap_mode & HAL_MODE_11A) + ar5k_rt_copy(&hal->ah_rt_11a, &rt_11a); + if(hal->ah_capabilities.cap_mode & HAL_MODE_11B) + ar5k_rt_copy(&hal->ah_rt_11b, &rt_11b); + if(hal->ah_capabilities.cap_mode & HAL_MODE_11G) + ar5k_rt_copy(&hal->ah_rt_11g, &rt_11g); + if(hal->ah_capabilities.cap_mode & HAL_MODE_TURBO) + ar5k_rt_copy(&hal->ah_rt_turbo, &rt_turbo); + + *status = HAL_OK; + + return(hal); + + failed: + free(hal, M_DEVBUF); + return(NULL); +} + +u_int16_t +ath_hal_computetxtime(hal, rates, frame_length, rate_index, short_preamble) + struct ath_hal *hal; + const HAL_RATE_TABLE *rates; + u_int32_t frame_length; + u_int16_t rate_index; + HAL_BOOL short_preamble; +{ + HAL_RATE *rate; + u_int32_t value; + + AR5K_ASSERT_ENTRY(rate_index, rates->rateCount); + + /* + * Get rate by index + */ + rate = (HAL_RATE*)&rates->info[rate_index]; + + /* + * Calculate the transmission time by operation (PHY) mode + */ + switch(rate->phy) { + case IEEE80211_T_CCK: + /* + * CCK / DS mode (802.11b) + */ + value = AR5K_CCK_TX_TIME(rate->rateKbps, frame_length, + (short_preamble && rate->shortPreamble)); + break; + + case IEEE80211_T_OFDM: + /* + * Orthogonal Frequency Division Multiplexing + */ + if(AR5K_OFDM_NUM_BITS_PER_SYM(rate->rateKbps) == 0) + return(0); + value = AR5K_OFDM_TX_TIME(rate->rateKbps, frame_length); + break; + + case IEEE80211_T_TURBO: + /* + * Orthogonal Frequency Division Multiplexing + * Atheros "Turbo Mode" (doubled rates) + */ + if(AR5K_TURBO_NUM_BITS_PER_SYM(rate->rateKbps) == 0) + return(0); + value = AR5K_TURBO_TX_TIME(rate->rateKbps, frame_length); + break; + + case IEEE80211_T_XR: + /* + * Orthogonal Frequency Division Multiplexing + * Atheros "eXtended Range" (XR) + */ + if(AR5K_XR_NUM_BITS_PER_SYM(rate->rateKbps) == 0) + return(0); + value = AR5K_XR_TX_TIME(rate->rateKbps, frame_length); + break; + + default: + return(0); + } + + return(value); +} + +u_int +ath_hal_mhz2ieee(mhz, flags) + u_int mhz; + u_int flags; +{ + return(ieee80211_mhz2ieee(mhz, flags)); +} + +u_int +ath_hal_ieee2mhz(ieee, flags) + u_int ieee; + u_int flags; +{ + return(ieee80211_ieee2mhz(ieee, flags)); +} + +HAL_BOOL +ath_hal_init_channels(hal, channels, max_channels, channels_size, country, mode, + outdoor, extended) + struct ath_hal *hal; + HAL_CHANNEL *channels; + u_int max_channels; + u_int *channels_size; + HAL_CTRY_CODE country; + u_int16_t mode; + HAL_BOOL outdoor; + HAL_BOOL extended; +{ + u_int i, c; + u_int32_t domain_current; + u_int domain_5ghz, domain_2ghz; + HAL_CHANNEL all_channels[max_channels]; + + c = 0; + domain_current = hal->ah_getRegDomain(hal); + domain_5ghz = ieee80211_regdomain2flag(domain_current, IEEE80211_CHANNELS_5GHZ_MIN); + domain_2ghz = ieee80211_regdomain2flag(domain_current, IEEE80211_CHANNELS_2GHZ_MIN); + + /* + * Create channel list based on chipset capabilities, regulation domain + * and mode. 5GHz... + */ + for(i = 0; (hal->ah_capabilities.cap_range.range_5ghz_max > 0) && + (i < (sizeof(ar5k_5ghz_channels) / sizeof(ar5k_5ghz_channels[0]))) && + (c < max_channels); i++) { + /* Check if channel is supported by the chipset */ + if((ar5k_5ghz_channels[i].rc_channel < + hal->ah_capabilities.cap_range.range_5ghz_min) || + (ar5k_5ghz_channels[i].rc_channel > + hal->ah_capabilities.cap_range.range_5ghz_max)) + continue; + + /* Match regulation domain */ + if((IEEE80211_DMN(ar5k_5ghz_channels[i].rc_domains) & + IEEE80211_DMN(domain_5ghz)) == 0) + continue; + + /* Match modes */ + if(ar5k_5ghz_channels[i].rc_mode & IEEE80211_CHAN_TURBO) + all_channels[c].channelFlags = CHANNEL_T; + else if(ar5k_5ghz_channels[i].rc_mode & IEEE80211_CHAN_OFDM) + all_channels[c].channelFlags = CHANNEL_A; + else + continue; + + /* Write channel and increment counter */ + all_channels[c++].channel = ar5k_5ghz_channels[i].rc_channel; + } + + /* + * ...and 2GHz. + */ + for(i = 0; (hal->ah_capabilities.cap_range.range_2ghz_max > 0) && + (i < (sizeof(ar5k_2ghz_channels) / sizeof(ar5k_2ghz_channels[0]))) && + (c < max_channels); i++) { + /* Check if channel is supported by the chipset */ + if((ar5k_2ghz_channels[i].rc_channel < + hal->ah_capabilities.cap_range.range_2ghz_min) || + (ar5k_2ghz_channels[i].rc_channel > + hal->ah_capabilities.cap_range.range_2ghz_max)) + continue; + + /* Match regulation domain */ + if((IEEE80211_DMN(ar5k_2ghz_channels[i].rc_domains) & + IEEE80211_DMN(domain_2ghz)) == 0) + continue; + + /* Match modes */ + if(ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_CCK) + all_channels[c].channelFlags = CHANNEL_B; + else if(ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_TURBO) + all_channels[c].channelFlags = CHANNEL_TG; + else if(ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_OFDM) + all_channels[c].channelFlags = CHANNEL_G; + else + continue; + + /* Write channel and increment counter */ + all_channels[c++].channel = ar5k_2ghz_channels[i].rc_channel; + } + + memcpy(channels, &all_channels, sizeof(all_channels)); + *channels_size = c; + + return(AH_TRUE); +} + +/* + * Common internal functions + */ + +void +ar5k_radar_alert(hal) + struct ath_hal *hal; +{ + /* + * Limit ~1/s + */ + if(hal->ah_radar.r_last_channel.channel == + hal->ah_current_channel.channel && + tick < (hal->ah_radar.r_last_alert + hz)) + return; + + hal->ah_radar.r_last_channel.channel = + hal->ah_current_channel.channel; + hal->ah_radar.r_last_channel.channelFlags = + hal->ah_current_channel.channelFlags; + hal->ah_radar.r_last_alert = tick; + + AR5K_PRINTF("Possible radar activity detected at %u MHz (tick %u)\n", + hal->ah_radar.r_last_alert, hal->ah_current_channel.channel); +} + +int +ar5k_eeprom_read_mac(hal, mac) + struct ath_hal *hal; + u_int8_t *mac; +{ + u_int32_t total, offset; + u_int16_t data; + int octet; + u_int8_t mac_d[IEEE80211_ADDR_LEN]; + + bzero(mac, IEEE80211_ADDR_LEN); + bzero(&mac_d, IEEE80211_ADDR_LEN); + + if(hal->ah_eeprom_is_busy(hal)) + return(-EBUSY); + + /* + * XXX Does this work with newer EEPROMs? + */ + if(hal->ah_eeprom_read(hal, 0x20, &data) != 0) + return(-EIO); + + for(offset = 0x1f, octet = 0, total = 0; + offset >= 0x1d; offset--) { + if(hal->ah_eeprom_read(hal, offset, &data) != 0) + return(-EIO); + + total += data; + mac_d[octet + 1] = data & 0xff; + mac_d[octet] = data >> 8; + octet += 2; + } + + memcpy(mac, &mac_d, IEEE80211_ADDR_LEN); + + if((!total) || total == (3 * 0xffff)) + return(-EINVAL); + + return(0); +} + +u_int8_t +ar5k_regdomain_from_ieee(regdomain) + ieee80211_regdomain_t *regdomain; +{ + /* + * XXX Fix + */ + return((u_int8_t)*regdomain); +} + +ieee80211_regdomain_t * +ar5k_regdomain_to_ieee(regdomain) + u_int8_t regdomain; +{ + /* + * XXX Fix + */ + return((ieee80211_regdomain_t*)®domain); +} + +u_int32_t +ar5k_bitswap(val, bits) + u_int32_t val; + u_int bits; +{ + u_int32_t retval = 0, bit, i; + + for (i = 0; i < bits; i++) { + bit = (val >> i) & 1; + retval = (retval << 1) | bit; + } + + return(retval); +} + +u_int +ar5k_htoclock(usec, turbo) + u_int usec; + HAL_BOOL turbo; +{ + return(turbo == AH_TRUE ? (usec * 80) : (usec * 40)); +} + +u_int +ar5k_clocktoh(clock, turbo) + u_int clock; + HAL_BOOL turbo; +{ + return(turbo == AH_TRUE ? (clock / 80) : (clock / 40)); +} + +void +ar5k_rt_copy(dst, src) + HAL_RATE_TABLE *dst; + HAL_RATE_TABLE *src; +{ + memset(dst, 0, sizeof(HAL_RATE_TABLE)); + dst->rateCount = src->rateCount; + memcpy(&dst->info, &src->info, sizeof(dst->info)); +} + +HAL_BOOL +ar5k_register_timeout(hal, reg, flag, val, is_set) + struct ath_hal *hal; + u_int32_t reg; + u_int32_t flag; + u_int32_t val; + HAL_BOOL is_set; +{ + int i; + + for(i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { + if((is_set == AH_TRUE) && (AR5K_REG_READ(reg) & flag)) + break; + else if((AR5K_REG_READ(reg) & flag) == val) + break; + AR5K_DELAY(15); + } + + if(i <= 0) + return(AH_FALSE); + + return(AH_TRUE); +} + + diff --git a/sys/dev/ic/ar5xxx.h b/sys/dev/ic/ar5xxx.h new file mode 100644 index 00000000000..6bc2b2babc7 --- /dev/null +++ b/sys/dev/ic/ar5xxx.h @@ -0,0 +1,962 @@ +/* $OpenBSD: ar5xxx.h,v 1.1 2004/11/02 03:01:16 reyk Exp $ */ + +/* + * Copyright (c) 2004 Reyk Floeter <reyk@vantronix.net>. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY + * SPECIAL 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. + */ + +/* + * HAL interface for Atheros Wireless LAN devices. + * + * ar5k is a free replacement of the binary-only HAL used by some drivers + * for Atheros chipsets. While using a different ABI, it tries to be + * source-compatible with the original (non-free) HAL interface. + * + * Many thanks to various contributors who supported the development of + * ar5k with hard work and useful information. And, of course, for all the + * people who encouraged me to continue this work which has been based + * on my initial approach found on http://team.vantronix.net/ar5k/. + */ + +#ifndef _AR5K_H +#define _AR5K_H + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/errno.h> + +#include <machine/endian.h> +#include <machine/bus.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_arp.h> +#include <net/if_llc.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/if_ether.h> +#endif + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_compat.h> +#include <net80211/ieee80211_regdomain.h> + +/* + * Enable support the first AR5000 chipset (AR5210 + AR5110) + */ +#define AR5K_SUPPORT_AR5210 1 + +/* + * NOTE: support for the newer AR5001+ chipsets has not been finished yet + * and will be included very soon. Work is in progress... + */ +#ifdef notyet +/* + * Enable support for the AR5001 chipset (AR5211 [AR5111] [AR2111]) + */ +#define AR5K_SUPPORT_AR5211 1 + +/* + * Enable support for the AR5002 chipset (AR5210 [AR5110] [AR2112]) + */ +#define AR5K_SUPPORT_AR5212 1 +#endif + +/* + * Generic definitions + */ + +typedef enum { + AH_FALSE = 0, + AH_TRUE, +} HAL_BOOL; + +typedef enum { + HAL_MODE_11A = 0x001, + HAL_MODE_TURBO = 0x002, + HAL_MODE_11B = 0x004, + HAL_MODE_PUREG = 0x008, + HAL_MODE_11G = 0x008, /* 0x010 for dynamic OFDM/CCK */ + HAL_MODE_108G = 0x020, + HAL_MODE_ALL = 0xfff +} HAL_MODE; + +typedef enum { + HAL_M_STA = 1, + HAL_M_IBSS = 0, + HAL_M_HOSTAP = 6, + HAL_M_MONITOR = 8, +} HAL_OPMODE; + +typedef int HAL_STATUS; + +#define HAL_OK 0 +#define HAL_EINPROGRESS -EINPROGRESS + +/* + * TX queues + */ + +typedef enum { + HAL_TX_QUEUE_INACTIVE = 0, + HAL_TX_QUEUE_DATA, + HAL_TX_QUEUE_BEACON, + HAL_TX_QUEUE_CAB, + HAL_TX_QUEUE_PSPOLL, +} HAL_TX_QUEUE; + +#define HAL_NUM_TX_QUEUES 10 + +typedef enum { + HAL_WME_AC_BK = 0, + HAL_WME_AC_BE = 1, + HAL_WME_AC_VI = 2, + HAL_WME_AC_VO = 3, + HAL_WME_UPSD = 4, +} HAL_TX_QUEUE_SUBTYPE; + +#define AR5K_TXQ_FLAG_TXINT_ENABLE 0x0001 +#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0002 +#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0004 +#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0008 +#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0010 +#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0020 + +typedef struct { + u_int32_t tqi_ver; + HAL_TX_QUEUE tqi_type; + HAL_TX_QUEUE_SUBTYPE tqi_subtype; + u_int16_t tqi_flags; + u_int32_t tqi_priority; + u_int32_t tqi_aifs; + int32_t tqi_cw_min; + int32_t tqi_cw_max; + u_int32_t tqi_cbr_period; + u_int32_t tqi_cbr_overflow_limit; + u_int32_t tqi_burst_time; + u_int32_t tqi_ready_time; +} HAL_TXQ_INFO; + +typedef enum { + HAL_PKT_TYPE_NORMAL = 0, + HAL_PKT_TYPE_ATIM, + HAL_PKT_TYPE_PSPOLL, + HAL_PKT_TYPE_BEACON, + HAL_PKT_TYPE_PROBE_RESP, + HAL_PKT_TYPE_PIFS, +} HAL_PKT_TYPE; + +/* + * Used to compute TX times + */ + +#define AR5K_CCK_SIFS_TIME 10 +#define AR5K_CCK_PREAMBLE_BITS 144 +#define AR5K_CCK_PLCP_BITS 48 +#define AR5K_CCK_NUM_BITS(_frmlen) (_frmlen << 3) +#define AR5K_CCK_PHY_TIME(_sp) (_sp ? \ + ((AR5K_CCK_PREAMBLE_BITS + AR5K_CCK_PLCP_BITS) >> 1) : \ + (AR5K_CCK_PREAMBLE_BITS + AR5K_CCK_PLCP_BITS)) +#define AR5K_CCK_TX_TIME(_kbps, _frmlen, _sp) \ + AR5K_CCK_PHY_TIME(_sp) + \ + ((AR5K_CCK_NUM_BITS(_frmlen) * 1000) / _kbps) + \ + AR5K_CCK_SIFS_TIME + +#define AR5K_OFDM_SIFS_TIME 16 +#define AR5K_OFDM_PREAMBLE_TIME 20 +#define AR5K_OFDM_PLCP_BITS 22 +#define AR5K_OFDM_SYMBOL_TIME 4 +#define AR5K_OFDM_NUM_BITS(_frmlen) (AR5K_OFDM_PLCP_BITS + (_frmlen << 3)) +#define AR5K_OFDM_NUM_BITS_PER_SYM(_kbps) ((_kbps * \ + AR5K_OFDM_SYMBOL_TIME) / 1000) +#define AR5K_OFDM_NUM_BITS(_frmlen) (AR5K_OFDM_PLCP_BITS + (_frmlen << 3)) +#define AR5K_OFDM_NUM_SYMBOLS(_kbps, _frmlen) \ + howmany(AR5K_OFDM_NUM_BITS(_frmlen), AR5K_OFDM_NUM_BITS_PER_SYM(_kbps)) +#define AR5K_OFDM_TX_TIME(_kbps, _frmlen) \ + AR5K_OFDM_PREAMBLE_TIME + AR5K_OFDM_SIFS_TIME + \ + (AR5K_OFDM_NUM_SYMBOLS(_kbps, _frmlen) * AR5K_OFDM_SYMBOL_TIME) + +#define AR5K_TURBO_SIFS_TIME 8 +#define AR5K_TURBO_PREAMBLE_TIME 14 +#define AR5K_TURBO_PLCP_BITS 22 +#define AR5K_TURBO_SYMBOL_TIME 4 +#define AR5K_TURBO_NUM_BITS(_frmlen) (AR5K_TURBO_PLCP_BITS + (_frmlen << 3)) +#define AR5K_TURBO_NUM_BITS_PER_SYM(_kbps) (((_kbps << 1) * \ + AR5K_TURBO_SYMBOL_TIME) / 1000) +#define AR5K_TURBO_NUM_BITS(_frmlen) (AR5K_TURBO_PLCP_BITS + (_frmlen << 3)) +#define AR5K_TURBO_NUM_SYMBOLS(_kbps, _frmlen) \ + howmany(AR5K_TURBO_NUM_BITS(_frmlen), \ + AR5K_TURBO_NUM_BITS_PER_SYM(_kbps)) +#define AR5K_TURBO_TX_TIME(_kbps, _frmlen) \ + AR5K_TURBO_PREAMBLE_TIME + AR5K_TURBO_SIFS_TIME + \ + (AR5K_TURBO_NUM_SYMBOLS(_kbps, _frmlen) * AR5K_TURBO_SYMBOL_TIME) + +#define AR5K_XR_SIFS_TIME 16 +#define AR5K_XR_PLCP_BITS 22 +#define AR5K_XR_SYMBOL_TIME 4 +#define AR5K_XR_PREAMBLE_TIME(_kbps) (((_kbps) < 1000) ? 173 : 76) +#define AR5K_XR_NUM_BITS_PER_SYM(_kbps) ((_kbps * \ + AR5K_XR_SYMBOL_TIME) / 1000) +#define AR5K_XR_NUM_BITS(_frmlen) (AR5K_XR_PLCP_BITS + (_frmlen << 3)) +#define AR5K_XR_NUM_SYMBOLS(_kbps, _frmlen) \ + howmany(AR5K_XR_NUM_BITS(_frmlen), AR5K_XR_NUM_BITS_PER_SYM(_kbps)) +#define AR5K_XR_TX_TIME(_kbps, _frmlen) \ + AR5K_XR_PREAMBLE_TIME(_kbps) + AR5K_XR_SIFS_TIME + \ + (AR5K_XR_NUM_SYMBOLS(_kbps, _frmlen) * AR5K_XR_SYMBOL_TIME) + +/* + * RX definitions + */ + +#define HAL_RX_FILTER_UCAST 0x00000001 +#define HAL_RX_FILTER_MCAST 0x00000002 +#define HAL_RX_FILTER_BCAST 0x00000004 +#define HAL_RX_FILTER_CONTROL 0x00000008 +#define HAL_RX_FILTER_BEACON 0x00000010 +#define HAL_RX_FILTER_PROM 0x00000020 +#define HAL_RX_FILTER_PROBEREQ 0x00000080 +#define HAL_RX_FILTER_PHYERR 0x00000100 +#define HAL_RX_FILTER_PHYRADAR 0x00000200 + +typedef struct { + u_int32_t ackrcv_bad; + u_int32_t rts_bad; + u_int32_t rts_good; + u_int32_t fcs_bad; + u_int32_t beacons; +} HAL_MIB_STATS; + +/* + * Beacon/AP definitions + */ + +#define HAL_BEACON_PERIOD 0x0000ffff +#define HAL_BEACON_ENA 0x00800000 +#define HAL_BEACON_RESET_TSF 0x01000000 + +typedef struct { + u_int32_t bs_next_beacon; + u_int32_t bs_next_dtim; + u_int32_t bs_interval; + u_int8_t bs_dtim_period; + u_int8_t bs_cfp_period; + u_int16_t bs_cfp_max_duration; + u_int16_t bs_cfp_du_remain; + u_int16_t bs_tim_offset; + u_int16_t bs_sleep_duration; + u_int16_t bs_bmiss_threshold; + +#define bs_nexttbtt bs_next_beacon +#define bs_intval bs_interval +#define bs_nextdtim bs_next_dtim +#define bs_bmissthreshold bs_bmiss_threshold +#define bs_sleepduration bs_sleep_duration +#define bs_dtimperiod bs_dtim_period + +} HAL_BEACON_STATE; + +/* + * Power management + */ + +typedef enum { + HAL_PM_UNDEFINED = 0, + HAL_PM_AUTO, + HAL_PM_AWAKE, + HAL_PM_FULL_SLEEP, + HAL_PM_NETWORK_SLEEP, +} HAL_POWER_MODE; + +/* + * Weak wireless crypto definitions (use IPsec/WLSec/...) + */ + +typedef enum { + HAL_CIPHER_WEP = 0, + HAL_CIPHER_AES_CCM, + HAL_CIPHER_CKIP, +} HAL_CIPHER; + +#define AR5K_MAX_KEYS 16 + +typedef struct { + int wk_len; + u_int8_t wk_key[AR5K_MAX_KEYS]; +} HAL_KEYVAL; + +#define AR5K_ASSERT_ENTRY(_e, _s) do { \ + if(_e >= _s) \ + return(AH_FALSE); \ +} while(0) + +/* + * PHY + */ + +#define AR5K_MAX_RATES 32 + +typedef struct { + u_int8_t valid; + u_int8_t phy; + u_int16_t rateKbps; + u_int8_t rateCode; + u_int8_t shortPreamble; + u_int8_t dot11Rate; + u_int8_t controlRate; + +#define r_valid valid +#define r_phy phy +#define r_rate_kbps rateKbps +#define r_short_preamble short_preamble +#define r_dot11_rate dot11Rate +#define r_control_rate controlRate + +} HAL_RATE; + +typedef struct { + u_int16_t rateCount; + u_int8_t rateCodeToIndex[AR5K_MAX_RATES]; + HAL_RATE info[AR5K_MAX_RATES]; + +#define rt_rate_count rateCount +#define rt_rate_code_index rateCodeToIndex +#define rt_info info + +} HAL_RATE_TABLE; + +#define AR5K_RATES_11A { 8, { 0 }, { \ + { 1, IEEE80211_T_OFDM, 6000, 11, 0, 140, 0 }, \ + { 1, IEEE80211_T_OFDM, 9000, 15, 0, 18, 0 }, \ + { 1, IEEE80211_T_OFDM, 12000, 10, 0, 152, 2 }, \ + { 1, IEEE80211_T_OFDM, 18000, 14, 0, 36, 2 }, \ + { 1, IEEE80211_T_OFDM, 24000, 9, 0, 176, 4 }, \ + { 1, IEEE80211_T_OFDM, 36000, 13, 0, 72, 4 }, \ + { 1, IEEE80211_T_OFDM, 48000, 8, 0, 96, 4 }, \ + { 1, IEEE80211_T_OFDM, 54000, 12, 0, 108, 4 } } \ +} + +#define AR5K_RATES_TURBO { 8, { 0 }, { \ + { 1, IEEE80211_T_TURBO, 6000, 11, 0, 140, 0 }, \ + { 1, IEEE80211_T_TURBO, 9000, 15, 0, 18, 0 }, \ + { 1, IEEE80211_T_TURBO, 12000, 10, 0, 152, 2 }, \ + { 1, IEEE80211_T_TURBO, 18000, 14, 0, 36, 2 }, \ + { 1, IEEE80211_T_TURBO, 24000, 9, 0, 176, 4 }, \ + { 1, IEEE80211_T_TURBO, 36000, 13, 0, 72, 4 }, \ + { 1, IEEE80211_T_TURBO, 48000, 8, 0, 96, 4 }, \ + { 1, IEEE80211_T_TURBO, 54000, 12, 0, 108, 4 } } \ +} + +/* XXX TODO: 2GHz rates for 11b/11g */ +#define AR5K_RATES_11B { 0, } +#define AR5K_RATES_11G { 0, } + +typedef enum { + HAL_RFGAIN_INACTIVE = 0, + HAL_RFGAIN_READ_REQUESTED, + HAL_RFGAIN_NEED_CHANGE, +} HAL_RFGAIN; + +typedef struct { + u_int16_t channel; /* MHz */ + u_int16_t channelFlags; + +#define c_channel channel +#define c_channel_flags cnannelFlags + +} HAL_CHANNEL; + +#define HAL_SLOT_TIME_9 9 +#define HAL_SLOT_TIME_20 20 +#define HAL_SLOT_TIME_MAX ar5k_clocktoh(0xffff, hal->ah_turbo) + +#define CHANNEL_A (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) +#define CHANNEL_B (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) +#define CHANNEL_G (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) /* _DYN */ +#define CHANNEL_PUREG (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) +#define CHANNEL_T (CHANNEL_A | IEEE80211_CHAN_TURBO) +#define CHANNEL_TG (CHANNEL_PUREG | IEEE80211_CHAN_TURBO) +#define CHANNEL_XR (CHANNEL_A | IEEE80211_CHAN_XR) + +/* + * Regulation stuff + */ + +typedef enum ieee80211_countrycode HAL_CTRY_CODE; + +/* + * HAL interrupt abstraction + */ + +#define HAL_INT_RX 0x00000001 +#define HAL_INT_RXDESC 0x00000002 +#define HAL_INT_RXNOFRM 0x00000008 +#define HAL_INT_RXEOL 0x00000010 +#define HAL_INT_RXORN 0x00000020 +#define HAL_INT_TX 0x00000040 +#define HAL_INT_TXDESC 0x00000080 +#define HAL_INT_TXURN 0x00000800 +#define HAL_INT_MIB 0x00001000 +#define HAL_INT_RXPHY 0x00004000 +#define HAL_INT_RXKCM 0x00008000 +#define HAL_INT_SWBA 0x00010000 +#define HAL_INT_BMISS 0x00040000 +#define HAL_INT_BNR 0x00100000 +#define HAL_INT_GPIO 0x01000000 +#define HAL_INT_FATAL 0x40000000 +#define HAL_INT_GLOBAL 0x80000000 +#define HAL_INT_NOCARD 0xffffffff +#define HAL_INT_COMMON ( \ + HAL_INT_RXNOFRM | HAL_INT_RXDESC | HAL_INT_RXEOL | \ + HAL_INT_RXORN | HAL_INT_TXURN | HAL_INT_TXDESC | \ + HAL_INT_MIB | HAL_INT_RXPHY | HAL_INT_RXKCM | \ + HAL_INT_SWBA | HAL_INT_BMISS | HAL_INT_GPIO \ +) + +typedef u_int32_t HAL_INT; + +/* + * LED states + */ + +typedef enum ieee80211_state HAL_LED_STATE; + +#define HAL_LED_INIT IEEE80211_S_INIT +#define HAL_LED_SCAN IEEE80211_S_SCAN +#define HAL_LED_AUTH IEEE80211_S_AUTH +#define HAL_LED_ASSOC IEEE80211_S_ASSOC +#define HAL_LED_RUN IEEE80211_S_RUN + +/* + * Chipset capabilities + */ + +typedef struct { + /* + * Supported PHY modes + * (ie. IEEE80211_CHAN_A, IEEE80211_CHAN_B, ...) + */ + u_int16_t cap_mode; + + /* + * Frequency range (without regulation restrictions) + */ + struct { + u_int16_t range_2ghz_min; + u_int16_t range_2ghz_max; + u_int16_t range_5ghz_min; + u_int16_t range_5ghz_max; + } cap_range; + + /* + * Active regulation domain settings + */ + struct { + ieee80211_regdomain_t reg_current; + ieee80211_regdomain_t reg_hw; + } cap_regdomain; + + /* + * Values stored in the EEPROM (some of them...) + */ + struct { + u_int16_t ee_magic; + u_int16_t ee_antenna; + u_int16_t ee_protect; + u_int16_t ee_regdomain; + u_int8_t ee_rfkill; + u_int16_t ee_version; + } cap_eeprom; + + /* + * Queue information + */ + struct { + u_int8_t q_tx_num; + } cap_queues; +} ar5k_capabilities_t; + +/* + * Atheros descriptor definitions + */ + +struct ath_tx_status { + u_int16_t ts_seqnum; + u_int16_t ts_tstamp; + u_int8_t ts_status; + u_int8_t ts_rate; + int8_t ts_rssi; + u_int8_t ts_shortretry; + u_int8_t ts_longretry; + u_int8_t ts_virtcol; + u_int8_t ts_antenna; +}; + +#define HAL_TXSTAT_ALTRATE 0x80 +#define HAL_TXERR_XRETRY 0x01 +#define HAL_TXERR_FILT 0x02 +#define HAL_TXERR_FIFO 0x04 + +struct ath_rx_status { + u_int16_t rs_datalen; + u_int16_t rs_tstamp; + u_int8_t rs_status; + u_int8_t rs_phyerr; + int8_t rs_rssi; + u_int8_t rs_keyix; + u_int8_t rs_rate; + u_int8_t rs_antenna; + u_int8_t rs_more; +}; + +#define HAL_RXERR_CRC 0x01 +#define HAL_RXERR_PHY 0x02 +#define HAL_RXERR_FIFO 0x04 +#define HAL_RXERR_DECRYPT 0x08 +#define HAL_RXERR_MIC 0x10 +#define HAL_RXKEYIX_INVALID ((u_int8_t) - 1) +#define HAL_TXKEYIX_INVALID ((u_int32_t) - 1) + +#define HAL_PHYERR_UNDERRUN 0x00 +#define HAL_PHYERR_TIMING 0x01 +#define HAL_PHYERR_PARITY 0x02 +#define HAL_PHYERR_RATE 0x03 +#define HAL_PHYERR_LENGTH 0x04 +#define HAL_PHYERR_RADAR 0x05 +#define HAL_PHYERR_SERVICE 0x06 +#define HAL_PHYERR_TOR 0x07 +#define HAL_PHYERR_OFDM_TIMING 0x11 +#define HAL_PHYERR_OFDM_SIGNAL_PARITY 0x12 +#define HAL_PHYERR_OFDM_RATE_ILLEGAL 0x13 +#define HAL_PHYERR_OFDM_LENGTH_ILLEGAL 0x14 +#define HAL_PHYERR_OFDM_POWER_DROP 0x15 +#define HAL_PHYERR_OFDM_SERVICE 0x16 +#define HAL_PHYERR_OFDM_RESTART 0x17 +#define HAL_PHYERR_CCK_TIMING 0x19 +#define HAL_PHYERR_CCK_HEADER_CRC 0x1a +#define HAL_PHYERR_CCK_RATE_ILLEGAL 0x1b +#define HAL_PHYERR_CCK_SERVICE 0x1e +#define HAL_PHYERR_CCK_RESTART 0x1f + +struct ath_desc { + u_int32_t ds_link; + u_int32_t ds_data; + u_int32_t ds_ctl0; + u_int32_t ds_ctl1; + u_int32_t ds_hw[4]; + + union { + struct ath_rx_status rx; + struct ath_tx_status tx; + } ds_us; + +#define ds_rxstat ds_us.rx +#define ds_txstat ds_us.tx + +} __attribute__((__packed__)); + +#define HAL_RXDESC_INTREQ 0x0020 + +#define HAL_TXDESC_CLRDMASK 0x0001 +#define HAL_TXDESC_NOACK 0x0002 +#define HAL_TXDESC_RTSENA 0x0004 +#define HAL_TXDESC_CTSENA 0x0008 +#define HAL_TXDESC_INTREQ 0x0010 +#define HAL_TXDESC_VEOL 0x0020 + +/* + * Hardware abstraction layer structure + */ + +#define AR5K_HAL_FUNCTION(_hal, _n, _f) (_hal)->ah_##_f = ar5k_##_n##_##_f +#define AR5K_HAL_FUNCTIONS(_t, _n, _a) \ + _t const HAL_RATE_TABLE *(_a ##_n##_getRateTable)(struct ath_hal *, u_int mode); \ + _t void (_a ##_n##_detach)(struct ath_hal *); \ + /* Reset functions */ \ + _t HAL_BOOL (_a ##_n##_reset)(struct ath_hal *, HAL_OPMODE, HAL_CHANNEL *, \ + HAL_BOOL change_channel, HAL_STATUS *status); \ + _t void (_a ##_n##_setPCUConfig)(struct ath_hal *); \ + _t HAL_BOOL (_a ##_n##_perCalibration)(struct ath_hal*, HAL_CHANNEL *); \ + /* Transmit functions */ \ + _t HAL_BOOL (_a ##_n##_updateTxTrigLevel)(struct ath_hal*, HAL_BOOL level); \ + _t int (_a ##_n##_setupTxQueue)(struct ath_hal *, HAL_TX_QUEUE, \ + const HAL_TXQ_INFO *); \ + _t HAL_BOOL (_a ##_n##_setTxQueueProps)(struct ath_hal *, int queue, \ + const HAL_TXQ_INFO *); \ + _t HAL_BOOL (_a ##_n##_releaseTxQueue)(struct ath_hal *, u_int queue); \ + _t HAL_BOOL (_a ##_n##_resetTxQueue)(struct ath_hal *, u_int queue); \ + _t u_int32_t (_a ##_n##_getTxDP)(struct ath_hal *, u_int queue); \ + _t HAL_BOOL (_a ##_n##_setTxDP)(struct ath_hal *, u_int, u_int32_t phys_addr); \ + _t HAL_BOOL (_a ##_n##_startTxDma)(struct ath_hal *, u_int queue); \ + _t HAL_BOOL (_a ##_n##_stopTxDma)(struct ath_hal *, u_int queue); \ + _t HAL_BOOL (_a ##_n##_setupTxDesc)(struct ath_hal *, struct ath_desc *, \ + u_int packet_length, u_int header_length, HAL_PKT_TYPE type, \ + u_int txPower, u_int tx_rate0, u_int tx_tries0, u_int key_index, \ + u_int antenna_mode, u_int flags, u_int rtscts_rate, \ + u_int rtscts_duration); \ + _t HAL_BOOL (_a ##_n##_setupXTxDesc)(struct ath_hal *, struct ath_desc *, \ + u_int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, \ + u_int tx_rate3, u_int tx_tries3); \ + _t HAL_BOOL (_a ##_n##_fillTxDesc)(struct ath_hal *, struct ath_desc *, \ + u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg); \ + _t HAL_STATUS (_a ##_n##_procTxDesc)(struct ath_hal *, struct ath_desc *); \ + _t HAL_BOOL (_a ##_n##_hasVEOL)(struct ath_hal *); \ + /* Receive Functions */ \ + _t u_int32_t (_a ##_n##_getRxDP)(struct ath_hal*); \ + _t void (_a ##_n##_setRxDP)(struct ath_hal*, u_int32_t rxdp); \ + _t void (_a ##_n##_enableReceive)(struct ath_hal*); \ + _t HAL_BOOL (_a ##_n##_stopDmaReceive)(struct ath_hal*); \ + _t void (_a ##_n##_startPcuReceive)(struct ath_hal*); \ + _t void (_a ##_n##_stopPcuReceive)(struct ath_hal*); \ + _t void (_a ##_n##_setMulticastFilter)(struct ath_hal*, u_int32_t filter0, \ + u_int32_t filter1); \ + _t HAL_BOOL (_a ##_n##_setMulticastFilterIndex)(struct ath_hal*, u_int32_t index); \ + _t HAL_BOOL (_a ##_n##_clrMulticastFilterIndex)(struct ath_hal*, u_int32_t index); \ + _t u_int32_t (_a ##_n##_getRxFilter)(struct ath_hal*); \ + _t void (_a ##_n##_setRxFilter)(struct ath_hal*, u_int32_t); \ + _t HAL_BOOL (_a ##_n##_setupRxDesc)(struct ath_hal *, struct ath_desc *, \ + u_int32_t size, u_int flags); \ + _t HAL_STATUS (_a ##_n##_procRxDesc)(struct ath_hal *, struct ath_desc *, \ + u_int32_t phyAddr, struct ath_desc *next); \ + _t void (_a ##_n##_rxMonitor)(struct ath_hal *); \ + /* Misc Functions */ \ + _t void (_a ##_n##_dumpState)(struct ath_hal *); \ + _t HAL_BOOL (_a ##_n##_getDiagState)(struct ath_hal *, int, void **, u_int *); \ + _t void (_a ##_n##_getMacAddress)(struct ath_hal *, u_int8_t *); \ + _t HAL_BOOL (_a ##_n##_setMacAddress)(struct ath_hal *, const u_int8_t*); \ + _t HAL_BOOL (_a ##_n##_setRegulatoryDomain)(struct ath_hal*, u_int16_t, HAL_STATUS *); \ + _t void (_a ##_n##_setLedState)(struct ath_hal*, HAL_LED_STATE); \ + _t void (_a ##_n##_writeAssocid)(struct ath_hal*, const u_int8_t *bssid, \ + u_int16_t assocId, u_int16_t timOffset); \ + _t HAL_BOOL (_a ##_n##_gpioCfgOutput)(struct ath_hal *, u_int32_t gpio); \ + _t HAL_BOOL (_a ##_n##_gpioCfgInput)(struct ath_hal *, u_int32_t gpio); \ + _t u_int32_t (_a ##_n##_gpioGet)(struct ath_hal *, u_int32_t gpio); \ + _t HAL_BOOL (_a ##_n##_gpioSet)(struct ath_hal *, u_int32_t gpio, u_int32_t val); \ + _t void (_a ##_n##_gpioSetIntr)(struct ath_hal*, u_int, u_int32_t); \ + _t u_int32_t (_a ##_n##_getTsf32)(struct ath_hal*); \ + _t u_int64_t (_a ##_n##_getTsf64)(struct ath_hal*); \ + _t void (_a ##_n##_resetTsf)(struct ath_hal*); \ + _t u_int16_t (_a ##_n##_getRegDomain)(struct ath_hal*); \ + _t HAL_BOOL (_a ##_n##_detectCardPresent)(struct ath_hal*); \ + _t void (_a ##_n##_updateMibCounters)(struct ath_hal*, HAL_MIB_STATS*); \ + _t HAL_BOOL (_a ##_n##_isHwCipherSupported)(struct ath_hal*, HAL_CIPHER); \ + _t HAL_RFGAIN (_a ##_n##_getRfGain)(struct ath_hal*); \ + /* \ + u_int32_t (_a ##_n##_getCurRssi)(struct ath_hal*); \ + u_int32_t (_a ##_n##_getDefAntenna)(struct ath_hal*); \ + void (_a ##_n##_setDefAntenna)(struct ath_hal*, u_int32_t ant); \ + */ \ + _t HAL_BOOL (_a ##_n##_setSlotTime)(struct ath_hal*, u_int); \ + _t u_int (_a ##_n##_getSlotTime)(struct ath_hal*); \ + _t HAL_BOOL (_a ##_n##_setAckTimeout)(struct ath_hal *, u_int); \ + _t u_int (_a ##_n##_getAckTimeout)(struct ath_hal*); \ + _t HAL_BOOL (_a ##_n##_setCTSTimeout)(struct ath_hal*, u_int); \ + _t u_int (_a ##_n##_getCTSTimeout)(struct ath_hal*); \ + /* Key Cache Functions */ \ + _t u_int32_t (_a ##_n##_getKeyCacheSize)(struct ath_hal*); \ + _t HAL_BOOL (_a ##_n##_resetKeyCacheEntry)(struct ath_hal*, u_int16_t); \ + _t HAL_BOOL (_a ##_n##_isKeyCacheEntryValid)(struct ath_hal *,u_int16_t); \ + _t HAL_BOOL (_a ##_n##_setKeyCacheEntry)(struct ath_hal*, u_int16_t, \ + const HAL_KEYVAL *, const u_int8_t *, int); \ + _t HAL_BOOL (_a ##_n##_setKeyCacheEntryMac)(struct ath_hal*, u_int16_t, \ + const u_int8_t *); \ + /* Power Management Functions */ \ + _t HAL_BOOL (_a ##_n##_setPowerMode)(struct ath_hal*, HAL_POWER_MODE mode, \ + int setChip, u_int16_t sleepDuration); \ + _t HAL_POWER_MODE (_a ##_n##_getPowerMode)(struct ath_hal*); \ + _t HAL_BOOL (_a ##_n##_queryPSPollSupport)(struct ath_hal*); \ + _t HAL_BOOL (_a ##_n##_initPSPoll)(struct ath_hal*); \ + _t HAL_BOOL (_a ##_n##_enablePSPoll)(struct ath_hal *, u_int8_t *, u_int16_t); \ + _t HAL_BOOL (_a ##_n##_disablePSPoll)(struct ath_hal *); \ + /* Beacon Management Functions */ \ + _t void (_a ##_n##_beaconInit)(struct ath_hal *, u_int32_t nexttbtt, \ + u_int32_t intval); \ + _t void (_a ##_n##_setStationBeaconTimers)(struct ath_hal *, \ + const HAL_BEACON_STATE *, u_int32_t tsf, u_int32_t dtimCount, \ + u_int32_t cfpCcount); \ + _t void (_a ##_n##_resetStationBeaconTimers)(struct ath_hal *); \ + _t HAL_BOOL (_a ##_n##_waitForBeaconDone)(struct ath_hal *, bus_addr_t); \ + /* Interrupt functions */ \ + _t HAL_BOOL (_a ##_n##_isInterruptPending)(struct ath_hal *); \ + _t HAL_BOOL (_a ##_n##_getPendingInterrupts)(struct ath_hal *, u_int32_t *); \ + _t u_int32_t (_a ##_n##_getInterrupts)(struct ath_hal *); \ + _t HAL_INT (_a ##_n##_setInterrupts)(struct ath_hal *, HAL_INT); \ + /* Chipset functions (ar5k-specific, non-HAL) */ \ + _t HAL_BOOL (_a ##_n##_get_capabilities)(struct ath_hal *); \ + _t void (_a ##_n##_radar_alert)(struct ath_hal *, HAL_BOOL enable); \ + _t HAL_BOOL (_a ##_n##_regulation_domain)(struct ath_hal *, HAL_BOOL read, \ + ieee80211_regdomain_t *); \ + _t int (_a ##_n##_eeprom_init)(struct ath_hal *); \ + _t HAL_BOOL (_a ##_n##_eeprom_is_busy)(struct ath_hal *); \ + _t int (_a ##_n##_eeprom_read)(struct ath_hal *, u_int32_t offset, \ + u_int16_t *data); \ + _t int (_a ##_n##_eeprom_write)(struct ath_hal *, u_int32_t offset, \ + u_int16_t data); + +#define AR5K_MAX_GPIO 10 + +struct ath_hal { + u_int32_t ah_magic; + u_int32_t ah_abi; + u_int16_t ah_device; + u_int16_t ah_sub_vendor; + + void *ah_sc; + bus_space_tag_t ah_st; + bus_space_handle_t ah_sh; + + HAL_INT ah_imr; + + HAL_CTRY_CODE ah_country_code; + HAL_OPMODE ah_op_mode; + HAL_POWER_MODE ah_power_mode; + HAL_CHANNEL ah_current_channel; + HAL_BOOL ah_turbo; + +#define ah_countryCode ah_country_code + + HAL_RATE_TABLE ah_rt_11a; + HAL_RATE_TABLE ah_rt_11b; + HAL_RATE_TABLE ah_rt_11g; + HAL_RATE_TABLE ah_rt_turbo; + + u_int32_t ah_mac_version; + u_int16_t ah_mac_revision; + u_int16_t ah_phy_revision; + u_int16_t ah_radio_5ghz_revision; + u_int16_t ah_radio_2ghz_revision; + +#define ah_macVersion ah_mac_version +#define ah_macRev ah_mac_revision +#define ah_phyRev ah_phy_revision +#define ah_analog5GhzRev ah_radio_5ghz_revision +#define ah_analog2GhzRev ah_radio_2ghz_revision +#define ah_regdomain ah_capabilities.cap_eeprom.ee_regdomain + + u_int32_t ah_atim_window; + u_int32_t ah_aifs; + u_int32_t ah_cw_min; + HAL_BOOL ah_software_retry; + u_int32_t ah_limit_tx_retries; + + u_int8_t ah_sta_id[IEEE80211_ADDR_LEN]; + u_int8_t ah_bssid[IEEE80211_ADDR_LEN]; + + u_int32_t ah_gpio[AR5K_MAX_GPIO]; + + ar5k_capabilities_t ah_capabilities; + + HAL_TXQ_INFO ah_txq[HAL_NUM_TX_QUEUES]; + + struct { + HAL_BOOL r_enabled; + int r_last_alert; + HAL_CHANNEL r_last_channel; + } ah_radar; + + /* + * Function pointers + */ + AR5K_HAL_FUNCTIONS(, ah, *); +}; + +/* + * Misc defines + */ + +#define HAL_ABI_VERSION 0x04090901 /* YYMMDDnn */ + +#define AR5K_PRINTF(_x, ...) printf(__func__ ": " _x) +#define AR5K_TRACE printf("%s:%d\n", __func__, __LINE__) +#define AR5K_DELAY(_n) delay(_n) + +#define AR5K_ELEMENTS(_array) (sizeof(_array) / sizeof(_array[0])) + +typedef struct ath_hal*(ar5k_attach_t) + (u_int16_t, void *, bus_space_tag_t, bus_space_handle_t, HAL_STATUS *); + +/* + * Some tuneable values (these should be changeable by the user) + */ + +#define AR5K_TUNE_DMA_BEACON_RESP 2 +#define AR5K_TUNE_SW_BEACON_RESP 10 +#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 +#define AR5K_TUNE_RADAR_ALERT AH_FALSE +#define AR5K_TUNE_MIN_TX_FIFO_THRES 1 +#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_LEN / 64) + 1) +#define AR5K_TUNE_RSSI_THRES 1792 +#define AR5K_TUNE_REGISTER_TIMEOUT 20000 +#define AR5K_TUNE_REGISTER_DWELL_TIME 20000 +#define AR5K_TUNE_BEACON_INTERVAL 100 +#define AR5K_TUNE_AIFS 2 +#define AR5K_TUNE_CWMIN 15 + +/* + * Common initial register values + */ + +#define AR5K_INIT_TX_LATENCY 502 +#define AR5K_INIT_USEC 39 +#define AR5K_INIT_USEC_TURBO 79 +#define AR5K_INIT_USEC_32 31 +#define AR5K_INIT_CARR_SENSE_EN 1 +#define AR5K_INIT_PROG_IFS 920 +#define AR5K_INIT_PROG_IFS_TURBO 960 +#define AR5K_INIT_EIFS 3440 +#define AR5K_INIT_EIFS_TURBO 6880 +#define AR5K_INIT_SLOT_TIME 360 +#define AR5K_INIT_SLOT_TIME_TURBO 480 +#define AR5K_INIT_ACK_CTS_TIMEOUT 1024 +#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800 +#define AR5K_INIT_SIFS 560 +#define AR5K_INIT_SIFS_TURBO 480 +#define AR5K_INIT_SH_RETRY 10 +#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY +#define AR5K_INIT_SSH_RETRY 32 +#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY +#define AR5K_INIT_TX_RETRY 10 +#define AR5K_INIT_TOPS 8 +#define AR5K_INIT_RXNOFRM 8 +#define AR5K_INIT_RPGTO 0 +#define AR5K_INIT_TXNOFRM 0 +#define AR5K_INIT_BEACON_PERIOD 65535 +#define AR5K_INIT_TIM_OFFSET 0 +#define AR5K_INIT_BEACON_EN 0 +#define AR5K_INIT_RESET_TSF 0 +#define AR5K_INIT_TRANSMIT_LATENCY ( \ + (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ + (AR5K_INIT_USEC) \ +) +#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \ + (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ + (AR5K_INIT_USEC_TURBO) \ +) +#define AR5K_INIT_PROTO_TIME_CNTRL ( \ + (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \ + (AR5K_INIT_PROG_IFS) \ +) +#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \ + (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) |\ + (AR5K_INIT_PROG_IFS_TURBO) \ +) +#define AR5K_INIT_BEACON_CONTROL ( \ + (AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) | \ + (AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD) \ +) + +/* + * AR5k register access + */ + +#define AR5K_REG_WRITE(_reg, _val) \ + bus_space_write_4(hal->ah_st, hal->ah_sh, (_reg), (_val)) +#define AR5K_REG_READ(_reg) \ + ((u_int32_t)bus_space_read_4(hal->ah_st, hal->ah_sh, (_reg))) + +#define AR5K_REG_SM(_val, _flags) \ + (((_val) << _flags##_S) & (_flags)) +#define AR5K_REG_MS(_val, _flags) \ + (((_val) & (_flags)) >> _flags##_S) +#define AR5K_REG_WRITE_BITS(_reg, _flags, _val) \ + AR5K_REG_WRITE(_reg, (AR5K_REG_READ(_reg) &~ (_flags)) | \ + (((_val) << _flags##_S) & (_flags))) +#define AR5K_REG_ENABLE_BITS(_reg, _flags) \ + AR5K_REG_WRITE(_reg, AR5K_REG_READ(_reg) | (_flags)) +#define AR5K_REG_DISABLE_BITS(_reg, _flags) \ + AR5K_REG_WRITE(_reg, AR5K_REG_READ(_reg) &~ (_flags)) + +/* + * Initial register values + */ + +struct ar5k_ini { + u_int32_t ini_register; + u_int32_t ini_value; + + enum { + INI_WRITE = 0, + INI_READ = 1, + } ini_mode; +}; + +/* + * Unaligned little endian access + */ + +#define AR5K_LE_READ_2(_p) \ + (((u_int8_t *)(_p))[0] | (((u_int8_t *)(_p))[1] << 8)) +#define AR5K_LE_READ_4(_p) \ + (((u_int8_t *)(_p))[0] | (((u_int8_t *)(_p))[1] << 8) | \ + (((u_int8_t *)(_p))[2] << 16) | (((u_int8_t *)(_p))[3] << 24)) +#define AR5K_LE_WRITE_2(_p, _val) \ + ((((u_int8_t *)(_p))[0] = ((u_int32_t)(_val) & 0xff)), \ + (((u_int8_t *)(_p))[1] = (((u_int32_t)(_val) >> 8) & 0xff))) +#define AR5K_LE_WRITE_4(_p, _val) \ + ((((u_int8_t *)(_p))[0] = ((u_int32_t)(_val) & 0xff)), \ + (((u_int8_t *)(_p))[1] = (((u_int32_t)(_val) >> 8) & 0xff)), \ + (((u_int8_t *)(_p))[2] = (((u_int32_t)(_val) >> 16) & 0xff)), \ + (((u_int8_t *)(_p))[3] = (((u_int32_t)(_val) >> 24) & 0xff))) + +/* + * Prototypes + */ + +__BEGIN_DECLS + +const char *ath_hal_probe(u_int16_t, u_int16_t); + +struct ath_hal *ath_hal_attach(u_int16_t, void *, bus_space_tag_t, + bus_space_handle_t, HAL_STATUS *); + +u_int16_t ath_hal_computetxtime(struct ath_hal *, + const HAL_RATE_TABLE *, u_int32_t, u_int16_t, HAL_BOOL); + +u_int ath_hal_mhz2ieee(u_int, u_int); +u_int ath_hal_ieee2mhz(u_int, u_int); + +HAL_BOOL ath_hal_init_channels(struct ath_hal *, HAL_CHANNEL *, + u_int, u_int *, HAL_CTRY_CODE, u_int16_t, HAL_BOOL, HAL_BOOL); + +void ar5k_radar_alert(struct ath_hal *); +int ar5k_eeprom_read_mac(struct ath_hal *, u_int8_t *); +ieee80211_regdomain_t *ar5k_regdomain_to_ieee(u_int8_t); +u_int8_t ar5k_regdomain_from_ieee(ieee80211_regdomain_t *); +u_int32_t ar5k_bitswap(u_int32_t, u_int); +u_int ar5k_clocktoh(u_int, HAL_BOOL); +u_int ar5k_htoclock(u_int, HAL_BOOL); +void ar5k_rt_copy(HAL_RATE_TABLE *, HAL_RATE_TABLE *); + +HAL_BOOL ar5k_register_timeout(struct ath_hal *, u_int32_t, + u_int32_t, u_int32_t, HAL_BOOL); + +__END_DECLS + +#endif /* _AR5K_H */ |