summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2004-11-02 03:01:17 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2004-11-02 03:01:17 +0000
commit6f310ee239544802e42e2a984bac432479b1a8ba (patch)
tree358dd508a47f8cb4c1cef09b798a9236c1cb6c3c /sys/dev/ic
parent811904472e873a7a84e99ef1b66849f83cbc0f3b (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/ic')
-rw-r--r--sys/dev/ic/ar5210.c2514
-rw-r--r--sys/dev/ic/ar5210reg.h687
-rw-r--r--sys/dev/ic/ar5210var.h440
-rw-r--r--sys/dev/ic/ar5xxx.c548
-rw-r--r--sys/dev/ic/ar5xxx.h962
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*)&regdomain);
+}
+
+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 */