Project : madwifi
Revision : 2232
Author : mickflemm (Nick Kossifidis)
Date : 2007-03-27 19:29:30 +0200 (Tue, 27 Mar 2007)
Log Message :
* Merge code and headers as a first step to a HAL-less driver
* This contains code for 5211/5212, only tested on 5212
* Needs cleanup/testing and some fixes before merging it with dadwifi (to
become ath5k)
* 5210 code is more tricky to include
* All functions except descriptor-related (hw descriptors are different for
each chipset) can work directly, i only left the function pointers there for
combatibility.
* Check TODOs
Affected Files:
* branches/madwifi-old-openhal/openhal/Makefile updated
* branches/madwifi-old-openhal/openhal/README updated
* branches/madwifi-old-openhal/openhal/ah.h updated
* branches/madwifi-old-openhal/openhal/ah_osdep.c updated
* branches/madwifi-old-openhal/openhal/ah_osdep.h updated
* branches/madwifi-old-openhal/openhal/ar5210.c deleted
* branches/madwifi-old-openhal/openhal/ar5210reg.h deleted
* branches/madwifi-old-openhal/openhal/ar5210var.h deleted
* branches/madwifi-old-openhal/openhal/ar5211.c deleted
* branches/madwifi-old-openhal/openhal/ar5211reg.h deleted
* branches/madwifi-old-openhal/openhal/ar5211var.h deleted
* branches/madwifi-old-openhal/openhal/ar5212.c deleted
* branches/madwifi-old-openhal/openhal/ar5212reg.h deleted
* branches/madwifi-old-openhal/openhal/ar5212var.h deleted
* branches/madwifi-old-openhal/openhal/ar5xxx.c deleted
* branches/madwifi-old-openhal/openhal/ar5xxx.h deleted
* branches/madwifi-old-openhal/openhal/ath5k.h added
* branches/madwifi-old-openhal/openhal/ath5k_hw.c added
* branches/madwifi-old-openhal/openhal/ath5k_hw.h added
* branches/madwifi-old-openhal/openhal/ath5kreg.h added
* branches/madwifi-old-openhal/openhal/ieee80211_regdomain.c updated
Modified: branches/madwifi-old-openhal/openhal/Makefile
===================================================================
--- branches/madwifi-old-openhal/openhal/Makefile 2007-03-27 07:43:32 UTC
(rev 2231)
+++ branches/madwifi-old-openhal/openhal/Makefile 2007-03-27 17:29:30 UTC
(rev 2232)
@@ -5,7 +5,7 @@
TOP = $(obj)/..
obj-m += ath_hal.o
-ath_hal-objs := ah_osdep.o ar5xxx.o ar5212.o ar5211.o ar5210.o
ieee80211_regdomain.o
+ath_hal-objs := ah_osdep.o ath5k_hw.o ieee80211_regdomain.o
include $(TOP)/Makefile.inc
Modified: branches/madwifi-old-openhal/openhal/README
===================================================================
--- branches/madwifi-old-openhal/openhal/README 2007-03-27 07:43:32 UTC (rev
2231)
+++ branches/madwifi-old-openhal/openhal/README 2007-03-27 17:29:30 UTC (rev
2232)
@@ -1,13 +1,14 @@
-Linux OpenHAL 20061412
+Linux OpenHAL 20072703
======================
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* This is a port of the ar5k hal for atheros device drivers that is *
- * source-compatible with the Madwifi driver for linux
*
- * (before the BSD - HEAD merge). *
+ * source-compatible with the Madwifi driver for linux.
*
* *
* Code ported, modified for combatibility and some bugs were fixed by
*
* Nick "Mick Flemm" Kossifidis (Athens Wireless Metropolitan Network) *
- * <mickflemm'at'gmail.com> so ar5k can work propertly on Linux. *
+ * <mickflemm'at'gmail.com> and Pavel Roskin so ar5k can work propertly *
+ * on Linux. *
+ * *
* Currently only the 5212 code has been tested due to lack of hardware. *
* *
* Some code from John Bicket's port (roofnet project) was taken, you can *
@@ -91,8 +92,7 @@
WARNING: Don't delete the empty files included (ah_desc.h etc)
-Note: Currenty works for MadWiFi versions before HEAD - BSD merge
-(that means it works with 07/11/05 snapshot).
+Note: Currenty works for MadWiFi-old
Use
=====
Modified: branches/madwifi-old-openhal/openhal/ah.h
===================================================================
--- branches/madwifi-old-openhal/openhal/ah.h 2007-03-27 07:43:32 UTC (rev
2231)
+++ branches/madwifi-old-openhal/openhal/ah.h 2007-03-27 17:29:30 UTC (rev
2232)
@@ -1,6 +1 @@
-#ifndef _AR5K_AH_H
-#define _AR5K_AH_H
-
-#include "ar5xxx.h"
-
-#endif
+#include "ath5k.h"
Modified: branches/madwifi-old-openhal/openhal/ah_osdep.c
===================================================================
--- branches/madwifi-old-openhal/openhal/ah_osdep.c 2007-03-27 07:43:32 UTC
(rev 2231)
+++ branches/madwifi-old-openhal/openhal/ah_osdep.c 2007-03-27 17:29:30 UTC
(rev 2232)
@@ -41,7 +41,7 @@
MODULE_AUTHOR("Nick Kossifidis");
MODULE_DESCRIPTION("OpenHAL");
-MODULE_SUPPORTED_DEVICE("");
+MODULE_SUPPORTED_DEVICE("Atheros AR5xxx WLAN cards");
#ifdef MODULE_LICENSE
MODULE_LICENSE("Dual BSD/GPL");
#endif
@@ -53,7 +53,7 @@
AR5K_BUS_TAG t, AR5K_BUS_HANDLE h, void* s)
{
AR5K_STATUS status;
- struct ath_hal *ah = ath_hal_attach(devid, sc, t, h, &status);
+ struct ath_hal *ah = ath5k_hw_init(devid, sc, t, h, &status);
*(AR5K_STATUS *)s = status;
if (ah)
Modified: branches/madwifi-old-openhal/openhal/ah_osdep.h
===================================================================
--- branches/madwifi-old-openhal/openhal/ah_osdep.h 2007-03-27 07:43:32 UTC
(rev 2231)
+++ branches/madwifi-old-openhal/openhal/ah_osdep.h 2007-03-27 17:29:30 UTC
(rev 2232)
@@ -74,8 +74,8 @@
#define bcopy(_a, _b, _c) memcpy(_b, _a, _c)
#define bzero(_a, _b) memset(_a, 0, _b)
-#define AR5K_REG_WRITE(_reg, _val) (writel(_val, hal->ah_sh + (_reg)))
+//#define AR5K_REG_WRITE(_reg, _val) (writel(_val, hal->ah_sh + (_reg)))
// bus_space_write_4(hal->ah_st, hal->ah_sh, (_reg), (_val))
-#define AR5K_REG_READ(_reg) (readl(hal->ah_sh + (_reg)))
+//#define AR5K_REG_READ(_reg) (readl(hal->ah_sh + (_reg)))
// bus_space_read_4(hal->ah_st, hal->ah_sh, (_reg))
Deleted: branches/madwifi-old-openhal/openhal/ar5210.c
Deleted: branches/madwifi-old-openhal/openhal/ar5210reg.h
Deleted: branches/madwifi-old-openhal/openhal/ar5210var.h
Deleted: branches/madwifi-old-openhal/openhal/ar5211.c
Deleted: branches/madwifi-old-openhal/openhal/ar5211reg.h
Deleted: branches/madwifi-old-openhal/openhal/ar5211var.h
Deleted: branches/madwifi-old-openhal/openhal/ar5212.c
Deleted: branches/madwifi-old-openhal/openhal/ar5212reg.h
Deleted: branches/madwifi-old-openhal/openhal/ar5212var.h
Deleted: branches/madwifi-old-openhal/openhal/ar5xxx.c
Deleted: branches/madwifi-old-openhal/openhal/ar5xxx.h
Added: branches/madwifi-old-openhal/openhal/ath5k.h
===================================================================
--- branches/madwifi-old-openhal/openhal/ath5k.h
(rev 0)
+++ branches/madwifi-old-openhal/openhal/ath5k.h 2007-03-27 17:29:30 UTC
(rev 2232)
@@ -0,0 +1,1241 @@
+/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@xxxxxxxxxxx>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@xxxxxxxxx>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+/*
+ * 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
+
+/*Os dependent definitions*/
+#include "ah_osdep.h"
+#include "ath5k_hw.h"
+
+/*Regulatory domain & Channel definitions*/
+#include "ieee80211_regdomain.h"
+
+/*Options*/
+#include "opt_ah.h"
+
+/*
+ *Translation for MadWiFi combatibility
+ *(damn this is changed AGAIN in if_ath.pci :P)
+ */
+#include "translation.h"
+
+/*Use with MadWiFi/net80211*/
+#include "stack_net80211.h"
+
+
+/****************************\
+ GENERIC DRIVER DEFINITIONS
+\****************************/
+
+/*
+ * C doesn't support boolean ;-(
+ * TODO: See if there is a bool definition somewere else
+ * in the kernel, we shouldn't redefine it if it does...
+ */
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+typedef u_int8_t AR5K_BOOL;
+
+/*
+ * Error codes reported from HAL to the driver
+ */
+typedef enum {
+ AR5K_OK = 0, /* Everything went O.K.*/
+ AR5K_ENOMEM = 1, /* Unable to allocate memory for ath_hal*/
+ AR5K_EIO = 2, /* Hardware I/O Error*/
+ AR5K_EELOCKED = 3, /* Unable to access EEPROM*/
+ AR5K_EEBADSUM = 4, /* Invalid EEPROM checksum*/
+ AR5K_EEREAD = 5, /* Unable to get device caps from EEPROM */
+ AR5K_EEBADMAC = 6, /* Unable to read MAC address from EEPROM */
+ AR5K_EINVAL = 7, /* Invalid parameter to function */
+ AR5K_ENOTSUPP = 8, /* Hardware revision not supported */
+ AR5K_EINPROGRESS= 9, /* Unexpected error ocured during process */
+} AR5K_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 FALSE
+#define AR5K_TUNE_MIN_TX_FIFO_THRES 1
+#define AR5K_TUNE_MAX_TX_FIFO_THRES ((MAX_PDU_LENGTH / 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_AIFS_11B 2
+#define AR5K_TUNE_AIFS_XR 0
+#define AR5K_TUNE_CWMIN 15
+#define AR5K_TUNE_CWMIN_11B 31
+#define AR5K_TUNE_CWMIN_XR 3
+#define AR5K_TUNE_CWMAX 1023
+#define AR5K_TUNE_CWMAX_11B 1023
+#define AR5K_TUNE_CWMAX_XR 7
+#define AR5K_TUNE_NOISE_FLOOR -72
+#define AR5K_TUNE_MAX_TXPOWER 60
+#define AR5K_TUNE_DEFAULT_TXPOWER 30
+#define AR5K_TUNE_TPC_TXPOWER TRUE
+#define AR5K_TUNE_ANT_DIVERSITY TRUE
+#define AR5K_TUNE_HWTXTRIES 4
+
+/* token to use for aifs, cwmin, cwmax in MadWiFi */
+#define AR5K_TXQ_USEDEFAULT ((u_int32_t) -1)
+
+#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
+#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */
+static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff,
0xff, 0xff, 0xff };
+//#define etherbroadcastaddr 0xff
+
+
+
+
+/*****************************\
+ GENERIC CHIPSET DEFINITIONS
+\*****************************/
+
+/* MAC Chips*/
+enum ath5k_version {
+ AR5K_AR5210 = 0,
+ AR5K_AR5211 = 1,
+ AR5K_AR5212 = 2,
+};
+
+/*PHY Chips*/
+enum ath5k_radio {
+ AR5K_AR5110 = 0,
+ AR5K_AR5111 = 1,
+ AR5K_AR5112 = 2,
+};
+
+/*
+ * Common silicon revision/version values
+ */
+enum ath5k_srev_type {
+ AR5K_VERSION_VER,
+ AR5K_VERSION_REV,
+ AR5K_VERSION_RAD,
+ AR5K_VERSION_DEV
+};
+
+struct ath5k_srev_name {
+ const char *sr_name;
+ enum ath5k_srev_type sr_type;
+ u_int sr_val;
+};
+
+#define AR5K_SREV_NAME { \
+ { "5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210 }, \
+ { "5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311 }, \
+ { "5311a", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A },\
+ { "5311b", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B },\
+ { "5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211 }, \
+ { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, \
+ { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, \
+ { "xxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN }, \
+ { "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 }, \
+ { "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 }, \
+ { "2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111 }, \
+ { "5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112 }, \
+ { "5112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, \
+ { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, \
+ { "2112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, \
+ { "xxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, \
+ { "2413", AR5K_VERSION_DEV, AR5K_DEVID_AR2413 }, \
+ { "5413", AR5K_VERSION_DEV, AR5K_DEVID_AR5413 }, \
+ { "5424", AR5K_VERSION_DEV, AR5K_DEVID_AR5424 }, \
+ { "xxxx", AR5K_VERSION_DEV, AR5K_SREV_UNKNOWN } \
+}
+
+#define AR5K_SREV_UNKNOWN 0xffff
+
+#define AR5K_SREV_VER_AR5210 0x00
+#define AR5K_SREV_VER_AR5311 0x10
+#define AR5K_SREV_VER_AR5311A 0x20
+#define AR5K_SREV_VER_AR5311B 0x30
+#define AR5K_SREV_VER_AR5211 0x40
+#define AR5K_SREV_VER_AR5212 0x50
+#define AR5K_SREV_VER_AR5213 0x55
+#define AR5K_SREV_VER_UNSUPP 0x60
+
+#define AR5K_SREV_RAD_5110 0x00
+#define AR5K_SREV_RAD_5111 0x10
+#define AR5K_SREV_RAD_5111A 0x15
+#define AR5K_SREV_RAD_2111 0x20
+#define AR5K_SREV_RAD_5112 0x30
+#define AR5K_SREV_RAD_5112A 0x35
+#define AR5K_SREV_RAD_2112 0x40
+#define AR5K_SREV_RAD_2112A 0x45
+#define AR5K_SREV_RAD_UNSUPP 0x50
+
+
+
+
+/****************\
+ TX DEFINITIONS
+\****************/
+
+/*
+ * Tx Descriptor
+ */
+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 AR5K_TXSTAT_ALTRATE 0x80
+#define AR5K_TXERR_XRETRY 0x01
+#define AR5K_TXERR_FILT 0x02
+#define AR5K_TXERR_FIFO 0x04
+
+/*
+ * Queue types used to classify tx queues.
+ */
+typedef enum {
+ AR5K_TX_QUEUE_INACTIVE = 0,/*This queue is not used -see
ath_hal_releasetxqueue*/
+ AR5K_TX_QUEUE_DATA, /*A normal data queue*/
+ AR5K_TX_QUEUE_XR_DATA, /*An XR-data queue*/
+ AR5K_TX_QUEUE_BEACON, /*The beacon queue*/
+ AR5K_TX_QUEUE_CAB, /*The ater-beacon queue*/
+ AR5K_TX_QUEUE_UAPSD, /*Unscheduled Automatic Power Save Delivery
queue*/
+} AR5K_TX_QUEUE;
+
+#define AR5K_NUM_TX_QUEUES 10
+
+/*
+ * Queue syb-types to classify normal data queues.
+ * These are the 4 Access Categories as defined in
+ * WME spec. 0 is the lowest priority and 4 is the
+ * highest. Normal data that hasn't been classified
+ * goes to the Best Effort AC.
+ */
+typedef enum {
+ AR5K_WME_AC_BK = 0, /*Background traffic*/
+ AR5K_WME_AC_BE, /*Best-effort (normal) traffic)*/
+ AR5K_WME_AC_VI, /*Video traffic*/
+ AR5K_WME_AC_VO, /*Voice traffic*/
+} AR5K_TX_QUEUE_SUBTYPE;
+
+/*
+ * Queue ID numbers as returned by the HAL, each number
+ * represents a hw queue. If hw does not support hw queues
+ * (eg 5210/5211) all data goes in one queue. These match
+ * d80211 definitions (net80211/MadWiFi don't use them).
+ */
+typedef enum {
+ AR5K_TX_QUEUE_ID_DATA_MIN = 0, /*IEEE80211_TX_QUEUE_DATA0*/
+ AR5K_TX_QUEUE_ID_DATA_MAX = 4, /*IEEE80211_TX_QUEUE_DATA4*/
+ AR5K_TX_QUEUE_ID_DATA_SVP = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink
Voice Protocol*/
+ AR5K_TX_QUEUE_ID_CAB = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/
+ AR5K_TX_QUEUE_ID_BEACON = 7, /*IEEE80211_TX_QUEUE_BEACON*/
+ AR5K_TX_QUEUE_ID_UAPSD = 8,
+ AR5K_TX_QUEUE_ID_XR_DATA = 9,
+} AR5K_TX_QUEUE_ID;
+
+
+/*
+ * Flags to set hw queue's parameters...
+ */
+#define AR5K_TXQ_FLAG_TXINT_ENABLE 0x0001 /* Enable TXOK and
TXERR interrupts -not used- */
+#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0002 /* Enable TXDESC
interrupt -not implemented- */
+#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0004 /* Disable random
post-backoff */
+#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0008 /* Enable hw
compression -not implemented-*/
+#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0010 /* Enable ready
time expiry policy (?)*/
+#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0020 /* Enable
backoff while bursting */
+#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x0040 /* Disable
backoff while bursting */
+#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0080 /* Enable TXEOL
interrupt -not implemented-*/
+
+/*
+ * A struct to hold tx queue's parameters
+ */
+typedef struct {
+ AR5K_TX_QUEUE tqi_type; /* See AR5K_TX_QUEUE */
+ AR5K_TX_QUEUE_SUBTYPE tqi_subtype; /* See
AR5K_TX_QUEUE_SUBTYPE */
+ u_int16_t tqi_flags; /* Tx queue flags (see
above) */
+ u_int32_t tqi_aifs; /* Arbitrated
Interframe Space */
+ int32_t tqi_cw_min; /* Minimum Contention
Window */
+ int32_t tqi_cw_max; /* Maximum Contention
Window */
+ u_int32_t tqi_cbr_period; /* Constant bit rate
period */
+ u_int32_t tqi_cbr_overflow_limit;
+ u_int32_t tqi_burst_time;
+ u_int32_t tqi_ready_time; /* Not used */
+ u_int32_t tqi_comp_buffer;/* Compression Buffer's
phys addr */
+} AR5K_TXQ_INFO;
+
+/*
+ * Transmit packet types.
+ * These are not fully used inside OpenHAL yet
+ */
+typedef enum {
+ AR5K_PKT_TYPE_NORMAL = 0,
+ AR5K_PKT_TYPE_ATIM = 1,
+ AR5K_PKT_TYPE_PSPOLL = 2,
+ AR5K_PKT_TYPE_BEACON = 3,
+ AR5K_PKT_TYPE_PROBE_RESP = 4,
+ AR5K_PKT_TYPE_PIFS = 5,
+} AR5K_PKT_TYPE;
+
+/*
+ * TX power and TPC settings
+ */
+#define AR5K_TXPOWER_OFDM(_r, _v) ( \
+ ((0 & 1) << ((_v) + 6)) | \
+ (((hal->ah_txpower.txp_rates[(_r)]) & 0x3f) << (_v)) \
+)
+
+#define AR5K_TXPOWER_CCK(_r, _v) ( \
+ (hal->ah_txpower.txp_rates[(_r)] & 0x3f) << (_v) \
+)
+
+/*
+ * 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_OFDM_SIFS_TIME 16
+#define AR5K_OFDM_PREAMBLE_TIME 20
+#define AR5K_OFDM_PLCP_BITS 22
+#define AR5K_OFDM_SYMBOL_TIME 4
+
+#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_XR_SIFS_TIME 16
+#define AR5K_XR_PLCP_BITS 22
+#define AR5K_XR_SYMBOL_TIME 4
+
+/* CCK */
+#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
+
+/* OFDM */
+#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)
+
+/* TURBO */
+#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)
+
+/* eXtendent Range (?)*/
+#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)
+
+/*
+ * DMA size definitions (2^n+2)
+ */
+typedef enum {
+ AR5K_DMASIZE_4B = 0,
+ AR5K_DMASIZE_8B,
+ AR5K_DMASIZE_16B,
+ AR5K_DMASIZE_32B,
+ AR5K_DMASIZE_64B,
+ AR5K_DMASIZE_128B,
+ AR5K_DMASIZE_256B,
+ AR5K_DMASIZE_512B
+} ath5k_dmasize_t;
+
+
+
+/****************\
+ RX DEFINITIONS
+\****************/
+
+/*
+ * Rx Descriptor
+ */
+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 AR5K_RXERR_CRC 0x01
+#define AR5K_RXERR_PHY 0x02
+#define AR5K_RXERR_FIFO 0x04
+#define AR5K_RXERR_DECRYPT 0x08
+#define AR5K_RXERR_MIC 0x10
+#define AR5K_RXKEYIX_INVALID ((u_int8_t) - 1)
+#define AR5K_TXKEYIX_INVALID ((u_int32_t) - 1)
+
+/*
+ * RX filters
+ * Most of them are not yet used inside OpenHAL
+ */
+#define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter
unicast frames */
+#define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter
multicast frames */
+#define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter
broadcast frames */
+#define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter
control frames */
+#define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter
beacon frames */
+#define AR5K_RX_FILTER_PROM 0x00000020 /* Set
promiscuous mode */
+#define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter
XR poll frame */
+#define AR5K_RX_FILTER_PROBEREQ 0x00000080 /* Don't filter
probe requests */
+#define AR5K_RX_FILTER_PHYERROR 0x00000100 /* Don't filter
phy errors */
+#define AR5K_RX_FILTER_PHYRADAR 0x00000200 /* Don't filter
phy radar errors*/
+
+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;
+} AR5K_MIB_STATS;
+
+
+
+
+/**************************\
+ BEACON TIMERS DEFINITIONS
+\**************************/
+
+#define AR5K_BEACON_PERIOD 0x0000ffff
+#define AR5K_BEACON_ENA 0x00800000 /*enable beacon xmit*/
+#define AR5K_BEACON_RESET_TSF 0x01000000 /*force a TSF reset*/
+
+/*
+ * Per-station beacon timer state.
+ */
+typedef struct {
+ u_int32_t bs_next_beacon;
+ u_int32_t bs_next_dtim;
+ u_int32_t bs_interval; /*in TU's -see
net80211/ieee80211_var.h-
+ can also include the above
flags*/
+ u_int8_t bs_dtim_period;
+ u_int8_t bs_cfp_period;
+ u_int16_t bs_cfp_max_duration; /*if non-zero hw is setup to
coexist with
+ a Point Coordination Function
capable AP*/
+ 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;
+ u_int32_t bs_cfp_next;
+} AR5K_BEACON_STATE;
+
+
+
+
+/********************\
+ COMMON DEFINITIONS
+\********************/
+
+/*
+ * Atheros descriptor
+ */
+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
+
+} __packed;
+
+#define AR5K_RXDESC_INTREQ 0x0020
+
+#define AR5K_TXDESC_CLRDMASK 0x0001
+#define AR5K_TXDESC_NOACK 0x0002
+#define AR5K_TXDESC_RTSENA 0x0004
+#define AR5K_TXDESC_CTSENA 0x0008
+#define AR5K_TXDESC_INTREQ 0x0010
+#define AR5K_TXDESC_VEOL 0x0020
+
+/*
+ * 802.11 operating modes...
+ */
+#define AR5K_MODE_11A 0x01
+#define AR5K_MODE_11B 0x02
+#define AR5K_MODE_11G 0x04
+#define AR5K_MODE_TURBO 0x08
+#define AR5K_MODE_108G 0x16
+#define AR5K_MODE_XR 0x32
+#define AR5K_MODE_ALL (AR5K_MODE_11A| \
+ AR5K_MODE_11B| \
+ AR5K_MODE_11G| \
+ AR5K_MODE_TURBO|\
+ AR5K_MODE_108G| \
+ AR5K_MODE_XR)
+
+/*
+ * Channel definitions
+ */
+typedef struct {
+ u_int16_t freq; /* setting in Mhz */
+ u_int16_t channel_flags;
+ u_int8_t private_flags; /* not used in OpenHAL yet*/
+} AR5K_CHANNEL;
+
+#define AR5K_SLOT_TIME_9 396
+#define AR5K_SLOT_TIME_20 880
+#define AR5K_SLOT_TIME_MAX 0xffff
+
+/* channel_flags */
+#define CHANNEL_CW_INT 0x0008 /* Contention Window interference
detected */
+#define CHANNEL_TURBO 0x0010 /* Turbo Channel */
+#define CHANNEL_CCK 0x0020 /* CCK channel */
+#define CHANNEL_OFDM 0x0040 /* OFDM channel */
+#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */
+#define CHANNEL_5GHZ 0x0100 /* 5GHz channel */
+#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */
+#define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g
operation)*/
+#define CHANNEL_XR 0x0800 /* XR channel */
+
+#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM)
+#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK)
+#define CHANNEL_PUREG (CHANNEL_2GHZ|CHANNEL_OFDM)
+//#ifdef notdef
+#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_DYN)
+//#else
+//#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM)
+//#endif
+#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define CHANNEL_TG (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define CHANNEL_108A CHANNEL_T
+#define CHANNEL_108G CHANNEL_TG
+#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
+
+#define CHANNEL_ALL (CHANNEL_OFDM|CHANNEL_CCK| CHANNEL_2GHZ |\
+ CHANNEL_5GHZ | CHANNEL_TURBO)
+
+#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL &~ CHANNEL_TURBO)
+#define CHANNEL_MODES CHANNEL_ALL
+
+/*
+ * Used internaly in OpenHAL (ar5211.c/ar5212.c
+ * for reset_tx_queue). Also see struct AR5K_CHANNEL.
+ */
+#define IS_CHAN_XR(_c) \
+ ((_c.channel_flags & CHANNEL_XR) != 0)
+
+#define IS_CHAN_B(_c) \
+ ((_c.channel_flags & CHANNEL_B) != 0)
+
+typedef enum {
+ AR5K_CHIP_5GHZ = CHANNEL_5GHZ,
+ AR5K_CHIP_2GHZ = CHANNEL_2GHZ,
+} AR5K_CHIP;
+
+/*
+ * The following structure will be used to map 2GHz channels to
+ * 5GHz Atheros channels.
+ */
+struct ath5k_athchan_2ghz {
+ u_int32_t a2_flags;
+ u_int16_t a2_athchan;
+};
+
+/*
+ * Rate definitions
+ */
+
+#define AR5K_MAX_RATES 32 /*max number of rates on the rate table*/
+
+typedef struct {
+ u_int8_t valid; /* Valid for rate control */
+ u_int32_t modulation;
+ u_int16_t rate_kbps;
+ u_int8_t rate_code; /* Rate mapping for h/w descriptors */
+ u_int8_t dot11_rate;
+ u_int8_t control_rate;
+ u_int16_t lp_ack_duration;/* long preamble ACK duration */
+ u_int16_t sp_ack_duration;/* short preamble ACK duration*/
+} AR5K_RATE;
+
+typedef struct {
+ u_int16_t rate_count;
+ u_int8_t rate_code_to_index[AR5K_MAX_RATES]; /* Back-mapping
*/
+ AR5K_RATE rates[AR5K_MAX_RATES];
+} AR5K_RATE_TABLE;
+
+/*
+ * Rate tables...
+ */
+#define AR5K_RATES_11A { 8, { \
+ 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \
+ 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \
+ 255, 255, 255, 255, 255, 255, 255, 255 }, { \
+ { 1, MODULATION_OFDM, 6000, 11, 140, 0 }, \
+ { 1, MODULATION_OFDM, 9000, 15, 18, 0 }, \
+ { 1, MODULATION_OFDM, 12000, 10, 152, 2 }, \
+ { 1, MODULATION_OFDM, 18000, 14, 36, 2 }, \
+ { 1, MODULATION_OFDM, 24000, 9, 176, 4 }, \
+ { 1, MODULATION_OFDM, 36000, 13, 72, 4 }, \
+ { 1, MODULATION_OFDM, 48000, 8, 96, 4 }, \
+ { 1, MODULATION_OFDM, 54000, 12, 108, 4 } } \
+}
+
+#define AR5K_RATES_11B { 4, { \
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \
+ 3, 2, 1, 0, 255, 255, 255, 255 }, { \
+ { 1, MODULATION_CCK, 1000, 27, 130, 0 }, \
+ { 1, MODULATION_CCK, 2000, 26, 132, 1 }, \
+ { 1, MODULATION_CCK, 5500, 25, 139, 1 }, \
+ { 1, MODULATION_CCK, 11000, 24, 150, 1 } } \
+}
+
+#define AR5K_RATES_11G { 12, { \
+ 255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4, \
+ 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \
+ 3, 2, 1, 0, 255, 255, 255, 255 }, { \
+ { 1, MODULATION_CCK, 1000, 27, 2, 0 }, \
+ { 1, MODULATION_CCK, 2000, 26, 4, 1 }, \
+ { 1, MODULATION_CCK, 5500, 25, 11, 1 }, \
+ { 1, MODULATION_CCK, 11000, 24, 22, 1 }, \
+ { 0, MODULATION_OFDM, 6000, 11, 12, 4 }, \
+ { 0, MODULATION_OFDM, 9000, 15, 18, 4 }, \
+ { 1, MODULATION_OFDM, 12000, 10, 24, 6 }, \
+ { 1, MODULATION_OFDM, 18000, 14, 36, 6 }, \
+ { 1, MODULATION_OFDM, 24000, 9, 48, 8 }, \
+ { 1, MODULATION_OFDM, 36000, 13, 72, 8 }, \
+ { 1, MODULATION_OFDM, 48000, 8, 96, 8 }, \
+ { 1, MODULATION_OFDM, 54000, 12, 108, 8 } } \
+}
+
+#define AR5K_RATES_TURBO { 8, { \
+ 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \
+ 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \
+ 255, 255, 255, 255, 255, 255, 255, 255 }, { \
+ { 1, MODULATION_TURBO, 6000, 11, 140, 0 }, \
+ { 1, MODULATION_TURBO, 9000, 15, 18, 0 }, \
+ { 1, MODULATION_TURBO, 12000, 10, 152, 2 }, \
+ { 1, MODULATION_TURBO, 18000, 14, 36, 2 }, \
+ { 1, MODULATION_TURBO, 24000, 9, 176, 4 }, \
+ { 1, MODULATION_TURBO, 36000, 13, 72, 4 }, \
+ { 1, MODULATION_TURBO, 48000, 8, 96, 4 }, \
+ { 1, MODULATION_TURBO, 54000, 12, 108, 4 } } \
+}
+
+#define AR5K_RATES_XR { 12, { \
+ 255, 3, 1, 255, 255, 255, 2, 0, 10, 8, 6, 4, \
+ 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \
+ 255, 255, 255, 255, 255, 255, 255, 255 }, { \
+ { 1, MODULATION_XR, 500, 7, 129, 0 }, \
+ { 1, MODULATION_XR, 1000, 2, 139, 1 }, \
+ { 1, MODULATION_XR, 2000, 6, 150, 2 }, \
+ { 1, MODULATION_XR, 3000, 1, 150, 3 }, \
+ { 1, MODULATION_OFDM, 6000, 11, 140, 4 }, \
+ { 1, MODULATION_OFDM, 9000, 15, 18, 4 }, \
+ { 1, MODULATION_OFDM, 12000, 10, 152, 6 }, \
+ { 1, MODULATION_OFDM, 18000, 14, 36, 6 }, \
+ { 1, MODULATION_OFDM, 24000, 9, 176, 8 }, \
+ { 1, MODULATION_OFDM, 36000, 13, 72, 8 }, \
+ { 1, MODULATION_OFDM, 48000, 8, 96, 8 }, \
+ { 1, MODULATION_OFDM, 54000, 12, 108, 8 } } \
+}
+
+/*
+ * Crypto definitions
+ */
+
+/* key types */
+typedef enum {
+ AR5K_CIPHER_WEP = 0,
+ AR5K_CIPHER_AES_OCB = 1,
+ AR5K_CIPHER_AES_CCM = 2,
+ AR5K_CIPHER_CKIP = 3,
+ AR5K_CIPHER_TKIP = 4,
+ AR5K_CIPHER_CLR = 5, /* no encryption */
+ AR5K_CIPHER_MIC = 127 /* used for Message
+ Integrity Code */
+} AR5K_CIPHER;
+
+#define AR5K_KEYVAL_LENGTH_40 5
+#define AR5K_KEYVAL_LENGTH_104 13
+#define AR5K_KEYVAL_LENGTH_128 16
+#define AR5K_KEYVAL_LENGTH_MAX AR5K_KEYVAL_LENGTH_128
+
+typedef struct {
+ int wk_len; /* key's length */
+ u_int8_t wk_key[AR5K_KEYVAL_LENGTH_MAX];
+ u_int8_t wk_type; /* see above */
+ u_int8_t wk_mic[8]; /* TKIP MIC key */
+} AR5K_KEYVAL;
+
+
+
+/***********************\
+ HW RELATED DEFINITIONS
+\***********************/
+
+/*
+ * Misc definitions
+ */
+#define AR5K_RSSI_EP_MULTIPLIER (1<<7)
+
+#define AR5K_ASSERT_ENTRY(_e, _s) do { \
+ if (_e >= _s) \
+ return (FALSE); \
+} while (0)
+
+
+typedef struct {
+ u_int32_t ns_avgbrssi; /* average beacon rssi */
+ u_int32_t ns_avgrssi; /* average data rssi */
+ u_int32_t ns_avgtxrssi; /* average tx rssi */
+} AR5K_NODE_STATS;
+
+typedef enum {
+ AR5K_ANT_VARIABLE = 0, /* variable by programming */
+ AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */
+ AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */
+ AR5K_ANT_MAX = 3,
+} AR5K_ANT_SETTING;
+
+/*
+ * HAL interrupt abstraction
+ */
+
+/*
+ * These are maped to take advantage of some common bits
+ * between the MAC chips, to be able to set intr properties
+ * easier. Some of them are not used yet inside OpenHAL.
+ */
+typedef enum {
+ AR5K_INT_RX = 0x00000001,
+ AR5K_INT_RXDESC = 0x00000002,
+ AR5K_INT_RXNOFRM = 0x00000008,
+ AR5K_INT_RXEOL = 0x00000010,
+ AR5K_INT_RXORN = 0x00000020,
+ AR5K_INT_TX = 0x00000040,
+ AR5K_INT_TXDESC = 0x00000080,
+ AR5K_INT_TXURN = 0x00000800,
+ AR5K_INT_MIB = 0x00001000,
+ AR5K_INT_RXPHY = 0x00004000,
+ AR5K_INT_RXKCM = 0x00008000,
+ AR5K_INT_SWBA = 0x00010000,
+ AR5K_INT_BMISS = 0x00040000,
+ AR5K_INT_BNR = 0x00100000,
+ AR5K_INT_GPIO = 0x01000000,
+ AR5K_INT_FATAL = 0x40000000,
+ AR5K_INT_GLOBAL = 0x80000000,
+
+ /*A sum of all the common bits*/
+ AR5K_INT_COMMON = AR5K_INT_RXNOFRM
+ | AR5K_INT_RXDESC
+ | AR5K_INT_RXEOL
+ | AR5K_INT_RXORN
+ | AR5K_INT_TXURN
+ | AR5K_INT_TXDESC
+ | AR5K_INT_MIB
+ | AR5K_INT_RXPHY
+ | AR5K_INT_RXKCM
+ | AR5K_INT_SWBA
+ | AR5K_INT_BMISS
+ | AR5K_INT_GPIO,
+ AR5K_INT_NOCARD = 0xffffffff /*Declare that the card
+ has been removed*/
+} AR5K_INT;
+
+/*
+ * Power management
+ */
+typedef enum {
+ AR5K_PM_UNDEFINED = 0,
+ AR5K_PM_AUTO,
+ AR5K_PM_AWAKE,
+ AR5K_PM_FULL_SLEEP,
+ AR5K_PM_NETWORK_SLEEP,
+} AR5K_POWER_MODE;
+
+
+/*
+ * LED states
+ */
+typedef int AR5K_LED_STATE;
+
+/*
+ * These match net80211 definitions (not used in
+ * d80211).
+ */
+#define AR5K_LED_INIT 0 /*IEEE80211_S_INIT*/
+#define AR5K_LED_SCAN 1 /*IEEE80211_S_SCAN*/
+#define AR5K_LED_AUTH 2 /*IEEE80211_S_AUTH*/
+#define AR5K_LED_ASSOC 3 /*IEEE80211_S_ASSOC*/
+#define AR5K_LED_RUN 4 /*IEEE80211_S_RUN*/
+
+/* GPIO-controlled software LED */
+#define AR5K_SOFTLED_PIN 0
+#define AR5K_SOFTLED_ON 0
+#define AR5K_SOFTLED_OFF 1
+
+/*
+ * Chipset capabilities -see ath_hal_getcapability-
+ * get_capability function is not yet fully implemented
+ * in OpenHAL so most of these don't work yet...
+ */
+typedef enum {
+ AR5K_CAP_REG_DMN = 0, /* Used to get current reg.
domain id */
+ AR5K_CAP_CIPHER = 1, /* Can handle encryption */
+ AR5K_CAP_TKIP_MIC = 2, /* Can handle TKIP MIC in
hardware */
+ AR5K_CAP_TKIP_SPLIT = 3, /* TKIP uses split keys */
+ AR5K_CAP_PHYCOUNTERS = 4, /* PHY error counters */
+ AR5K_CAP_DIVERSITY = 5, /* Supports fast diversity */
+ AR5K_CAP_NUM_TXQUEUES = 6, /* Used to get max number of hw
txqueues */
+ AR5K_CAP_VEOL = 7, /* Supports virtual EOL */
+ AR5K_CAP_COMPRESSION = 8, /* Supports compression */
+ AR5K_CAP_BURST = 9, /* Supports packet bursting */
+ AR5K_CAP_FASTFRAME = 10, /* Supports fast frames */
+ AR5K_CAP_TXPOW = 11, /* Used to get global tx power
limit */
+ AR5K_CAP_TPC = 12, /* Can do per-packet tx power
control (needed for 802.11a) */
+ AR5K_CAP_BSSIDMASK = 13, /* Supports bssid mask */
+ AR5K_CAP_MCAST_KEYSRCH = 14, /* Supports multicast key
search */
+ AR5K_CAP_TSF_ADJUST = 15, /* Supports beacon tsf adjust */
+ AR5K_CAP_XR = 16, /* Supports XR mode */
+ AR5K_CAP_WME_TKIPMIC = 17, /* Supports TKIP MIC when using
WMM */
+ AR5K_CAP_CHAN_HALFRATE = 18, /* Supports half rate channels
*/
+ AR5K_CAP_CHAN_QUARTERRATE = 19, /* Supports quarter rate
channels */
+ AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */
+} AR5K_CAPABILITY_TYPE;
+
+typedef struct {
+ /*
+ * Supported PHY modes
+ * (ie. CHANNEL_A, CHANNEL_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 ath5k_eeprom_info cap_eeprom;
+
+ /*
+ * Queue information
+ */
+ struct {
+ u_int8_t q_tx_num;
+ } cap_queues;
+} ath5k_capabilities_t;
+
+
+/***************************************\
+ HARDWARE ABSTRACTION LAYER STRUCTURE
+\***************************************/
+
+/*
+ * Regulation stuff
+ */
+typedef enum ieee80211_countrycode AR5K_CTRY_CODE;
+
+/* Default regulation domain if stored value EEPROM value is invalid */
+#define AR5K_TUNE_REGDOMAIN DMN_FCC2_FCCA /* Canada */
+#define AR5K_TUNE_CTRY CTRY_DEFAULT
+
+/*
+ * Misc defines
+ */
+
+#define AR5K_ELEMENTS(_array) (sizeof(_array) / sizeof(_array[0]))
+
+typedef struct ath_hal * (ath5k_attach_t)
+ (u_int16_t, AR5K_SOFTC, AR5K_BUS_TAG, AR5K_BUS_HANDLE, AR5K_STATUS *);
+
+typedef AR5K_BOOL (ath5k_rfgain_t)
+ (struct ath_hal *, AR5K_CHANNEL *, u_int);
+
+/*
+ * HAL Functions that have different implementations for each chipset...
+ */
+#define AR5K_HAL_FUNCTION(_hal, _n, _f) (_hal)->ah_##_f =
ath5k_##_n##_##_f
+#define AR5K_HAL_FUNCTIONS(_t, _n, _a) \
+ _t const AR5K_RATE_TABLE *(_a _n##_get_rate_table)(struct ath_hal *,
u_int mode); \
+ _t void (_a _n##_detach)(struct ath_hal *);
\
+ /* Reset functions */
\
+ _t AR5K_BOOL (_a _n##_reset)(struct ath_hal *, AR5K_OPMODE,
AR5K_CHANNEL *, \
+ AR5K_BOOL change_channel, AR5K_STATUS *status);
\
+ _t void (_a _n##_set_opmode)(struct ath_hal *);
\
+ _t AR5K_BOOL (_a _n##_calibrate)(struct ath_hal*, AR5K_CHANNEL *);
\
+ /* Transmit functions */
\
+ _t AR5K_BOOL (_a _n##_update_tx_triglevel)(struct ath_hal*, AR5K_BOOL
level); \
+ _t int (_a _n##_setup_tx_queue)(struct ath_hal *, AR5K_TX_QUEUE,
AR5K_TXQ_INFO *); \
+ _t AR5K_BOOL (_a _n##_setup_tx_queueprops)(struct ath_hal *, int queue,
\
+ const AR5K_TXQ_INFO *);
\
+ _t AR5K_BOOL (_a _n##_release_tx_queue)(struct ath_hal *, u_int queue);
\
+ _t AR5K_BOOL (_a _n##_reset_tx_queue)(struct ath_hal *, u_int queue);
\
+ _t u_int32_t (_a _n##_get_tx_buf)(struct ath_hal *, u_int queue);
\
+ _t AR5K_BOOL (_a _n##_put_tx_buf)(struct ath_hal *, u_int, u_int32_t
phys_addr); \
+ _t AR5K_BOOL (_a _n##_tx_start)(struct ath_hal *, u_int queue);
\
+ _t AR5K_BOOL (_a _n##_stop_tx_dma)(struct ath_hal *, u_int queue);
\
+ _t AR5K_BOOL (_a _n##_setup_tx_desc)(struct ath_hal *, struct ath_desc
*, \
+ u_int packet_length, u_int header_length,
AR5K_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 AR5K_BOOL (_a _n##_setup_xtx_desc)(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 AR5K_BOOL (_a _n##_fill_tx_desc)(struct ath_hal *, struct ath_desc
*, u_int segLen, \
+ AR5K_BOOL firstSeg, AR5K_BOOL lastSeg, const
struct ath_desc *);\
+ _t AR5K_STATUS (_a _n##_proc_tx_desc)(struct ath_hal *, struct ath_desc
*); \
+ _t AR5K_BOOL (_a _n##_has_veol)(struct ath_hal *);
\
+ /* Receive Functions */
\
+ _t u_int32_t (_a _n##_get_rx_buf)(struct ath_hal*);
\
+ _t void (_a _n##_put_rx_buf)(struct ath_hal*, u_int32_t rxdp);
\
+ _t void (_a _n##_start_rx)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_stop_rx_dma)(struct ath_hal*);
\
+ _t void (_a _n##_start_rx_pcu)(struct ath_hal*);
\
+ _t void (_a _n##_stop_pcu_recv)(struct ath_hal*);
\
+ _t void (_a _n##_set_mcast_filter)(struct ath_hal*, u_int32_t filter0,
\
+ u_int32_t filter1);
\
+ _t AR5K_BOOL (_a _n##_set_mcast_filterindex)(struct ath_hal*, u_int32_t
index); \
+ _t AR5K_BOOL (_a _n##_clear_mcast_filter_idx)(struct ath_hal*,u_int32_t
index); \
+ _t u_int32_t (_a _n##_get_rx_filter)(struct ath_hal*);
\
+ _t void (_a _n##_set_rx_filter)(struct ath_hal*, u_int32_t);
\
+ _t AR5K_BOOL (_a _n##_setup_rx_desc)(struct ath_hal *, struct ath_desc
*, \
+ u_int32_t size, u_int flags);
\
+ _t AR5K_STATUS (_a _n##_proc_rx_desc)(struct ath_hal *, struct ath_desc
*, \
+ u_int32_t phyAddr, struct ath_desc *next);
\
+ _t void (_a _n##_set_rx_signal)(struct ath_hal *, const AR5K_NODE_STATS
*); \
+ /* Misc Functions */
\
+ _t void (_a _n##_dump_state)(struct ath_hal *);
\
+ _t AR5K_BOOL (_a _n##_get_diag_state)(struct ath_hal *, int
request,const void *args, \
+ u_int32_t argsize, void **result, u_int32_t
*resultsize); \
+ _t void (_a _n##_get_lladdr)(struct ath_hal *, u_int8_t *);
\
+ _t AR5K_BOOL (_a _n##_set_lladdr)(struct ath_hal *, const u_int8_t*);
\
+ _t AR5K_BOOL (_a _n##_set_regdomain)(struct ath_hal*, u_int16_t,
AR5K_STATUS *); \
+ _t void (_a _n##_set_ledstate)(struct ath_hal*, AR5K_LED_STATE);
\
+ _t void (_a _n##_set_associd)(struct ath_hal*, const u_int8_t *bssid,
\
+ u_int16_t assocId);
\
+ _t AR5K_BOOL (_a _n##_set_gpio_input)(struct ath_hal *, u_int32_t
gpio); \
+ _t AR5K_BOOL (_a _n##_set_gpio_output)(struct ath_hal *, u_int32_t
gpio); \
+ _t u_int32_t (_a _n##_get_gpio)(struct ath_hal *, u_int32_t gpio);
\
+ _t AR5K_BOOL (_a _n##_set_gpio)(struct ath_hal *, u_int32_t gpio,
u_int32_t val); \
+ _t void (_a _n##_set_gpio_intr)(struct ath_hal*, u_int, u_int32_t);
\
+ _t u_int32_t (_a _n##_get_tsf32)(struct ath_hal*);
\
+ _t u_int64_t (_a _n##_get_tsf64)(struct ath_hal*);
\
+ _t void (_a _n##_reset_tsf)(struct ath_hal*);
\
+ _t u_int16_t (_a _n##_get_regdomain)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_detect_card_present)(struct ath_hal*);
\
+ _t void (_a _n##_update_mib_counters)(struct ath_hal*,
AR5K_MIB_STATS*); \
+ _t AR5K_RFGAIN (_a _n##_get_rf_gain)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_set_slot_time)(struct ath_hal*, u_int);
\
+ _t u_int (_a _n##_get_slot_time)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_set_ack_timeout)(struct ath_hal *, u_int);
\
+ _t u_int (_a _n##_get_ack_timeout)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_set_cts_timeout)(struct ath_hal*, u_int);
\
+ _t u_int (_a _n##_get_cts_timeout)(struct ath_hal*);
\
+ /* Key Cache Functions */
\
+ _t AR5K_BOOL (_a _n##_is_cipher_supported)(struct ath_hal*,
AR5K_CIPHER); \
+ _t u_int32_t (_a _n##_get_keycache_size)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_reset_key)(struct ath_hal*, u_int16_t);
\
+ _t AR5K_BOOL (_a _n##_is_key_valid)(struct ath_hal *, u_int16_t);
\
+ _t AR5K_BOOL (_a _n##_set_key)(struct ath_hal*, u_int16_t, const
AR5K_KEYVAL *, \
+ const u_int8_t *, int);
\
+ _t AR5K_BOOL (_a _n##_set_key_lladdr)(struct ath_hal*, u_int16_t, const
u_int8_t *); \
+ /* Power Management Functions */
\
+ _t AR5K_BOOL (_a _n##_set_power)(struct ath_hal*, AR5K_POWER_MODE mode,
\
+ AR5K_BOOL set_chip, u_int16_t sleep_duration);
\
+ _t AR5K_POWER_MODE (_a _n##_get_power_mode)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_query_pspoll_support)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_init_pspoll)(struct ath_hal*);
\
+ _t AR5K_BOOL (_a _n##_enable_pspoll)(struct ath_hal *, u_int8_t *,
u_int16_t); \
+ _t AR5K_BOOL (_a _n##_disable_pspoll)(struct ath_hal *);
\
+ /* Beacon Management Functions */
\
+ _t void (_a _n##_init_beacon)(struct ath_hal *, u_int32_t nexttbtt,
u_int32_t intval); \
+ _t void (_a _n##_set_beacon_timers)(struct ath_hal *, const
AR5K_BEACON_STATE *); \
+ _t void (_a _n##_reset_beacon)(struct ath_hal *);
\
+ _t AR5K_BOOL (_a _n##_wait_for_beacon)(struct ath_hal *,
AR5K_BUS_ADDR); \
+ /* Interrupt functions */
\
+ _t AR5K_BOOL (_a _n##_is_intr_pending)(struct ath_hal *);
\
+ _t AR5K_BOOL (_a _n##_get_isr)(struct ath_hal *, u_int32_t *);
\
+ _t u_int32_t (_a _n##_get_intr)(struct ath_hal *);
\
+ _t AR5K_INT (_a _n##_set_intr)(struct ath_hal *, AR5K_INT);
\
+ /* Chipset functions (ar5k-specific, non-HAL) */
\
+ _t AR5K_BOOL (_a _n##_get_capabilities)(struct ath_hal *);
\
+ _t void (_a _n##_radar_alert)(struct ath_hal *, AR5K_BOOL enable);
\
+ _t AR5K_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); \
+ /* Functions not found in OpenBSD */
\
+ _t AR5K_BOOL (_a _n##_get_tx_queueprops)(struct ath_hal *, int,
AR5K_TXQ_INFO *); \
+ _t AR5K_STATUS (_a _n##_get_capability)(struct ath_hal *,
AR5K_CAPABILITY_TYPE, \
+ u_int32_t, u_int32_t *);
\
+ _t u_int32_t (_a _n##_num_tx_pending)(struct ath_hal *, u_int);
\
+ _t AR5K_BOOL (_a _n##_phy_disable)(struct ath_hal *);
\
+ _t void (_a _n##_set_pcu_config)(struct ath_hal *);
\
+ _t AR5K_BOOL (_a _n##_set_txpower_limit)(struct ath_hal *, u_int);
\
+ _t void (_a _n##_set_def_antenna)(struct ath_hal *, u_int);
\
+ _t u_int (_a _n ##_get_def_antenna)(struct ath_hal *);
\
+ _t AR5K_BOOL (_a _n ##_set_bssid_mask)(struct ath_hal *, const
u_int8_t*); \
+ /*Totaly unimplemented*/
\
+ _t AR5K_BOOL (_a _n##_set_capability)(struct ath_hal *,
AR5K_CAPABILITY_TYPE, u_int32_t,\
+ u_int32_t,AR5K_STATUS *) ;
\
+ _t void (_a _n##_proc_mib_event)(struct ath_hal *, const
AR5K_NODE_STATS *) ; \
+ _t void (_a _n##_get_tx_inter_queue)(struct ath_hal *, u_int32_t *);
+
+
+#define AR5K_MAX_GPIO 10
+#define AR5K_MAX_RF_BANKS 8
+
+struct ath_hal {
+ u_int32_t ah_magic;
+ u_int16_t ah_device;
+ u_int16_t ah_sub_vendor;
+
+ AR5K_SOFTC ah_sc;
+ bus_space_tag_t ah_st;
+ bus_space_handle_t ah_sh;
+ AR5K_CTRY_CODE ah_country_code;
+
+ AR5K_INT ah_imr;
+
+ AR5K_OPMODE ah_op_mode;
+ AR5K_POWER_MODE ah_power_mode;
+ AR5K_CHANNEL ah_current_channel;
+ AR5K_BOOL ah_turbo;
+ AR5K_BOOL ah_calibration;
+ AR5K_BOOL ah_running;
+ AR5K_BOOL ah_single_chip;
+ AR5K_RFGAIN ah_rf_gain;
+
+ AR5K_RATE_TABLE ah_rt_11a;
+ AR5K_RATE_TABLE ah_rt_11b;
+ AR5K_RATE_TABLE ah_rt_11g;
+ AR5K_RATE_TABLE ah_rt_turbo;
+ AR5K_RATE_TABLE ah_rt_xr;
+
+ u_int32_t ah_mac_srev;
+ u_int16_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;
+
+ enum ath5k_version ah_version;
+ enum ath5k_radio ah_radio;
+ u_int32_t ah_phy;
+
+ AR5K_BOOL ah_5ghz;
+ AR5K_BOOL ah_2ghz;
+
+#define ah_regdomain ah_capabilities.cap_regdomain.reg_current
+#define ah_regdomain_hw ah_capabilities.cap_regdomain.reg_hw
+#define ah_modes ah_capabilities.cap_mode
+#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
+
+ u_int32_t ah_atim_window;
+ u_int32_t ah_aifs;
+ u_int32_t ah_cw_min;
+ u_int32_t ah_cw_max;
+ AR5K_BOOL ah_software_retry;
+ u_int32_t ah_limit_tx_retries;
+
+ u_int32_t ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
+ AR5K_BOOL ah_ant_diversity;
+
+ 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];
+ int ah_gpio_npins;
+
+ ath5k_capabilities_t ah_capabilities;
+
+ AR5K_TXQ_INFO ah_txq[AR5K_NUM_TX_QUEUES];
+ u_int32_t ah_txq_interrupts;
+
+ u_int32_t *ah_rf_banks;
+ size_t ah_rf_banks_size;
+ struct ath5k_gain ah_gain;
+ u_int32_t ah_offset[AR5K_MAX_RF_BANKS];
+
+ struct {
+ u_int16_t txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE];
+ u_int16_t txp_rates[AR5K_MAX_RATES];
+ int16_t txp_min, txp_max;
+ AR5K_BOOL txp_tpc;
+ int16_t txp_ofdm;
+ } ah_txpower;
+
+ struct {
+ AR5K_BOOL r_enabled;
+ int r_last_alert;
+ AR5K_CHANNEL r_last_channel;
+ } ah_radar;
+
+ /*
+ * Function pointers
+ */
+ AR5K_HAL_FUNCTIONS(, ah, *)
+
+};
+
+/*
+ * Prototypes
+ */
+
+const char *ath_hal_probe(u_int16_t, u_int16_t);
+struct ath_hal *ath5k_hw_init(u_int16_t device, AR5K_SOFTC sc,
AR5K_BUS_TAG,
+ AR5K_BUS_HANDLE, AR5K_STATUS *);
+u_int16_t ath_hal_computetxtime(struct ath_hal *, const
AR5K_RATE_TABLE *,
+ u_int32_t, u_int16_t, AR5K_BOOL);
+u_int ath_hal_mhz2ieee(u_int, u_int);
+u_int ath_hal_ieee2mhz(u_int, u_int);
+AR5K_BOOL ath_hal_init_channels(struct ath_hal *, AR5K_CHANNEL *,
+ u_int, u_int *, AR5K_CTRY_CODE,
u_int16_t,
+ AR5K_BOOL, AR5K_BOOL);
+const char *ath5k_printver(enum ath5k_srev_type, u_int32_t);
+void ath5k_radar_alert(struct ath_hal *);
+ieee80211_regdomain_t ath5k_regdomain_to_ieee(u_int16_t);
+u_int16_t ath5k_regdomain_from_ieee(ieee80211_regdomain_t);
+u_int16_t ath5k_get_regdomain(struct ath_hal *);
+u_int32_t ath5k_bitswap(u_int32_t, u_int);
+inline u_int ath5k_clocktoh(u_int, AR5K_BOOL);
+inline u_int ath5k_htoclock(u_int, AR5K_BOOL);
+void ath5k_rt_copy(AR5K_RATE_TABLE *, const AR5K_RATE_TABLE
*);
+AR5K_BOOL ath5k_register_timeout(struct ath_hal *, u_int32_t,
u_int32_t,
+ u_int32_t, AR5K_BOOL);
+int ath5k_eeprom_init(struct ath_hal *);
+int ath5k_eeprom_read_mac(struct ath_hal *, u_int8_t *);
+AR5K_BOOL ath5k_eeprom_regulation_domain(struct ath_hal *,
AR5K_BOOL,
+ ieee80211_regdomain_t *);
+int ath5k_eeprom_read_ants(struct ath_hal *, u_int32_t *,
u_int);
+int ath5k_eeprom_read_modes(struct ath_hal *, u_int32_t *,
u_int);
+u_int16_t ath5k_eeprom_bin2freq(struct ath_hal *, u_int16_t,
u_int);
+
+AR5K_BOOL ath5k_channel(struct ath_hal *, AR5K_CHANNEL *);
+AR5K_BOOL ath5k_ar5110_channel(struct ath_hal *, AR5K_CHANNEL *);
+u_int32_t ath5k_ar5110_chan2athchan(AR5K_CHANNEL *);
+AR5K_BOOL ath5k_ar5111_channel(struct ath_hal *, AR5K_CHANNEL *);
+AR5K_BOOL ath5k_ar5111_chan2athchan(u_int, struct
ath5k_athchan_2ghz *);
+AR5K_BOOL ath5k_ar5112_channel(struct ath_hal *, AR5K_CHANNEL *);
+AR5K_BOOL ath5k_check_channel(struct ath_hal *, u_int16_t, u_int
flags);
+
+AR5K_BOOL ath5k_rfregs(struct ath_hal *, AR5K_CHANNEL *, u_int);
+AR5K_BOOL ath5k_ar5111_rfregs(struct ath_hal *, AR5K_CHANNEL *,
u_int);
+AR5K_BOOL ath5k_ar5112_rfregs(struct ath_hal *, AR5K_CHANNEL *,
u_int);
+void ath5k_ar5211_rfregs(struct ath_hal *, AR5K_CHANNEL *,
u_int, u_int);
+u_int ath5k_rfregs_op(u_int32_t *, u_int32_t, u_int32_t,
u_int32_t,
+ u_int32_t, u_int32_t, AR5K_BOOL);
+u_int32_t ath5k_rfregs_gainf_corr(struct ath_hal *);
+AR5K_BOOL ath5k_rfregs_gain_readback(struct ath_hal *);
+int32_t ath5k_rfregs_gain_adjust(struct ath_hal *);
+AR5K_BOOL ath5k_rfgain(struct ath_hal *, u_int, u_int);
+void ath5k_txpower_table(struct ath_hal *, AR5K_CHANNEL *,
int16_t);
+
+/*added*/
+extern u_int ath_hal_getwirelessmodes(struct ath_hal*, AR5K_CTRY_CODE);
+void ath_hal_detach(struct ath_hal *ah);
+struct ath_hal * _ath_hal_attach(u_int16_t devid, AR5K_SOFTC sc, AR5K_BUS_TAG
t,
+ AR5K_BUS_HANDLE h, void* s);
+#endif /* _AR5K_H */
Added: branches/madwifi-old-openhal/openhal/ath5k_hw.c
===================================================================
--- branches/madwifi-old-openhal/openhal/ath5k_hw.c
(rev 0)
+++ branches/madwifi-old-openhal/openhal/ath5k_hw.c 2007-03-27 17:29:30 UTC
(rev 2232)
@@ -0,0 +1,5873 @@
+/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@xxxxxxxxxxx>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@xxxxxxxxx>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+/*
+ * HAL interface for Atheros Wireless LAN devices.
+ * (Please have a look at ar5xxx.h for further information)
+ */
+
+#include "ah_devid.h"
+#include "ath5k.h"
+#include "ath5kreg.h"
+
+/*
+ * Known pci ids
+ */
+
+static const struct {
+ u_int16_t vendor;
+ u_int16_t device;
+ u_int8_t mac_version;
+} ath5k_known_products[] = {
+ /*
+ * From pcidevs_data.h
+ */
+ /* 5210 is not supported yet
+ { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210,AR5K_AR5210},
+ { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210_AP,AR5K_AR5210},
+ { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5210_DEFAULT,AR5K_AR5210},*/
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5211, AR5K_AR5211},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5211_DEFAULT,AR5K_AR5211},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5311, AR5K_AR5211},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5211_FPGA11B,AR5K_AR5211},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5211_LEGACY, AR5K_AR5211},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_DEFAULT,AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_FPGA, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_IBM, AR5K_AR5212},
+ { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRDAG675, AR5K_AR5212},
+ { PCI_VENDOR_3COM2, PCI_PRODUCT_3COM2_3CRPAG175, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_REV2, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_REV7, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_REV8, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_0014, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_0015, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_0016, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_0017, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_0018, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5212_0019, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR2413, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5413, AR5K_AR5212},
+ { PCI_VENDOR_ATHEROS,PCI_PRODUCT_ATHEROS_AR5424, AR5K_AR5212},
+};
+
+/*Rate tables*/
+static const AR5K_RATE_TABLE ath5k_rt_11a = AR5K_RATES_11A;
+static const AR5K_RATE_TABLE ath5k_rt_11b = AR5K_RATES_11B;
+static const AR5K_RATE_TABLE ath5k_rt_11g = AR5K_RATES_11G;
+static const AR5K_RATE_TABLE ath5k_rt_turbo = AR5K_RATES_TURBO;
+static const AR5K_RATE_TABLE ath5k_rt_xr = AR5K_RATES_XR;
+
+/*Prototypes*/
+AR5K_BOOL ath5k_hw_nic_reset(struct ath_hal *, u_int32_t);
+AR5K_BOOL ath5k_hw_nic_wakeup(struct ath_hal *, u_int16_t);
+u_int16_t ath5k_hw_radio_revision(struct ath_hal *, AR5K_CHIP);
+void ath5k_hw_fill(struct ath_hal *);
+AR5K_BOOL ath5k_hw_txpower(struct ath_hal *, AR5K_CHANNEL *, u_int);
+
+AR5K_HAL_FUNCTIONS(extern, ath5k_hw,);
+
+/*
+ * Supported channels
+ */
+static const struct
+ieee80211_regchannel ath5k_5ghz_channels[] = IEEE80211_CHANNELS_5GHZ;
+static const struct
+ieee80211_regchannel ath5k_2ghz_channels[] = IEEE80211_CHANNELS_2GHZ;
+
+/*
+ * Initial register dumps
+ */
+static const struct ath5k_ar5212_ini ar5212_ini[] = AR5K_AR5212_INI;
+static const struct ath5k_ar5212_ini_mode ar5212_mode[] = AR5K_AR5212_INI_MODE;
+static const struct ath5k_ini ar5211_ini[] = AR5K_AR5211_INI;
+static const struct ath5k_ar5211_ini_mode ar5211_mode[] = AR5K_AR5211_INI_MODE;
+static const struct ath5k_ar5211_ini_rf ar5211_rf[] = AR5K_AR5211_INI_RF;
+
+/*
+ * Initial gain optimization values
+ */
+static const struct ath5k_gain_opt ar5111_gain_opt = AR5K_AR5111_GAIN_OPT;
+static const struct ath5k_gain_opt ar5112_gain_opt = AR5K_AR5112_GAIN_OPT;
+
+/*
+ * Initial register for the radio chipsets
+ */
+static const struct ath5k_ini_rf ar5111_rf[] = AR5K_AR5111_INI_RF;
+static const struct ath5k_ini_rf ar5112_rf[] = AR5K_AR5112_INI_RF;
+static const struct ath5k_ini_rf ar5112a_rf[] = AR5K_AR5112A_INI_RF;
+static const struct ath5k_ini_rfgain ath5k_rfg[] = AR5K_INI_RFGAIN;
+
+/*
+ * Enable to overwrite the country code (use "00" for debug)
+ */
+#if 0
+#define COUNTRYCODE "00"
+#endif
+
+/*******************\
+ General Functions
+\*******************/
+
+/*
+ * Perform a lookup if the device is supported by the HAL
+ * and return the chip name.
+ * TODO:Left here for combatibility, change it in at5k
+ */
+const char *
+ath_hal_probe(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(ath5k_known_products); i++) {
+ if (vendor == ath5k_known_products[i].vendor &&
+ device == ath5k_known_products[i].device){
+ switch (ath5k_known_products[i].mac_version) {
+ case AR5K_AR5210:
+ return("AR5210");
+ case AR5K_AR5211:
+ return("AR5211");
+ case AR5K_AR5212:
+ return("AR5212");
+ default:
+ return ("");
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Calculate transmition time of a frame
+ * TODO:Left here for combatibility, change it in at5k
+ */
+u_int16_t /*TODO: Is this realy hardware dependent ?*/
+ath_hal_computetxtime(struct ath_hal *hal, const AR5K_RATE_TABLE *rates,
+ u_int32_t frame_length, u_int16_t rate_index, AR5K_BOOL short_preamble)
+{
+ const AR5K_RATE *rate;
+ u_int32_t value;
+
+ AR5K_ASSERT_ENTRY(rate_index, rates->rate_count);
+
+ /*
+ * Get rate by index
+ */
+ rate = &rates->rates[rate_index];
+
+ /*
+ * Calculate the transmission time by operation (PHY) mode
+ */
+ switch (rate->modulation) {
+ case MODULATION_CCK:
+ /*
+ * CCK / DS mode (802.11b)
+ */
+ value = AR5K_CCK_TX_TIME(rate->rate_kbps, frame_length,
+ (short_preamble && (rate->modulation ==
MODULATION_CCK_SP)));
+ break;
+
+ case MODULATION_OFDM:
+ /*
+ * Orthogonal Frequency Division Multiplexing
+ */
+ if (AR5K_OFDM_NUM_BITS_PER_SYM(rate->rate_kbps) == 0)
+ return (0);
+ value = AR5K_OFDM_TX_TIME(rate->rate_kbps, frame_length);
+ break;
+
+ case MODULATION_TURBO:
+ /*
+ * Orthogonal Frequency Division Multiplexing
+ * Atheros "Turbo Mode" (doubled rates)
+ */
+ if (AR5K_TURBO_NUM_BITS_PER_SYM(rate->rate_kbps) == 0)
+ return (0);
+ value = AR5K_TURBO_TX_TIME(rate->rate_kbps, frame_length);
+ break;
+
+ case MODULATION_XR:
+ /*
+ * Orthogonal Frequency Division Multiplexing
+ * Atheros "eXtended Range" (XR)
+ */
+ if (AR5K_XR_NUM_BITS_PER_SYM(rate->rate_kbps) == 0)
+ return (0);
+ value = AR5K_XR_TX_TIME(rate->rate_kbps, frame_length);
+ break;
+
+ default:
+ return (0);
+ }
+
+ return (value);
+}
+
+/*
+ * Return the supported 802.11 operation modes
+ * TODO:Left here for combatibility, change it in at5k
+ */
+u_int/*TODO:Fix this & fix g support*/
+ath_hal_getwirelessmodes(struct ath_hal *hal, AR5K_CTRY_CODE country)
+{
+ switch(hal->ah_version){
+ case AR5K_AR5212:
+ return (AR5K_MODE_11A|AR5K_MODE_11B);
+ case AR5K_AR5211:
+ return (AR5K_MODE_11A|AR5K_MODE_11B);
+ default :
+ return(AR5K_MODE_11A);
+ }
+}
+
+/*
+ * Functions used internaly
+ */
+
+u_int32_t
+ath5k_hw_bitswap(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);
+}
+
+inline u_int
+ath5k_hw_htoclock(u_int usec, AR5K_BOOL turbo)
+{
+ return (turbo == TRUE ? (usec * 80) : (usec * 40));
+}
+
+inline u_int
+ath5k_hw_clocktoh(u_int clock, AR5K_BOOL turbo)
+{
+ return (turbo == TRUE ? (clock / 80) : (clock / 40));
+}
+
+/*
+ * Copy a rate table to a new one
+ */
+inline void
+ath5k_hw_rtcopy(AR5K_RATE_TABLE *dst, const AR5K_RATE_TABLE *src)
+{
+ bzero(dst, sizeof(AR5K_RATE_TABLE));
+ dst->rate_count = src->rate_count;
+ bcopy(src->rates, dst->rates, sizeof(dst->rates));
+}
+
+/*
+ * Read from a device register
+ */
+static inline u32 ath5k_hw_reg_read(struct ath_hal *hal, u16 reg)
+{
+ return readl(hal->ah_sh + reg);
+}
+
+/*
+ * Write to a device register
+ */
+static inline void ath5k_hw_reg_write(struct ath_hal *hal, u32 val, u16 reg)
+{
+ writel(val, hal->ah_sh + reg);
+}
+
+/*
+ * Check if a register write has been completed
+ */
+AR5K_BOOL
+ath5k_hw_register_timeout(struct ath_hal *hal, u_int32_t reg, u_int32_t flag,
+ u_int32_t val, AR5K_BOOL is_set)
+{
+ int i;
+ u_int32_t data;
+
+ for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+ data = AR5K_REG_READ(reg);
+ if ((is_set == TRUE) && (data & flag))
+ break;
+ else if ((data & flag) == val)
+ break;
+ AR5K_DELAY(15);
+ }
+
+ if (i <= 0)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+
+
+/***************************************\
+ Attach/Detach Functions
+\***************************************/
+
+/*
+ * Check if the device is supported and initialize the needed structs
+ */
+struct ath_hal *
+ath5k_hw_init(u_int16_t device, AR5K_SOFTC sc, AR5K_BUS_TAG st,
+ AR5K_BUS_HANDLE sh, AR5K_STATUS *status)
+{
+ struct ath_hal *hal = NULL;
+ u_int8_t mac[IEEE80211_ADDR_LEN];
+ u_int8_t mac_version = 255; /*Initialize this to something else than
ath5k_version*/
+ int i;
+ u_int32_t srev;
+ *status = AR5K_EINVAL;
+
+ /*TODO:Use eeprom_magic to verify chipset*/
+
+ /*
+ * Check if device is a known one
+ */
+ for (i = 0; i < AR5K_ELEMENTS(ath5k_known_products); i++) {
+ if (device == ath5k_known_products[i].device)
+ mac_version = ath5k_known_products[i].mac_version;
+ }
+
+ /*If there wasn't a match, the device is not supported*/
+ if (mac_version == 255) {
+ *status = AR5K_ENOTSUPP;
+ AR5K_PRINTF("device not supported: 0x%04x\n", device);
+ return (NULL);
+ }
+
+ /*If we passed the test malloc a hal struct*/
+ if ((hal = malloc(sizeof(struct ath_hal),
+ M_DEVBUF, M_NOWAIT)) == NULL) {
+ *status = AR5K_ENOMEM;
+ AR5K_PRINT("out of memory\n");
+ return (NULL);
+ }
+
+ /*Initialize it*/
+ 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
+ */
+
+ /* Regulation Stuff */
+ hal->ah_country_code = AR5K_TUNE_CTRY;
+ ath5k_get_regdomain(hal);
+
+ hal->ah_op_mode = AR5K_M_STA;
+ hal->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
+ hal->ah_turbo = FALSE;
+ hal->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
+ 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 = FALSE;
+ hal->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
+
+ switch (device) {
+ case PCI_PRODUCT_ATHEROS_AR2413:
+ case PCI_PRODUCT_ATHEROS_AR5413:
+ case PCI_PRODUCT_ATHEROS_AR5424:
+ /*
+ * Known single chip solutions
+ */
+ hal->ah_single_chip = TRUE;
+ break;
+ default:
+ /*
+ * Multi chip solutions
+ */
+ hal->ah_single_chip = FALSE;
+ break;
+ }
+
+ /*
+ * Set the mac revision based on the pci id
+ */
+ hal->ah_version = mac_version;
+
+ /*Fill the hal struct with the needed functions*/
+ ath5k_hw_fill(hal);
+
+ /* Bring device out of sleep and reset it's units */
+ if (ath5k_hw_nic_wakeup(hal, AR5K_INIT_MODE) != TRUE)
+ goto failed;
+
+ /* Get MAC, PHY and RADIO revisions */
+ srev = AR5K_REG_READ(AR5K_SREV);
+ hal->ah_mac_srev = srev;
+ hal->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+ hal->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
+ hal->ah_phy_revision = AR5K_REG_READ(AR5K_PHY_CHIP_ID) &
+ 0x00ffffffff;
+ hal->ah_radio_5ghz_revision =
+ ath5k_hw_radio_revision(hal, AR5K_CHIP_5GHZ);
+ hal->ah_radio_2ghz_revision =
+ ath5k_hw_radio_revision(hal, AR5K_CHIP_2GHZ);
+
+ /* Single chip radio */
+ if (hal->ah_radio_2ghz_revision == hal->ah_radio_5ghz_revision)
+ hal->ah_radio_2ghz_revision = 0;
+
+ /* Identify the radio chip*/
+ hal->ah_radio = hal->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112 ?
+ AR5K_AR5111 : AR5K_AR5112;
+
+ hal->ah_phy = AR5K_PHY(0);
+
+ /*Is this bcopy O.K. ?*/
+ bcopy(etherbroadcastaddr, mac, IEEE80211_ADDR_LEN);
+
+ ath5k_hw_set_associd(hal, mac, 0);
+ ath5k_hw_get_lladdr(hal, mac);
+ ath5k_hw_set_opmode(hal);
+
+#ifdef AR5K_DEBUG
+ hal->ah_dump_state(hal);
+#endif
+
+ /*
+ * Get card capabilities, values, ...
+ */
+
+ if (ath5k_eeprom_init(hal) != 0) {
+ *status = AR5K_EELOCKED;
+ AR5K_PRINT("unable to init EEPROM\n");
+ goto failed;
+ }
+
+ /* Get misc capabilities */
+ if (hal->ah_get_capabilities(hal) != TRUE) {
+ *status = AR5K_EEREAD;
+ AR5K_PRINTF("unable to get device capabilities: 0x%04x\n",
+ device);
+ goto failed;
+ }
+
+ /* Get MAC address */
+ if ((*status = ath5k_eeprom_read_mac(hal, mac)) != 0) {
+ *status = AR5K_EEBADMAC;
+ AR5K_PRINTF("unable to read address from EEPROM: 0x%04x\n",
+ device);
+ goto failed;
+ }
+
+ hal->ah_set_lladdr(hal, mac);
+
+ /* Get rate tables */
+ if (hal->ah_capabilities.cap_mode & AR5K_MODE_11A)
+ ath5k_hw_rtcopy(&hal->ah_rt_11a, &ath5k_rt_11a);
+ if (hal->ah_capabilities.cap_mode & AR5K_MODE_11B)
+ ath5k_hw_rtcopy(&hal->ah_rt_11b, &ath5k_rt_11b);
+ if (hal->ah_capabilities.cap_mode & AR5K_MODE_11G)
+ ath5k_hw_rtcopy(&hal->ah_rt_11g, &ath5k_rt_11g);
+ if (hal->ah_capabilities.cap_mode & AR5K_MODE_TURBO)
+ ath5k_hw_rtcopy(&hal->ah_rt_turbo, &ath5k_rt_turbo);
+ if (hal->ah_capabilities.cap_mode & AR5K_MODE_XR)
+ ath5k_hw_rtcopy(&hal->ah_rt_xr, &ath5k_rt_xr);
+
+ /* Initialize the gain optimization values */
+ /*For RF5111*/
+ if (hal->ah_radio == AR5K_AR5111) {
+ hal->ah_gain.g_step_idx = ar5111_gain_opt.go_default;
+ hal->ah_gain.g_step =
+ &ar5111_gain_opt.go_step[hal->ah_gain.g_step_idx];
+ hal->ah_gain.g_low = 20;
+ hal->ah_gain.g_high = 35;
+ hal->ah_gain.g_active = 1;
+ /*For RF5112*/
+ } else if (hal->ah_radio == AR5K_AR5112) {
+ hal->ah_gain.g_step_idx = ar5112_gain_opt.go_default;
+ hal->ah_gain.g_step =
+ &ar5111_gain_opt.go_step[hal->ah_gain.g_step_idx];
+ hal->ah_gain.g_low = 20;
+ hal->ah_gain.g_high = 85;
+ hal->ah_gain.g_active = 1;
+ }
+
+ *status = AR5K_OK;
+
+ return (hal);
+
+ failed:
+ free(hal, M_DEVBUF);
+ return (NULL);
+}
+
+/*
+ * Bring up MAC + PHY Chips
+ */
+AR5K_BOOL
+ath5k_hw_nic_wakeup(struct ath_hal *hal, u_int16_t flags)
+{
+ u_int32_t turbo, mode, clock;
+
+ turbo = 0;
+ mode = 0;
+ clock = 0;
+
+ AR5K_TRACE;
+
+ /*
+ * Get channel mode flags
+ */
+
+ if (hal->ah_radio >= AR5K_AR5112) {
+ mode = AR5K_PHY_MODE_RAD_AR5112;
+ clock = AR5K_PHY_PLL_AR5112;
+ } else {
+ mode = AR5K_PHY_MODE_RAD_AR5111; /*Zero -backwards
combatible*/
+ clock = AR5K_PHY_PLL_AR5111; /*Zero -backwards
combatible*/
+ }
+
+ if (flags & CHANNEL_2GHZ) {
+ mode |= AR5K_PHY_MODE_FREQ_2GHZ;
+ clock |= AR5K_PHY_PLL_44MHZ;
+ } else if (flags & CHANNEL_5GHZ) {
+ mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+ clock |= AR5K_PHY_PLL_40MHZ;
+ } else {
+ AR5K_PRINT("invalid radio frequency mode\n");
+ return (FALSE);
+ }
+
+ if (flags & CHANNEL_CCK) {
+ mode |= AR5K_PHY_MODE_MOD_CCK;
+ } else if (flags & CHANNEL_OFDM) {
+ mode |= AR5K_PHY_MODE_MOD_OFDM;
+ } else if (flags & CHANNEL_DYN) {
+ /* Dynamic OFDM/CCK is not supported by the AR5211 */
+ if (hal->ah_version == AR5K_AR5211){
+ mode |= AR5K_PHY_MODE_MOD_CCK;
+ }else{
+ mode |= AR5K_PHY_MODE_MOD_DYN;
+ }
+ } else {
+ AR5K_PRINT("invalid radio frequency mode\n");
+ return (FALSE);
+ }
+
+ if (flags & CHANNEL_TURBO) {
+ turbo = AR5K_PHY_TURBO_MODE |
+ AR5K_PHY_TURBO_SHORT;
+ }
+
+ /*
+ * Reset and wakeup the device
+ */
+
+ /* ...reset chipset and PCI device */
+ if (hal->ah_single_chip == FALSE &&
+ ath5k_hw_nic_reset(hal,AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI) ==
FALSE) {
+ AR5K_PRINT("failed to reset the MAC + PCI Chipset\n");
+ return (FALSE);
+ }
+
+ /* ...wakeup */
+ if (ath5k_hw_set_power(hal,
+ AR5K_PM_AWAKE, TRUE, 0) == FALSE) {
+ AR5K_PRINT("failed to resume the MAC Chip (again)\n");
+ return (FALSE);
+ }
+
+ /* ...final warm reset */
+ if (ath5k_hw_nic_reset(hal, 0) == FALSE) {
+ AR5K_PRINT("failed to warm reset the MAC Chip\n");
+ return (FALSE);
+ }
+
+ /* ...set the PHY operating mode */
+ AR5K_REG_WRITE(AR5K_PHY_PLL, clock);
+ AR5K_DELAY(300);
+
+ AR5K_REG_WRITE(AR5K_PHY_MODE, mode);
+ AR5K_REG_WRITE(AR5K_PHY_TURBO, turbo);
+
+ return (TRUE);
+}
+
+/*
+ * Get the PHY Chip revision
+ */
+u_int16_t
+ath5k_hw_radio_revision(struct ath_hal *hal, AR5K_CHIP chip)
+{
+ int i;
+ u_int32_t srev;
+ u_int16_t ret;
+
+ AR5K_TRACE;
+
+ /*
+ * Set the radio chip access register
+ */
+ switch (chip) {
+ case AR5K_CHIP_2GHZ:
+ AR5K_REG_WRITE(AR5K_PHY(0), AR5K_PHY_SHIFT_2GHZ);
+ break;
+ case AR5K_CHIP_5GHZ:
+ AR5K_REG_WRITE(AR5K_PHY(0), AR5K_PHY_SHIFT_5GHZ);
+ break;
+ default:
+ return (0);
+ }
+
+ AR5K_DELAY(2000);
+
+ /* ...wait until PHY is ready and read the selected radio revision */
+ AR5K_REG_WRITE(AR5K_PHY(0x34), 0x00001c16);
+
+ for (i = 0; i < 8; i++)
+ AR5K_REG_WRITE(AR5K_PHY(0x20), 0x00010000);
+ srev = (AR5K_REG_READ(AR5K_PHY(0x100)) >> 24) & 0xff;
+
+ ret = ath5k_hw_bitswap(((srev & 0xf0) >> 4) | ((srev & 0x0f) << 4), 8);
+
+ /* Reset to the 5GHz mode */
+ AR5K_REG_WRITE(AR5K_PHY(0), AR5K_PHY_SHIFT_5GHZ);
+
+ return (ret);
+}
+
+/*
+ * Get the rate table for a specific operation mode
+ */
+const AR5K_RATE_TABLE *
+ath5k_hw_get_rate_table(struct ath_hal *hal, u_int mode)
+{
+
+ AR5K_TRACE;
+
+ switch (mode) {
+ case AR5K_MODE_11A:
+ return (&hal->ah_rt_11a);
+ case AR5K_MODE_TURBO:
+ return (&hal->ah_rt_turbo);
+ case AR5K_MODE_11B:
+ return (&hal->ah_rt_11b);
+ case AR5K_MODE_11G:
+ return (&hal->ah_rt_11g);
+ case AR5K_MODE_XR:
+ return (&hal->ah_rt_xr);
+ default:
+ return (NULL);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Free the hal struct
+ */
+void
+ath5k_hw_detach(struct ath_hal *hal)
+{
+ AR5K_TRACE;
+
+ if (hal->ah_rf_banks != NULL)
+ free(hal->ah_rf_banks, M_DEVBUF);
+
+ /*
+ * Free HAL structure, assume interrupts are down
+ */
+ free(hal, M_DEVBUF);
+}
+
+
+
+
+/*******************************\
+ Reset Functions
+\*******************************/
+
+/*
+ * Main reset function
+ */
+AR5K_BOOL
+ath5k_hw_reset(struct ath_hal *hal, AR5K_OPMODE op_mode, AR5K_CHANNEL *channel,
+ AR5K_BOOL change_channel, AR5K_STATUS *status)
+{
+ struct ath5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
+ u_int8_t mac[IEEE80211_ADDR_LEN];
+ u_int32_t data, s_seq, s_ant, s_led[3];
+ u_int i, phy, mode, freq, off, ee_mode, ant[2];
+ const AR5K_RATE_TABLE *rt;
+
+ AR5K_TRACE;
+
+ *status = AR5K_OK;
+
+ /*
+ * Save some registers before a reset
+ */
+ if (change_channel == TRUE) {
+ /*Sequence number for queue 0 -do this for all queues ?*/
+ s_seq = AR5K_REG_READ(AR5K_QUEUE_DFS_SEQNUM(0));
+ /*Default antenna*/
+ s_ant = AR5K_REG_READ(AR5K_DEFAULT_ANTENNA);
+ } else {
+ s_seq = 0;
+ s_ant = 1;
+ }
+
+ /*GPIOs*/
+ s_led[0] = AR5K_REG_READ(AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE;
+ s_led[1] = AR5K_REG_READ(AR5K_GPIOCR);
+ s_led[2] = AR5K_REG_READ(AR5K_GPIODO);
+
+ if (change_channel == TRUE && hal->ah_rf_banks != NULL)
+ ath5k_hw_get_rf_gain(hal);
+
+ if (ath5k_hw_nic_wakeup(hal, channel->channel_flags) == FALSE) {
+ *status = AR5K_EIO;
+ return (FALSE);
+ }
+
+ /*
+ * Initialize operating mode
+ */
+ hal->ah_op_mode = op_mode;
+
+ if (hal->ah_radio == AR5K_AR5111) {
+ phy = AR5K_INI_PHY_5111;
+ } else if (hal->ah_radio == AR5K_AR5112) {
+ phy = AR5K_INI_PHY_5112;
+ } else {
+ AR5K_PRINTF("invalid phy radio: %u\n", hal->ah_radio);
+ *status = AR5K_EINVAL;
+ return (FALSE);
+ }
+
+ switch (channel->channel_flags & CHANNEL_MODES) {
+ case CHANNEL_A:
+ mode = AR5K_INI_VAL_11A;
+ freq = AR5K_INI_RFGAIN_5GHZ;
+ ee_mode = AR5K_EEPROM_MODE_11A;
+ break;
+ case CHANNEL_B:
+ mode = AR5K_INI_VAL_11B;
+ freq = AR5K_INI_RFGAIN_2GHZ;
+ ee_mode = AR5K_EEPROM_MODE_11B;
+ break;
+ case CHANNEL_G:
+ mode = AR5K_INI_VAL_11G;
+ freq = AR5K_INI_RFGAIN_2GHZ;
+ ee_mode = AR5K_EEPROM_MODE_11G;
+ break;
+ case CHANNEL_T:
+ mode = AR5K_INI_VAL_11A_TURBO;
+ freq = AR5K_INI_RFGAIN_5GHZ;
+ ee_mode = AR5K_EEPROM_MODE_11A;
+ break;
+ /*Is this ok on 5211 too ?*/
+ case CHANNEL_TG:
+ mode = AR5K_INI_VAL_11G_TURBO;
+ freq = AR5K_INI_RFGAIN_2GHZ;
+ ee_mode = AR5K_EEPROM_MODE_11G;
+ break;
+ case CHANNEL_XR:
+ if(hal->ah_version == AR5K_AR5211){
+ AR5K_PRINTF("XR mode not available on 5211");
+ return (FALSE);
+ }
+ mode = AR5K_INI_VAL_XR;
+ freq = AR5K_INI_RFGAIN_5GHZ;
+ ee_mode = AR5K_EEPROM_MODE_11A;
+ break;
+ default:
+ AR5K_PRINTF("invalid channel: %d\n", channel->freq);
+ *status = AR5K_EINVAL;
+ return (FALSE);
+ }
+
+ /* PHY access enable */
+ AR5K_REG_WRITE(AR5K_PHY(0), AR5K_PHY_SHIFT_5GHZ);
+
+ /*
+ * Write initial RF registers on 5211
+ * do we need that ? Is ath5k_rfregs going to work for 5211 (5111) ?
+ */
+ if(hal->ah_version == AR5K_AR5211){
+ ath5k_ar5211_rfregs(hal, channel, freq, ee_mode);
+ }
+
+ /*
+ * Write initial mode settings
+ * TODO:Clean/merge arrays
+ */
+ /*For 5212*/
+ if(hal->ah_version == AR5K_AR5212){
+ for (i = 0; i < AR5K_ELEMENTS(ar5212_mode); i++) {
+ if (ar5212_mode[i].mode_flags == AR5K_INI_FLAG_511X)
+ off = AR5K_INI_PHY_511X;
+ else if (ar5212_mode[i].mode_flags & AR5K_INI_FLAG_5111
&&
+ hal->ah_radio == AR5K_AR5111)
+ off = AR5K_INI_PHY_5111;
+ else if (ar5212_mode[i].mode_flags & AR5K_INI_FLAG_5112
&&
+ hal->ah_radio == AR5K_AR5112)
+ off = AR5K_INI_PHY_5112;
+ else
+ continue;
+
+ AR5K_REG_WAIT(i);
+ AR5K_REG_WRITE((u_int32_t)ar5212_mode[i].mode_register,
+ ar5212_mode[i].mode_value[off][mode]);
+ }
+ }
+ /*For 5211*/
+ if(hal->ah_version == AR5K_AR5211){
+ for (i = 0; i < AR5K_ELEMENTS(ar5211_mode); i++) {
+ AR5K_REG_WAIT(i);
+ AR5K_REG_WRITE((u_int32_t)ar5211_mode[i].mode_register,
+ ar5211_mode[i].mode_value[mode]);
+ }
+ }
+
+ /*
+ * Write initial register settings
+ * TODO:Clean/merge arrays
+ */
+ /*For 5212*/
+ if(hal->ah_version == AR5K_AR5212){
+ for (i = 0; i < AR5K_ELEMENTS(ar5212_ini); i++) {
+ if (change_channel == TRUE &&
+ ar5212_ini[i].ini_register >= AR5K_PCU_MIN &&
+ ar5212_ini[i].ini_register <= AR5K_PCU_MAX)
+ continue;
+
+ if ((hal->ah_radio == AR5K_AR5111 &&
+ ar5212_ini[i].ini_flags & AR5K_INI_FLAG_5111) ||
+ (hal->ah_radio == AR5K_AR5112 &&
+ ar5212_ini[i].ini_flags & AR5K_INI_FLAG_5112)) {
+ AR5K_REG_WAIT(i);
+
AR5K_REG_WRITE((u_int32_t)ar5212_ini[i].ini_register,
+ ar5212_ini[i].ini_value);
+ }
+ }
+ }
+ /*For 5211*/
+ if(hal->ah_version == AR5K_AR5211){
+ for (i = 0; i < AR5K_ELEMENTS(ar5211_ini); i++) {
+ if (change_channel == TRUE &&
+ ar5211_ini[i].ini_register >= AR5K_PCU_MIN &&
+ ar5211_ini[i].ini_register <= AR5K_PCU_MAX)
+ continue;
+
+ AR5K_REG_WAIT(i);
+ AR5K_REG_WRITE((u_int32_t)ar5211_ini[i].ini_register,
+ ar5211_ini[i].ini_value);
+ }
+ }
+
+ /*
+ * Write initial RF gain settings
+ * This should work for all chipsets
+ */
+ if (ath5k_rfgain(hal, phy, freq) == FALSE) {
+ *status = AR5K_EIO;
+ return (FALSE);
+ }
+
+ AR5K_DELAY(1000);
+
+ /*
+ * Set rate duration table on 5212
+ */
+ if(hal->ah_version == AR5K_AR5212){
+
+ /*For 802.11b*/
+ if (!(channel->channel_flags & CHANNEL_B)) {
+
+ /*Get rate table for this operation mode*/
+ rt = ath5k_hw_get_rate_table(hal, AR5K_MODE_11B);
+
+ /*Write rate duration table*/
+ for (i = 0; i < rt->rate_count; i++) {
+ data = AR5K_RATE_DUR(rt->rates[i].rate_code);
+ AR5K_REG_WRITE(data,
+ ath_hal_computetxtime(hal, rt, 14,
+ rt->rates[i].control_rate, FALSE));
+ if (HAS_SHPREAMBLE(i)) {
+ AR5K_REG_WRITE(data +
+ (AR5K_SET_SHORT_PREAMBLE << 2),
+ ath_hal_computetxtime(hal, rt, 14,
+ rt->rates[i].control_rate, FALSE));
+ }
+ }
+
+ } else {
+ /*For 802.11a/g Turbo/XR mode (AR5K_MODE_XR here is O.K. for
both a/g - OFDM)*/
+
+ /*Get rate table for this operation mode*/
+ rt = ath5k_hw_get_rate_table(hal,
+ channel->channel_flags & CHANNEL_TURBO ?
+ AR5K_MODE_TURBO : AR5K_MODE_XR);
+
+ /*Write rate duration table*/
+ for (i = 0; i < rt->rate_count; i++) {
+
AR5K_REG_WRITE(AR5K_RATE_DUR(rt->rates[i].rate_code),
+ ath_hal_computetxtime(hal, rt, 14,
+ rt->rates[i].control_rate, FALSE));
+ }
+
+ }
+ }
+
+ /* Fix for first revision of the AR5112 RF chipset */
+ if (hal->ah_radio >= AR5K_AR5112 &&
+ hal->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
+ AR5K_REG_WRITE(AR5K_PHY_CCKTXCTL,
+ AR5K_PHY_CCKTXCTL_WORLD);
+ if (channel->channel_flags & CHANNEL_OFDM)
+ data = 0xffb81020;
+ else
+ data = 0xffb80d20;
+ AR5K_REG_WRITE(AR5K_PHY_FRAME_CTL, data);
+ }
+
+ /*
+ * Set TX power (XXX use txpower from net80211)
+ */
+ if (ath5k_hw_txpower(hal, channel,
+ AR5K_TUNE_DEFAULT_TXPOWER) == FALSE) {
+ *status = AR5K_EIO;
+ return (FALSE);
+ }
+
+ /*
+ * Write RF registers
+ * TODO:Does this work on 5211 (5111) ?
+ */
+ if (ath5k_rfregs(hal, channel, mode) == FALSE) {
+ *status = AR5K_EINPROGRESS;
+ return (FALSE);
+ }
+
+ /*
+ * Configure additional registers
+ */
+
+ /* Write OFDM timings on 5212*/
+ if(hal->ah_version == AR5K_AR5212){
+ if (channel->channel_flags & CHANNEL_OFDM) {
+ u_int32_t coef_scaled, coef_exp, coef_man, ds_coef_exp,
+ ds_coef_man, clock;
+
+ clock = channel->channel_flags & CHANNEL_T ? 80 : 40;
+ coef_scaled = ((5 * (clock << 24)) / 2) / channel->freq;
+
+ for (coef_exp = 31; coef_exp > 0; coef_exp--)
+ if ((coef_scaled >> coef_exp) & 0x1)
+ break;
+
+ if (!coef_exp) {
+ *status = AR5K_EINVAL;
+ return (FALSE);
+ }
+
+ coef_exp = 14 - (coef_exp - 24);
+ coef_man = coef_scaled + (1 << (24 - coef_exp - 1));
+ ds_coef_man = coef_man >> (24 - coef_exp);
+ ds_coef_exp = coef_exp - 16;
+
+ AR5K_REG_WRITE_BITS(AR5K_PHY_TIMING_3,
+ AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
+ AR5K_REG_WRITE_BITS(AR5K_PHY_TIMING_3,
+ AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+ }
+ }
+
+ /*Enable/disable 802.11b mode on 5111
+ (enable 2111 frequency converter + CCK)*/
+ if (hal->ah_radio == AR5K_AR5111) {
+ if (channel->channel_flags & CHANNEL_B)
+ AR5K_REG_ENABLE_BITS(AR5K_TXCFG,
+ AR5K_TXCFG_B_MODE);
+ else
+ AR5K_REG_DISABLE_BITS(AR5K_TXCFG,
+ AR5K_TXCFG_B_MODE);
+ }
+
+ /* Set antenna mode */
+ AR5K_REG_MASKED_BITS(AR5K_PHY(0x44),
+ hal->ah_antenna[ee_mode][0], 0xfffffc06);
+
+ if (freq == AR5K_INI_RFGAIN_2GHZ)
+ ant[0] = ant[1] = AR5K_ANT_FIXED_B;
+ else
+ ant[0] = ant[1] = AR5K_ANT_FIXED_A;
+
+
+ AR5K_REG_WRITE(AR5K_PHY_ANT_SWITCH_TABLE_0,
+ hal->ah_antenna[ee_mode][ant[0]]);
+ AR5K_REG_WRITE(AR5K_PHY_ANT_SWITCH_TABLE_1,
+ hal->ah_antenna[ee_mode][ant[1]]);
+
+ /* Commit values from EEPROM */
+ if (hal->ah_radio == AR5K_AR5111)
+ AR5K_REG_WRITE_BITS(AR5K_PHY_FRAME_CTL,
+ AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip);
+
+ AR5K_REG_WRITE(AR5K_PHY(0x5a),
+ AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]));
+
+ AR5K_REG_MASKED_BITS(AR5K_PHY(0x11),
+ (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, 0xffffc07f);
+ AR5K_REG_MASKED_BITS(AR5K_PHY(0x12),
+ (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, 0xfffc0fff);
+ AR5K_REG_MASKED_BITS(AR5K_PHY(0x14),
+ (ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
+ ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), 0xffff0000);
+
+ AR5K_REG_WRITE(AR5K_PHY(0x0d),
+ (ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
+ (ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
+ (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
+ (ee->ee_tx_frm2xpa_enable[ee_mode]));
+
+ AR5K_REG_MASKED_BITS(AR5K_PHY(0x0a),
+ ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
+ AR5K_REG_MASKED_BITS(AR5K_PHY(0x19),
+ (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
+ AR5K_REG_MASKED_BITS(AR5K_PHY(0x49), 4, 0xffffff01);
+
+ AR5K_REG_ENABLE_BITS(AR5K_PHY_IQ,
+ AR5K_PHY_IQ_CORR_ENABLE |
+ (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
+ ee->ee_q_cal[ee_mode]);
+
+ if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
+ AR5K_REG_WRITE_BITS(AR5K_PHY_GAIN_2GHZ,
+ AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+ ee->ee_margin_tx_rx[ee_mode]);
+ }
+
+ /*
+ * Restore saved values
+ */
+ AR5K_REG_WRITE(AR5K_QUEUE_DFS_SEQNUM(0), s_seq);
+ AR5K_REG_WRITE(AR5K_DEFAULT_ANTENNA, s_ant);
+ AR5K_REG_ENABLE_BITS(AR5K_PCICFG, s_led[0]);
+ AR5K_REG_WRITE(AR5K_GPIOCR, s_led[1]);
+ AR5K_REG_WRITE(AR5K_GPIODO, s_led[2]);
+
+ /*
+ * Misc
+ */
+ bcopy(etherbroadcastaddr, mac, IEEE80211_ADDR_LEN);
+ ath5k_hw_set_associd(hal, mac, 0);
+ ath5k_hw_set_opmode(hal);
+ AR5K_REG_WRITE(AR5K_PISR, 0xffffffff);
+ AR5K_REG_WRITE(AR5K_RSSI_THR, AR5K_TUNE_RSSI_THRES);
+
+ /*
+ * Set Rx/Tx DMA Configuration
+ */
+ AR5K_REG_WRITE_BITS(AR5K_TXCFG, AR5K_TXCFG_SDMAMR,
+ AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE);
+ AR5K_REG_WRITE_BITS(AR5K_RXCFG, AR5K_RXCFG_SDMAMW,
+ AR5K_DMASIZE_512B);
+
+ /*
+ * Set channel and calibrate the PHY
+ */
+ if (ath5k_channel(hal, channel) == FALSE) {
+ *status = AR5K_EIO;
+ return (FALSE);
+ }
+
+ /*
+ * Enable the PHY and wait until completion
+ */
+ AR5K_REG_WRITE(AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE);
+
+ data = AR5K_REG_READ(AR5K_PHY_RX_DELAY) & AR5K_PHY_RX_DELAY_M;
+ data = (channel->channel_flags & CHANNEL_CCK) ?
+ ((data << 2) / 22) : (data / 10);
+
+ AR5K_DELAY(100 + data);
+
+ /*
+ * Start calibration
+ */
+ AR5K_REG_ENABLE_BITS(AR5K_PHY_AGCCTL,
+ AR5K_PHY_AGCCTL_NF |
+ AR5K_PHY_AGCCTL_CAL);
+
+
+ hal->ah_calibration = FALSE;
+
+ if (!(channel->channel_flags & CHANNEL_B)) {
+ hal->ah_calibration = TRUE;
+ AR5K_REG_WRITE_BITS(AR5K_PHY_IQ,
+ AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+ AR5K_REG_ENABLE_BITS(AR5K_PHY_IQ,
+ AR5K_PHY_IQ_RUN);
+ }
+
+ /*
+ * 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++) {
+ AR5K_REG_WRITE_Q(AR5K_QUEUE_QCUMASK(i), i);
+ if (ath5k_hw_reset_tx_queue(hal, i) == FALSE) {
+ AR5K_PRINTF("failed to reset TX queue #%d\n", i);
+ *status = AR5K_EINVAL;
+ return (FALSE);
+ }
+ }
+
+ /* Pre-enable interrupts */
+ ath5k_hw_set_intr(hal, AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_FATAL);
+
+ /*
+ * Set RF kill flags if supported by the device (read from the EEPROM)
+ * Disable gpio_intr for now since it results system hang.
+ * TODO:Handle this in ath_intr
+ */
+/* if (AR5K_EEPROM_HDR_RFKILL(hal->ah_capabilities.cap_eeprom.ee_header)) {
+ ath5k_hw_set_gpio_input(hal, 0);
+ if ((hal->ah_gpio[0] = ath5k_hw_get_gpio(hal, 0)) == 0)
+ ath5k_hw_set_gpio_intr(hal, 0, 1);
+ else
+ ath5k_hw_set_gpio_intr(hal, 0, 0);
+ }
+*/
+
+ /*
+ * Set the 32MHz reference clock on 5212 phy clock sleep register
+ */
+ if(hal->ah_version == AR5K_AR5212){
+ AR5K_REG_WRITE(AR5K_PHY_SCR, AR5K_PHY_SCR_32MHZ);
+ AR5K_REG_WRITE(AR5K_PHY_SLMT, AR5K_PHY_SLMT_32MHZ);
+ AR5K_REG_WRITE(AR5K_PHY_SCAL, AR5K_PHY_SCAL_32MHZ);
+ AR5K_REG_WRITE(AR5K_PHY_SCLOCK, AR5K_PHY_SCLOCK_32MHZ);
+ AR5K_REG_WRITE(AR5K_PHY_SDELAY, AR5K_PHY_SDELAY_32MHZ);
+ AR5K_REG_WRITE(AR5K_PHY_SPENDING, hal->ah_radio == AR5K_AR5111 ?
+ AR5K_PHY_SPENDING_AR5111 :
AR5K_PHY_SPENDING_AR5112);
+ }
+
+ /*
+ * Disable beacons and reset the register
+ */
+ AR5K_REG_DISABLE_BITS(AR5K_BEACON,
+ AR5K_BEACON_ENABLE | AR5K_BEACON_RESET_TSF);
+
+ return (TRUE);
+}
+
+/*
+ * Reset chipset
+ */
+AR5K_BOOL
+ath5k_hw_nic_reset(struct ath_hal *hal, u_int32_t val)
+{
+ AR5K_BOOL ret = FALSE;
+ u_int32_t mask = val ? val : ~0;
+
+ AR5K_TRACE;
+
+ /* Read-and-clear RX Descriptor Pointer*/
+ AR5K_REG_READ(AR5K_RXDP);
+
+ /*
+ * Reset the device and wait until success
+ */
+ AR5K_REG_WRITE(AR5K_RESET_CTL, val);
+
+ /* Wait at least 128 PCI clocks */
+ AR5K_DELAY(15);
+
+ val &=
+ AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+
+ mask &=
+ AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+
+ ret = ath5k_hw_register_timeout(hal, AR5K_RESET_CTL, mask, val, FALSE);
+
+ /*
+ * Reset configuration register (for hw bitswap)
+ */
+ if ((val & AR5K_RESET_CTL_PCU) == 0)
+ AR5K_REG_WRITE(AR5K_CFG, AR5K_INIT_CFG);
+
+ return (ret);
+}
+
+/*
+ * Power management functions
+ */
+
+/*
+ * Sleep control
+ */
+AR5K_BOOL
+ath5k_hw_set_power(struct ath_hal *hal, AR5K_POWER_MODE mode,
+ AR5K_BOOL set_chip, u_int16_t sleep_duration)
+{
+ u_int32_t staid;
+ int i;
+
+ AR5K_TRACE;
+ staid = AR5K_REG_READ(AR5K_STA_ID1);
+
+ switch (mode) {
+ case AR5K_PM_AUTO:
+ staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
+ /* fallthrough */
+ case AR5K_PM_NETWORK_SLEEP:
+ if (set_chip == TRUE) {
+ AR5K_REG_WRITE(AR5K_SLEEP_CTL,
+ AR5K_SLEEP_CTL_SLE | sleep_duration);
+ }
+ staid |= AR5K_STA_ID1_PWR_SV;
+ break;
+
+ case AR5K_PM_FULL_SLEEP:
+ if (set_chip == TRUE) {
+ AR5K_REG_WRITE(AR5K_SLEEP_CTL,
+ AR5K_SLEEP_CTL_SLE_SLP);
+ }
+ staid |= AR5K_STA_ID1_PWR_SV;
+ break;
+
+ case AR5K_PM_AWAKE:
+ if (set_chip == FALSE)
+ goto commit;
+
+ AR5K_REG_WRITE(AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLE_WAKE);
+
+ for (i = 5000; i > 0; i--) {
+ /* Check if the chip did wake up */
+ if ((AR5K_REG_READ(AR5K_PCICFG) &
+ AR5K_PCICFG_SPWR_DN) == 0)
+ break;
+
+ /* Wait a bit and retry */
+ AR5K_DELAY(200);
+ AR5K_REG_WRITE(AR5K_SLEEP_CTL,
+ AR5K_SLEEP_CTL_SLE_WAKE);
+ }
+
+ /* Fail if the chip didn't wake up */
+ if (i <= 0)
+ return (FALSE);
+
+ staid &= ~AR5K_STA_ID1_PWR_SV;
+ break;
+
+ default:
+ return (FALSE);
+ }
+
+ commit:
+ hal->ah_power_mode = mode;
+
+ AR5K_REG_WRITE(AR5K_STA_ID1, staid);
+
+ return (TRUE);
+}
+
+/*
+ * Get power mode (sleep state)
+ * TODO:Remove ?
+ */
+AR5K_POWER_MODE
+ath5k_hw_get_power_mode(struct ath_hal *hal)
+{
+ AR5K_TRACE;
+ return (hal->ah_power_mode);
+}
+
+
+
+
+/***********************\
+ DMA Related Functions
+\***********************/
+
+/*
+ * Receive functions
+ */
+
+/*
+ * Start DMA receive
+ */
+void
+ath5k_hw_start_rx(struct ath_hal *hal)
+{
+ AR5K_TRACE;
+ AR5K_REG_WRITE(AR5K_CR, AR5K_CR_RXE);
+}
+
+/*
+ * Stop DMA receive
+ */
+AR5K_BOOL
+ath5k_hw_stop_rx_dma(struct ath_hal *hal)
+{
+ int i;
+
+ AR5K_TRACE;
+ AR5K_REG_WRITE(AR5K_CR, AR5K_CR_RXD);
+
+ /*
+ * It may take some time to disable the DMA receive unit
+ */
+ for (i = 2000;
+ i > 0 && (AR5K_REG_READ(AR5K_CR) & AR5K_CR_RXE) != 0;
+ i--)
+ AR5K_DELAY(10);
+
+ return (i > 0 ? TRUE : FALSE);
+}
+
+/*
+ * Get the address of the RX Descriptor
+ */
+u_int32_t
+ath5k_hw_get_rx_buf(struct ath_hal *hal)
+{
+ return (AR5K_REG_READ(AR5K_RXDP));
+}
+
+/*
+ * Set the address of the RX Descriptor
+ */
+void
+ath5k_hw_put_rx_buf(struct ath_hal *hal, u_int32_t phys_addr)
+{
+ AR5K_TRACE;
+
+ /*TODO:Shouldn't we check if RX is enabled first ?*/
+ AR5K_REG_WRITE(AR5K_RXDP, phys_addr);
+}
+
+/*
+ * Transmit functions
+ */
+
+/*
+ * Start DMA transmit for a specific queue
+ * (see also QCU/DCU functions)
+ */
+AR5K_BOOL
+ath5k_hw_tx_start(struct ath_hal *hal, u_int queue)
+{
+ AR5K_TRACE;
+ AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num);
+
+ /* Return if queue is disabled */
+ if (AR5K_REG_READ_Q(AR5K_QCU_TXD, queue))
+ return (FALSE);
+
+ /* Start queue */
+ AR5K_REG_WRITE_Q(AR5K_QCU_TXE, queue);
+
+ return (TRUE);
+}
+
+/*
+ * Stop DMA transmit for a specific queue
+ * (see also QCU/DCU functions)
+ */
+AR5K_BOOL
+ath5k_hw_stop_tx_dma(struct ath_hal *hal, u_int queue)
+{
+ int i = 100, pending;
+
+ AR5K_TRACE;
+ AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num);
+
+ /*
+ * Schedule TX disable and wait until queue is empty
+ */
+ AR5K_REG_WRITE_Q(AR5K_QCU_TXD, queue);
+
+ /*Check for pending frames*/
+ do {
+ pending = AR5K_REG_READ(AR5K_QUEUE_STATUS(queue)) &
+ AR5K_QCU_STS_FRMPENDCNT;
+ AR5K_DELAY(100);
+ } while (--i && pending);
+
+ /* Clear register */
+ AR5K_REG_WRITE(AR5K_QCU_TXD, 0);
+
+ /*TODO: Check for success else return false*/
+ return (TRUE);
+}
+
+/*
+ * Get the address of the TX Descriptor for a specific queue
+ * (see also QCU/DCU functions)
+ */
+u_int32_t
+ath5k_hw_get_tx_buf(struct ath_hal *hal, u_int queue)
+{
+ AR5K_TRACE;
+ AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num);
+
+ /*
+ * Get the transmit queue descriptor pointer from the selected queue
+ */
+ return (AR5K_REG_READ(AR5K_QUEUE_TXDP(queue)));
+}
+
+/*
+ * Set the address of the TX Descriptor for a specific queue
+ * (see also QCU/DCU functions)
+ */
+AR5K_BOOL
+ath5k_hw_put_tx_buf(struct ath_hal *hal, u_int queue, u_int32_t phys_addr)
+{
+ AR5K_TRACE;
+ AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num);
+
+ /*
+ * Set the transmit queue descriptor pointer for the selected queue
+ * (this won't work if the queue is still active)
+ */
+ if (AR5K_REG_READ_Q(AR5K_QCU_TXE, queue))
+ return (FALSE);
+
+ AR5K_REG_WRITE(AR5K_QUEUE_TXDP(queue), phys_addr);
+
+ return (TRUE);
+}
+
+/*
+ * Update tx trigger level
+ */
+AR5K_BOOL
+ath5k_hw_update_tx_triglevel(struct ath_hal *hal, AR5K_BOOL increase)
+{
+ u_int32_t trigger_level, imr;
+ AR5K_BOOL status = FALSE;
+ AR5K_TRACE;
+
+ /*
+ * Disable interrupts by setting the mask
+ */
+ imr = ath5k_hw_set_intr(hal, hal->ah_imr & ~AR5K_INT_GLOBAL);
+
+ /*TODO: Boundary check on trigger_level*/
+ trigger_level = AR5K_REG_MS(AR5K_REG_READ(AR5K_TXCFG),
+ AR5K_TXCFG_TXFULL);
+
+ if (increase == 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_BITS(AR5K_TXCFG,
+ AR5K_TXCFG_TXFULL, trigger_level);
+ status = TRUE;
+
+ done:
+ /*
+ * Restore interrupt mask
+ */
+ ath5k_hw_set_intr(hal, imr);
+
+ return (status);
+}
+
+/*
+ * Interrupt handling
+ */
+
+/*
+ * Check if we have pending interrupts
+ */
+AR5K_BOOL
+ath5k_hw_is_intr_pending(struct ath_hal *hal)
+{
+ AR5K_TRACE;
+ return (AR5K_REG_READ(AR5K_INTPEND) == TRUE ? TRUE : FALSE);
+}
+
+/*
+ * Get interrupt mask (ISR)
+ */
+AR5K_BOOL
+ath5k_hw_get_isr(struct ath_hal *hal, u_int32_t *interrupt_mask)
+{
+ u_int32_t data;
+
+ AR5K_TRACE;
+ /*
+ * Read interrupt status from the Read-And-Clear shadow register
+ */
+ data = AR5K_REG_READ(AR5K_RAC_PISR);
+
+ /*
+ * Get abstract interrupt mask (HAL-compatible)
+ */
+ *interrupt_mask = (data & AR5K_INT_COMMON) & hal->ah_imr;
+
+ if (data == AR5K_INT_NOCARD)
+ return (FALSE);
+
+ if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
+ *interrupt_mask |= AR5K_INT_RX;
+
+ if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR))
+ *interrupt_mask |= AR5K_INT_TX;
+
+ /*HIU = Host Interface Unit (PCI etc)*/
+ if (data & (AR5K_ISR_HIUERR))
+ *interrupt_mask |= AR5K_INT_FATAL;
+
+ /*Beacon Not Ready*/
+ if (data & (AR5K_ISR_BNR))
+ *interrupt_mask |= AR5K_INT_BNR;
+
+ /*
+ * Special interrupt handling (not caught by the driver)
+ */
+ if (((*interrupt_mask) & AR5K_ISR_RXPHY) &&
+ hal->ah_radar.r_enabled == TRUE)
+ ath5k_radar_alert(hal);
+
+ if (*interrupt_mask == 0)
+ AR5K_PRINTF("0x%08x\n", data);
+
+ return (TRUE);
+}
+
+/*
+ * Return the interrupt mask stored previously
+ * TODO: Remove ?
+ */
+u_int32_t
+ath5k_hw_get_intr(struct ath_hal *hal)
+{
+ AR5K_TRACE;
+ return (hal->ah_imr);
+}
+
+/*
+ * Set interrupt mask
+ */
+AR5K_INT
+ath5k_hw_set_intr(struct ath_hal *hal, AR5K_INT new_mask)
+{
+ AR5K_INT old_mask, int_mask;
+
+ /*
+ * Disable card interrupts to prevent any race conditions
+ * (they will be re-enabled afterwards).
+ */
+ AR5K_REG_WRITE(AR5K_IER, AR5K_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 & AR5K_INT_COMMON;
+
+ if (new_mask & AR5K_INT_RX)
+ int_mask |=
+ AR5K_IMR_RXOK |
+ AR5K_IMR_RXERR |
+ AR5K_IMR_RXORN |
+ AR5K_IMR_RXDESC;
+
+ if (new_mask & AR5K_INT_TX)
+ int_mask |=
+ AR5K_IMR_TXOK |
+ AR5K_IMR_TXERR |
+ AR5K_IMR_TXDESC |
+ AR5K_IMR_TXURN;
+
+ if (new_mask & AR5K_INT_FATAL) {
+ int_mask |= AR5K_IMR_HIUERR;
+ AR5K_REG_ENABLE_BITS(AR5K_SIMR2,
+ AR5K_SIMR2_MCABT |
+ AR5K_SIMR2_SSERR |
+ AR5K_SIMR2_DPERR);
+ }
+
+ AR5K_REG_WRITE(AR5K_PIMR, int_mask);
+
+ /* Store new interrupt mask */
+ hal->ah_imr = new_mask;
+
+ /* ..re-enable interrupts */
+ AR5K_REG_WRITE(AR5K_IER, AR5K_IER_ENABLE);
+
+ return (old_mask);
+}
+
+/*
+ * Enalbe HW radar detection
+ */
+void
+ath5k_hw_radar_alert(struct ath_hal *hal, AR5K_BOOL enable)
+{
+
+ AR5K_TRACE;
+ /*
+ * Enable radar detection
+ */
+
+ /*Disable interupts*/
+ AR5K_REG_WRITE(AR5K_IER, AR5K_IER_DISABLE);
+
+ /*Set AR5K_PHY_RADAR register*/
+ if (enable == TRUE) {
+ AR5K_REG_WRITE(AR5K_PHY_RADAR,
+ AR5K_PHY_RADAR_ENABLE);
+ AR5K_REG_ENABLE_BITS(AR5K_PIMR,
+ AR5K_IMR_RXPHY);
+ } else {
+ AR5K_REG_WRITE(AR5K_PHY_RADAR,
+ AR5K_PHY_RADAR_DISABLE);
+ AR5K_REG_DISABLE_BITS(AR5K_PIMR,
+ AR5K_IMR_RXPHY);
+ }
+
+ /*Re-enable interrupts*/
+ AR5K_REG_WRITE(AR5K_IER, AR5K_IER_ENABLE);
+}
+
+
+
+
+/*************************\
+ EEPROM access functions
+\*************************/
+
+/*
+ * Check if eeprom is busy
+ */
+AR5K_BOOL
+ath5k_hw_eeprom_is_busy(struct ath_hal *hal)
+{
+ AR5K_TRACE;
+ return (AR5K_REG_READ(AR5K_CFG) & AR5K_CFG_EEBS ?
+ TRUE : FALSE);
+}
+
+/*
+ * Read from eeprom
+ */
+int
+ath5k_hw_eeprom_read(struct ath_hal *hal, u_int32_t offset, u_int16_t *data)
+{
+ u_int32_t status, i;
+
+ AR5K_TRACE;
+ /*
+ * Initialize EEPROM access
+ */
+ AR5K_REG_WRITE(AR5K_EEPROM_BASE, (u_int8_t)offset);
+ AR5K_REG_ENABLE_BITS(AR5K_EEPROM_CMD,
+ AR5K_EEPROM_CMD_READ);
+
+ for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+ status = AR5K_REG_READ(AR5K_EEPROM_STATUS);
+ if (status & AR5K_EEPROM_STAT_RDDONE) {
+ if (status & AR5K_EEPROM_STAT_RDERR)
+ return (EIO);
+ *data = (u_int16_t)
+ (AR5K_REG_READ(AR5K_EEPROM_DATA) & 0xffff);
+ return (0);
+ }
+ AR5K_DELAY(15);
+ }
+
+ return (ETIMEDOUT);
+}
+
+/*
+ * Write to eeprom - currently disabled, use at your own risk
+ */
+int
+ath5k_hw_eeprom_write(struct ath_hal *hal, u_int32_t offset, u_int16_t data)
+{
+ u_int32_t status, timeout;
+
+ AR5K_TRACE;
+ /* Enable eeprom access */
+ AR5K_REG_ENABLE_BITS(AR5K_EEPROM_CMD,
+ AR5K_EEPROM_CMD_RESET);
+
+ /*
+ * Write data to data register
+ * Disable this, it's not needed for
+ * normal operation, uncomment it if you
+ * need it.
+ */
+ /*
+ AR5K_REG_WRITE(AR5K_EEPROM_DATA, data);
+ */
+ AR5K_PRINTF("EEPROM Write is disabled!");
+
+ /* Write offset to base register */
+ AR5K_REG_WRITE(AR5K_EEPROM_BASE, (u_int8_t)offset - 1);
+
+ /* Issue write command */
+ AR5K_REG_ENABLE_BITS(AR5K_EEPROM_CMD,
+ AR5K_EEPROM_CMD_WRITE);
+
+ /*
+ * Check status
+ */
+
+ for (timeout = 10000; timeout > 0; timeout--) {
+ AR5K_DELAY(1);
+ status = AR5K_REG_READ(AR5K_EEPROM_STATUS);
+ if (status & AR5K_EEPROM_STAT_WRDONE) {
+ if (status & AR5K_EEPROM_STAT_WRERR)
+ return (EIO);
+ return (0);
+ }
+ }
+
+ return (ETIMEDOUT);
+}
+
+u_int16_t
+ath5k_eeprom_bin2freq(struct ath_hal *hal, u_int16_t bin, u_int mode)
+{
+ u_int16_t val;
+
+ if (bin == AR5K_EEPROM_CHANNEL_DIS)
+ return (bin);
+
+ if (mode == AR5K_EEPROM_MODE_11A) {
+ if (hal->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+ val = (5 * bin) + 4800;
+ else
+ val = bin > 62 ?
+ (10 * 62) + (5 * (bin - 62)) + 5100 :
+ (bin * 10) + 5100;
+ } else {
+ if (hal->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+ val = bin + 2300;
+ else
+ val = bin + 2400;
+ }
+
+ return (val);
+}
+
+/*
+ * Read antenna infos from eeprom
+ */
+int
+ath5k_eeprom_read_ants(struct ath_hal *hal, u_int32_t *offset, u_int mode)
+{
+ struct ath5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
+ u_int32_t o = *offset;
+ u_int16_t val;
+ int ret, i = 0;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_switch_settling[mode] = (val >> 8) & 0x7f;
+ ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f;
+ ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;
+ ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;
+ ee->ee_ant_control[mode][i++] = val & 0x3f;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f;
+ ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f;
+ ee->ee_ant_control[mode][i] = (val << 2) & 0x3f;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3;
+ ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f;
+ ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f;
+ ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;
+ ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;
+ ee->ee_ant_control[mode][i++] = val & 0x3f;
+
+ /* Get antenna modes */
+ hal->ah_antenna[mode][0] =
+ (ee->ee_ant_control[mode][0] << 4) | 0x1;
+ hal->ah_antenna[mode][AR5K_ANT_FIXED_A] =
+ ee->ee_ant_control[mode][1] |
+ (ee->ee_ant_control[mode][2] << 6) |
+ (ee->ee_ant_control[mode][3] << 12) |
+ (ee->ee_ant_control[mode][4] << 18) |
+ (ee->ee_ant_control[mode][5] << 24);
+ hal->ah_antenna[mode][AR5K_ANT_FIXED_B] =
+ ee->ee_ant_control[mode][6] |
+ (ee->ee_ant_control[mode][7] << 6) |
+ (ee->ee_ant_control[mode][8] << 12) |
+ (ee->ee_ant_control[mode][9] << 18) |
+ (ee->ee_ant_control[mode][10] << 24);
+
+ /* return new offset */
+ *offset = o;
+
+ return (0);
+}
+
+/*
+ * Read supported modes from eeprom
+ */
+int
+ath5k_eeprom_read_modes(struct ath_hal *hal, u_int32_t *offset, u_int mode)
+{
+ struct ath5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
+ u_int32_t o = *offset;
+ u_int16_t val;
+ int ret;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;
+ ee->ee_thr_62[mode] = val & 0xff;
+
+ if (hal->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+ ee->ee_thr_62[mode] =
+ mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff;
+ ee->ee_tx_frm2xpa_enable[mode] = val & 0xff;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff;
+
+ if ((val & 0xff) & 0x80)
+ ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
+ else
+ ee->ee_noise_floor_thr[mode] = val & 0xff;
+
+ if (hal->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+ ee->ee_noise_floor_thr[mode] =
+ mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_xlna_gain[mode] = (val >> 5) & 0xff;
+ ee->ee_x_gain[mode] = (val >> 1) & 0xf;
+ ee->ee_xpd[mode] = val & 0x1;
+
+ if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
+ ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
+
+ if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
+
+ if (mode == AR5K_EEPROM_MODE_11A)
+ ee->ee_xr_power[mode] = val & 0x3f;
+ else {
+ ee->ee_ob[mode][0] = val & 0x7;
+ ee->ee_db[mode][0] = (val >> 3) & 0x7;
+ }
+ }
+
+ if (hal->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
+ ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
+ ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
+ } else {
+ ee->ee_i_gain[mode] = (val >> 13) & 0x7;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_i_gain[mode] |= (val << 3) & 0x38;
+
+ if (mode == AR5K_EEPROM_MODE_11G)
+ ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+ }
+
+ if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
+ mode == AR5K_EEPROM_MODE_11A) {
+ ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+ ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+ }
+
+ if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
+ mode == AR5K_EEPROM_MODE_11G)
+ ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+
+ /* return new offset */
+ *offset = o;
+
+ return (0);
+}
+
+/*
+ * Initialize eeprom & capabilities structs
+ */
+int
+ath5k_eeprom_init(struct ath_hal *hal)
+{
+ struct ath5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom;
+ u_int32_t offset;
+ u_int16_t val;
+ int ret, i;
+ u_int mode;
+
+ /* Initial TX thermal adjustment values */
+ ee->ee_tx_clip = 4;
+ ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
+ ee->ee_gain_select = 1;
+
+ /*
+ * Read values from EEPROM and store them in the capability structure
+ */
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+ /* Return if we have an old EEPROM */
+ if (hal->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+ return (0);
+
+#ifdef notyet
+ /*
+ * Validate the checksum of the EEPROM date. There are some
+ * devices with invalid EEPROMs.
+ */
+ for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
+ AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
+ cksum ^= val;
+ }
+ if (cksum != AR5K_EEPROM_INFO_CKSUM) {
+ AR5K_PRINTF("Invalid EEPROM checksum 0x%04x\n", cksum);
+ return (AR5K_EEBADSUM);
+ }
+#endif
+
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(hal->ah_ee_version),
+ ee_ant_gain);
+
+ if (hal->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+ }
+
+ if (hal->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+ ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+ ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+ ee->ee_ob[AR5K_EEPROM |