]> err.no Git - linux-2.6/commitdiff
[PATCH] Net: add ath5k wireless driver
authorJiri Slaby <jirislaby@gmail.com>
Sun, 12 Aug 2007 15:33:16 +0000 (17:33 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:09:35 +0000 (15:09 -0800)
add ath5k wireless driver

Portions of this driver are covered by one or both of the ISC and
3-clause BSD licenses.  Specific license information is cited at the top
of each file.

Acked-by and Signed-off-by information is collected from individual
patches as collected in the wireless-2.6 tree prior to upstream
submission.

Acked-by: Matthew W. S. Bell <mentor@madwifi.org>
Acked-by: Michael Taylor <mike.taylor@apprion.com>
Acked-by: Pavel Roskin <proski@gnu.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Bradley M. Kuhn <bkuhn@softwarefreedom.org>
Signed-off-by: Bruno Randolf <bruno@thinktube.com>
Signed-off-by: Dave Young <hidave.darkstar@gmail.com>
Signed-off-by: Francesco Gringoli <francesco.gringoli@ing.unibs.it>
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Karen Sandler <karen@softwarefreedom.org>
Signed-off-by: Krzysztof Halasa <khc@pm.waw.pl>
Signed-off-by: Luis R. Rodriguez <mcgrof@gmail.com>
Signed-off-by: Matt Norwood <norwood@softwarefreedom.org>
Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: Richard Fontana <fontana@softwarefreedom.org>
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Ulrich Meis <meis@nets.rwth-aachen.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
16 files changed:
MAINTAINERS
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/ath5k/Makefile [new file with mode: 0644]
drivers/net/wireless/ath5k/ath5k.h [new file with mode: 0644]
drivers/net/wireless/ath5k/base.c [new file with mode: 0644]
drivers/net/wireless/ath5k/base.h [new file with mode: 0644]
drivers/net/wireless/ath5k/debug.c [new file with mode: 0644]
drivers/net/wireless/ath5k/debug.h [new file with mode: 0644]
drivers/net/wireless/ath5k/hw.c [new file with mode: 0644]
drivers/net/wireless/ath5k/hw.h [new file with mode: 0644]
drivers/net/wireless/ath5k/initvals.c [new file with mode: 0644]
drivers/net/wireless/ath5k/phy.c [new file with mode: 0644]
drivers/net/wireless/ath5k/reg.h [new file with mode: 0644]
drivers/net/wireless/ath5k/regdom.c [new file with mode: 0644]
drivers/net/wireless/ath5k/regdom.h [new file with mode: 0644]

index a19469318ded78bc09c5d1d738a8e3007ae6f798..ba05e8058689dc0471ddb9fe753290075404774d 100644 (file)
@@ -646,6 +646,17 @@ M: ecashin@coraid.com
 W:     http://www.coraid.com/support/linux
 S:     Supported
 
+ATHEROS ATH5K WIRELESS DRIVER
+P:     Jiri Slaby
+M:     jirislaby@gmail.com
+P:     Nick Kossifidis
+M:     mickflemm@gmail.com
+P:     Luis R. Rodriguez
+M:     mcgrof@gmail.com
+L:     linux-wireless@vger.kernel.org
+L:     ath5k-devel@lists.ath5k.org
+S:     Maintained
+
 ATL1 ETHERNET DRIVER
 P:     Jay Cliburn
 M:     jcliburn@gmail.com
index 2c08c0a5a0df0221b561a4dc5ce6f45e0d8de583..50a8b6c2fa00aa70ec6677e0dbcbfc706a6a076e 100644 (file)
@@ -648,6 +648,23 @@ config P54_PCI
 
          If you choose to build a module, it'll be called p54pci.
 
+config ATH5K
+       tristate "Atheros 5xxx wireless cards support"
+       depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+       ---help---
+         This module adds support for wireless adapters based on
+         Atheros 5xxx chipset.
+
+         Currently the following chip versions are supported:
+
+         MAC: AR5211 AR5212
+         PHY: RF5111/2111 RF5112/2112 RF5413/2413
+
+         This driver uses the kernel's mac80211 subsystem.
+
+         If you choose to build a module, it'll be called ath5k. Say M if
+         unsure.
+
 source "drivers/net/wireless/iwlwifi/Kconfig"
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/bcm43xx/Kconfig"
index d48f7d19745b8bd0c89733d2447a940a34422d3d..7e1535ece17ad11c24523e380ebf65726408be58 100644 (file)
@@ -59,3 +59,5 @@ obj-$(CONFIG_RT2X00)  += rt2x00/
 obj-$(CONFIG_P54_COMMON)       += p54common.o
 obj-$(CONFIG_P54_USB)          += p54usb.o
 obj-$(CONFIG_P54_PCI)          += p54pci.o
+
+obj-$(CONFIG_ATH5K)    += ath5k/
diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath5k/Makefile
new file mode 100644 (file)
index 0000000..321641f
--- /dev/null
@@ -0,0 +1,2 @@
+ath5k-objs             = base.o hw.o regdom.o initvals.o phy.o debug.o
+obj-$(CONFIG_ATH5K)    += ath5k.o
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
new file mode 100644 (file)
index 0000000..878609f
--- /dev/null
@@ -0,0 +1,1173 @@
+/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef _ATH5K_H
+#define _ATH5K_H
+
+/* Set this to 1 to disable regulatory domain restrictions for channel tests.
+ * WARNING: This is for debuging only and has side effects (eg. scan takes too
+ * long and results timeouts). It's also illegal to tune to some of the
+ * supported frequencies in some countries, so use this at your own risk,
+ * you've been warned. */
+#define CHAN_DEBUG     0
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <net/mac80211.h>
+
+#include "hw.h"
+#include "regdom.h"
+
+/* PCI IDs */
+#define PCI_DEVICE_ID_ATHEROS_AR5210           0x0007 /* AR5210 */
+#define PCI_DEVICE_ID_ATHEROS_AR5311           0x0011 /* AR5311 */
+#define PCI_DEVICE_ID_ATHEROS_AR5211           0x0012 /* AR5211 */
+#define PCI_DEVICE_ID_ATHEROS_AR5212           0x0013 /* AR5212 */
+#define PCI_DEVICE_ID_3COM_3CRDAG675           0x0013 /* 3CRDAG675 (Atheros AR5212) */
+#define PCI_DEVICE_ID_3COM_2_3CRPAG175                 0x0013 /* 3CRPAG175 (Atheros AR5212) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_AP        0x0207 /* AR5210 (Early) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM       0x1014 /* AR5212 (IBM MiniPCI) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT   0x1107 /* AR5210 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT   0x1113 /* AR5212 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT   0x1112 /* AR5211 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA      0xf013 /* AR5212 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY    0xff12 /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B   0xf11b /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2      0x0052 /* AR5312 WMAC (AP31) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7      0x0057 /* AR5312 WMAC (AP30-040) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8      0x0058 /* AR5312 WMAC (AP43-030) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0014      0x0014 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0015      0x0015 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0016      0x0016 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0017      0x0017 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0018      0x0018 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0019      0x0019 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR2413           0x001a /* AR2413 (Griffin-lite) */
+#define PCI_DEVICE_ID_ATHEROS_AR5413           0x001b /* AR5413 (Eagle) */
+#define PCI_DEVICE_ID_ATHEROS_AR5424           0x001c /* AR5424 (Condor PCI-E) */
+#define PCI_DEVICE_ID_ATHEROS_AR5416           0x0023 /* AR5416 */
+#define PCI_DEVICE_ID_ATHEROS_AR5418           0x0024 /* AR5418 */
+
+/****************************\
+  GENERIC DRIVER DEFINITIONS
+\****************************/
+
+#define ATH5K_PRINTF(fmt, ...)   printk("%s: " fmt, __func__, ##__VA_ARGS__)
+
+#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \
+       printk(_level "ath5k %s: " _fmt, \
+               ((_sc) && (_sc)->hw) ? wiphy_name((_sc)->hw->wiphy) : "", \
+               ##__VA_ARGS__)
+
+#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) do { \
+       if (net_ratelimit()) \
+               ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \
+       } while (0)
+
+#define ATH5K_INFO(_sc, _fmt, ...) \
+       ATH5K_PRINTK(_sc, KERN_INFO, _fmt, ##__VA_ARGS__)
+
+#define ATH5K_WARN(_sc, _fmt, ...) \
+       ATH5K_PRINTK_LIMIT(_sc, KERN_WARNING, _fmt, ##__VA_ARGS__)
+
+#define ATH5K_ERR(_sc, _fmt, ...) \
+       ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__)
+
+/*
+ * 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            ((IEEE80211_MAX_LEN / 64) + 1)
+#define AR5K_TUNE_REGISTER_TIMEOUT             20000
+/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
+ * be the max value. */
+#define AR5K_TUNE_RSSI_THRES                   129
+/* This must be set when setting the RSSI threshold otherwise it can
+ * prevent a reset. If AR5K_RSSI_THR is read after writing to it
+ * the BMISS_THRES will be seen as 0, seems harware doesn't keep
+ * track of it. Max value depends on harware. For AR5210 this is just 7.
+ * For AR5211+ this seems to be up to 255. */
+#define AR5K_TUNE_BMISS_THRES                  7
+#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     ((u32) -1)
+
+/* GENERIC CHIPSET DEFINITIONS */
+
+/* MAC Chips */
+enum ath5k_version {
+       AR5K_AR5210     = 0,
+       AR5K_AR5211     = 1,
+       AR5K_AR5212     = 2,
+};
+
+/* PHY Chips */
+enum ath5k_radio {
+       AR5K_RF5110     = 0,
+       AR5K_RF5111     = 1,
+       AR5K_RF5112     = 2,
+       AR5K_RF5413     = 3,
+};
+
+/*
+ * Common silicon revision/version values
+ */
+
+enum ath5k_srev_type {
+       AR5K_VERSION_VER,
+       AR5K_VERSION_RAD,
+};
+
+struct ath5k_srev_name {
+       const char              *sr_name;
+       enum ath5k_srev_type    sr_type;
+       u_int                   sr_val;
+};
+
+#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_AR5213A  0x59
+#define AR5K_SREV_VER_AR2424   0xa0
+#define AR5K_SREV_VER_AR5424   0xa3
+#define AR5K_SREV_VER_AR5413   0xa4
+#define AR5K_SREV_VER_AR5414   0xa5
+#define AR5K_SREV_VER_AR5416   0xc0    /* ? */
+#define AR5K_SREV_VER_AR5418   0xca
+
+#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_SC1      0x63    /* Found on 5413/5414 */
+#define AR5K_SREV_RAD_SC2      0xa2    /* Found on 2424/5424 */
+#define AR5K_SREV_RAD_5133     0xc0    /* MIMO found on 5418 */
+
+/* IEEE defs */
+
+#define IEEE80211_MAX_LEN       2500
+
+/* TODO add support to mac80211 for vendor-specific rates and modes */
+
+/*
+ * Some of this information is based on Documentation from:
+ *
+ * http://madwifi.org/wiki/ChipsetFeatures/SuperAG
+ *
+ * Modulation for Atheros' eXtended Range - range enhancing extension that is
+ * supposed to double the distance an Atheros client device can keep a
+ * connection with an Atheros access point. This is achieved by increasing
+ * the receiver sensitivity up to, -105dBm, which is about 20dB above what
+ * the 802.11 specifications demand. In addition, new (proprietary) data rates
+ * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
+ *
+ * Please note that can you either use XR or TURBO but you cannot use both,
+ * they are exclusive.
+ *
+ */
+#define MODULATION_XR          0x00000200
+/*
+ * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a
+ * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s
+ * signaling rate achieved through the bonding of two 54Mbit/s 802.11g
+ * channels. To use this feature your Access Point must also suport it.
+ * There is also a distinction between "static" and "dynamic" turbo modes:
+ *
+ * - Static: is the dumb version: devices set to this mode stick to it until
+ *     the mode is turned off.
+ * - Dynamic: is the intelligent version, the network decides itself if it
+ *     is ok to use turbo. As soon as traffic is detected on adjacent channels
+ *     (which would get used in turbo mode), or when a non-turbo station joins
+ *     the network, turbo mode won't be used until the situation changes again.
+ *     Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which
+ *     monitors the used radio band in order to decide whether turbo mode may
+ *     be used or not.
+ *
+ * This article claims Super G sticks to bonding of channels 5 and 6 for
+ * USA:
+ *
+ * http://www.pcworld.com/article/id,113428-page,1/article.html
+ *
+ * The channel bonding seems to be driver specific though. In addition to
+ * deciding what channels will be used, these "Turbo" modes are accomplished
+ * by also enabling the following features:
+ *
+ * - Bursting: allows multiple frames to be sent at once, rather than pausing
+ *     after each frame. Bursting is a standards-compliant feature that can be
+ *     used with any Access Point.
+ * - Fast frames: increases the amount of information that can be sent per
+ *     frame, also resulting in a reduction of transmission overhead. It is a
+ *     proprietary feature that needs to be supported by the Access Point.
+ * - Compression: data frames are compressed in real time using a Lempel Ziv
+ *     algorithm. This is done transparently. Once this feature is enabled,
+ *     compression and decompression takes place inside the chipset, without
+ *     putting additional load on the host CPU.
+ *
+ */
+#define MODULATION_TURBO       0x00000080
+
+enum ath5k_vendor_mode {
+       MODE_ATHEROS_TURBO = NUM_IEEE80211_MODES+1,
+       MODE_ATHEROS_TURBOG
+};
+
+/* Number of supported mac80211 enum ieee80211_phymode modes by this driver */
+#define NUM_DRIVER_MODES       3
+
+/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */
+#define AR5K_SET_SHORT_PREAMBLE 0x04
+
+#define HAS_SHPREAMBLE(_ix) (rt->rates[_ix].modulation == IEEE80211_RATE_CCK_2)
+#define SHPREAMBLE_FLAG(_ix) (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0)
+
+/****************\
+  TX DEFINITIONS
+\****************/
+
+/*
+ * Tx Descriptor
+ */
+struct ath5k_tx_status {
+       u16     ts_seqnum;
+       u16     ts_tstamp;
+       u8      ts_status;
+       u8      ts_rate;
+       s8      ts_rssi;
+       u8      ts_shortretry;
+       u8      ts_longretry;
+       u8      ts_virtcol;
+       u8      ts_antenna;
+};
+
+#define AR5K_TXSTAT_ALTRATE    0x80
+#define AR5K_TXERR_XRETRY      0x01
+#define AR5K_TXERR_FILT                0x02
+#define AR5K_TXERR_FIFO                0x04
+
+/**
+ * enum ath5k_tx_queue - Queue types used to classify tx queues.
+ * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue
+ * @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 after-beacon queue
+ * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue
+ */
+enum ath5k_tx_queue {
+       AR5K_TX_QUEUE_INACTIVE = 0,
+       AR5K_TX_QUEUE_DATA,
+       AR5K_TX_QUEUE_XR_DATA,
+       AR5K_TX_QUEUE_BEACON,
+       AR5K_TX_QUEUE_CAB,
+       AR5K_TX_QUEUE_UAPSD,
+};
+
+#define        AR5K_NUM_TX_QUEUES              10
+#define        AR5K_NUM_TX_QUEUES_NOQCU        2
+
+/*
+ * 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.
+ */
+enum ath5k_tx_queue_subtype {
+       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*/
+};
+
+/*
+ * Queue ID numbers as returned by the hw functions, each number
+ * represents a hw queue. If hw does not support hw queues
+ * (eg 5210) all data goes in one queue. These match
+ * d80211 definitions (net80211/MadWiFi don't use them).
+ */
+enum ath5k_tx_queue_id {
+       AR5K_TX_QUEUE_ID_NOQCU_DATA     = 0,
+       AR5K_TX_QUEUE_ID_NOQCU_BEACON   = 1,
+       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,
+};
+
+
+/*
+ * Flags to set hw queue's parameters...
+ */
+#define AR5K_TXQ_FLAG_TXOKINT_ENABLE           0x0001  /* Enable TXOK interrupt */
+#define AR5K_TXQ_FLAG_TXERRINT_ENABLE          0x0002  /* Enable TXERR interrupt */
+#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE          0x0004  /* Enable TXEOL interrupt -not used- */
+#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE         0x0008  /* Enable TXDESC interrupt -not used- */
+#define AR5K_TXQ_FLAG_TXURNINT_ENABLE          0x0010  /* Enable TXURN interrupt */
+#define AR5K_TXQ_FLAG_BACKOFF_DISABLE          0x0020  /* Disable random post-backoff */
+#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE        0x0040  /* Enable ready time expiry policy (?)*/
+#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE        0x0080  /* Enable backoff while bursting */
+#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS                0x0100  /* Disable backoff while bursting */
+#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE       0x0200  /* Enable hw compression -not implemented-*/
+
+/*
+ * A struct to hold tx queue's parameters
+ */
+struct ath5k_txq_info {
+       enum ath5k_tx_queue tqi_type;
+       enum ath5k_tx_queue_subtype tqi_subtype;
+       u16     tqi_flags;      /* Tx queue flags (see above) */
+       u32     tqi_aifs;       /* Arbitrated Interframe Space */
+       s32     tqi_cw_min;     /* Minimum Contention Window */
+       s32     tqi_cw_max;     /* Maximum Contention Window */
+       u32     tqi_cbr_period; /* Constant bit rate period */
+       u32     tqi_cbr_overflow_limit;
+       u32     tqi_burst_time;
+       u32     tqi_ready_time; /* Not used */
+};
+
+/*
+ * Transmit packet types.
+ * These are not fully used inside OpenHAL yet
+ */
+enum ath5k_pkt_type {
+       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,
+};
+
+/*
+ * TX power and TPC settings
+ */
+#define AR5K_TXPOWER_OFDM(_r, _v)      (                       \
+       ((0 & 1) << ((_v) + 6)) |                               \
+       (((ah->ah_txpower.txp_rates[(_r)]) & 0x3f) << (_v))     \
+)
+
+#define AR5K_TXPOWER_CCK(_r, _v)       (                       \
+       (ah->ah_txpower.txp_rates[(_r)] & 0x3f) << (_v) \
+)
+
+/*
+ * DMA size definitions (2^n+2)
+ */
+enum ath5k_dmasize {
+       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
+};
+
+
+/****************\
+  RX DEFINITIONS
+\****************/
+
+/*
+ * Rx Descriptor
+ */
+struct ath5k_rx_status {
+       u16     rs_datalen;
+       u16     rs_tstamp;
+       u8      rs_status;
+       u8      rs_phyerr;
+       s8      rs_rssi;
+       u8      rs_keyix;
+       u8      rs_rate;
+       u8      rs_antenna;
+       u8      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   ((u8) - 1)
+#define AR5K_TXKEYIX_INVALID   ((u32) - 1)
+
+struct ath5k_mib_stats {
+       u32     ackrcv_bad;
+       u32     rts_bad;
+       u32     rts_good;
+       u32     fcs_bad;
+       u32     beacons;
+};
+
+
+
+
+/**************************\
+ 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*/
+
+#if 0
+/**
+ * struct ath5k_beacon_state - Per-station beacon timer state.
+ * @bs_interval: in TU's, can also include the above flags
+ * @bs_cfp_max_duration: if non-zero hw is setup to coexist with a
+ *     Point Coordination Function capable AP
+ */
+struct ath5k_beacon_state {
+       u32     bs_next_beacon;
+       u32     bs_next_dtim;
+       u32     bs_interval;
+       u8      bs_dtim_period;
+       u8      bs_cfp_period;
+       u16     bs_cfp_max_duration;
+       u16     bs_cfp_du_remain;
+       u16     bs_tim_offset;
+       u16     bs_sleep_duration;
+       u16     bs_bmiss_threshold;
+       u32     bs_cfp_next;
+};
+#endif
+
+
+/*
+ * TSF to TU conversion:
+ *
+ * TSF is a 64bit value in usec (microseconds).
+ * TU is a 32bit value in roughly msec (milliseconds): usec / 1024
+ * (1000ms equals 976 TU)
+ */
+#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
+
+
+
+/********************\
+  COMMON DEFINITIONS
+\********************/
+
+/*
+ * Atheros descriptor
+ */
+struct ath5k_desc {
+       u32     ds_link;
+       u32     ds_data;
+       u32     ds_ctl0;
+       u32     ds_ctl1;
+       u32     ds_hw[4];
+
+       union {
+               struct ath5k_rx_status rx;
+               struct ath5k_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  /*[5211+]*/
+#define AR5K_TXDESC_RTSENA     0x0004
+#define AR5K_TXDESC_CTSENA     0x0008
+#define AR5K_TXDESC_INTREQ     0x0010
+#define AR5K_TXDESC_VEOL       0x0020  /*[5211+]*/
+
+#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_G       (CHANNEL_2GHZ|CHANNEL_OFDM)
+#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 struct ieee80211_channel.
+ */
+#define IS_CHAN_XR(_c) ((_c.val & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c)  ((_c.val & CHANNEL_B) != 0)
+
+/*
+ * The following structure will be used to map 2GHz channels to
+ * 5GHz Atheros channels.
+ */
+struct ath5k_athchan_2ghz {
+       u32     a2_flags;
+       u16     a2_athchan;
+};
+
+/*
+ * Rate definitions
+ * TODO: Clean them up or move them on mac80211 -most of these infos are
+ *      used by the rate control algorytm on MadWiFi.
+ */
+
+/* Max number of rates on the rate table and what it seems
+ * Atheros hardware supports */
+#define AR5K_MAX_RATES 32
+
+/**
+ * struct ath5k_rate - rate structure
+ * @valid: is this a valid rate for the current mode
+ * @modulation: respective mac80211 modulation
+ * @rate_kbps: rate in kbit/s
+ * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on
+ *     &struct ath5k_rx_status.rs_rate and on TX on
+ *     &struct ath5k_tx_status.ts_rate. Seems the ar5xxx harware supports
+ *     up to 32 rates, indexed by 1-32. This means we really only need
+ *     6 bits for the rate_code.
+ * @dot11_rate: respective IEEE-802.11 rate value
+ * @control_rate: index of rate assumed to be used to send control frames.
+ *     This can be used to set override the value on the rate duration
+ *     registers. This is only useful if we can override in the harware at
+ *     what rate we want to send control frames at. Note that IEEE-802.11
+ *     Ch. 9.6 (after IEEE 802.11g changes) defines the rate at which we
+ *     should send ACK/CTS, if we change this value we can be breaking
+ *     the spec.
+ *
+ * This structure is used to get the RX rate or set the TX rate on the
+ * hardware descriptors. It is also used for internal modulation control
+ * and settings.
+ *
+ * On RX after the &struct ath5k_desc is parsed by the appropriate
+ * ah_proc_rx_desc() the respective hardware rate value is set in
+ * &struct ath5k_rx_status.rs_rate. On TX the desired rate is set in
+ * &struct ath5k_tx_status.ts_rate which is later used to setup the
+ * &struct ath5k_desc correctly. This is the hardware rate map we are
+ * aware of:
+ *
+ * rate_code   1       2       3       4       5       6       7       8
+ * rate_kbps   3000    1000    ?       ?       ?       2000    500     48000
+ *
+ * rate_code   9       10      11      12      13      14      15      16
+ * rate_kbps   24000   12000   6000    54000   36000   18000   9000    ?
+ *
+ * rate_code   17      18      19      20      21      22      23      24
+ * rate_kbps   ?       ?       ?       ?       ?       ?       ?       11000
+ *
+ * rate_code   25      26      27      28      29      30      31      32
+ * rate_kbps   5500    2000    1000    ?       ?       ?       ?       ?
+ *
+ */
+struct ath5k_rate {
+       u8      valid;
+       u32     modulation;
+       u16     rate_kbps;
+       u8      rate_code;
+       u8      dot11_rate;
+       u8      control_rate;
+};
+
+/* XXX: GRR all this stuff to get leds blinking ??? (check out setcurmode) */
+struct ath5k_rate_table {
+       u16     rate_count;
+       u8      rate_code_to_index[AR5K_MAX_RATES];     /* Back-mapping */
+       struct ath5k_rate rates[AR5K_MAX_RATES];
+};
+
+/*
+ * 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, IEEE80211_RATE_OFDM, 6000, 11, 140, 0 },           \
+       { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 0 },            \
+       { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 2 },          \
+       { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 2 },           \
+       { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 4 },           \
+       { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 4 },           \
+       { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 4 },            \
+       { 1, IEEE80211_RATE_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, IEEE80211_RATE_CCK, 1000, 27, 130, 0 },    \
+       { 1, IEEE80211_RATE_CCK_2, 2000, 26, 132, 1 },  \
+       { 1, IEEE80211_RATE_CCK_2, 5500, 25, 139, 1 },  \
+       { 1, IEEE80211_RATE_CCK_2, 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, IEEE80211_RATE_CCK, 1000, 27, 2, 0 },              \
+       { 1, IEEE80211_RATE_CCK_2, 2000, 26, 4, 1 },            \
+       { 1, IEEE80211_RATE_CCK_2, 5500, 25, 11, 1 },           \
+       { 1, IEEE80211_RATE_CCK_2, 11000, 24, 22, 1 },  \
+       { 0, IEEE80211_RATE_OFDM, 6000, 11, 12, 4 },    \
+       { 0, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 },    \
+       { 1, IEEE80211_RATE_OFDM, 12000, 10, 24, 6 },   \
+       { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 },   \
+       { 1, IEEE80211_RATE_OFDM, 24000, 9, 48, 8 },    \
+       { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 },   \
+       { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 },    \
+       { 1, IEEE80211_RATE_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, IEEE80211_RATE_OFDM, 6000, 11, 140, 4 },   \
+       { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 },    \
+       { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 6 },  \
+       { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 },   \
+       { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 8 },   \
+       { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 },   \
+       { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 },    \
+       { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \
+}
+
+/*
+ * Crypto definitions
+ */
+
+#define AR5K_KEYCACHE_SIZE     8
+
+/***********************\
+ 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)
+
+
+enum ath5k_ant_setting {
+       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,
+};
+
+/*
+ * Hardware interrupt abstraction
+ */
+
+/**
+ * enum ath5k_int - Hardware interrupt masks helpers
+ *
+ * @AR5K_INT_RX: mask to identify received frame interrupts, of type
+ *     AR5K_ISR_RXOK or AR5K_ISR_RXERR
+ * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
+ * @AR5K_INT_RXNOFRM: No frame received (?)
+ * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
+ *     Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
+ *     LinkPtr is NULL. For more details, refer to:
+ *     http://www.freepatentsonline.com/20030225739.html
+ * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
+ *     Note that Rx overrun is not always fatal, on some chips we can continue
+ *     operation without reseting the card, that's why int_fatal is not
+ *     common for all chips.
+ * @AR5K_INT_TX: mask to identify received frame interrupts, of type
+ *     AR5K_ISR_TXOK or AR5K_ISR_TXERR
+ * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
+ * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
+ *     We currently do increments on interrupt by
+ *     (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
+ * @AR5K_INT_MIB: Indicates the Management Information Base counters should be
+ *     checked. We should do this with ath5k_hw_update_mib_counters() but
+ *     it seems we should also then do some noise immunity work.
+ * @AR5K_INT_RXPHY: RX PHY Error
+ * @AR5K_INT_RXKCM: ??
+ * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
+ *     beacon that must be handled in software. The alternative is if you
+ *     have VEOL support, in that case you let the hardware deal with things.
+ * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
+ *     beacons from the AP have associated with, we should probably try to
+ *     reassociate. When in IBSS mode this might mean we have not received
+ *     any beacons from any local stations. Note that every station in an
+ *     IBSS schedules to send beacons at the Target Beacon Transmission Time
+ *     (TBTT) with a random backoff.
+ * @AR5K_INT_BNR: Beacon Not Ready interrupt - ??
+ * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now
+ *     until properly handled
+ * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
+ *     errors. These types of errors we can enable seem to be of type
+ *     AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
+ * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER
+ * @AR5K_INT_NOCARD: signals the card has been removed
+ * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
+ *     bit value
+ *
+ * These are mapped to take advantage of some common bits
+ * between the MACs, to be able to set intr properties
+ * easier. Some of them are not used yet inside hw.c. Most map
+ * to the respective hw interrupt value as they are common amogst different
+ * MACs.
+ */
+enum ath5k_int {
+       AR5K_INT_RX     = 0x00000001, /* Not common */
+       AR5K_INT_RXDESC = 0x00000002,
+       AR5K_INT_RXNOFRM = 0x00000008,
+       AR5K_INT_RXEOL  = 0x00000010,
+       AR5K_INT_RXORN  = 0x00000020,
+       AR5K_INT_TX     = 0x00000040, /* Not common */
+       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, /* Not common */
+       AR5K_INT_GPIO   = 0x01000000,
+       AR5K_INT_FATAL  = 0x40000000, /* Not common */
+       AR5K_INT_GLOBAL = 0x80000000,
+
+       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
+};
+
+/*
+ * Power management
+ */
+enum ath5k_power_mode {
+       AR5K_PM_UNDEFINED = 0,
+       AR5K_PM_AUTO,
+       AR5K_PM_AWAKE,
+       AR5K_PM_FULL_SLEEP,
+       AR5K_PM_NETWORK_SLEEP,
+};
+
+/*
+ * 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 ath5k_hw_get_capability-
+ * get_capability function is not yet fully implemented
+ * in OpenHAL so most of these don't work yet...
+ */
+enum ath5k_capability_type {
+       AR5K_CAP_REG_DMN                = 0,    /* Used to get current reg. domain id */
+       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 */
+};
+
+struct ath5k_capabilities {
+       /*
+        * Supported PHY modes
+        * (ie. CHANNEL_A, CHANNEL_B, ...)
+        */
+       DECLARE_BITMAP(cap_mode, NUM_DRIVER_MODES);
+
+       /*
+        * Frequency range (without regulation restrictions)
+        */
+       struct {
+               u16     range_2ghz_min;
+               u16     range_2ghz_max;
+               u16     range_5ghz_min;
+               u16     range_5ghz_max;
+       } cap_range;
+
+       /*
+        * Active regulation domain settings
+        */
+       struct {
+               enum ath5k_regdom reg_current;
+               enum ath5k_regdom reg_hw;
+       } cap_regdomain;
+
+       /*
+        * Values stored in the EEPROM (some of them...)
+        */
+       struct ath5k_eeprom_info        cap_eeprom;
+
+       /*
+        * Queue information
+        */
+       struct {
+               u8      q_tx_num;
+       } cap_queues;
+};
+
+
+/***************************************\
+  HARDWARE ABSTRACTION LAYER STRUCTURE
+\***************************************/
+
+/*
+ * Misc defines
+ */
+
+#define AR5K_MAX_GPIO          10
+#define AR5K_MAX_RF_BANKS      8
+
+struct ath5k_hw {
+       u32                     ah_magic;
+
+       struct ath5k_softc      *ah_sc;
+       void __iomem            *ah_iobase;
+
+       enum ath5k_int          ah_imr;
+
+       enum ieee80211_if_types ah_op_mode;
+       enum ath5k_power_mode   ah_power_mode;
+       struct ieee80211_channel ah_current_channel;
+       bool                    ah_turbo;
+       bool                    ah_calibration;
+       bool                    ah_running;
+       bool                    ah_single_chip;
+       enum ath5k_rfgain       ah_rf_gain;
+
+       u32                     ah_mac_srev;
+       u16                     ah_mac_version;
+       u16                     ah_mac_revision;
+       u16                     ah_phy_revision;
+       u16                     ah_radio_5ghz_revision;
+       u16                     ah_radio_2ghz_revision;
+
+       enum ath5k_version      ah_version;
+       enum ath5k_radio        ah_radio;
+       u32                     ah_phy;
+
+       bool                    ah_5ghz;
+       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
+
+       u32                     ah_atim_window;
+       u32                     ah_aifs;
+       u32                     ah_cw_min;
+       u32                     ah_cw_max;
+       bool                    ah_software_retry;
+       u32                     ah_limit_tx_retries;
+
+       u32                     ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
+       bool                    ah_ant_diversity;
+
+       u8                      ah_sta_id[ETH_ALEN];
+
+       /* Current BSSID we are trying to assoc to / creating.
+        * This is passed by mac80211 on config_interface() and cached here for
+        * use in resets */
+       u8                      ah_bssid[ETH_ALEN];
+
+       u32                     ah_gpio[AR5K_MAX_GPIO];
+       int                     ah_gpio_npins;
+
+       struct ath5k_capabilities ah_capabilities;
+
+       struct ath5k_txq_info   ah_txq[AR5K_NUM_TX_QUEUES];
+       u32                     ah_txq_status;
+       u32                     ah_txq_imr_txok;
+       u32                     ah_txq_imr_txerr;
+       u32                     ah_txq_imr_txurn;
+       u32                     ah_txq_imr_txdesc;
+       u32                     ah_txq_imr_txeol;
+       u32                     *ah_rf_banks;
+       size_t                  ah_rf_banks_size;
+       struct ath5k_gain       ah_gain;
+       u32                     ah_offset[AR5K_MAX_RF_BANKS];
+
+       struct {
+               u16             txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE];
+               u16             txp_rates[AR5K_MAX_RATES];
+               s16             txp_min;
+               s16             txp_max;
+               bool            txp_tpc;
+               s16             txp_ofdm;
+       } ah_txpower;
+
+       struct {
+               bool            r_enabled;
+               int             r_last_alert;
+               struct ieee80211_channel r_last_channel;
+       } ah_radar;
+
+       /* noise floor from last periodic calibration */
+       s32                     ah_noise_floor;
+
+       /*
+        * Function pointers
+        */
+       int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+               unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+               unsigned int, unsigned int, unsigned int, unsigned int,
+               unsigned int, unsigned int, unsigned int);
+       bool (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+               unsigned int, unsigned int, unsigned int, unsigned int,
+               unsigned int, unsigned int);
+       int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *);
+       int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *);
+};
+
+/*
+ * Prototypes
+ */
+
+/* General Functions */
+extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set);
+/* Attach/Detach Functions */
+extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
+extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode);
+extern void ath5k_hw_detach(struct ath5k_hw *ah);
+/* Reset Functions */
+extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel);
+/* Power management functions */
+extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
+/* DMA Related Functions */
+extern void ath5k_hw_start_rx(struct ath5k_hw *ah);
+extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
+extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah);
+extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr);
+extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr);
+extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
+/* Interrupt handling */
+extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
+extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
+extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask);
+/* EEPROM access functions */
+extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
+/* Protocol Control Unit Functions */
+extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
+/* BSSID Functions */
+extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac);
+extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
+extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id);
+extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
+/* Receive start/stop functions */
+extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
+extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah);
+/* RX Filter functions */
+extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
+extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index);
+extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
+extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
+extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
+/* Beacon related functions */
+extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah);
+extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
+extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
+extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
+#if 0
+extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state);
+extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah);
+extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr);
+#endif
+extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ath5k_mib_stats *statistics);
+/* ACK bit rate */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
+/* ACK/CTS Timeouts */
+extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
+extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
+extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
+extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
+/* Key table (WEP) functions */
+extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
+extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry);
+extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac);
+extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
+/* Queue Control Unit, DFS Control Unit Functions */
+extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info);
+extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info);
+extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info);
+extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
+extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
+extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah);
+/* Hardware Descriptor Functions */
+extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags);
+/* GPIO Functions */
+extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
+extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
+extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
+extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
+/* Regulatory Domain/Channels Setup */
+extern u16 ath5k_get_regdomain(struct ath5k_hw *ah);
+/* Misc functions */
+extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
+
+
+/* Initial register settings functions */
+extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
+/* Initialize RF */
+extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
+extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq);
+extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah);
+extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah);
+
+
+/* PHY/RF channel functions */
+extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
+extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
+/* PHY calibration */
+extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
+extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
+/* Misc PHY functions */
+extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
+extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
+extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
+/* TX power setup */
+extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower);
+extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power);
+
+
+static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
+{
+       return ioread32(ah->ah_iobase + reg);
+}
+
+static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
+{
+       iowrite32(val, ah->ah_iobase + reg);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
new file mode 100644 (file)
index 0000000..d3d3728
--- /dev/null
@@ -0,0 +1,2817 @@
+/*-
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/cache.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/uaccess.h>
+
+#include <net/ieee80211_radiotap.h>
+
+#include <asm/unaligned.h>
+
+#include "base.h"
+#include "reg.h"
+#include "debug.h"
+
+/* unaligned little endian access */
+#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p))))
+#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p))))
+
+enum {
+       ATH_LED_TX,
+       ATH_LED_RX,
+};
+
+static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
+
+
+/******************\
+* Internal defines *
+\******************/
+
+/* Module info */
+MODULE_AUTHOR("Jiri Slaby");
+MODULE_AUTHOR("Nick Kossifidis");
+MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards.");
+MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION("0.1.1 (EXPERIMENTAL)");
+
+
+/* Known PCI ids */
+static struct pci_device_id ath5k_pci_id_table[] __devinitdata = {
+       { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */
+       { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */
+       { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/
+       { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */
+       { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */
+       { PCI_VDEVICE(3COM_2,  0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */
+       { PCI_VDEVICE(3COM,    0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */
+       { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */
+       { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */
+       { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */
+       { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/
+       { PCI_VDEVICE(ATHEROS, 0x0023), .driver_data = AR5K_AR5212 }, /* 5416 */
+       { PCI_VDEVICE(ATHEROS, 0x0024), .driver_data = AR5K_AR5212 }, /* 5418 */
+       { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
+
+/* Known SREVs */
+static struct ath5k_srev_name srev_names[] = {
+       { "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 },
+       { "5213A",      AR5K_VERSION_VER,       AR5K_SREV_VER_AR5213A },
+       { "2424",       AR5K_VERSION_VER,       AR5K_SREV_VER_AR2424 },
+       { "5424",       AR5K_VERSION_VER,       AR5K_SREV_VER_AR5424 },
+       { "5413",       AR5K_VERSION_VER,       AR5K_SREV_VER_AR5413 },
+       { "5414",       AR5K_VERSION_VER,       AR5K_SREV_VER_AR5414 },
+       { "5416",       AR5K_VERSION_VER,       AR5K_SREV_VER_AR5416 },
+       { "5418",       AR5K_VERSION_VER,       AR5K_SREV_VER_AR5418 },
+       { "xxxxx",      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 },
+       { "SChip",      AR5K_VERSION_RAD,       AR5K_SREV_RAD_SC1 },
+       { "SChip",      AR5K_VERSION_RAD,       AR5K_SREV_RAD_SC2 },
+       { "5133",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5133 },
+       { "xxxxx",      AR5K_VERSION_RAD,       AR5K_SREV_UNKNOWN },
+};
+
+/*
+ * Prototypes - PCI stack related functions
+ */
+static int __devinit   ath5k_pci_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *id);
+static void __devexit  ath5k_pci_remove(struct pci_dev *pdev);
+#ifdef CONFIG_PM
+static int             ath5k_pci_suspend(struct pci_dev *pdev,
+                                       pm_message_t state);
+static int             ath5k_pci_resume(struct pci_dev *pdev);
+#else
+#define ath5k_pci_suspend NULL
+#define ath5k_pci_resume NULL
+#endif /* CONFIG_PM */
+
+static struct pci_driver ath5k_pci_drv_id = {
+       .name           = "ath5k_pci",
+       .id_table       = ath5k_pci_id_table,
+       .probe          = ath5k_pci_probe,
+       .remove         = __devexit_p(ath5k_pci_remove),
+       .suspend        = ath5k_pci_suspend,
+       .resume         = ath5k_pci_resume,
+};
+
+
+
+/*
+ * Prototypes - MAC 802.11 stack related functions
+ */
+static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+               struct ieee80211_tx_control *ctl);
+static int ath5k_reset(struct ieee80211_hw *hw);
+static int ath5k_start(struct ieee80211_hw *hw);
+static void ath5k_stop(struct ieee80211_hw *hw);
+static int ath5k_add_interface(struct ieee80211_hw *hw,
+               struct ieee80211_if_init_conf *conf);
+static void ath5k_remove_interface(struct ieee80211_hw *hw,
+               struct ieee80211_if_init_conf *conf);
+static int ath5k_config(struct ieee80211_hw *hw,
+               struct ieee80211_conf *conf);
+static int ath5k_config_interface(struct ieee80211_hw *hw, int if_id,
+               struct ieee80211_if_conf *conf);
+static void ath5k_configure_filter(struct ieee80211_hw *hw,
+               unsigned int changed_flags,
+               unsigned int *new_flags,
+               int mc_count, struct dev_mc_list *mclist);
+static int ath5k_set_key(struct ieee80211_hw *hw,
+               enum set_key_cmd cmd,
+               const u8 *local_addr, const u8 *addr,
+               struct ieee80211_key_conf *key);
+static int ath5k_get_stats(struct ieee80211_hw *hw,
+               struct ieee80211_low_level_stats *stats);
+static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
+               struct ieee80211_tx_queue_stats *stats);
+static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
+static void ath5k_reset_tsf(struct ieee80211_hw *hw);
+static int ath5k_beacon_update(struct ieee80211_hw *hw,
+               struct sk_buff *skb,
+               struct ieee80211_tx_control *ctl);
+
+static struct ieee80211_ops ath5k_hw_ops = {
+       .tx             = ath5k_tx,
+       .start          = ath5k_start,
+       .stop           = ath5k_stop,
+       .add_interface  = ath5k_add_interface,
+       .remove_interface = ath5k_remove_interface,
+       .config         = ath5k_config,
+       .config_interface = ath5k_config_interface,
+       .configure_filter = ath5k_configure_filter,
+       .set_key        = ath5k_set_key,
+       .get_stats      = ath5k_get_stats,
+       .conf_tx        = NULL,
+       .get_tx_stats   = ath5k_get_tx_stats,
+       .get_tsf        = ath5k_get_tsf,
+       .reset_tsf      = ath5k_reset_tsf,
+       .beacon_update  = ath5k_beacon_update,
+};
+
+/*
+ * Prototypes - Internal functions
+ */
+/* Attach detach */
+static int     ath5k_attach(struct pci_dev *pdev,
+                       struct ieee80211_hw *hw);
+static void    ath5k_detach(struct pci_dev *pdev,
+                       struct ieee80211_hw *hw);
+/* Channel/mode setup */
+static inline short ath5k_ieee2mhz(short chan);
+static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates,
+                               const struct ath5k_rate_table *rt,
+                               unsigned int max);
+static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
+                               struct ieee80211_channel *channels,
+                               unsigned int mode,
+                               unsigned int max);
+static int     ath5k_getchannels(struct ieee80211_hw *hw);
+static int     ath5k_chan_set(struct ath5k_softc *sc,
+                               struct ieee80211_channel *chan);
+static void    ath5k_setcurmode(struct ath5k_softc *sc,
+                               unsigned int mode);
+static void    ath5k_mode_setup(struct ath5k_softc *sc);
+/* Descriptor setup */
+static int     ath5k_desc_alloc(struct ath5k_softc *sc,
+                               struct pci_dev *pdev);
+static void    ath5k_desc_free(struct ath5k_softc *sc,
+                               struct pci_dev *pdev);
+/* Buffers setup */
+static int     ath5k_rxbuf_setup(struct ath5k_softc *sc,
+                               struct ath5k_buf *bf);
+static int     ath5k_txbuf_setup(struct ath5k_softc *sc,
+                               struct ath5k_buf *bf,
+                               struct ieee80211_tx_control *ctl);
+
+static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
+                               struct ath5k_buf *bf)
+{
+       BUG_ON(!bf);
+       if (!bf->skb)
+               return;
+       pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len,
+                       PCI_DMA_TODEVICE);
+       dev_kfree_skb(bf->skb);
+       bf->skb = NULL;
+}
+
+/* Queues setup */
+static struct  ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc,
+                               int qtype, int subtype);
+static int     ath5k_beaconq_setup(struct ath5k_hw *ah);
+static int     ath5k_beaconq_config(struct ath5k_softc *sc);
+static void    ath5k_txq_drainq(struct ath5k_softc *sc,
+                               struct ath5k_txq *txq);
+static void    ath5k_txq_cleanup(struct ath5k_softc *sc);
+static void    ath5k_txq_release(struct ath5k_softc *sc);
+/* Rx handling */
+static int     ath5k_rx_start(struct ath5k_softc *sc);
+static void    ath5k_rx_stop(struct ath5k_softc *sc);
+static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc,
+                                       struct ath5k_desc *ds,
+                                       struct sk_buff *skb);
+static void    ath5k_tasklet_rx(unsigned long data);
+/* Tx handling */
+static void    ath5k_tx_processq(struct ath5k_softc *sc,
+                               struct ath5k_txq *txq);
+static void    ath5k_tasklet_tx(unsigned long data);
+/* Beacon handling */
+static int     ath5k_beacon_setup(struct ath5k_softc *sc,
+                               struct ath5k_buf *bf,
+                               struct ieee80211_tx_control *ctl);
+static void    ath5k_beacon_send(struct ath5k_softc *sc);
+static void    ath5k_beacon_config(struct ath5k_softc *sc);
+
+static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
+{
+       u64 tsf = ath5k_hw_get_tsf64(ah);
+
+       if ((tsf & 0x7fff) < rstamp)
+               tsf -= 0x8000;
+
+       return (tsf & ~0x7fff) | rstamp;
+}
+
+/* Interrupt handling */
+static int     ath5k_init(struct ath5k_softc *sc);
+static int     ath5k_stop_locked(struct ath5k_softc *sc);
+static int     ath5k_stop_hw(struct ath5k_softc *sc);
+static irqreturn_t ath5k_intr(int irq, void *dev_id);
+static void    ath5k_tasklet_reset(unsigned long data);
+
+static void    ath5k_calibrate(unsigned long data);
+/* LED functions */
+static void    ath5k_led_off(unsigned long data);
+static void    ath5k_led_blink(struct ath5k_softc *sc,
+                               unsigned int on,
+                               unsigned int off);
+static void    ath5k_led_event(struct ath5k_softc *sc,
+                               int event);
+
+
+/*
+ * Module init/exit functions
+ */
+static int __init
+init_ath5k_pci(void)
+{
+       int ret;
+
+       ath5k_debug_init();
+
+       ret = pci_register_driver(&ath5k_pci_drv_id);
+       if (ret) {
+               printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit
+exit_ath5k_pci(void)
+{
+       pci_unregister_driver(&ath5k_pci_drv_id);
+
+       ath5k_debug_finish();
+}
+
+module_init(init_ath5k_pci);
+module_exit(exit_ath5k_pci);
+
+
+/********************\
+* PCI Initialization *
+\********************/
+
+static const char *
+ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
+{
+       const char *name = "xxxxx";
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(srev_names); i++) {
+               if (srev_names[i].sr_type != type)
+                       continue;
+               if ((val & 0xff) < srev_names[i + 1].sr_val) {
+                       name = srev_names[i].sr_name;
+                       break;
+               }
+       }
+
+       return name;
+}
+
+static int __devinit
+ath5k_pci_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       void __iomem *mem;
+       struct ath5k_softc *sc;
+       struct ieee80211_hw *hw;
+       int ret;
+       u8 csz;
+
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "can't enable device\n");
+               goto err;
+       }
+
+       /* XXX 32-bit addressing only */
+       ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       if (ret) {
+               dev_err(&pdev->dev, "32-bit DMA not available\n");
+               goto err_dis;
+       }
+
+       /*
+        * Cache line size is used to size and align various
+        * structures used to communicate with the hardware.
+        */
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+       if (csz == 0) {
+               /*
+                * Linux 2.4.18 (at least) writes the cache line size
+                * register as a 16-bit wide register which is wrong.
+                * We must have this setup properly for rx buffer
+                * DMA to work so force a reasonable value here if it
+                * comes up zero.
+                */
+               csz = L1_CACHE_BYTES / sizeof(u32);
+               pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+       }
+       /*
+        * The default setting of latency timer yields poor results,
+        * set it to the value used by other systems.  It may be worth
+        * tweaking this setting more.
+        */
+       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+       /* Enable bus mastering */
+       pci_set_master(pdev);
+
+       /*
+        * Disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state.
+        */
+       pci_write_config_byte(pdev, 0x41, 0);
+
+       ret = pci_request_region(pdev, 0, "ath5k");
+       if (ret) {
+               dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
+               goto err_dis;
+       }
+
+       mem = pci_iomap(pdev, 0, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
+               ret = -EIO;
+               goto err_reg;
+       }
+
+       /*
+        * Allocate hw (mac80211 main struct)
+        * and hw->priv (driver private data)
+        */
+       hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
+       if (hw == NULL) {
+               dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
+               ret = -ENOMEM;
+               goto err_map;
+       }
+
+       dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
+
+       /* Initialize driver private data */
+       SET_IEEE80211_DEV(hw, &pdev->dev);
+       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS;
+       hw->extra_tx_headroom = 2;
+       hw->channel_change_time = 5000;
+       /* these names are misleading */
+       hw->max_rssi = -110; /* signal in dBm */
+       hw->max_noise = -110; /* noise in dBm */
+       hw->max_signal = 100; /* we will provide a percentage based on rssi */
+       sc = hw->priv;
+       sc->hw = hw;
+       sc->pdev = pdev;
+
+       ath5k_debug_init_device(sc);
+
+       /*
+        * Mark the device as detached to avoid processing
+        * interrupts until setup is complete.
+        */
+       __set_bit(ATH_STAT_INVALID, sc->status);
+
+       sc->iobase = mem; /* So we can unmap it on detach */
+       sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
+       sc->opmode = IEEE80211_IF_TYPE_STA;
+       mutex_init(&sc->lock);
+       spin_lock_init(&sc->rxbuflock);
+       spin_lock_init(&sc->txbuflock);
+
+       /* Set private data */
+       pci_set_drvdata(pdev, hw);
+
+       /* Enable msi for devices that support it */
+       pci_enable_msi(pdev);
+
+       /* Setup interrupt handler */
+       ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
+       if (ret) {
+               ATH5K_ERR(sc, "request_irq failed\n");
+               goto err_free;
+       }
+
+       /* Initialize device */
+       sc->ah = ath5k_hw_attach(sc, id->driver_data);
+       if (IS_ERR(sc->ah)) {
+               ret = PTR_ERR(sc->ah);
+               goto err_irq;
+       }
+
+       /* Finish private driver data initialization */
+       ret = ath5k_attach(pdev, hw);
+       if (ret)
+               goto err_ah;
+
+       ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
+                       ath5k_chip_name(AR5K_VERSION_VER,sc->ah->ah_mac_srev),
+                                       sc->ah->ah_mac_srev,
+                                       sc->ah->ah_phy_revision);
+
+       if(!sc->ah->ah_single_chip){
+               /* Single chip radio (!RF5111) */
+               if(sc->ah->ah_radio_5ghz_revision && !sc->ah->ah_radio_2ghz_revision) {
+                       /* No 5GHz support -> report 2GHz radio */
+                       if(!test_bit(MODE_IEEE80211A, sc->ah->ah_capabilities.cap_mode)){
+                               ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+                                       ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
+                                                       sc->ah->ah_radio_5ghz_revision);
+                       /* No 2GHz support (5110 and some 5Ghz only cards) -> report 5Ghz radio */
+                       } else if(!test_bit(MODE_IEEE80211B, sc->ah->ah_capabilities.cap_mode)){
+                               ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+                                       ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
+                                                       sc->ah->ah_radio_5ghz_revision);
+                       /* Multiband radio */
+                       } else {
+                               ATH5K_INFO(sc, "RF%s multiband radio found"
+                                       " (0x%x)\n",
+                                       ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
+                                                       sc->ah->ah_radio_5ghz_revision);
+                       }
+               }
+               /* Multi chip radio (RF5111 - RF2111) -> report both 2GHz/5GHz radios */
+               else if(sc->ah->ah_radio_5ghz_revision && sc->ah->ah_radio_2ghz_revision){
+                       ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+                               ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
+                                               sc->ah->ah_radio_5ghz_revision);
+                       ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+                               ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_2ghz_revision),
+                                               sc->ah->ah_radio_2ghz_revision);
+               }
+       }
+
+
+       /* ready to process interrupts */
+       __clear_bit(ATH_STAT_INVALID, sc->status);
+
+       return 0;
+err_ah:
+       ath5k_hw_detach(sc->ah);
+err_irq:
+       free_irq(pdev->irq, sc);
+err_free:
+       pci_disable_msi(pdev);
+       ieee80211_free_hw(hw);
+err_map:
+       pci_iounmap(pdev, mem);
+err_reg:
+       pci_release_region(pdev, 0);
+err_dis:
+       pci_disable_device(pdev);
+err:
+       return ret;
+}
+
+static void __devexit
+ath5k_pci_remove(struct pci_dev *pdev)
+{
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct ath5k_softc *sc = hw->priv;
+
+       ath5k_debug_finish_device(sc);
+       ath5k_detach(pdev, hw);
+       ath5k_hw_detach(sc->ah);
+       free_irq(pdev->irq, sc);
+       pci_disable_msi(pdev);
+       pci_iounmap(pdev, sc->iobase);
+       pci_release_region(pdev, 0);
+       pci_disable_device(pdev);
+       ieee80211_free_hw(hw);
+}
+
+#ifdef CONFIG_PM
+static int
+ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct ath5k_softc *sc = hw->priv;
+
+       if (test_bit(ATH_STAT_LEDSOFT, sc->status))
+               ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1);
+
+       ath5k_stop_hw(sc);
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       return 0;
+}
+
+static int
+ath5k_pci_resume(struct pci_dev *pdev)
+{
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct ath5k_softc *sc = hw->priv;
+       int err;
+
+       err = pci_set_power_state(pdev, PCI_D0);
+       if (err)
+               return err;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       pci_restore_state(pdev);
+       /*
+        * Suspend/Resume resets the PCI configuration space, so we have to
+        * re-disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state
+        */
+       pci_write_config_byte(pdev, 0x41, 0);
+
+       ath5k_init(sc);
+       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+               ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
+               ath5k_hw_set_gpio(sc->ah, sc->led_pin, 0);
+       }
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+
+
+/***********************\
+* Driver Initialization *
+\***********************/
+
+static int
+ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+{
+       struct ath5k_softc *sc = hw->priv;
+       struct ath5k_hw *ah = sc->ah;
+       u8 mac[ETH_ALEN];
+       unsigned int i;
+       int ret;
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
+
+       /*
+        * Check if the MAC has multi-rate retry support.
+        * We do this by trying to setup a fake extended
+        * descriptor.  MAC's that don't have support will
+        * return false w/o doing anything.  MAC's that do
+        * support it will return true w/o doing anything.
+        */
+       if (ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0))
+               __set_bit(ATH_STAT_MRRETRY, sc->status);
+
+       /*
+        * Reset the key cache since some parts do not
+        * reset the contents on initial power up.
+        */
+       for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
+               ath5k_hw_reset_key(ah, i);
+
+       /*
+        * Collect the channel list.  The 802.11 layer
+        * is resposible for filtering this list based
+        * on settings like the phy mode and regulatory
+        * domain restrictions.
+        */
+       ret = ath5k_getchannels(hw);
+       if (ret) {
+               ATH5K_ERR(sc, "can't get channels\n");
+               goto err;
+       }
+
+       /* NB: setup here so ath5k_rate_update is happy */
+       if (test_bit(MODE_IEEE80211A, ah->ah_modes))
+               ath5k_setcurmode(sc, MODE_IEEE80211A);
+       else
+               ath5k_setcurmode(sc, MODE_IEEE80211B);
+
+       /*
+        * Allocate tx+rx descriptors and populate the lists.
+        */
+       ret = ath5k_desc_alloc(sc, pdev);
+       if (ret) {
+               ATH5K_ERR(sc, "can't allocate descriptors\n");
+               goto err;
+       }
+
+       /*
+        * Allocate hardware transmit queues: one queue for
+        * beacon frames and one data queue for each QoS
+        * priority.  Note that hw functions handle reseting
+        * these queues at the needed time.
+        */
+       ret = ath5k_beaconq_setup(ah);
+       if (ret < 0) {
+               ATH5K_ERR(sc, "can't setup a beacon xmit queue\n");
+               goto err_desc;
+       }
+       sc->bhalq = ret;
+
+       sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
+       if (IS_ERR(sc->txq)) {
+               ATH5K_ERR(sc, "can't setup xmit queue\n");
+               ret = PTR_ERR(sc->txq);
+               goto err_bhal;
+       }
+
+       tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
+       tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
+       tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
+       setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
+       setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc);
+
+       sc->led_on = 0; /* low true */
+       /*
+        * Auto-enable soft led processing for IBM cards and for
+        * 5211 minipci cards.
+        */
+       if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
+                       pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
+               __set_bit(ATH_STAT_LEDSOFT, sc->status);
+               sc->led_pin = 0;
+       }
+       /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
+       if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
+               __set_bit(ATH_STAT_LEDSOFT, sc->status);
+               sc->led_pin = 0;
+       }
+       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+               ath5k_hw_set_gpio_output(ah, sc->led_pin);
+               ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
+       }
+
+       ath5k_hw_get_lladdr(ah, mac);
+       SET_IEEE80211_PERM_ADDR(hw, mac);
+       /* All MAC address bits matter for ACKs */
+       memset(sc->bssidmask, 0xff, ETH_ALEN);
+       ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+
+       ret = ieee80211_register_hw(hw);
+       if (ret) {
+               ATH5K_ERR(sc, "can't register ieee80211 hw\n");
+               goto err_queues;
+       }
+
+       return 0;
+err_queues:
+       ath5k_txq_release(sc);
+err_bhal:
+       ath5k_hw_release_tx_queue(ah, sc->bhalq);
+err_desc:
+       ath5k_desc_free(sc, pdev);
+err:
+       return ret;
+}
+
+static void
+ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       /*
+        * NB: the order of these is important:
+        * o call the 802.11 layer before detaching ath5k_hw to
+        *   insure callbacks into the driver to delete global
+        *   key cache entries can be handled
+        * o reclaim the tx queue data structures after calling
+        *   the 802.11 layer as we'll get called back to reclaim
+        *   node state and potentially want to use them
+        * o to cleanup the tx queues the hal is called, so detach
+        *   it last
+        * XXX: ??? detach ath5k_hw ???
+        * Other than that, it's straightforward...
+        */
+       ieee80211_unregister_hw(hw);
+       ath5k_desc_free(sc, pdev);
+       ath5k_txq_release(sc);
+       ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
+
+       /*
+        * NB: can't reclaim these until after ieee80211_ifdetach
+        * returns because we'll get called back to reclaim node
+        * state and potentially want to use them.
+        */
+}
+
+
+
+
+/********************\
+* Channel/mode setup *
+\********************/
+
+/*
+ * Convert IEEE channel number to MHz frequency.
+ */
+static inline short
+ath5k_ieee2mhz(short chan)
+{
+       if (chan <= 14 || chan >= 27)
+               return ieee80211chan2mhz(chan);
+       else
+               return 2212 + chan * 20;
+}
+
+static unsigned int
+ath5k_copy_rates(struct ieee80211_rate *rates,
+               const struct ath5k_rate_table *rt,
+               unsigned int max)
+{
+       unsigned int i, count;
+
+       if (rt == NULL)
+               return 0;
+
+       for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) {
+               if (!rt->rates[i].valid)
+                       continue;
+               rates->rate = rt->rates[i].rate_kbps / 100;
+               rates->val = rt->rates[i].rate_code;
+               rates->flags = rt->rates[i].modulation;
+               rates++;
+               count++;
+               max--;
+       }
+
+       return count;
+}
+
+static unsigned int
+ath5k_copy_channels(struct ath5k_hw *ah,
+               struct ieee80211_channel *channels,
+               unsigned int mode,
+               unsigned int max)
+{
+       static const struct { unsigned int mode, mask, chan; } map[] = {
+               [MODE_IEEE80211A] = { CHANNEL_OFDM, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_A },
+               [MODE_ATHEROS_TURBO] = { CHANNEL_OFDM|CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_T },
+               [MODE_IEEE80211B] = { CHANNEL_CCK, CHANNEL_CCK, CHANNEL_B },
+               [MODE_IEEE80211G] = { CHANNEL_OFDM, CHANNEL_OFDM, CHANNEL_G },
+               [MODE_ATHEROS_TURBOG] = { CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_TG },
+       };
+       static const struct ath5k_regchannel chans_2ghz[] =
+               IEEE80211_CHANNELS_2GHZ;
+       static const struct ath5k_regchannel chans_5ghz[] =
+               IEEE80211_CHANNELS_5GHZ;
+       const struct ath5k_regchannel *chans;
+       enum ath5k_regdom dmn;
+       unsigned int i, count, size, chfreq, all, f, ch;
+
+       if (!test_bit(mode, ah->ah_modes))
+               return 0;
+
+       all = ah->ah_regdomain == DMN_DEFAULT || CHAN_DEBUG == 1;
+
+       switch (mode) {
+       case MODE_IEEE80211A:
+       case MODE_ATHEROS_TURBO:
+               /* 1..220, but 2GHz frequencies are filtered by check_channel */
+               size = all ? 220 : ARRAY_SIZE(chans_5ghz);
+               chans = chans_5ghz;
+               dmn = ath5k_regdom2flag(ah->ah_regdomain,
+                               IEEE80211_CHANNELS_5GHZ_MIN);
+               chfreq = CHANNEL_5GHZ;
+               break;
+       case MODE_IEEE80211B:
+       case MODE_IEEE80211G:
+       case MODE_ATHEROS_TURBOG:
+               size = all ? 26 : ARRAY_SIZE(chans_2ghz);
+               chans = chans_2ghz;
+               dmn = ath5k_regdom2flag(ah->ah_regdomain,
+                               IEEE80211_CHANNELS_2GHZ_MIN);
+               chfreq = CHANNEL_2GHZ;
+               break;
+       default:
+               ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n");
+               return 0;
+       }
+
+       for (i = 0, count = 0; i < size && max > 0; i++) {
+               ch = all ? i + 1 : chans[i].chan;
+               f = ath5k_ieee2mhz(ch);
+               /* Check if channel is supported by the chipset */
+               if (!ath5k_channel_ok(ah, f, chfreq))
+                       continue;
+
+               /* Match regulation domain */
+               if (!all && !(IEEE80211_DMN(chans[i].domain) &
+                                                       IEEE80211_DMN(dmn)))
+                       continue;
+
+               if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode)
+                       continue;
+
+               /* Write channel and increment counter */
+               channels->chan = ch;
+               channels->freq = f;
+               channels->val = map[mode].chan;
+               channels++;
+               count++;
+               max--;
+       }
+
+       return count;
+}
+
+/* Only tries to register modes our EEPROM says it can support */
+#define REGISTER_MODE(m) do { \
+       ret = ath5k_register_mode(hw, m); \
+       if (ret) \
+               return ret; \
+} while (0) \
+
+static inline int
+ath5k_register_mode(struct ieee80211_hw *hw, u8 m)
+{
+       struct ath5k_softc *sc = hw->priv;
+       struct ieee80211_hw_mode *modes = sc->modes;
+       unsigned int i;
+       int ret;
+
+       if (!test_bit(m, sc->ah->ah_capabilities.cap_mode))
+               return 0;
+
+       for (i = 0; i < NUM_DRIVER_MODES; i++) {
+               if (modes[i].mode != m || !modes[i].num_channels)
+                       continue;
+               ret = ieee80211_register_hwmode(hw, &modes[i]);
+               if (ret) {
+                       ATH5K_ERR(sc, "can't register hwmode %u\n", m);
+                       return ret;
+               }
+               return 0;
+       }
+       BUG();
+}
+
+static int
+ath5k_getchannels(struct ieee80211_hw *hw)
+{
+       struct ath5k_softc *sc = hw->priv;
+       struct ath5k_hw *ah = sc->ah;
+       struct ieee80211_hw_mode *modes = sc->modes;
+       unsigned int i, max_r, max_c;
+       int ret;
+
+       BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 3);
+
+       /* The order here does not matter */
+       modes[0].mode = MODE_IEEE80211G;
+       modes[1].mode = MODE_IEEE80211B;
+       modes[2].mode = MODE_IEEE80211A;
+
+       max_r = ARRAY_SIZE(sc->rates);
+       max_c = ARRAY_SIZE(sc->channels);
+
+       for (i = 0; i < NUM_DRIVER_MODES; i++) {
+               struct ieee80211_hw_mode *mode = &modes[i];
+               const struct ath5k_rate_table *hw_rates;
+
+               if (i == 0) {
+                       modes[0].rates  = sc->rates;
+                       modes->channels = sc->channels;
+               } else {
+                       struct ieee80211_hw_mode *prev_mode = &modes[i-1];
+                       int prev_num_r  = prev_mode->num_rates;
+                       int prev_num_c  = prev_mode->num_channels;
+                       mode->rates     = &prev_mode->rates[prev_num_r];
+                       mode->channels  = &prev_mode->channels[prev_num_c];
+               }
+
+               hw_rates = ath5k_hw_get_rate_table(ah, mode->mode);
+               mode->num_rates    = ath5k_copy_rates(mode->rates, hw_rates,
+                       max_r);
+               mode->num_channels = ath5k_copy_channels(ah, mode->channels,
+                       mode->mode, max_c);
+               max_r -= mode->num_rates;
+               max_c -= mode->num_channels;
+       }
+
+       /* We try to register all modes this driver supports. We don't bother
+        * with MODE_IEEE80211B for AR5212 as MODE_IEEE80211G already accounts
+        * for that as per mac80211. Then, REGISTER_MODE() will will actually
+        * check the eeprom reading for more reliable capability information.
+        * Order matters here as per mac80211's latest preference. This will
+        * all hopefullly soon go away. */
+
+       REGISTER_MODE(MODE_IEEE80211G);
+       if (ah->ah_version != AR5K_AR5212)
+               REGISTER_MODE(MODE_IEEE80211B);
+       REGISTER_MODE(MODE_IEEE80211A);
+
+       ath5k_debug_dump_modes(sc, modes);
+
+       return ret;
+}
+
+/*
+ * Set/change channels.  If the channel is really being changed,
+ * it's done by reseting the chip.  To accomplish this we must
+ * first cleanup any pending DMA, then restart stuff after a la
+ * ath5k_init.
+ */
+static int
+ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
+{
+       struct ath5k_hw *ah = sc->ah;
+       int ret;
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "%u (%u MHz) -> %u (%u MHz)\n",
+               sc->curchan->chan, sc->curchan->freq,
+               chan->chan, chan->freq);
+
+       if (chan->freq != sc->curchan->freq || chan->val != sc->curchan->val) {
+               /*
+                * To switch channels clear any pending DMA operations;
+                * wait long enough for the RX fifo to drain, reset the
+                * hardware at the new frequency, and then re-enable
+                * the relevant bits of the h/w.
+                */
+               ath5k_hw_set_intr(ah, 0);       /* disable interrupts */
+               ath5k_txq_cleanup(sc);          /* clear pending tx frames */
+               ath5k_rx_stop(sc);              /* turn off frame recv */
+               ret = ath5k_hw_reset(ah, sc->opmode, chan, true);
+               if (ret) {
+                       ATH5K_ERR(sc, "%s: unable to reset channel %u "
+                               "(%u Mhz)\n", __func__, chan->chan, chan->freq);
+                       return ret;
+               }
+               sc->curchan = chan;
+               ath5k_hw_set_txpower_limit(sc->ah, 0);
+
+               /*
+                * Re-enable rx framework.
+                */
+               ret = ath5k_rx_start(sc);
+               if (ret) {
+                       ATH5K_ERR(sc, "%s: unable to restart recv logic\n",
+                                       __func__);
+                       return ret;
+               }
+
+               /*
+                * Change channels and update the h/w rate map
+                * if we're switching; e.g. 11a to 11b/g.
+                *
+                * XXX needed?
+                */
+/*             ath5k_chan_change(sc, chan); */
+
+               ath5k_beacon_config(sc);
+               /*
+                * Re-enable interrupts.
+                */
+               ath5k_hw_set_intr(ah, sc->imask);
+       }
+
+       return 0;
+}
+
+static void
+ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
+{
+       if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) {
+               /* from Atheros NDIS driver, w/ permission */
+               static const struct {
+                       u16 rate;       /* tx/rx 802.11 rate */
+                       u16 timeOn;     /* LED on time (ms) */
+                       u16 timeOff;    /* LED off time (ms) */
+               } blinkrates[] = {
+                       { 108,  40,  10 },
+                       {  96,  44,  11 },
+                       {  72,  50,  13 },
+                       {  48,  57,  14 },
+                       {  36,  67,  16 },
+                       {  24,  80,  20 },
+                       {  22, 100,  25 },
+                       {  18, 133,  34 },
+                       {  12, 160,  40 },
+                       {  10, 200,  50 },
+                       {   6, 240,  58 },
+                       {   4, 267,  66 },
+                       {   2, 400, 100 },
+                       {   0, 500, 130 }
+               };
+               const struct ath5k_rate_table *rt =
+                               ath5k_hw_get_rate_table(sc->ah, mode);
+               unsigned int i, j;
+
+               BUG_ON(rt == NULL);
+
+               memset(sc->hwmap, 0, sizeof(sc->hwmap));
+               for (i = 0; i < 32; i++) {
+                       u8 ix = rt->rate_code_to_index[i];
+                       if (ix == 0xff) {
+                               sc->hwmap[i].ledon = msecs_to_jiffies(500);
+                               sc->hwmap[i].ledoff = msecs_to_jiffies(130);
+                               continue;
+                       }
+                       sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
+                       if (SHPREAMBLE_FLAG(ix) || rt->rates[ix].modulation ==
+                                       IEEE80211_RATE_OFDM)
+                               sc->hwmap[i].txflags |=
+                                               IEEE80211_RADIOTAP_F_SHORTPRE;
+                       /* receive frames include FCS */
+                       sc->hwmap[i].rxflags = sc->hwmap[i].txflags |
+                                       IEEE80211_RADIOTAP_F_FCS;
+                       /* setup blink rate table to avoid per-packet lookup */
+                       for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++)
+                               if (blinkrates[j].rate == /* XXX why 7f? */
+                                               (rt->rates[ix].dot11_rate&0x7f))
+                                       break;
+
+                       sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j].
+                                       timeOn);
+                       sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j].
+                                       timeOff);
+               }
+       }
+
+       sc->curmode = mode;
+}
+
+static void
+ath5k_mode_setup(struct ath5k_softc *sc)
+{
+       struct ath5k_hw *ah = sc->ah;
+       u32 rfilt;
+
+       /* configure rx filter */
+       rfilt = sc->filter_flags;
+       ath5k_hw_set_rx_filter(ah, rfilt);
+
+       if (ath5k_hw_hasbssidmask(ah))
+               ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
+
+       /* configure operational mode */
+       ath5k_hw_set_opmode(ah);
+
+       ath5k_hw_set_mcast_filter(ah, 0, 0);
+       ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
+}
+
+
+
+
+/***************\
+* Buffers setup *
+\***************/
+
+static int
+ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+{
+       struct ath5k_hw *ah = sc->ah;
+       struct sk_buff *skb = bf->skb;
+       struct ath5k_desc *ds;
+
+       if (likely(skb == NULL)) {
+               unsigned int off;
+
+               /*
+                * Allocate buffer with headroom_needed space for the
+                * fake physical layer header at the start.
+                */
+               skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
+               if (unlikely(skb == NULL)) {
+                       ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
+                                       sc->rxbufsize + sc->cachelsz - 1);
+                       return -ENOMEM;
+               }
+               /*
+                * Cache-line-align.  This is important (for the
+                * 5210 at least) as not doing so causes bogus data
+                * in rx'd frames.
+                */
+               off = ((unsigned long)skb->data) % sc->cachelsz;
+               if (off != 0)
+                       skb_reserve(skb, sc->cachelsz - off);
+
+               bf->skb = skb;
+               bf->skbaddr = pci_map_single(sc->pdev,
+                       skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
+               if (unlikely(pci_dma_mapping_error(bf->skbaddr))) {
+                       ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
+                       dev_kfree_skb(skb);
+                       bf->skb = NULL;
+                       return -ENOMEM;
+               }
+       }
+
+       /*
+        * Setup descriptors.  For receive we always terminate
+        * the descriptor list with a self-linked entry so we'll
+        * not get overrun under high load (as can happen with a
+        * 5212 when ANI processing enables PHY error frames).
+        *
+        * To insure the last descriptor is self-linked we create
+        * each descriptor as self-linked and add it to the end.  As
+        * each additional descriptor is added the previous self-linked
+        * entry is ``fixed'' naturally.  This should be safe even
+        * if DMA is happening.  When processing RX interrupts we
+        * never remove/process the last, self-linked, entry on the
+        * descriptor list.  This insures the hardware always has
+        * someplace to write a new frame.
+        */
+       ds = bf->desc;
+       ds->ds_link = bf->daddr;        /* link to self */
+       ds->ds_data = bf->skbaddr;
+       ath5k_hw_setup_rx_desc(ah, ds,
+               skb_tailroom(skb),      /* buffer size */
+               0);
+
+       if (sc->rxlink != NULL)
+               *sc->rxlink = bf->daddr;
+       sc->rxlink = &ds->ds_link;
+       return 0;
+}
+
+static int
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+               struct ieee80211_tx_control *ctl)
+{
+       struct ath5k_hw *ah = sc->ah;
+       struct ath5k_txq *txq = sc->txq;
+       struct ath5k_desc *ds = bf->desc;
+       struct sk_buff *skb = bf->skb;
+       unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
+       int ret;
+
+       flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
+       bf->ctl = *ctl;
+       /* XXX endianness */
+       bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
+                       PCI_DMA_TODEVICE);
+
+       if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
+               flags |= AR5K_TXDESC_NOACK;
+
+       pktlen = skb->len + FCS_LEN;
+
+       if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
+               keyidx = ctl->key_idx;
+               pktlen += ctl->icv_len;
+       }
+
+       ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
+               ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
+               (ctl->power_level * 2), ctl->tx_rate, ctl->retry_limit, keyidx, 0, flags, 0, 0);
+       if (ret)
+               goto err_unmap;
+
+       ds->ds_link = 0;
+       ds->ds_data = bf->skbaddr;
+
+       spin_lock_bh(&txq->lock);
+       list_add_tail(&bf->list, &txq->q);
+       sc->tx_stats.data[txq->qnum].len++;
+       if (txq->link == NULL) /* is this first packet? */
+               ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr);
+       else /* no, so only link it */
+               *txq->link = bf->daddr;
+
+       txq->link = &ds->ds_link;
+       ath5k_hw_tx_start(ah, txq->qnum);
+       spin_unlock_bh(&txq->lock);
+
+       return 0;
+err_unmap:
+       pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
+       return ret;
+}
+
+/*******************\
+* Descriptors setup *
+\*******************/
+
+static int
+ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
+{
+       struct ath5k_desc *ds;
+       struct ath5k_buf *bf;
+       dma_addr_t da;
+       unsigned int i;
+       int ret;
+
+       /* allocate descriptors */
+       sc->desc_len = sizeof(struct ath5k_desc) *
+                       (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1);
+       sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr);
+       if (sc->desc == NULL) {
+               ATH5K_ERR(sc, "can't allocate descriptors\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       ds = sc->desc;
+       da = sc->desc_daddr;
+       ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n",
+               ds, sc->desc_len, (unsigned long long)sc->desc_daddr);
+
+       bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF,
+                       sizeof(struct ath5k_buf), GFP_KERNEL);
+       if (bf == NULL) {
+               ATH5K_ERR(sc, "can't allocate bufptr\n");
+               ret = -ENOMEM;
+               goto err_free;
+       }
+       sc->bufptr = bf;
+
+       INIT_LIST_HEAD(&sc->rxbuf);
+       for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+               bf->desc = ds;
+               bf->daddr = da;
+               list_add_tail(&bf->list, &sc->rxbuf);
+       }
+
+       INIT_LIST_HEAD(&sc->txbuf);
+       sc->txbuf_len = ATH_TXBUF;
+       for (i = 0; i < ATH_TXBUF; i++, bf++, ds++,
+                       da += sizeof(*ds)) {
+               bf->desc = ds;
+               bf->daddr = da;
+               list_add_tail(&bf->list, &sc->txbuf);
+       }
+
+       /* beacon buffer */
+       bf->desc = ds;
+       bf->daddr = da;
+       sc->bbuf = bf;
+
+       return 0;
+err_free:
+       pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+err:
+       sc->desc = NULL;
+       return ret;
+}
+
+static void
+ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
+{
+       struct ath5k_buf *bf;
+
+       ath5k_txbuf_free(sc, sc->bbuf);
+       list_for_each_entry(bf, &sc->txbuf, list)
+               ath5k_txbuf_free(sc, bf);
+       list_for_each_entry(bf, &sc->rxbuf, list)
+               ath5k_txbuf_free(sc, bf);
+
+       /* Free memory associated with all descriptors */
+       pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+
+       kfree(sc->bufptr);
+       sc->bufptr = NULL;
+}
+
+
+
+
+
+/**************\
+* Queues setup *
+\**************/
+
+static struct ath5k_txq *
+ath5k_txq_setup(struct ath5k_softc *sc,
+               int qtype, int subtype)
+{
+       struct ath5k_hw *ah = sc->ah;
+       struct ath5k_txq *txq;
+       struct ath5k_txq_info qi = {
+               .tqi_subtype = subtype,
+               .tqi_aifs = AR5K_TXQ_USEDEFAULT,
+               .tqi_cw_min = AR5K_TXQ_USEDEFAULT,
+               .tqi_cw_max = AR5K_TXQ_USEDEFAULT
+       };
+       int qnum;
+
+       /*
+        * Enable interrupts only for EOL and DESC conditions.
+        * We mark tx descriptors to receive a DESC interrupt
+        * when a tx queue gets deep; otherwise waiting for the
+        * EOL to reap descriptors.  Note that this is done to
+        * reduce interrupt load and this only defers reaping
+        * descriptors, never transmitting frames.  Aside from
+        * reducing interrupts this also permits more concurrency.
+        * The only potential downside is if the tx queue backs
+        * up in which case the top half of the kernel may backup
+        * due to a lack of tx descriptors.
+        */
+       qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE |
+                               AR5K_TXQ_FLAG_TXDESCINT_ENABLE;
+       qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi);
+       if (qnum < 0) {
+               /*
+                * NB: don't print a message, this happens
+                * normally on parts with too few tx queues
+                */
+               return ERR_PTR(qnum);
+       }
+       if (qnum >= ARRAY_SIZE(sc->txqs)) {
+               ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n",
+                       qnum, ARRAY_SIZE(sc->txqs));
+               ath5k_hw_release_tx_queue(ah, qnum);
+               return ERR_PTR(-EINVAL);
+       }
+       txq = &sc->txqs[qnum];
+       if (!txq->setup) {
+               txq->qnum = qnum;
+               txq->link = NULL;
+               INIT_LIST_HEAD(&txq->q);
+               spin_lock_init(&txq->lock);
+               txq->setup = true;
+       }
+       return &sc->txqs[qnum];
+}
+
+static int
+ath5k_beaconq_setup(struct ath5k_hw *ah)
+{
+       struct ath5k_txq_info qi = {
+               .tqi_aifs = AR5K_TXQ_USEDEFAULT,
+               .tqi_cw_min = AR5K_TXQ_USEDEFAULT,
+               .tqi_cw_max = AR5K_TXQ_USEDEFAULT,
+               /* NB: for dynamic turbo, don't enable any other interrupts */
+               .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE
+       };
+
+       return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi);
+}
+
+static int
+ath5k_beaconq_config(struct ath5k_softc *sc)
+{
+       struct ath5k_hw *ah = sc->ah;
+       struct ath5k_txq_info qi;
+       int ret;
+
+       ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi);
+       if (ret)
+               return ret;
+       if (sc->opmode == IEEE80211_IF_TYPE_AP ||
+           sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+               /*
+                * Always burst out beacon and CAB traffic
+                * (aifs = cwmin = cwmax = 0)
+                */
+               qi.tqi_aifs = 0;
+               qi.tqi_cw_min = 0;
+               qi.tqi_cw_max = 0;
+       }
+
+       ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi);
+       if (ret) {
+               ATH5K_ERR(sc, "%s: unable to update parameters for beacon "
+                       "hardware queue!\n", __func__);
+               return ret;
+       }
+
+       return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */;
+}
+
+static void
+ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+{
+       struct ath5k_buf *bf, *bf0;
+
+       /*
+        * NB: this assumes output has been stopped and
+        *     we do not need to block ath5k_tx_tasklet
+        */
+       spin_lock_bh(&txq->lock);
+       list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+               ath5k_debug_printtxbuf(sc, bf, !sc->ah->ah_proc_tx_desc(sc->ah,
+                                       bf->desc));
+
+               ath5k_txbuf_free(sc, bf);
+
+               spin_lock_bh(&sc->txbuflock);
+               sc->tx_stats.data[txq->qnum].len--;
+               list_move_tail(&bf->list, &sc->txbuf);
+               sc->txbuf_len++;
+               spin_unlock_bh(&sc->txbuflock);
+       }
+       txq->link = NULL;
+       spin_unlock_bh(&txq->lock);
+}
+
+/*
+ * Drain the transmit queues and reclaim resources.
+ */
+static void
+ath5k_txq_cleanup(struct ath5k_softc *sc)
+{
+       struct ath5k_hw *ah = sc->ah;
+       unsigned int i;
+
+       /* XXX return value */
+       if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) {
+               /* don't touch the hardware if marked invalid */
+               ath5k_hw_stop_tx_dma(ah, sc->bhalq);
+               ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n",
+                       ath5k_hw_get_tx_buf(ah, sc->bhalq));
+               for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
+                       if (sc->txqs[i].setup) {
+                               ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum);
+                               ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, "
+                                       "link %p\n",
+                                       sc->txqs[i].qnum,
+                                       ath5k_hw_get_tx_buf(ah,
+                                                       sc->txqs[i].qnum),
+                                       sc->txqs[i].link);
+                       }
+       }
+       ieee80211_start_queues(sc->hw); /* XXX move to callers */
+
+       for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
+               if (sc->txqs[i].setup)
+                       ath5k_txq_drainq(sc, &sc->txqs[i]);
+}
+
+static void
+ath5k_txq_release(struct ath5k_softc *sc)
+{
+       struct ath5k_txq *txq = sc->txqs;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++)
+               if (txq->setup) {
+                       ath5k_hw_release_tx_queue(sc->ah, txq->qnum);
+                       txq->setup = false;
+               }
+}
+
+
+
+
+/*************\
+* RX Handling *
+\*************/
+
+/*
+ * Enable the receive h/w following a reset.
+ */
+static int
+ath5k_rx_start(struct ath5k_softc *sc)
+{
+       struct ath5k_hw *ah = sc->ah;
+       struct ath5k_buf *bf;
+       int ret;
+
+       sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz);
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
+               sc->cachelsz, sc->rxbufsize);
+
+       sc->rxlink = NULL;
+
+       spin_lock_bh(&sc->rxbuflock);
+       list_for_each_entry(bf, &sc->rxbuf, list) {
+               ret = ath5k_rxbuf_setup(sc, bf);
+               if (ret != 0) {
+                       spin_unlock_bh(&sc->rxbuflock);
+                       goto err;
+               }
+       }
+       bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
+       spin_unlock_bh(&sc->rxbuflock);
+
+       ath5k_hw_put_rx_buf(ah, bf->daddr);
+       ath5k_hw_start_rx(ah);          /* enable recv descriptors */
+       ath5k_mode_setup(sc);           /* set filters, etc. */
+       ath5k_hw_start_rx_pcu(ah);      /* re-enable PCU/DMA engine */
+
+       return 0;
+err:
+       return ret;
+}
+
+/*
+ * Disable the receive h/w in preparation for a reset.
+ */
+static void
+ath5k_rx_stop(struct ath5k_softc *sc)
+{
+       struct ath5k_hw *ah = sc->ah;
+
+       ath5k_hw_stop_pcu_recv(ah);     /* disable PCU */
+       ath5k_hw_set_rx_filter(ah, 0);  /* clear recv filter */
+       ath5k_hw_stop_rx_dma(ah);       /* disable DMA engine */
+       mdelay(3);                      /* 3ms is long enough for 1 frame */
+
+       ath5k_debug_printrxbuffs(sc, ah);
+
+       sc->rxlink = NULL;              /* just in case */
+}
+
+static unsigned int
+ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
+               struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb);
+
+       if (!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) &&
+                       ds->ds_rxstat.rs_keyix != AR5K_RXKEYIX_INVALID)
+               return RX_FLAG_DECRYPTED;
+
+       /* Apparently when a default key is used to decrypt the packet
+          the hw does not set the index used to decrypt.  In such cases
+          get the index from the packet. */
+       if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) &&
+                       !(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) &&
+                       skb->len >= hlen + 4) {
+               keyix = skb->data[hlen + 3] >> 6;
+
+               if (test_bit(keyix, sc->keymap))
+                       return RX_FLAG_DECRYPTED;
+       }
+
+       return 0;
+}
+
+static void
+ath5k_tasklet_rx(unsigned long data)
+{
+       struct ieee80211_rx_status rxs = {};
+       struct sk_buff *skb;
+       struct ath5k_softc *sc = (void *)data;
+       struct ath5k_buf *bf;
+       struct ath5k_desc *ds;
+       u16 len;
+       u8 stat;
+       int ret;
+       int hdrlen;
+       int pad;
+
+       spin_lock(&sc->rxbuflock);
+       do {
+               if (unlikely(list_empty(&sc->rxbuf))) {
+                       ATH5K_WARN(sc, "empty rx buf pool\n");
+                       break;
+               }
+               bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
+               BUG_ON(bf->skb == NULL);
+               skb = bf->skb;
+               ds = bf->desc;
+
+               /* TODO only one segment */
+               pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
+                               sc->desc_len, PCI_DMA_FROMDEVICE);
+
+               if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */
+                       break;
+
+               ret = sc->ah->ah_proc_rx_desc(sc->ah, ds);
+               if (unlikely(ret == -EINPROGRESS))
+                       break;
+               else if (unlikely(ret)) {
+                       ATH5K_ERR(sc, "error in processing rx descriptor\n");
+                       return;
+               }
+
+               if (unlikely(ds->ds_rxstat.rs_more)) {
+                       ATH5K_WARN(sc, "unsupported jumbo\n");
+                       goto next;
+               }
+
+               stat = ds->ds_rxstat.rs_status;
+               if (unlikely(stat)) {
+                       if (stat & AR5K_RXERR_PHY)
+                               goto next;
+                       if (stat & AR5K_RXERR_DECRYPT) {
+                               /*
+                                * Decrypt error.  If the error occurred
+                                * because there was no hardware key, then
+                                * let the frame through so the upper layers
+                                * can process it.  This is necessary for 5210
+                                * parts which have no way to setup a ``clear''
+                                * key cache entry.
+                                *
+                                * XXX do key cache faulting
+                                */
+                               if (ds->ds_rxstat.rs_keyix ==
+                                               AR5K_RXKEYIX_INVALID &&
+                                               !(stat & AR5K_RXERR_CRC))
+                                       goto accept;
+                       }
+                       if (stat & AR5K_RXERR_MIC) {
+                               rxs.flag |= RX_FLAG_MMIC_ERROR;
+                               goto accept;
+                       }
+
+                       /* let crypto-error packets fall through in MNTR */
+                       if ((stat & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
+                                       sc->opmode != IEEE80211_IF_TYPE_MNTR)
+                               goto next;
+               }
+accept:
+               len = ds->ds_rxstat.rs_datalen;
+               pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len,
+                               PCI_DMA_FROMDEVICE);
+               pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
+                               PCI_DMA_FROMDEVICE);
+               bf->skb = NULL;
+
+               skb_put(skb, len);
+
+               /*
+                * the hardware adds a padding to 4 byte boundaries between
+                * the header and the payload data if the header length is
+                * not multiples of 4 - remove it
+                */
+               hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+               if (hdrlen & 3) {
+                       pad = hdrlen % 4;
+                       memmove(skb->data + pad, skb->data, hdrlen);
+                       skb_pull(skb, pad);
+               }
+
+               if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+                       rxs.mactime = ath5k_extend_tsf(sc->ah,
+                                       ds->ds_rxstat.rs_tstamp);
+               else
+                       rxs.mactime = ds->ds_rxstat.rs_tstamp;
+               rxs.freq = sc->curchan->freq;
+               rxs.channel = sc->curchan->chan;
+               rxs.phymode = sc->curmode;
+
+               /*
+                * signal quality:
+                * the names here are misleading and the usage of these
+                * values by iwconfig makes it even worse
+                */
+               /* noise floor in dBm, from the last noise calibration */
+               rxs.noise = sc->ah->ah_noise_floor;
+               /* signal level in dBm */
+               rxs.ssi = rxs.noise + ds->ds_rxstat.rs_rssi;
+               /*
+                * "signal" is actually displayed as Link Quality by iwconfig
+                * we provide a percentage based on rssi (assuming max rssi 64)
+                */
+               rxs.signal = ds->ds_rxstat.rs_rssi * 100 / 64;
+
+               rxs.antenna = ds->ds_rxstat.rs_antenna;
+               rxs.rate = ds->ds_rxstat.rs_rate;
+               rxs.flag |= ath5k_rx_decrypted(sc, ds, skb);
+
+               ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
+
+               __ieee80211_rx(sc->hw, skb, &rxs);
+               sc->led_rxrate = ds->ds_rxstat.rs_rate;
+               ath5k_led_event(sc, ATH_LED_RX);
+next:
+               list_move_tail(&bf->list, &sc->rxbuf);
+       } while (ath5k_rxbuf_setup(sc, bf) == 0);
+       spin_unlock(&sc->rxbuflock);
+}
+
+
+
+
+/*************\
+* TX Handling *
+\*************/
+
+static void
+ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+{
+       struct ieee80211_tx_status txs = {};
+       struct ath5k_buf *bf, *bf0;
+       struct ath5k_desc *ds;
+       struct sk_buff *skb;
+       int ret;
+
+       spin_lock(&txq->lock);
+       list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+               ds = bf->desc;
+
+               /* TODO only one segment */
+               pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
+                               sc->desc_len, PCI_DMA_FROMDEVICE);
+               ret = sc->ah->ah_proc_tx_desc(sc->ah, ds);
+               if (unlikely(ret == -EINPROGRESS))
+                       break;
+               else if (unlikely(ret)) {
+                       ATH5K_ERR(sc, "error %d while processing queue %u\n",
+                               ret, txq->qnum);
+                       break;
+               }
+
+               skb = bf->skb;
+               bf->skb = NULL;
+               pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
+                               PCI_DMA_TODEVICE);
+
+               txs.control = bf->ctl;
+               txs.retry_count = ds->ds_txstat.ts_shortretry +
+                       ds->ds_txstat.ts_longretry / 6;
+               if (unlikely(ds->ds_txstat.ts_status)) {
+                       sc->ll_stats.dot11ACKFailureCount++;
+                       if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY)
+                               txs.excessive_retries = 1;
+                       else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT)
+                               txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+               } else {
+                       txs.flags |= IEEE80211_TX_STATUS_ACK;
+                       txs.ack_signal = ds->ds_txstat.ts_rssi;
+               }
+
+               ieee80211_tx_status(sc->hw, skb, &txs);
+               sc->tx_stats.data[txq->qnum].count++;
+
+               spin_lock(&sc->txbuflock);
+               sc->tx_stats.data[txq->qnum].len--;
+               list_move_tail(&bf->list, &sc->txbuf);
+               sc->txbuf_len++;
+               spin_unlock(&sc->txbuflock);
+       }
+       if (likely(list_empty(&txq->q)))
+               txq->link = NULL;
+       spin_unlock(&txq->lock);
+       if (sc->txbuf_len > ATH_TXBUF / 5)
+               ieee80211_wake_queues(sc->hw);
+}
+
+static void
+ath5k_tasklet_tx(unsigned long data)
+{
+       struct ath5k_softc *sc = (void *)data;
+
+       ath5k_tx_processq(sc, sc->txq);
+
+       ath5k_led_event(sc, ATH_LED_TX);
+}
+
+
+
+
+/*****************\
+* Beacon handling *
+\*****************/
+
+/*
+ * Setup the beacon frame for transmit.
+ */
+static int
+ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+               struct ieee80211_tx_control *ctl)
+{
+       struct sk_buff *skb = bf->skb;
+       struct ath5k_hw *ah = sc->ah;
+       struct ath5k_desc *ds;
+       int ret, antenna = 0;
+       u32 flags;
+
+       bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
+                       PCI_DMA_TODEVICE);
+       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] "
+                       "skbaddr %llx\n", skb, skb->data, skb->len,
+                       (unsigned long long)bf->skbaddr);
+       if (pci_dma_mapping_error(bf->skbaddr)) {
+               ATH5K_ERR(sc, "beacon DMA mapping failed\n");
+               return -EIO;
+       }
+
+       ds = bf->desc;
+
+       flags = AR5K_TXDESC_NOACK;
+       if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) {
+               ds->ds_link = bf->daddr;        /* self-linked */
+               flags |= AR5K_TXDESC_VEOL;
+               /*
+                * Let hardware handle antenna switching if txantenna is not set
+                */
+       } else {
+               ds->ds_link = 0;
+               /*
+                * Switch antenna every 4 beacons if txantenna is not set
+                * XXX assumes two antennas
+                */
+               if (antenna == 0)
+                       antenna = sc->bsent & 4 ? 2 : 1;
+       }
+
+       ds->ds_data = bf->skbaddr;
+       ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN,
+                       ieee80211_get_hdrlen_from_skb(skb),
+                       AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1,
+                       AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0);
+       if (ret)
+               goto err_unmap;
+
+       return 0;
+err_unmap:
+       pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
+       return ret;
+}
+
+/*
+ * Transmit a beacon frame at SWBA.  Dynamic updates to the
+ * frame contents are done as needed and the slot time is
+ * also adjusted based on current state.
+ *
+ * this is usually called from interrupt context (ath5k_intr())
+ * but also from ath5k_beacon_config() in IBSS mode which in turn
+ * can be called from a tasklet and user context
+ */
+static void
+ath5k_beacon_send(struct ath5k_softc *sc)
+{
+       struct ath5k_buf *bf = sc->bbuf;
+       struct ath5k_hw *ah = sc->ah;
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "in beacon_send\n");
+
+       if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA ||
+                       sc->opmode == IEEE80211_IF_TYPE_MNTR)) {
+               ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
+               return;
+       }
+       /*
+        * Check if the previous beacon has gone out.  If
+        * not don't don't try to post another, skip this
+        * period and wait for the next.  Missed beacons
+        * indicate a problem and should not occur.  If we
+        * miss too many consecutive beacons reset the device.
+        */
+       if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) {
+               sc->bmisscount++;
+               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+                       "missed %u consecutive beacons\n", sc->bmisscount);
+               if (sc->bmisscount > 3) {               /* NB: 3 is a guess */
+                       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+                               "stuck beacon time (%u missed)\n",
+                               sc->bmisscount);
+                       tasklet_schedule(&sc->restq);
+               }
+               return;
+       }
+       if (unlikely(sc->bmisscount != 0)) {
+               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+                       "resume beacon xmit after %u misses\n",
+                       sc->bmisscount);
+               sc->bmisscount = 0;
+       }
+
+       /*
+        * Stop any current dma and put the new frame on the queue.
+        * This should never fail since we check above that no frames
+        * are still pending on the queue.
+        */
+       if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) {
+               ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq);
+               /* NB: hw still stops DMA, so proceed */
+       }
+       pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len,
+                       PCI_DMA_TODEVICE);
+
+       ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
+       ath5k_hw_tx_start(ah, sc->bhalq);
+       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "TXDP[%u] = %llx (%p)\n",
+               sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
+
+       sc->bsent++;
+}
+
+
+static void
+ath5k_beacon_update_timers(struct ath5k_softc *sc)
+{
+       struct ath5k_hw *ah = sc->ah;
+       u32 uninitialized_var(nexttbtt), intval, tsftu;
+       u64 tsf;
+
+       intval = sc->bintval & AR5K_BEACON_PERIOD;
+       if (WARN_ON(!intval))
+               return;
+
+       /* current TSF converted to TU */
+       tsf = ath5k_hw_get_tsf64(ah);
+       tsftu = TSF_TO_TU(tsf);
+
+       /*
+        * Pull nexttbtt forward to reflect the current
+        * TSF. Add one intval otherwise the timespan
+        * can be too short for ibss merges.
+        */
+       nexttbtt = tsftu + 2 * intval;
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+               "hw tsftu %u nexttbtt %u intval %u\n", tsftu, nexttbtt, intval);
+
+       intval |= AR5K_BEACON_ENA;
+
+       ath5k_hw_init_beacon(ah, nexttbtt, intval);
+}
+
+
+/*
+ * Configure the beacon timers and interrupts based on the operating mode
+ *
+ * When operating in station mode we want to receive a BMISS interrupt when we
+ * stop seeing beacons from the AP we've associated with so we can look for
+ * another AP to associate with.
+ *
+ * In IBSS mode we need to configure the beacon timers and use a self-linked tx
+ * descriptor if possible. If the hardware cannot deal with that we enable SWBA
+ * interrupts to send the beacons from the interrupt handler.
+ */
+static void
+ath5k_beacon_config(struct ath5k_softc *sc)
+{
+       struct ath5k_hw *ah = sc->ah;
+
+       ath5k_hw_set_intr(ah, 0);
+       sc->bmisscount = 0;
+
+       if (sc->opmode == IEEE80211_IF_TYPE_STA) {
+               sc->imask |= AR5K_INT_BMISS;
+       } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+               /*
+                * In IBSS mode enable the beacon timers but only enable SWBA
+                * interrupts if we need to manually prepare beacon frames.
+                * Otherwise we use a self-linked tx descriptor and let the
+                * hardware deal with things. In that case we have to load it
+                * only once here.
+                */
+               ath5k_beaconq_config(sc);
+               ath5k_beacon_update_timers(sc);
+
+               if (!ath5k_hw_hasveol(ah))
+                       sc->imask |= AR5K_INT_SWBA;
+               else
+                       ath5k_beacon_send(sc);
+       }
+       /* TODO else AP */
+
+       ath5k_hw_set_intr(ah, sc->imask);
+}
+
+
+/********************\
+* Interrupt handling *
+\********************/
+
+static int
+ath5k_init(struct ath5k_softc *sc)
+{
+       int ret;
+
+       mutex_lock(&sc->lock);
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode);
+
+       /*
+        * Stop anything previously setup.  This is safe
+        * no matter this is the first time through or not.
+        */
+       ath5k_stop_locked(sc);
+
+       /*
+        * The basic interface to setting the hardware in a good
+        * state is ``reset''.  On return the hardware is known to
+        * be powered up and with interrupts disabled.  This must
+        * be followed by initialization of the appropriate bits
+        * and then setup of the interrupt mask.
+        */
+       sc->curchan = sc->hw->conf.chan;
+       ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false);
+       if (ret) {
+               ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret);
+               goto done;
+       }
+       /*
+        * This is needed only to setup initial state
+        * but it's best done after a reset.
+        */
+       ath5k_hw_set_txpower_limit(sc->ah, 0);
+
+       /*
+        * Setup the hardware after reset: the key cache
+        * is filled as needed and the receive engine is
+        * set going.  Frame transmit is handled entirely
+        * in the frame output path; there's nothing to do
+        * here except setup the interrupt mask.
+        */
+       ret = ath5k_rx_start(sc);
+       if (ret)
+               goto done;
+
+       /*
+        * Enable interrupts.
+        */
+       sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
+               AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL;
+
+       ath5k_hw_set_intr(sc->ah, sc->imask);
+       /* Set ack to be sent at low bit-rates */
+       ath5k_hw_set_ack_bitrate_high(sc->ah, false);
+
+       mod_timer(&sc->calib_tim, round_jiffies(jiffies +
+                       msecs_to_jiffies(ath5k_calinterval * 1000)));
+
+       ret = 0;
+done:
+       mutex_unlock(&sc->lock);
+       return ret;
+}
+
+static int
+ath5k_stop_locked(struct ath5k_softc *sc)
+{
+       struct ath5k_hw *ah = sc->ah;
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n",
+                       test_bit(ATH_STAT_INVALID, sc->status));
+
+       /*
+        * Shutdown the hardware and driver:
+        *    stop output from above
+        *    disable interrupts
+        *    turn off timers
+        *    turn off the radio
+        *    clear transmit machinery
+        *    clear receive machinery
+        *    drain and release tx queues
+        *    reclaim beacon resources
+        *    power down hardware
+        *
+        * Note that some of this work is not possible if the
+        * hardware is gone (invalid).
+        */
+       ieee80211_stop_queues(sc->hw);
+
+       if (!test_bit(ATH_STAT_INVALID, sc->status)) {
+               if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+                       del_timer_sync(&sc->led_tim);
+                       ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
+                       __clear_bit(ATH_STAT_LEDBLINKING, sc->status);
+               }
+               ath5k_hw_set_intr(ah, 0);
+       }
+       ath5k_txq_cleanup(sc);
+       if (!test_bit(ATH_STAT_INVALID, sc->status)) {
+               ath5k_rx_stop(sc);
+               ath5k_hw_phy_disable(ah);
+       } else
+               sc->rxlink = NULL;
+
+       return 0;
+}
+
+/*
+ * Stop the device, grabbing the top-level lock to protect
+ * against concurrent entry through ath5k_init (which can happen
+ * if another thread does a system call and the thread doing the
+ * stop is preempted).
+ */
+static int
+ath5k_stop_hw(struct ath5k_softc *sc)
+{
+       int ret;
+
+       mutex_lock(&sc->lock);
+       ret = ath5k_stop_locked(sc);
+       if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
+               /*
+                * Set the chip in full sleep mode.  Note that we are
+                * careful to do this only when bringing the interface
+                * completely to a stop.  When the chip is in this state
+                * it must be carefully woken up or references to
+                * registers in the PCI clock domain may freeze the bus
+                * (and system).  This varies by chip and is mostly an
+                * issue with newer parts that go to sleep more quickly.
+                */
+               if (sc->ah->ah_mac_srev >= 0x78) {
+                       /*
+                        * XXX
+                        * don't put newer MAC revisions > 7.8 to sleep because
+                        * of the above mentioned problems
+                        */
+                       ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, "
+                               "not putting device to sleep\n");
+               } else {
+                       ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+                               "putting device to full sleep\n");
+                       ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);
+               }
+       }
+       ath5k_txbuf_free(sc, sc->bbuf);
+       mutex_unlock(&sc->lock);
+
+       del_timer_sync(&sc->calib_tim);
+
+       return ret;
+}
+
+static irqreturn_t
+ath5k_intr(int irq, void *dev_id)
+{
+       struct ath5k_softc *sc = dev_id;
+       struct ath5k_hw *ah = sc->ah;
+       enum ath5k_int status;
+       unsigned int counter = 1000;
+
+       if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
+                               !ath5k_hw_is_intr_pending(ah)))
+               return IRQ_NONE;
+
+       do {
+               /*
+                * Figure out the reason(s) for the interrupt.  Note
+                * that get_isr returns a pseudo-ISR that may include
+                * bits we haven't explicitly enabled so we mask the
+                * value to insure we only process bits we requested.
+                */
+               ath5k_hw_get_isr(ah, &status);          /* NB: clears IRQ too */
+               ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n",
+                               status, sc->imask);
+               status &= sc->imask; /* discard unasked for bits */
+               if (unlikely(status & AR5K_INT_FATAL)) {
+                       /*
+                        * Fatal errors are unrecoverable.
+                        * Typically these are caused by DMA errors.
+                        */
+                       tasklet_schedule(&sc->restq);
+               } else if (unlikely(status & AR5K_INT_RXORN)) {
+                       tasklet_schedule(&sc->restq);
+               } else {
+                       if (status & AR5K_INT_SWBA) {
+                               /*
+                               * Software beacon alert--time to send a beacon.
+                               * Handle beacon transmission directly; deferring
+                               * this is too slow to meet timing constraints
+                               * under load.
+                               */
+                               ath5k_beacon_send(sc);
+                       }
+                       if (status & AR5K_INT_RXEOL) {
+                               /*
+                               * NB: the hardware should re-read the link when
+                               *     RXE bit is written, but it doesn't work at
+                               *     least on older hardware revs.
+                               */
+                               sc->rxlink = NULL;
+                       }
+                       if (status & AR5K_INT_TXURN) {
+                               /* bump tx trigger level */
+                               ath5k_hw_update_tx_triglevel(ah, true);
+                       }
+                       if (status & AR5K_INT_RX)
+                               tasklet_schedule(&sc->rxtq);
+                       if (status & AR5K_INT_TX)
+                               tasklet_schedule(&sc->txtq);
+                       if (status & AR5K_INT_BMISS) {
+                       }
+                       if (status & AR5K_INT_MIB) {
+                               /* TODO */
+                       }
+               }
+       } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
+
+       if (unlikely(!counter))
+               ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
+
+       return IRQ_HANDLED;
+}
+
+static void
+ath5k_tasklet_reset(unsigned long data)
+{
+       struct ath5k_softc *sc = (void *)data;
+
+       ath5k_reset(sc->hw);
+}
+
+/*
+ * Periodically recalibrate the PHY to account
+ * for temperature/environment changes.
+ */
+static void
+ath5k_calibrate(unsigned long data)
+{
+       struct ath5k_softc *sc = (void *)data;
+       struct ath5k_hw *ah = sc->ah;
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
+               sc->curchan->chan, sc->curchan->val);
+
+       if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) {
+               /*
+                * Rfgain is out of bounds, reset the chip
+                * to load new gain values.
+                */
+               ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
+               ath5k_reset(sc->hw);
+       }
+       if (ath5k_hw_phy_calibrate(ah, sc->curchan))
+               ATH5K_ERR(sc, "calibration of channel %u failed\n",
+                               sc->curchan->chan);
+
+       mod_timer(&sc->calib_tim, round_jiffies(jiffies +
+                       msecs_to_jiffies(ath5k_calinterval * 1000)));
+}
+
+
+
+/***************\
+* LED functions *
+\***************/
+
+static void
+ath5k_led_off(unsigned long data)
+{
+       struct ath5k_softc *sc = (void *)data;
+
+       if (test_bit(ATH_STAT_LEDENDBLINK, sc->status))
+               __clear_bit(ATH_STAT_LEDBLINKING, sc->status);
+       else {
+               __set_bit(ATH_STAT_LEDENDBLINK, sc->status);
+               ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
+               mod_timer(&sc->led_tim, jiffies + sc->led_off);
+       }
+}
+
+/*
+ * Blink the LED according to the specified on/off times.
+ */
+static void
+ath5k_led_blink(struct ath5k_softc *sc, unsigned int on,
+               unsigned int off)
+{
+       ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off);
+       ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
+       __set_bit(ATH_STAT_LEDBLINKING, sc->status);
+       __clear_bit(ATH_STAT_LEDENDBLINK, sc->status);
+       sc->led_off = off;
+       mod_timer(&sc->led_tim, jiffies + on);
+}
+
+static void
+ath5k_led_event(struct ath5k_softc *sc, int event)
+{
+       if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
+               return;
+       if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status)))
+               return; /* don't interrupt active blink */
+       switch (event) {
+       case ATH_LED_TX:
+               ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon,
+                       sc->hwmap[sc->led_txrate].ledoff);
+               break;
+       case ATH_LED_RX:
+               ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon,
+                       sc->hwmap[sc->led_rxrate].ledoff);
+               break;
+       }
+}
+
+
+
+
+/********************\
+* Mac80211 functions *
+\********************/
+
+static int
+ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+                       struct ieee80211_tx_control *ctl)
+{
+       struct ath5k_softc *sc = hw->priv;
+       struct ath5k_buf *bf;
+       unsigned long flags;
+       int hdrlen;
+       int pad;
+
+       ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
+
+       if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+               ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");
+
+       /*
+        * the hardware expects the header padded to 4 byte boundaries
+        * if this is not the case we add the padding after the header
+        */
+       hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+       if (hdrlen & 3) {
+               pad = hdrlen % 4;
+               if (skb_headroom(skb) < pad) {
+                       ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
+                               " headroom to pad %d\n", hdrlen, pad);
+                       return -1;
+               }
+               skb_push(skb, pad);
+               memmove(skb->data, skb->data+pad, hdrlen);
+       }
+
+       sc->led_txrate = ctl->tx_rate;
+
+       spin_lock_irqsave(&sc->txbuflock, flags);
+       if (list_empty(&sc->txbuf)) {
+               ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
+               spin_unlock_irqrestore(&sc->txbuflock, flags);
+               ieee80211_stop_queue(hw, ctl->queue);
+               return -1;
+       }
+       bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
+       list_del(&bf->list);
+       sc->txbuf_len--;
+       if (list_empty(&sc->txbuf))
+               ieee80211_stop_queues(hw);
+       spin_unlock_irqrestore(&sc->txbuflock, flags);
+
+       bf->skb = skb;
+
+       if (ath5k_txbuf_setup(sc, bf, ctl)) {
+               bf->skb = NULL;
+               spin_lock_irqsave(&sc->txbuflock, flags);
+               list_add_tail(&bf->list, &sc->txbuf);
+               sc->txbuf_len++;
+               spin_unlock_irqrestore(&sc->txbuflock, flags);
+               dev_kfree_skb_any(skb);
+               return 0;
+       }
+
+       return 0;
+}
+
+static int
+ath5k_reset(struct ieee80211_hw *hw)
+{
+       struct ath5k_softc *sc = hw->priv;
+       struct ath5k_hw *ah = sc->ah;
+       int ret;
+
+       ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
+       /*
+        * Convert to a hw channel description with the flags
+        * constrained to reflect the current operating mode.
+        */
+       sc->curchan = hw->conf.chan;
+
+       ath5k_hw_set_intr(ah, 0);
+       ath5k_txq_cleanup(sc);
+       ath5k_rx_stop(sc);
+
+       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+       if (unlikely(ret)) {
+               ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
+               goto err;
+       }
+       ath5k_hw_set_txpower_limit(sc->ah, 0);
+
+       ret = ath5k_rx_start(sc);
+       if (unlikely(ret)) {
+               ATH5K_ERR(sc, "can't start recv logic\n");
+               goto err;
+       }
+       /*
+        * We may be doing a reset in response to an ioctl
+        * that changes the channel so update any state that
+        * might change as a result.
+        *
+        * XXX needed?
+        */
+/*     ath5k_chan_change(sc, c); */
+       ath5k_beacon_config(sc);
+       /* intrs are started by ath5k_beacon_config */
+
+       ieee80211_wake_queues(hw);
+
+       return 0;
+err:
+       return ret;
+}
+
+static int ath5k_start(struct ieee80211_hw *hw)
+{
+       return ath5k_init(hw->priv);
+}
+
+static void ath5k_stop(struct ieee80211_hw *hw)
+{
+       ath5k_stop_hw(hw->priv);
+}
+
+static int ath5k_add_interface(struct ieee80211_hw *hw,
+               struct ieee80211_if_init_conf *conf)
+{
+       struct ath5k_softc *sc = hw->priv;
+       int ret;
+
+       mutex_lock(&sc->lock);
+       if (sc->iface_id) {
+               ret = 0;
+               goto end;
+       }
+
+       sc->iface_id = conf->if_id;
+
+       switch (conf->type) {
+       case IEEE80211_IF_TYPE_STA:
+       case IEEE80211_IF_TYPE_IBSS:
+       case IEEE80211_IF_TYPE_MNTR:
+               sc->opmode = conf->type;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               goto end;
+       }
+       ret = 0;
+end:
+       mutex_unlock(&sc->lock);
+       return ret;
+}
+
+static void
+ath5k_remove_interface(struct ieee80211_hw *hw,
+                       struct ieee80211_if_init_conf *conf)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       mutex_lock(&sc->lock);
+       if (sc->iface_id != conf->if_id)
+               goto end;
+
+       sc->iface_id = 0;
+end:
+       mutex_unlock(&sc->lock);
+}
+
+static int
+ath5k_config(struct ieee80211_hw *hw,
+                       struct ieee80211_conf *conf)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       sc->bintval = conf->beacon_int * 1000 / 1024;
+       ath5k_setcurmode(sc, conf->phymode);
+
+       return ath5k_chan_set(sc, conf->chan);
+}
+
+static int
+ath5k_config_interface(struct ieee80211_hw *hw, int if_id,
+                       struct ieee80211_if_conf *conf)
+{
+       struct ath5k_softc *sc = hw->priv;
+       struct ath5k_hw *ah = sc->ah;
+       int ret;
+
+       /* Set to a reasonable value. Note that this will
+        * be set to mac80211's value at ath5k_config(). */
+       sc->bintval = 1000 * 1000 / 1024;
+       mutex_lock(&sc->lock);
+       if (sc->iface_id != if_id) {
+               ret = -EIO;
+               goto unlock;
+       }
+       if (conf->bssid) {
+               /* Cache for later use during resets */
+               memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN);
+               /* XXX: assoc id is set to 0 for now, mac80211 doesn't have
+                * a clean way of letting us retrieve this yet. */
+               ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+       }
+       mutex_unlock(&sc->lock);
+
+       return ath5k_reset(hw);
+unlock:
+       mutex_unlock(&sc->lock);
+       return ret;
+}
+
+#define SUPPORTED_FIF_FLAGS \
+       FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
+       FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
+       FIF_BCN_PRBRESP_PROMISC
+/*
+ * o always accept unicast, broadcast, and multicast traffic
+ * o multicast traffic for all BSSIDs will be enabled if mac80211
+ *   says it should be
+ * o maintain current state of phy ofdm or phy cck error reception.
+ *   If the hardware detects any of these type of errors then
+ *   ath5k_hw_get_rx_filter() will pass to us the respective
+ *   hardware filters to be able to receive these type of frames.
+ * o probe request frames are accepted only when operating in
+ *   hostap, adhoc, or monitor modes
+ * o enable promiscuous mode according to the interface state
+ * o accept beacons:
+ *   - when operating in adhoc mode so the 802.11 layer creates
+ *     node table entries for peers,
+ *   - when operating in station mode for collecting rssi data when
+ *     the station is otherwise quiet, or
+ *   - when scanning
+ */
+static void ath5k_configure_filter(struct ieee80211_hw *hw,
+               unsigned int changed_flags,
+               unsigned int *new_flags,
+               int mc_count, struct dev_mc_list *mclist)
+{
+       struct ath5k_softc *sc = hw->priv;
+       struct ath5k_hw *ah = sc->ah;
+       u32 mfilt[2], val, rfilt;
+       u8 pos;
+       int i;
+
+       mfilt[0] = 0;
+       mfilt[1] = 0;
+
+       /* Only deal with supported flags */
+       changed_flags &= SUPPORTED_FIF_FLAGS;
+       *new_flags &= SUPPORTED_FIF_FLAGS;
+
+       /* If HW detects any phy or radar errors, leave those filters on.
+        * Also, always enable Unicast, Broadcasts and Multicast
+        * XXX: move unicast, bssid broadcasts and multicast to mac80211 */
+       rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
+               (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
+               AR5K_RX_FILTER_MCAST);
+
+       if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+               if (*new_flags & FIF_PROMISC_IN_BSS) {
+                       rfilt |= AR5K_RX_FILTER_PROM;
+                       __set_bit(ATH_STAT_PROMISC, sc->status);
+               }
+               else
+                       __clear_bit(ATH_STAT_PROMISC, sc->status);
+       }
+
+       /* Note, AR5K_RX_FILTER_MCAST is already enabled */
+       if (*new_flags & FIF_ALLMULTI) {
+               mfilt[0] =  ~0;
+               mfilt[1] =  ~0;
+       } else {
+               for (i = 0; i < mc_count; i++) {
+                       if (!mclist)
+                               break;
+                       /* calculate XOR of eight 6-bit values */
+                       val = LE_READ_4(mclist->dmi_addr + 0);
+                       pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+                       val = LE_READ_4(mclist->dmi_addr + 3);
+                       pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+                       pos &= 0x3f;
+                       mfilt[pos / 32] |= (1 << (pos % 32));
+                       /* XXX: we might be able to just do this instead,
+                       * but not sure, needs testing, if we do use this we'd
+                       * neet to inform below to not reset the mcast */
+                       /* ath5k_hw_set_mcast_filterindex(ah,
+                        *      mclist->dmi_addr[5]); */
+                       mclist = mclist->next;
+               }
+       }
+
+       /* This is the best we can do */
+       if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
+               rfilt |= AR5K_RX_FILTER_PHYERR;
+
+       /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
+       * and probes for any BSSID, this needs testing */
+       if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+               rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ;
+
+       /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
+        * set we should only pass on control frames for this
+        * station. This needs testing. I believe right now this
+        * enables *all* control frames, which is OK.. but
+        * but we should see if we can improve on granularity */
+       if (*new_flags & FIF_CONTROL)
+               rfilt |= AR5K_RX_FILTER_CONTROL;
+
+       /* Additional settings per mode -- this is per ath5k */
+
+       /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
+
+       if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+               rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
+                       AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
+       if (sc->opmode != IEEE80211_IF_TYPE_STA)
+               rfilt |= AR5K_RX_FILTER_PROBEREQ;
+       if (sc->opmode != IEEE80211_IF_TYPE_AP &&
+               test_bit(ATH_STAT_PROMISC, sc->status))
+               rfilt |= AR5K_RX_FILTER_PROM;
+       if (sc->opmode == IEEE80211_IF_TYPE_STA ||
+               sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+               rfilt |= AR5K_RX_FILTER_BEACON;
+       }
+
+       /* Set filters */
+       ath5k_hw_set_rx_filter(ah,rfilt);
+
+       /* Set multicast bits */
+       ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
+       /* Set the cached hw filter flags, this will alter actually
+        * be set in HW */
+       sc->filter_flags = rfilt;
+}
+
+static int
+ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+               const u8 *local_addr, const u8 *addr,
+               struct ieee80211_key_conf *key)
+{
+       struct ath5k_softc *sc = hw->priv;
+       int ret = 0;
+
+       switch(key->alg) {
+       case ALG_WEP:
+               break;
+       case ALG_TKIP:
+       case ALG_CCMP:
+               return -EOPNOTSUPP;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       mutex_lock(&sc->lock);
+
+       switch (cmd) {
+       case SET_KEY:
+               ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, addr);
+               if (ret) {
+                       ATH5K_ERR(sc, "can't set the key\n");
+                       goto unlock;
+               }
+               __set_bit(key->keyidx, sc->keymap);
+               key->hw_key_idx = key->keyidx;
+               break;
+       case DISABLE_KEY:
+               ath5k_hw_reset_key(sc->ah, key->keyidx);
+               __clear_bit(key->keyidx, sc->keymap);
+               break;
+       default:
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+unlock:
+       mutex_unlock(&sc->lock);
+       return ret;
+}
+
+static int
+ath5k_get_stats(struct ieee80211_hw *hw,
+               struct ieee80211_low_level_stats *stats)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));
+
+       return 0;
+}
+
+static int
+ath5k_get_tx_stats(struct ieee80211_hw *hw,
+               struct ieee80211_tx_queue_stats *stats)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats));
+
+       return 0;
+}
+
+static u64
+ath5k_get_tsf(struct ieee80211_hw *hw)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       return ath5k_hw_get_tsf64(sc->ah);
+}
+
+static void
+ath5k_reset_tsf(struct ieee80211_hw *hw)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       ath5k_hw_reset_tsf(sc->ah);
+}
+
+static int
+ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+                       struct ieee80211_tx_control *ctl)
+{
+       struct ath5k_softc *sc = hw->priv;
+       int ret;
+
+       ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
+
+       mutex_lock(&sc->lock);
+
+       if (sc->opmode != IEEE80211_IF_TYPE_IBSS) {
+               ret = -EIO;
+               goto end;
+       }
+
+       ath5k_txbuf_free(sc, sc->bbuf);
+       sc->bbuf->skb = skb;
+       ret = ath5k_beacon_setup(sc, sc->bbuf, ctl);
+       if (ret)
+               sc->bbuf->skb = NULL;
+       else
+               ath5k_beacon_config(sc);
+
+end:
+       mutex_unlock(&sc->lock);
+       return ret;
+}
+
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
new file mode 100644 (file)
index 0000000..927d67d
--- /dev/null
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
+/*
+ * Defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_ATHVAR_H
+#define _DEV_ATH_ATHVAR_H
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/wireless.h>
+#include <linux/if_ether.h>
+
+#include "ath5k.h"
+#include "debug.h"
+
+#define        ATH_RXBUF       40              /* number of RX buffers */
+#define        ATH_TXBUF       200             /* number of TX buffers */
+#define ATH_BCBUF      1               /* number of beacon buffers */
+
+struct ath5k_buf {
+       struct list_head        list;
+       unsigned int            flags;  /* tx descriptor flags */
+       struct ath5k_desc       *desc;  /* virtual addr of desc */
+       dma_addr_t              daddr;  /* physical addr of desc */
+       struct sk_buff          *skb;   /* skbuff for buf */
+       dma_addr_t              skbaddr;/* physical addr of skb data */
+       struct ieee80211_tx_control ctl;
+};
+
+/*
+ * Data transmit queue state.  One of these exists for each
+ * hardware transmit queue.  Packets sent to us from above
+ * are assigned to queues based on their priority.  Not all
+ * devices support a complete set of hardware transmit queues.
+ * For those devices the array sc_ac2q will map multiple
+ * priorities to fewer hardware queues (typically all to one
+ * hardware queue).
+ */
+struct ath5k_txq {
+       unsigned int            qnum;   /* hardware q number */
+       u32                     *link;  /* link ptr in last TX desc */
+       struct list_head        q;      /* transmit queue */
+       spinlock_t              lock;   /* lock on q and link */
+       bool                    setup;
+};
+
+#if CHAN_DEBUG
+#define ATH_CHAN_MAX   (26+26+26+200+200)
+#else
+#define ATH_CHAN_MAX   (14+14+14+252+20)       /* XXX what's the max? */
+#endif
+
+/* Software Carrier, keeps track of the driver state
+ * associated with an instance of a device */
+struct ath5k_softc {
+       struct pci_dev          *pdev;          /* for dma mapping */
+       void __iomem            *iobase;        /* address of the device */
+       struct mutex            lock;           /* dev-level lock */
+       struct ieee80211_tx_queue_stats tx_stats;
+       struct ieee80211_low_level_stats ll_stats;
+       struct ieee80211_hw     *hw;            /* IEEE 802.11 common */
+       struct ieee80211_hw_mode modes[NUM_DRIVER_MODES];
+       struct ieee80211_channel channels[ATH_CHAN_MAX];
+       struct ieee80211_rate   rates[AR5K_MAX_RATES * NUM_DRIVER_MODES];
+       enum ieee80211_if_types opmode;
+       struct ath5k_hw         *ah;            /* Atheros HW */
+
+#if ATH5K_DEBUG
+       struct ath5k_dbg_info   debug;          /* debug info */
+#endif
+
+       struct ath5k_buf        *bufptr;        /* allocated buffer ptr */
+       struct ath5k_desc       *desc;          /* TX/RX descriptors */
+       dma_addr_t              desc_daddr;     /* DMA (physical) address */
+       size_t                  desc_len;       /* size of TX/RX descriptors */
+       u16                     cachelsz;       /* cache line size */
+
+       DECLARE_BITMAP(status, 6);
+#define ATH_STAT_INVALID       0               /* disable hardware accesses */
+#define ATH_STAT_MRRETRY       1               /* multi-rate retry support */
+#define ATH_STAT_PROMISC       2
+#define ATH_STAT_LEDBLINKING   3               /* LED blink operation active */
+#define ATH_STAT_LEDENDBLINK   4               /* finish LED blink operation */
+#define ATH_STAT_LEDSOFT       5               /* enable LED gpio status */
+
+       unsigned int            filter_flags;   /* HW flags, AR5K_RX_FILTER_* */
+       unsigned int            curmode;        /* current phy mode */
+       struct ieee80211_channel *curchan;      /* current h/w channel */
+
+       int                     iface_id;       /* add/remove_interface id */
+
+       struct {
+               u8      rxflags;        /* radiotap rx flags */
+               u8      txflags;        /* radiotap tx flags */
+               u16     ledon;          /* softled on time */
+               u16     ledoff;         /* softled off time */
+       } hwmap[32];                            /* h/w rate ix mappings */
+
+       enum ath5k_int          imask;          /* interrupt mask copy */
+
+       DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
+
+       u8                      bssidmask[ETH_ALEN];
+
+       unsigned int            led_pin,        /* GPIO pin for driving LED */
+                               led_on,         /* pin setting for LED on */
+                               led_off;        /* off time for current blink */
+       struct timer_list       led_tim;        /* led off timer */
+       u8                      led_rxrate;     /* current rx rate for LED */
+       u8                      led_txrate;     /* current tx rate for LED */
+
+       struct tasklet_struct   restq;          /* reset tasklet */
+
+       unsigned int            rxbufsize;      /* rx size based on mtu */
+       struct list_head        rxbuf;          /* receive buffer */
+       spinlock_t              rxbuflock;
+       u32                     *rxlink;        /* link ptr in last RX desc */
+       struct tasklet_struct   rxtq;           /* rx intr tasklet */
+
+       struct list_head        txbuf;          /* transmit buffer */
+       spinlock_t              txbuflock;
+       unsigned int            txbuf_len;      /* buf count in txbuf list */
+       struct ath5k_txq        txqs[2];        /* beacon and tx */
+
+       struct ath5k_txq        *txq;           /* beacon and tx*/
+       struct tasklet_struct   txtq;           /* tx intr tasklet */
+
+       struct ath5k_buf        *bbuf;          /* beacon buffer */
+       unsigned int            bhalq,          /* SW q for outgoing beacons */
+                               bmisscount,     /* missed beacon transmits */
+                               bintval,        /* beacon interval */
+                               bsent;
+
+       struct timer_list       calib_tim;      /* calibration timer */
+};
+
+#define ath5k_hw_hasbssidmask(_ah) \
+       (ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0)
+#define ath5k_hw_hasveol(_ah) \
+       (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
+
+#endif
diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c
new file mode 100644 (file)
index 0000000..4ba649e
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2007 Bruno Randolf <bruno@thinktube.com>
+ *
+ *  This file is free software: you may copy, redistribute and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  This file is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include "debug.h"
+#include "base.h"
+
+static unsigned int ath5k_debug;
+module_param_named(debug, ath5k_debug, uint, 0);
+
+
+#if ATH5K_DEBUG
+
+#include <linux/seq_file.h>
+#include "reg.h"
+
+static struct dentry *ath5k_global_debugfs;
+
+static int ath5k_debugfs_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+
+/* debugfs: registers */
+
+struct reg {
+       char *name;
+       int addr;
+};
+
+#define REG_STRUCT_INIT(r) { #r, r }
+
+/* just a few random registers, might want to add more */
+static struct reg regs[] = {
+       REG_STRUCT_INIT(AR5K_CR),
+       REG_STRUCT_INIT(AR5K_RXDP),
+       REG_STRUCT_INIT(AR5K_CFG),
+       REG_STRUCT_INIT(AR5K_IER),
+       REG_STRUCT_INIT(AR5K_BCR),
+       REG_STRUCT_INIT(AR5K_RTSD0),
+       REG_STRUCT_INIT(AR5K_RTSD1),
+       REG_STRUCT_INIT(AR5K_TXCFG),
+       REG_STRUCT_INIT(AR5K_RXCFG),
+       REG_STRUCT_INIT(AR5K_RXJLA),
+       REG_STRUCT_INIT(AR5K_MIBC),
+       REG_STRUCT_INIT(AR5K_TOPS),
+       REG_STRUCT_INIT(AR5K_RXNOFRM),
+       REG_STRUCT_INIT(AR5K_TXNOFRM),
+       REG_STRUCT_INIT(AR5K_RPGTO),
+       REG_STRUCT_INIT(AR5K_RFCNT),
+       REG_STRUCT_INIT(AR5K_MISC),
+       REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT),
+       REG_STRUCT_INIT(AR5K_ISR),
+       REG_STRUCT_INIT(AR5K_PISR),
+       REG_STRUCT_INIT(AR5K_SISR0),
+       REG_STRUCT_INIT(AR5K_SISR1),
+       REG_STRUCT_INIT(AR5K_SISR2),
+       REG_STRUCT_INIT(AR5K_SISR3),
+       REG_STRUCT_INIT(AR5K_SISR4),
+       REG_STRUCT_INIT(AR5K_IMR),
+       REG_STRUCT_INIT(AR5K_PIMR),
+       REG_STRUCT_INIT(AR5K_SIMR0),
+       REG_STRUCT_INIT(AR5K_SIMR1),
+       REG_STRUCT_INIT(AR5K_SIMR2),
+       REG_STRUCT_INIT(AR5K_SIMR3),
+       REG_STRUCT_INIT(AR5K_SIMR4),
+       REG_STRUCT_INIT(AR5K_DCM_ADDR),
+       REG_STRUCT_INIT(AR5K_DCCFG),
+       REG_STRUCT_INIT(AR5K_CCFG),
+       REG_STRUCT_INIT(AR5K_CPC0),
+       REG_STRUCT_INIT(AR5K_CPC1),
+       REG_STRUCT_INIT(AR5K_CPC2),
+       REG_STRUCT_INIT(AR5K_CPC3),
+       REG_STRUCT_INIT(AR5K_CPCORN),
+       REG_STRUCT_INIT(AR5K_RESET_CTL),
+       REG_STRUCT_INIT(AR5K_SLEEP_CTL),
+       REG_STRUCT_INIT(AR5K_INTPEND),
+       REG_STRUCT_INIT(AR5K_SFR),
+       REG_STRUCT_INIT(AR5K_PCICFG),
+       REG_STRUCT_INIT(AR5K_GPIOCR),
+       REG_STRUCT_INIT(AR5K_GPIODO),
+       REG_STRUCT_INIT(AR5K_SREV),
+};
+
+static void *reg_start(struct seq_file *seq, loff_t *pos)
+{
+       return *pos < ARRAY_SIZE(regs) ? &regs[*pos] : NULL;
+}
+
+static void reg_stop(struct seq_file *seq, void *p)
+{
+       /* nothing to do */
+}
+
+static void *reg_next(struct seq_file *seq, void *p, loff_t *pos)
+{
+       ++*pos;
+       return *pos < ARRAY_SIZE(regs) ? &regs[*pos] : NULL;
+}
+
+static int reg_show(struct seq_file *seq, void *p)
+{
+       struct ath5k_softc *sc = seq->private;
+       struct reg *r = p;
+       seq_printf(seq, "%-25s0x%08x\n", r->name,
+               ath5k_hw_reg_read(sc->ah, r->addr));
+       return 0;
+}
+
+static struct seq_operations register_seq_ops = {
+       .start = reg_start,
+       .next  = reg_next,
+       .stop  = reg_stop,
+       .show  = reg_show
+};
+
+static int open_file_registers(struct inode *inode, struct file *file)
+{
+       struct seq_file *s;
+       int res;
+       res = seq_open(file, &register_seq_ops);
+       if (res == 0) {
+               s = file->private_data;
+               s->private = inode->i_private;
+       }
+       return res;
+}
+
+static const struct file_operations fops_registers = {
+       .open = open_file_registers,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+       .owner = THIS_MODULE,
+};
+
+
+/* debugfs: TSF */
+
+static ssize_t read_file_tsf(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       char buf[100];
+       snprintf(buf, 100, "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
+}
+
+static ssize_t write_file_tsf(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       if (strncmp(userbuf, "reset", 5) == 0) {
+               ath5k_hw_reset_tsf(sc->ah);
+               printk(KERN_INFO "debugfs reset TSF\n");
+       }
+       return count;
+}
+
+static const struct file_operations fops_tsf = {
+       .read = read_file_tsf,
+       .write = write_file_tsf,
+       .open = ath5k_debugfs_open,
+       .owner = THIS_MODULE,
+};
+
+
+/* debugfs: beacons */
+
+static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       struct ath5k_hw *ah = sc->ah;
+       char buf[1000];
+       int len = 0;
+       unsigned int v;
+       u64 tsf;
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n",
+               "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD,
+               (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S);
+
+       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n",
+               "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP));
+
+       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n",
+               "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT));
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0);
+       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+               "AR5K_TIMER0 (TBTT)", v, v);
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1);
+       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+               "AR5K_TIMER1 (DMA)", v, v >> 3);
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2);
+       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+               "AR5K_TIMER2 (SWBA)", v, v >> 3);
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3);
+       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+               "AR5K_TIMER3 (ATIM)", v, v);
+
+       tsf = ath5k_hw_get_tsf64(sc->ah);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "TSF\t\t0x%016llx\tTU: %08x\n", tsf, TSF_TO_TU(tsf));
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_beacon(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       struct ath5k_hw *ah = sc->ah;
+
+       if (strncmp(userbuf, "disable", 7) == 0) {
+               AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
+               printk(KERN_INFO "debugfs disable beacons\n");
+       } else if (strncmp(userbuf, "enable", 6) == 0) {
+               AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
+               printk(KERN_INFO "debugfs enable beacons\n");
+       }
+       return count;
+}
+
+static const struct file_operations fops_beacon = {
+       .read = read_file_beacon,
+       .write = write_file_beacon,
+       .open = ath5k_debugfs_open,
+       .owner = THIS_MODULE,
+};
+
+
+/* debugfs: reset */
+
+static ssize_t write_file_reset(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       tasklet_schedule(&sc->restq);
+       return count;
+}
+
+static const struct file_operations fops_reset = {
+       .write = write_file_reset,
+       .open = ath5k_debugfs_open,
+       .owner = THIS_MODULE,
+};
+
+
+/* init */
+
+void
+ath5k_debug_init(void)
+{
+       ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL);
+}
+
+void
+ath5k_debug_init_device(struct ath5k_softc *sc)
+{
+       sc->debug.level = ath5k_debug;
+       sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
+                       ath5k_global_debugfs);
+       sc->debug.debugfs_debug = debugfs_create_u32("debug",
+                       0666, sc->debug.debugfs_phydir, &sc->debug.level);
+
+       sc->debug.debugfs_registers = debugfs_create_file("registers", 0444,
+                               sc->debug.debugfs_phydir,
+                               sc, &fops_registers);
+
+       sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666,
+                               sc->debug.debugfs_phydir,
+                               sc, &fops_tsf);
+
+       sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666,
+                               sc->debug.debugfs_phydir,
+                               sc, &fops_beacon);
+
+       sc->debug.debugfs_reset = debugfs_create_file("reset", 0222,
+                               sc->debug.debugfs_phydir,
+                               sc, &fops_reset);
+}
+
+void
+ath5k_debug_finish(void)
+{
+       debugfs_remove(ath5k_global_debugfs);
+}
+
+void
+ath5k_debug_finish_device(struct ath5k_softc *sc)
+{
+       debugfs_remove(sc->debug.debugfs_debug);
+       debugfs_remove(sc->debug.debugfs_registers);
+       debugfs_remove(sc->debug.debugfs_tsf);
+       debugfs_remove(sc->debug.debugfs_beacon);
+       debugfs_remove(sc->debug.debugfs_reset);
+       debugfs_remove(sc->debug.debugfs_phydir);
+}
+
+
+/* functions used in other places */
+
+void
+ath5k_debug_dump_modes(struct ath5k_softc *sc, struct ieee80211_hw_mode *modes)
+{
+       unsigned int m, i;
+
+       if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPMODES)))
+               return;
+
+       for (m = 0; m < NUM_DRIVER_MODES; m++) {
+               printk(KERN_DEBUG "Mode %u: channels %d, rates %d\n", m,
+                               modes[m].num_channels, modes[m].num_rates);
+               printk(KERN_DEBUG " channels:\n");
+               for (i = 0; i < modes[m].num_channels; i++)
+                       printk(KERN_DEBUG "  %3d %d %.4x %.4x\n",
+                                       modes[m].channels[i].chan,
+                                       modes[m].channels[i].freq,
+                                       modes[m].channels[i].val,
+                                       modes[m].channels[i].flag);
+               printk(KERN_DEBUG " rates:\n");
+               for (i = 0; i < modes[m].num_rates; i++)
+                       printk(KERN_DEBUG "  %4d %.4x %.4x %.4x\n",
+                                       modes[m].rates[i].rate,
+                                       modes[m].rates[i].val,
+                                       modes[m].rates[i].flags,
+                                       modes[m].rates[i].val2);
+       }
+}
+
+static inline void
+ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done)
+{
+       struct ath5k_desc *ds = bf->desc;
+
+       printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n",
+               ds, (unsigned long long)bf->daddr,
+               ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1,
+               ds->ds_hw[0], ds->ds_hw[1],
+               !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!');
+}
+
+void
+ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
+{
+       struct ath5k_desc *ds;
+       struct ath5k_buf *bf;
+       int status;
+
+       if (likely(!(sc->debug.level &
+           (ATH5K_DEBUG_RESET | ATH5K_DEBUG_FATAL))))
+               return;
+
+       printk(KERN_DEBUG "rx queue %x, link %p\n",
+               ath5k_hw_get_rx_buf(ah), sc->rxlink);
+
+       spin_lock_bh(&sc->rxbuflock);
+       list_for_each_entry(bf, &sc->rxbuf, list) {
+               ds = bf->desc;
+               status = ah->ah_proc_rx_desc(ah, ds);
+               if (!status || (sc->debug.level & ATH5K_DEBUG_FATAL))
+                       ath5k_debug_printrxbuf(bf, status == 0);
+       }
+       spin_unlock_bh(&sc->rxbuflock);
+}
+
+void
+ath5k_debug_dump_skb(struct ath5k_softc *sc,
+                       struct sk_buff *skb, const char *prefix, int tx)
+{
+       char buf[16];
+
+       if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) ||
+                    (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX)))))
+               return;
+
+       snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix);
+
+       print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data,
+               min(200U, skb->len));
+
+       printk(KERN_DEBUG "\n");
+}
+
+void
+ath5k_debug_printtxbuf(struct ath5k_softc *sc,
+                       struct ath5k_buf *bf, int done)
+{
+       struct ath5k_desc *ds = bf->desc;
+
+       if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+               return;
+
+       printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x "
+               "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link,
+               ds->ds_data, ds->ds_ctl0, ds->ds_ctl1,
+               ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3],
+               !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!');
+}
+
+#endif /* if ATH5K_DEBUG */
diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h
new file mode 100644 (file)
index 0000000..2b491cb
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2007 Bruno Randolf <bruno@thinktube.com>
+ *
+ *  This file is free software: you may copy, redistribute and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  This file is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef _ATH5K_DEBUG_H
+#define _ATH5K_DEBUG_H
+
+/* set this to 1 for debugging output */
+#ifndef ATH5K_DEBUG
+#define ATH5K_DEBUG    0
+#endif
+
+struct ath5k_softc;
+struct ath5k_hw;
+struct ieee80211_hw_mode;
+struct sk_buff;
+struct ath5k_buf;
+
+struct ath5k_dbg_info {
+       unsigned int            level;          /* debug level */
+       /* debugfs entries */
+       struct dentry           *debugfs_phydir;
+       struct dentry           *debugfs_debug;
+       struct dentry           *debugfs_registers;
+       struct dentry           *debugfs_tsf;
+       struct dentry           *debugfs_beacon;
+       struct dentry           *debugfs_reset;
+};
+
+/**
+ * enum ath5k_debug_level - ath5k debug level
+ *
+ * @ATH5K_DEBUG_RESET: reset processing
+ * @ATH5K_DEBUG_INTR: interrupt handling
+ * @ATH5K_DEBUG_MODE: mode init/setup
+ * @ATH5K_DEBUG_XMIT: basic xmit operation
+ * @ATH5K_DEBUG_BEACON: beacon handling
+ * @ATH5K_DEBUG_BEACON_PROC: beacon ISR proc
+ * @ATH5K_DEBUG_CALIBRATE: periodic calibration
+ * @ATH5K_DEBUG_TXPOWER: transmit power setting
+ * @ATH5K_DEBUG_LED: led management
+ * @ATH5K_DEBUG_DUMP_RX: print received skb content
+ * @ATH5K_DEBUG_DUMP_TX: print transmit skb content
+ * @ATH5K_DEBUG_DUMPMODES: dump modes
+ * @ATH5K_DEBUG_TRACE: trace function calls
+ * @ATH5K_DEBUG_FATAL: fatal errors
+ * @ATH5K_DEBUG_ANY: show at any debug level
+ *
+ * The debug level is used to control the amount and type of debugging output
+ * we want to see. The debug level is given in calls to ATH5K_DBG to specify
+ * where the message should appear, and the user can control the debugging
+ * messages he wants to see, either by the module parameter 'debug' on module
+ * load, or dynamically by using debugfs 'ath5k/phyX/debug'. these levels can
+ * be combined together by bitwise OR.
+ */
+enum ath5k_debug_level {
+       ATH5K_DEBUG_RESET       = 0x00000001,
+       ATH5K_DEBUG_INTR        = 0x00000002,
+       ATH5K_DEBUG_MODE        = 0x00000004,
+       ATH5K_DEBUG_XMIT        = 0x00000008,
+       ATH5K_DEBUG_BEACON      = 0x00000010,
+       ATH5K_DEBUG_BEACON_PROC = 0x00000020,
+       ATH5K_DEBUG_CALIBRATE   = 0x00000100,
+       ATH5K_DEBUG_TXPOWER     = 0x00000200,
+       ATH5K_DEBUG_LED         = 0x00000400,
+       ATH5K_DEBUG_DUMP_RX     = 0x00001000,
+       ATH5K_DEBUG_DUMP_TX     = 0x00002000,
+       ATH5K_DEBUG_DUMPMODES   = 0x00004000,
+       ATH5K_DEBUG_TRACE       = 0x00010000,
+       ATH5K_DEBUG_FATAL       = 0x80000000,
+       ATH5K_DEBUG_ANY         = 0xffffffff
+};
+
+#if ATH5K_DEBUG
+
+#define ATH5K_TRACE(_sc) do { \
+       if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \
+               printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \
+       } while (0)
+
+#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \
+       if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \
+               ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
+                       __func__, __LINE__, ##__VA_ARGS__); \
+       } while (0)
+
+#define ATH5K_DBG_UNLIMIT(_sc, _m, _fmt, ...) do { \
+       if (unlikely((_sc)->debug.level & (_m))) \
+               ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
+                       __func__, __LINE__, ##__VA_ARGS__); \
+       } while (0)
+
+void
+ath5k_debug_init(void);
+
+void
+ath5k_debug_init_device(struct ath5k_softc *sc);
+
+void
+ath5k_debug_finish(void);
+
+void
+ath5k_debug_finish_device(struct ath5k_softc *sc);
+
+void
+ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
+
+void
+ath5k_debug_dump_modes(struct ath5k_softc *sc,
+                       struct ieee80211_hw_mode *modes);
+
+void
+ath5k_debug_dump_skb(struct ath5k_softc *sc,
+                       struct sk_buff *skb, const char *prefix, int tx);
+
+void
+ath5k_debug_printtxbuf(struct ath5k_softc *sc,
+                       struct ath5k_buf *bf, int done);
+
+#else /* no debugging */
+
+#define ATH5K_TRACE(_sc) /* empty */
+
+static inline void __attribute__ ((format (printf, 3, 4)))
+ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {}
+
+static inline void __attribute__ ((format (printf, 3, 4)))
+ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...)
+{}
+
+static inline void
+ath5k_debug_init(void) {}
+
+static inline void
+ath5k_debug_init_device(struct ath5k_softc *sc) {}
+
+static inline void
+ath5k_debug_finish(void) {}
+
+static inline void
+ath5k_debug_finish_device(struct ath5k_softc *sc) {}
+
+static inline void
+ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
+
+static inline void
+ath5k_debug_dump_modes(struct ath5k_softc *sc,
+                       struct ieee80211_hw_mode *modes) {}
+
+static inline void
+ath5k_debug_dump_skb(struct ath5k_softc *sc,
+                       struct sk_buff *skb, const char *prefix, int tx) {}
+
+static inline void
+ath5k_debug_printtxbuf(struct ath5k_softc *sc,
+                       struct ath5k_buf *bf, int done) {}
+
+#endif /* if ATH5K_DEBUG */
+
+#endif /* ifndef _ATH5K_DEBUG_H */
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
new file mode 100644 (file)
index 0000000..5623d7d
--- /dev/null
@@ -0,0 +1,4349 @@
+ /*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Matthew W. S. Bell  <mentor@madwifi.org>
+ * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright (c) 2007 Pavel Roskin <proski@gnu.org>
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * HW related functions for Atheros Wireless LAN devices.
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "reg.h"
+#include "base.h"
+#include "debug.h"
+
+/*Rate tables*/
+static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A;
+static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B;
+static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G;
+static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO;
+static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR;
+
+/*Prototypes*/
+static int ath5k_hw_nic_reset(struct ath5k_hw *, u32);
+static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool);
+static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
+       unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+       unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
+       unsigned int, unsigned int);
+static bool ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
+       unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
+       unsigned int);
+static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
+       unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+       unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
+       unsigned int, unsigned int);
+static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_get_capabilities(struct ath5k_hw *);
+
+static int ath5k_eeprom_init(struct ath5k_hw *);
+static int ath5k_eeprom_read_mac(struct ath5k_hw *, u8 *);
+
+static int ath5k_hw_enable_pspoll(struct ath5k_hw *, u8 *, u16);
+static int ath5k_hw_disable_pspoll(struct ath5k_hw *);
+
+/*
+ * Enable to overwrite the country code (use "00" for debug)
+ */
+#if 0
+#define COUNTRYCODE "00"
+#endif
+
+/*******************\
+  General Functions
+\*******************/
+
+/*
+ * Functions used internaly
+ */
+
+static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
+{
+       return turbo == true ? (usec * 80) : (usec * 40);
+}
+
+static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
+{
+       return turbo == true ? (clock / 80) : (clock / 40);
+}
+
+/*
+ * Check if a register write has been completed
+ */
+int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
+               bool is_set)
+{
+       int i;
+       u32 data;
+
+       for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+               data = ath5k_hw_reg_read(ah, reg);
+               if ((is_set == true) && (data & flag))
+                       break;
+               else if ((data & flag) == val)
+                       break;
+               udelay(15);
+       }
+
+       return (i <= 0) ? -EAGAIN : 0;
+}
+
+
+/***************************************\
+       Attach/Detach Functions
+\***************************************/
+
+/*
+ * Check if the device is supported and initialize the needed structs
+ */
+struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
+{
+       struct ath5k_hw *ah;
+       u8 mac[ETH_ALEN];
+       int ret;
+       u32 srev;
+
+       /*If we passed the test malloc a ath5k_hw struct*/
+       ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
+       if (ah == NULL) {
+               ret = -ENOMEM;
+               ATH5K_ERR(sc, "out of memory\n");
+               goto err;
+       }
+
+       ah->ah_sc = sc;
+       ah->ah_iobase = sc->iobase;
+
+       /*
+        * HW information
+        */
+
+       /* Get reg domain from eeprom */
+       ath5k_get_regdomain(ah);
+
+       ah->ah_op_mode = IEEE80211_IF_TYPE_STA;
+       ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
+       ah->ah_turbo = false;
+       ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
+       ah->ah_imr = 0;
+       ah->ah_atim_window = 0;
+       ah->ah_aifs = AR5K_TUNE_AIFS;
+       ah->ah_cw_min = AR5K_TUNE_CWMIN;
+       ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
+       ah->ah_software_retry = false;
+       ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
+
+       /*
+        * Set the mac revision based on the pci id
+        */
+       ah->ah_version = mac_version;
+
+       /*Fill the ath5k_hw struct with the needed functions*/
+       if (ah->ah_version == AR5K_AR5212)
+               ah->ah_magic = AR5K_EEPROM_MAGIC_5212;
+       else if (ah->ah_version == AR5K_AR5211)
+               ah->ah_magic = AR5K_EEPROM_MAGIC_5211;
+
+       if (ah->ah_version == AR5K_AR5212) {
+               ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
+               ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc;
+               ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
+       } else {
+               ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
+               ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc;
+               ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
+       }
+
+       if (ah->ah_version == AR5K_AR5212)
+               ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status;
+       else if (ah->ah_version <= AR5K_AR5211)
+               ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status;
+
+       /* Bring device out of sleep and reset it's units */
+       ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true);
+       if (ret)
+               goto err_free;
+
+       /* Get MAC, PHY and RADIO revisions */
+       srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+       ah->ah_mac_srev = srev;
+       ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+       ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
+       ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
+                       0xffffffff;
+       ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
+                       CHANNEL_5GHZ);
+
+       if (ah->ah_version == AR5K_AR5210)
+               ah->ah_radio_2ghz_revision = 0;
+       else
+               ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+                               CHANNEL_2GHZ);
+
+       /* Return on unsuported chips (unsupported eeprom etc) */
+       if(srev >= AR5K_SREV_VER_AR5416){
+               ATH5K_ERR(sc, "Device not yet supported.\n");
+               ret = -ENODEV;
+               goto err_free;
+       }
+
+       /* Identify single chip solutions */
+       if((srev <= AR5K_SREV_VER_AR5414) &&
+       (srev >= AR5K_SREV_VER_AR2424)) {
+               ah->ah_single_chip = true;
+       } else {
+               ah->ah_single_chip = false;
+       }
+
+       /* Single chip radio */
+       if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision)
+               ah->ah_radio_2ghz_revision = 0;
+
+       /* Identify the radio chip*/
+       if (ah->ah_version == AR5K_AR5210) {
+               ah->ah_radio = AR5K_RF5110;
+       } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
+               ah->ah_radio = AR5K_RF5111;
+       } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
+               ah->ah_radio = AR5K_RF5112;
+       } else {
+               ah->ah_radio = AR5K_RF5413;
+       }
+
+       ah->ah_phy = AR5K_PHY(0);
+
+       /*
+        * Get card capabilities, values, ...
+        */
+
+       ret = ath5k_eeprom_init(ah);
+       if (ret) {
+               ATH5K_ERR(sc, "unable to init EEPROM\n");
+               goto err_free;
+       }
+
+       /* Get misc capabilities */
+       ret = ath5k_hw_get_capabilities(ah);
+       if (ret) {
+               ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n",
+                       sc->pdev->device);
+               goto err_free;
+       }
+
+       /* Get MAC address */
+       ret = ath5k_eeprom_read_mac(ah, mac);
+       if (ret) {
+               ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
+                       sc->pdev->device);
+               goto err_free;
+       }
+
+       ath5k_hw_set_lladdr(ah, mac);
+       /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
+       memset(ah->ah_bssid, 0xff, ETH_ALEN);
+       ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+       ath5k_hw_set_opmode(ah);
+
+       ath5k_hw_set_rfgain_opt(ah);
+
+       return ah;
+err_free:
+       kfree(ah);
+err:
+       return ERR_PTR(ret);
+}
+
+/*
+ * Bring up MAC + PHY Chips
+ */
+static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
+{
+       u32 turbo, mode, clock;
+       int ret;
+
+       turbo = 0;
+       mode = 0;
+       clock = 0;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /* Wakeup the device */
+       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+       if (ret) {
+               ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
+               return ret;
+       }
+
+       if (ah->ah_version != AR5K_AR5210) {
+               /*
+                * Get channel mode flags
+                */
+
+               if (ah->ah_radio >= AR5K_RF5112) {
+                       mode = AR5K_PHY_MODE_RAD_RF5112;
+                       clock = AR5K_PHY_PLL_RF5112;
+               } else {
+                       mode = AR5K_PHY_MODE_RAD_RF5111;        /*Zero*/
+                       clock = AR5K_PHY_PLL_RF5111;            /*Zero*/
+               }
+
+               if (flags & CHANNEL_2GHZ) {
+                       mode |= AR5K_PHY_MODE_FREQ_2GHZ;
+                       clock |= AR5K_PHY_PLL_44MHZ;
+
+                       if (flags & CHANNEL_CCK) {
+                               mode |= AR5K_PHY_MODE_MOD_CCK;
+                       } else if (flags & CHANNEL_OFDM) {
+                               /* XXX Dynamic OFDM/CCK is not supported by the
+                                * AR5211 so we set MOD_OFDM for plain g (no
+                                * CCK headers) operation. We need to test
+                                * this, 5211 might support ofdm-only g after
+                                * all, there are also initial register values
+                                * in the code for g mode (see initvals.c). */
+                               if (ah->ah_version == AR5K_AR5211)
+                                       mode |= AR5K_PHY_MODE_MOD_OFDM;
+                               else
+                                       mode |= AR5K_PHY_MODE_MOD_DYN;
+                       } else {
+                               ATH5K_ERR(ah->ah_sc,
+                                       "invalid radio modulation mode\n");
+                               return -EINVAL;
+                       }
+               } else if (flags & CHANNEL_5GHZ) {
+                       mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+                       clock |= AR5K_PHY_PLL_40MHZ;
+
+                       if (flags & CHANNEL_OFDM)
+                               mode |= AR5K_PHY_MODE_MOD_OFDM;
+                       else {
+                               ATH5K_ERR(ah->ah_sc,
+                                       "invalid radio modulation mode\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n");
+                       return -EINVAL;
+               }
+
+               if (flags & CHANNEL_TURBO)
+                       turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
+       } else { /* Reset the device */
+
+               /* ...enable Atheros turbo mode if requested */
+               if (flags & CHANNEL_TURBO)
+                       ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
+                                       AR5K_PHY_TURBO);
+       }
+
+       /* ...reset chipset and PCI device */
+       if (ah->ah_single_chip == false && ath5k_hw_nic_reset(ah,
+                               AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI)) {
+               ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n");
+               return -EIO;
+       }
+
+       if (ah->ah_version == AR5K_AR5210)
+               udelay(2300);
+
+       /* ...wakeup again!*/
+       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+       if (ret) {
+               ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
+               return ret;
+       }
+
+       /* ...final warm reset */
+       if (ath5k_hw_nic_reset(ah, 0)) {
+               ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
+               return -EIO;
+       }
+
+       if (ah->ah_version != AR5K_AR5210) {
+               /* ...set the PHY operating mode */
+               ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
+               udelay(300);
+
+               ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
+               ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
+       }
+
+       return 0;
+}
+
+/*
+ * Get the rate table for a specific operation mode
+ */
+const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah,
+               unsigned int mode)
+{
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (!test_bit(mode, ah->ah_capabilities.cap_mode))
+               return NULL;
+
+       /* Get rate tables */
+       switch (mode) {
+       case MODE_IEEE80211A:
+               return &ath5k_rt_11a;
+       case MODE_ATHEROS_TURBO:
+               return &ath5k_rt_turbo;
+       case MODE_IEEE80211B:
+               return &ath5k_rt_11b;
+       case MODE_IEEE80211G:
+               return &ath5k_rt_11g;
+       case MODE_ATHEROS_TURBOG:
+               return &ath5k_rt_xr;
+       }
+
+       return NULL;
+}
+
+/*
+ * Free the ath5k_hw struct
+ */
+void ath5k_hw_detach(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (ah->ah_rf_banks != NULL)
+               kfree(ah->ah_rf_banks);
+
+       /* assume interrupts are down */
+       kfree(ah);
+}
+
+/****************************\
+  Reset function and helpers
+\****************************/
+
+/**
+ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ *
+ * @ah: the &struct ath5k_hw
+ * @channel: the currently set channel upon reset
+ *
+ * Write the OFDM timings for the AR5212 upon reset. This is a helper for
+ * ath5k_hw_reset(). This seems to tune the PLL a specified frequency
+ * depending on the bandwidth of the channel.
+ *
+ */
+static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
+       struct ieee80211_channel *channel)
+{
+       /* Get exponent and mantissa and set it */
+       u32 coef_scaled, coef_exp, coef_man,
+               ds_coef_exp, ds_coef_man, clock;
+
+       if (!(ah->ah_version == AR5K_AR5212) ||
+               !(channel->val & CHANNEL_OFDM))
+               BUG();
+
+       /* Seems there are two PLLs, one for baseband sampling and one
+        * for tuning. Tuning basebands are 40 MHz or 80MHz when in
+        * turbo. */
+       clock = channel->val & CHANNEL_TURBO ? 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)
+               return -EINVAL;
+
+       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(ah, AR5K_PHY_TIMING_3,
+               AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+               AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+
+       return 0;
+}
+
+/**
+ * ath5k_hw_write_rate_duration - set rate duration during hw resets
+ *
+ * @ah: the &struct ath5k_hw
+ * @driver_mode: one of enum ieee80211_phymode or our one of our own
+ *     vendor modes
+ *
+ * Write the rate duration table for the current mode upon hw reset. This
+ * is a helper for ath5k_hw_reset(). It seems all this is doing is setting
+ * an ACK timeout for the hardware for the current mode for each rate. The
+ * rates which are capable of short preamble (802.11b rates 2Mbps, 5.5Mbps,
+ * and 11Mbps) have another register for the short preamble ACK timeout
+ * calculation.
+ *
+ */
+static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
+       unsigned int driver_mode)
+{
+       struct ath5k_softc *sc = ah->ah_sc;
+       const struct ath5k_rate_table *rt;
+       unsigned int i;
+
+       /* Get rate table for the current operating mode */
+       rt = ath5k_hw_get_rate_table(ah,
+               driver_mode);
+
+       /* Write rate duration table */
+       for (i = 0; i < rt->rate_count; i++) {
+               const struct ath5k_rate *rate, *control_rate;
+               u32 reg;
+               u16 tx_time;
+
+               rate = &rt->rates[i];
+               control_rate = &rt->rates[rate->control_rate];
+
+               /* Set ACK timeout */
+               reg = AR5K_RATE_DUR(rate->rate_code);
+
+               /* An ACK frame consists of 10 bytes. If you add the FCS,
+                * which ieee80211_generic_frame_duration() adds,
+                * its 14 bytes. Note we use the control rate and not the
+                * actual rate for this rate. See mac80211 tx.c
+                * ieee80211_duration() for a brief description of
+                * what rate we should choose to TX ACKs. */
+               tx_time = ieee80211_generic_frame_duration(sc->hw,
+                       sc->iface_id, 10, control_rate->rate_kbps/100);
+
+               ath5k_hw_reg_write(ah, tx_time, reg);
+
+               if (!HAS_SHPREAMBLE(i))
+                       continue;
+
+               /*
+                * We're not distinguishing short preamble here,
+                * This is true, all we'll get is a longer value here
+                * which is not necessarilly bad. We could use
+                * export ieee80211_frame_duration() but that needs to be
+                * fixed first to be properly used by mac802111 drivers:
+                *
+                *  - remove erp stuff and let the routine figure ofdm
+                *    erp rates
+                *  - remove passing argument ieee80211_local as
+                *    drivers don't have access to it
+                *  - move drivers using ieee80211_generic_frame_duration()
+                *    to this
+                */
+               ath5k_hw_reg_write(ah, tx_time,
+                       reg + (AR5K_SET_SHORT_PREAMBLE << 2));
+       }
+}
+
+/*
+ * Main reset function
+ */
+int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
+       struct ieee80211_channel *channel, bool change_channel)
+{
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+       u32 data, s_seq, s_ant, s_led[3];
+       unsigned int i, mode, freq, ee_mode, ant[2], driver_mode = -1;
+       int ret;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       s_seq = 0;
+       s_ant = 0;
+       ee_mode = 0;
+       freq = 0;
+       mode = 0;
+
+       /*
+        * Save some registers before a reset
+        */
+       /*DCU/Antenna selection not available on 5210*/
+       if (ah->ah_version != AR5K_AR5210) {
+               if (change_channel == true) {
+                       /* Seq number for queue 0 -do this for all queues ? */
+                       s_seq = ath5k_hw_reg_read(ah,
+                                       AR5K_QUEUE_DFS_SEQNUM(0));
+                       /*Default antenna*/
+                       s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+               }
+       }
+
+       /*GPIOs*/
+       s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE;
+       s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
+       s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+       if (change_channel == true && ah->ah_rf_banks != NULL)
+               ath5k_hw_get_rf_gain(ah);
+
+
+       /*Wakeup the device*/
+       ret = ath5k_hw_nic_wakeup(ah, channel->val, false);
+       if (ret)
+               return ret;
+
+       /*
+        * Initialize operating mode
+        */
+       ah->ah_op_mode = op_mode;
+
+       /*
+        * 5111/5112 Settings
+        * 5210 only comes with RF5110
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               if (ah->ah_radio != AR5K_RF5111 &&
+                       ah->ah_radio != AR5K_RF5112 &&
+                       ah->ah_radio != AR5K_RF5413) {
+                       ATH5K_ERR(ah->ah_sc,
+                               "invalid phy radio: %u\n", ah->ah_radio);
+                       return -EINVAL;
+               }
+
+               switch (channel->val & CHANNEL_MODES) {
+               case CHANNEL_A:
+                       mode = AR5K_INI_VAL_11A;
+                       freq = AR5K_INI_RFGAIN_5GHZ;
+                       ee_mode = AR5K_EEPROM_MODE_11A;
+                       driver_mode = MODE_IEEE80211A;
+                       break;
+               case CHANNEL_G:
+                       mode = AR5K_INI_VAL_11G;
+                       freq = AR5K_INI_RFGAIN_2GHZ;
+                       ee_mode = AR5K_EEPROM_MODE_11G;
+                       driver_mode = MODE_IEEE80211G;
+                       break;
+               case CHANNEL_B:
+                       mode = AR5K_INI_VAL_11B;
+                       freq = AR5K_INI_RFGAIN_2GHZ;
+                       ee_mode = AR5K_EEPROM_MODE_11B;
+                       driver_mode = MODE_IEEE80211B;
+                       break;
+               case CHANNEL_T:
+                       mode = AR5K_INI_VAL_11A_TURBO;
+                       freq = AR5K_INI_RFGAIN_5GHZ;
+                       ee_mode = AR5K_EEPROM_MODE_11A;
+                       driver_mode = MODE_ATHEROS_TURBO;
+                       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;
+                       driver_mode = MODE_ATHEROS_TURBOG;
+                       break;
+               case CHANNEL_XR:
+                       if (ah->ah_version == AR5K_AR5211) {
+                               ATH5K_ERR(ah->ah_sc,
+                                       "XR mode not available on 5211");
+                               return -EINVAL;
+                       }
+                       mode = AR5K_INI_VAL_XR;
+                       freq = AR5K_INI_RFGAIN_5GHZ;
+                       ee_mode = AR5K_EEPROM_MODE_11A;
+                       driver_mode = MODE_IEEE80211A;
+                       break;
+               default:
+                       ATH5K_ERR(ah->ah_sc,
+                               "invalid channel: %d\n", channel->freq);
+                       return -EINVAL;
+               }
+
+               /* PHY access enable */
+               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+       }
+
+       ret = ath5k_hw_write_initvals(ah, mode, change_channel);
+       if (ret)
+               return ret;
+
+       /*
+        * 5211/5212 Specific
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               /*
+                * Write initial RF gain settings
+                * This should work for both 5111/5112
+                */
+               ret = ath5k_hw_rfgain(ah, freq);
+               if (ret)
+                       return ret;
+
+               mdelay(1);
+
+               /*
+                * Write some more initial register settings
+                */
+               if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */
+                       ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11));
+
+                       if (channel->val == CHANNEL_G)
+                               ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */
+                       else
+                               ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83));
+
+                       ath5k_hw_reg_write(ah, 0x000001b5, 0xa228); /* 0x000009b5 */
+                       ath5k_hw_reg_write(ah, 0x000009b5, 0xa228);
+                       ath5k_hw_reg_write(ah, 0x0000000f, 0x8060);
+                       ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
+                       ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
+               }
+
+               /* Fix for first revision of the RF5112 RF chipset */
+               if (ah->ah_radio >= AR5K_RF5112 &&
+                               ah->ah_radio_5ghz_revision <
+                               AR5K_SREV_RAD_5112A) {
+                       ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
+                                       AR5K_PHY_CCKTXCTL);
+                       if (channel->val & CHANNEL_5GHZ)
+                               data = 0xffb81020;
+                       else
+                               data = 0xffb80d20;
+                       ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+               }
+
+               /*
+                * Set TX power (FIXME)
+                */
+               ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER);
+               if (ret)
+                       return ret;
+
+               /* Write rate duration table */
+               if (ah->ah_version == AR5K_AR5212)
+                       ath5k_hw_write_rate_duration(ah, driver_mode);
+
+               /*
+                * Write RF registers
+                * TODO:Does this work on 5211 (5111) ?
+                */
+               ret = ath5k_hw_rfregs(ah, channel, mode);
+               if (ret)
+                       return ret;
+
+               /*
+                * Configure additional registers
+                */
+
+               /* Write OFDM timings on 5212*/
+               if (ah->ah_version == AR5K_AR5212 &&
+                       channel->val & CHANNEL_OFDM) {
+                       ret = ath5k_hw_write_ofdm_timings(ah, channel);
+                       if (ret)
+                               return ret;
+               }
+
+               /*Enable/disable 802.11b mode on 5111
+               (enable 2111 frequency converter + CCK)*/
+               if (ah->ah_radio == AR5K_RF5111) {
+                       if (driver_mode == MODE_IEEE80211B)
+                               AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
+                                   AR5K_TXCFG_B_MODE);
+                       else
+                               AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+                                   AR5K_TXCFG_B_MODE);
+               }
+
+               /*
+                * Set channel and calibrate the PHY
+                */
+               ret = ath5k_hw_channel(ah, channel);
+               if (ret)
+                       return ret;
+
+               /* Set antenna mode */
+               AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x44),
+                       ah->ah_antenna[ee_mode][0], 0xfffffc06);
+
+               /*
+                * In case a fixed antenna was set as default
+                * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
+                * registers.
+                */
+               if (s_ant != 0){
+                       if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
+                               ant[0] = ant[1] = AR5K_ANT_FIXED_A;
+                       else    /* 2 - Aux */
+                               ant[0] = ant[1] = AR5K_ANT_FIXED_B;
+               } else {
+                       ant[0] = AR5K_ANT_FIXED_A;
+                       ant[1] = AR5K_ANT_FIXED_B;
+               }
+
+               ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
+                       AR5K_PHY_ANT_SWITCH_TABLE_0);
+               ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
+                       AR5K_PHY_ANT_SWITCH_TABLE_1);
+
+               /* Commit values from EEPROM */
+               if (ah->ah_radio == AR5K_RF5111)
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
+                           AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip);
+
+               ath5k_hw_reg_write(ah,
+                       AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
+                       AR5K_PHY(0x5a));
+
+               AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x11),
+                       (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
+                       0xffffc07f);
+               AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x12),
+                       (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
+                       0xfffc0fff);
+               AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x14),
+                       (ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
+                       ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
+                       0xffff0000);
+
+               ath5k_hw_reg_write(ah,
+                       (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_PHY(0x0d));
+
+               AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x0a),
+                       ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
+               AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x19),
+                       (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
+               AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x49), 4, 0xffffff01);
+
+               AR5K_REG_ENABLE_BITS(ah, 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 (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+                               AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+                               ee->ee_margin_tx_rx[ee_mode]);
+
+       } else {
+               mdelay(1);
+               /* Disable phy and wait */
+               ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+               mdelay(1);
+       }
+
+       /*
+        * Restore saved values
+        */
+       /*DCU/Antenna selection not available on 5210*/
+       if (ah->ah_version != AR5K_AR5210) {
+               ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0));
+               ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
+       }
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
+       ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
+       ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
+
+       /*
+        * Misc
+        */
+       /* XXX: add ah->aid once mac80211 gives this to us */
+       ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+
+       ath5k_hw_set_opmode(ah);
+       /*PISR/SISR Not available on 5210*/
+       if (ah->ah_version != AR5K_AR5210) {
+               ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
+               /* If we later allow tuning for this, store into sc structure */
+               data = AR5K_TUNE_RSSI_THRES |
+                       AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S;
+               ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR);
+       }
+
+       /*
+        * Set Rx/Tx DMA Configuration
+        *(passing dma size not available on 5210)
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR,
+                               AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE);
+               AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_SDMAMW,
+                               AR5K_DMASIZE_512B);
+       }
+
+       /*
+        * Enable the PHY and wait until completion
+        */
+       ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+
+       /*
+        * 5111/5112 Specific
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+                       AR5K_PHY_RX_DELAY_M;
+               data = (channel->val & CHANNEL_CCK) ?
+                       ((data << 2) / 22) : (data / 10);
+
+               udelay(100 + data);
+       } else {
+               mdelay(1);
+       }
+
+       /*
+        * Enable calibration and wait until completion
+        */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+                               AR5K_PHY_AGCCTL_CAL);
+
+       if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+                       AR5K_PHY_AGCCTL_CAL, 0, false)) {
+               ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
+                       channel->freq);
+               return -EAGAIN;
+       }
+
+       ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
+       if (ret)
+               return ret;
+
+       ah->ah_calibration = false;
+
+       /* A and G modes can use QAM modulation which requires enabling
+        * I and Q calibration. Don't bother in B mode. */
+       if (!(driver_mode == MODE_IEEE80211B)) {
+               ah->ah_calibration = true;
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+                               AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+                               AR5K_PHY_IQ_RUN);
+       }
+
+       /*
+        * Reset queues and start beacon timers at the end of the reset routine
+        */
+       for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
+               /*No QCU on 5210*/
+               if (ah->ah_version != AR5K_AR5210)
+                       AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i);
+
+               ret = ath5k_hw_reset_tx_queue(ah, i);
+               if (ret) {
+                       ATH5K_ERR(ah->ah_sc,
+                               "failed to reset TX queue #%d\n", i);
+                       return ret;
+               }
+       }
+
+       /* Pre-enable interrupts on 5211/5212*/
+       if (ah->ah_version != AR5K_AR5210)
+               ath5k_hw_set_intr(ah, 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 ath5k_intr
+        */
+#if 0
+       if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
+               ath5k_hw_set_gpio_input(ah, 0);
+               ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
+               if (ah->ah_gpio[0] == 0)
+                       ath5k_hw_set_gpio_intr(ah, 0, 1);
+               else
+                       ath5k_hw_set_gpio_intr(ah, 0, 0);
+       }
+#endif
+
+       /*
+        * Set the 32MHz reference clock on 5212 phy clock sleep register
+        */
+       if (ah->ah_version == AR5K_AR5212) {
+               ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
+               ath5k_hw_reg_write(ah, ah->ah_radio == AR5K_RF5111 ?
+                       AR5K_PHY_SPENDING_RF5111 : AR5K_PHY_SPENDING_RF5112,
+                       AR5K_PHY_SPENDING);
+       }
+
+       /*
+        * Disable beacons and reset the register
+        */
+       AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
+                       AR5K_BEACON_RESET_TSF);
+
+       return 0;
+}
+
+/*
+ * Reset chipset
+ */
+static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
+{
+       int ret;
+       u32 mask = val ? val : ~0U;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /* Read-and-clear RX Descriptor Pointer*/
+       ath5k_hw_reg_read(ah, AR5K_RXDP);
+
+       /*
+        * Reset the device and wait until success
+        */
+       ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
+
+       /* Wait at least 128 PCI clocks */
+       udelay(15);
+
+       if (ah->ah_version == AR5K_AR5210) {
+               val &= AR5K_RESET_CTL_CHIP;
+               mask &= AR5K_RESET_CTL_CHIP;
+       } else {
+               val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+               mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+       }
+
+       ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false);
+
+       /*
+        * Reset configuration register (for hw byte-swap). Note that this
+        * is only set for big endian. We do the necessary magic in
+        * AR5K_INIT_CFG.
+        */
+       if ((val & AR5K_RESET_CTL_PCU) == 0)
+               ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
+
+       return ret;
+}
+
+/*
+ * Power management functions
+ */
+
+/*
+ * Sleep control
+ */
+int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
+               bool set_chip, u16 sleep_duration)
+{
+       unsigned int i;
+       u32 staid;
+
+       ATH5K_TRACE(ah->ah_sc);
+       staid = ath5k_hw_reg_read(ah, 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)
+                       ath5k_hw_reg_write(ah,
+                               AR5K_SLEEP_CTL_SLE | sleep_duration,
+                               AR5K_SLEEP_CTL);
+
+               staid |= AR5K_STA_ID1_PWR_SV;
+               break;
+
+       case AR5K_PM_FULL_SLEEP:
+               if (set_chip == true)
+                       ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
+                               AR5K_SLEEP_CTL);
+
+               staid |= AR5K_STA_ID1_PWR_SV;
+               break;
+
+       case AR5K_PM_AWAKE:
+               if (set_chip == false)
+                       goto commit;
+
+               ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
+                               AR5K_SLEEP_CTL);
+
+               for (i = 5000; i > 0; i--) {
+                       /* Check if the chip did wake up */
+                       if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
+                                       AR5K_PCICFG_SPWR_DN) == 0)
+                               break;
+
+                       /* Wait a bit and retry */
+                       udelay(200);
+                       ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
+                               AR5K_SLEEP_CTL);
+               }
+
+               /* Fail if the chip didn't wake up */
+               if (i <= 0)
+                       return -EIO;
+
+               staid &= ~AR5K_STA_ID1_PWR_SV;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+commit:
+       ah->ah_power_mode = mode;
+       ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
+
+       return 0;
+}
+
+/***********************\
+  DMA Related Functions
+\***********************/
+
+/*
+ * Receive functions
+ */
+
+/*
+ * Start DMA receive
+ */
+void ath5k_hw_start_rx(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
+}
+
+/*
+ * Stop DMA receive
+ */
+int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
+{
+       unsigned int i;
+
+       ATH5K_TRACE(ah->ah_sc);
+       ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
+
+       /*
+        * It may take some time to disable the DMA receive unit
+        */
+       for (i = 2000; i > 0 &&
+                       (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
+                       i--)
+               udelay(10);
+
+       return i ? 0 : -EBUSY;
+}
+
+/*
+ * Get the address of the RX Descriptor
+ */
+u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah)
+{
+       return ath5k_hw_reg_read(ah, AR5K_RXDP);
+}
+
+/*
+ * Set the address of the RX Descriptor
+ */
+void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr)
+{
+       ATH5K_TRACE(ah->ah_sc);
+
+       /*TODO:Shouldn't we check if RX is enabled first ?*/
+       ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
+}
+
+/*
+ * Transmit functions
+ */
+
+/*
+ * Start DMA transmit for a specific queue
+ * (see also QCU/DCU functions)
+ */
+int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue)
+{
+       u32 tx_queue;
+
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+       /* Return if queue is declared inactive */
+       if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+               return -EIO;
+
+       if (ah->ah_version == AR5K_AR5210) {
+               tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+               /*
+                * Set the queue by type on 5210
+                */
+               switch (ah->ah_txq[queue].tqi_type) {
+               case AR5K_TX_QUEUE_DATA:
+                       tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
+                       break;
+               case AR5K_TX_QUEUE_BEACON:
+                       tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
+                       ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
+                                       AR5K_BSR);
+                       break;
+               case AR5K_TX_QUEUE_CAB:
+                       tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
+                       ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V |
+                               AR5K_BCR_BDMAE, AR5K_BSR);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               /* Start queue */
+               ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+       } else {
+               /* Return if queue is disabled */
+               if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
+                       return -EIO;
+
+               /* Start queue */
+               AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
+       }
+
+       return 0;
+}
+
+/*
+ * Stop DMA transmit for a specific queue
+ * (see also QCU/DCU functions)
+ */
+int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+{
+       unsigned int i = 100;
+       u32 tx_queue, pending;
+
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+       /* Return if queue is declared inactive */
+       if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+               return -EIO;
+
+       if (ah->ah_version == AR5K_AR5210) {
+               tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+               /*
+                * Set by queue type
+                */
+               switch (ah->ah_txq[queue].tqi_type) {
+               case AR5K_TX_QUEUE_DATA:
+                       tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
+                       break;
+               case AR5K_TX_QUEUE_BEACON:
+               case AR5K_TX_QUEUE_CAB:
+                       /* XXX Fix me... */
+                       tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1;
+                       ath5k_hw_reg_write(ah, 0, AR5K_BSR);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               /* Stop queue */
+               ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+       } else {
+               /*
+                * Schedule TX disable and wait until queue is empty
+                */
+               AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
+
+               /*Check for pending frames*/
+               do {
+                       pending = ath5k_hw_reg_read(ah,
+                               AR5K_QUEUE_STATUS(queue)) &
+                               AR5K_QCU_STS_FRMPENDCNT;
+                       udelay(100);
+               } while (--i && pending);
+
+               /* Clear register */
+               ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
+       }
+
+       /* TODO: Check for success else return error */
+       return 0;
+}
+
+/*
+ * Get the address of the TX Descriptor for a specific queue
+ * (see also QCU/DCU functions)
+ */
+u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue)
+{
+       u16 tx_reg;
+
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+       /*
+        * Get the transmit queue descriptor pointer from the selected queue
+        */
+       /*5210 doesn't have QCU*/
+       if (ah->ah_version == AR5K_AR5210) {
+               switch (ah->ah_txq[queue].tqi_type) {
+               case AR5K_TX_QUEUE_DATA:
+                       tx_reg = AR5K_NOQCU_TXDP0;
+                       break;
+               case AR5K_TX_QUEUE_BEACON:
+               case AR5K_TX_QUEUE_CAB:
+                       tx_reg = AR5K_NOQCU_TXDP1;
+                       break;
+               default:
+                       return 0xffffffff;
+               }
+       } else {
+               tx_reg = AR5K_QUEUE_TXDP(queue);
+       }
+
+       return ath5k_hw_reg_read(ah, tx_reg);
+}
+
+/*
+ * Set the address of the TX Descriptor for a specific queue
+ * (see also QCU/DCU functions)
+ */
+int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
+{
+       u16 tx_reg;
+
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+       /*
+        * Set the transmit queue descriptor pointer register by type
+        * on 5210
+        */
+       if (ah->ah_version == AR5K_AR5210) {
+               switch (ah->ah_txq[queue].tqi_type) {
+               case AR5K_TX_QUEUE_DATA:
+                       tx_reg = AR5K_NOQCU_TXDP0;
+                       break;
+               case AR5K_TX_QUEUE_BEACON:
+               case AR5K_TX_QUEUE_CAB:
+                       tx_reg = AR5K_NOQCU_TXDP1;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               /*
+                * Set the transmit queue descriptor pointer for
+                * the selected queue on QCU for 5211+
+                * (this won't work if the queue is still active)
+                */
+               if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+                       return -EIO;
+
+               tx_reg = AR5K_QUEUE_TXDP(queue);
+       }
+
+       /* Set descriptor pointer */
+       ath5k_hw_reg_write(ah, phys_addr, tx_reg);
+
+       return 0;
+}
+
+/*
+ * Update tx trigger level
+ */
+int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
+{
+       u32 trigger_level, imr;
+       int ret = -EIO;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /*
+        * Disable interrupts by setting the mask
+        */
+       imr = ath5k_hw_set_intr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
+
+       /*TODO: Boundary check on trigger_level*/
+       trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, 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
+        */
+       if (ah->ah_version == AR5K_AR5210)
+               ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
+       else
+               AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+                               AR5K_TXCFG_TXFULL, trigger_level);
+
+       ret = 0;
+
+done:
+       /*
+        * Restore interrupt mask
+        */
+       ath5k_hw_set_intr(ah, imr);
+
+       return ret;
+}
+
+/*
+ * Interrupt handling
+ */
+
+/*
+ * Check if we have pending interrupts
+ */
+bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       return ath5k_hw_reg_read(ah, AR5K_INTPEND);
+}
+
+/*
+ * Get interrupt mask (ISR)
+ */
+int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
+{
+       u32 data;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /*
+        * Read interrupt status from the Interrupt Status register
+        * on 5210
+        */
+       if (ah->ah_version == AR5K_AR5210) {
+               data = ath5k_hw_reg_read(ah, AR5K_ISR);
+               if (unlikely(data == AR5K_INT_NOCARD)) {
+                       *interrupt_mask = data;
+                       return -ENODEV;
+               }
+       } else {
+               /*
+                * Read interrupt status from the Read-And-Clear shadow register
+                * Note: PISR/SISR Not available on 5210
+                */
+               data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
+       }
+
+       /*
+        * Get abstract interrupt mask (driver-compatible)
+        */
+       *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
+
+       if (unlikely(data == AR5K_INT_NOCARD))
+               return -ENODEV;
+
+       if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
+               *interrupt_mask |= AR5K_INT_RX;
+
+       if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
+               | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
+               *interrupt_mask |= AR5K_INT_TX;
+
+       if (ah->ah_version != AR5K_AR5210) {
+               /*HIU = Host Interface Unit (PCI etc)*/
+               if (unlikely(data & (AR5K_ISR_HIUERR)))
+                       *interrupt_mask |= AR5K_INT_FATAL;
+
+               /*Beacon Not Ready*/
+               if (unlikely(data & (AR5K_ISR_BNR)))
+                       *interrupt_mask |= AR5K_INT_BNR;
+       }
+
+       /*
+        * XXX: BMISS interrupts may occur after association.
+        * I found this on 5210 code but it needs testing. If this is
+        * true we should disable them before assoc and re-enable them
+        * after a successfull assoc + some jiffies.
+        */
+#if 0
+       interrupt_mask &= ~AR5K_INT_BMISS;
+#endif
+
+       /*
+        * In case we didn't handle anything,
+        * print the register value.
+        */
+       if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
+               ATH5K_PRINTF("0x%08x\n", data);
+
+       return 0;
+}
+
+/*
+ * Set interrupt mask
+ */
+enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
+{
+       enum ath5k_int old_mask, int_mask;
+
+       /*
+        * Disable card interrupts to prevent any race conditions
+        * (they will be re-enabled afterwards).
+        */
+       ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+
+       old_mask = ah->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 (ah->ah_version != AR5K_AR5210) {
+               if (new_mask & AR5K_INT_FATAL) {
+                       int_mask |= AR5K_IMR_HIUERR;
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT |
+                                       AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR);
+               }
+       }
+
+       ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+
+       /* Store new interrupt mask */
+       ah->ah_imr = new_mask;
+
+       /* ..re-enable interrupts */
+       ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
+
+       return old_mask;
+}
+
+
+/*************************\
+  EEPROM access functions
+\*************************/
+
+/*
+ * Read from eeprom
+ */
+static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
+{
+       u32 status, timeout;
+
+       ATH5K_TRACE(ah->ah_sc);
+       /*
+        * Initialize EEPROM access
+        */
+       if (ah->ah_version == AR5K_AR5210) {
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+               (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
+       } else {
+               ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+               AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+                               AR5K_EEPROM_CMD_READ);
+       }
+
+       for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+               status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+               if (status & AR5K_EEPROM_STAT_RDDONE) {
+                       if (status & AR5K_EEPROM_STAT_RDERR)
+                               return -EIO;
+                       *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
+                                       0xffff);
+                       return 0;
+               }
+               udelay(15);
+       }
+
+       return -ETIMEDOUT;
+}
+
+/*
+ * Write to eeprom - currently disabled, use at your own risk
+ */
+static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data)
+{
+#if 0
+       u32 status, timeout;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /*
+        * Initialize eeprom access
+        */
+
+       if (ah->ah_version == AR5K_AR5210) {
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+       } else {
+               AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+                               AR5K_EEPROM_CMD_RESET);
+       }
+
+       /*
+        * Write data to data register
+        */
+
+       if (ah->ah_version == AR5K_AR5210) {
+               ath5k_hw_reg_write(ah, data, AR5K_EEPROM_BASE + (4 * offset));
+       } else {
+               ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+               ath5k_hw_reg_write(ah, data, AR5K_EEPROM_DATA);
+               AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+                               AR5K_EEPROM_CMD_WRITE);
+       }
+
+       /*
+        * Check status
+        */
+
+       for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+               status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+               if (status & AR5K_EEPROM_STAT_WRDONE) {
+                       if (status & AR5K_EEPROM_STAT_WRERR)
+                               return EIO;
+                       return 0;
+               }
+               udelay(15);
+       }
+#endif
+       ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!");
+       return -EIO;
+}
+
+/*
+ * Translate binary channel representation in EEPROM to frequency
+ */
+static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, unsigned int mode)
+{
+       u16 val;
+
+       if (bin == AR5K_EEPROM_CHANNEL_DIS)
+               return bin;
+
+       if (mode == AR5K_EEPROM_MODE_11A) {
+               if (ah->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 (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+                       val = bin + 2300;
+               else
+                       val = bin + 2400;
+       }
+
+       return val;
+}
+
+/*
+ * Read antenna infos from eeprom
+ */
+static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
+               unsigned int mode)
+{
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+       u32 o = *offset;
+       u16 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 */
+       ah->ah_antenna[mode][0] =
+           (ee->ee_ant_control[mode][0] << 4) | 0x1;
+       ah->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);
+       ah->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
+ */
+static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
+               unsigned int mode)
+{
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+       u32 o = *offset;
+       u16 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 (ah->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 (ah->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 (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
+               ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
+
+       if (ah->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 (ah->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 (ah->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 (ah->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
+ */
+static int ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+       unsigned int mode, i;
+       int ret;
+       u32 offset;
+       u16 val;
+
+       /* 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 (ah->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) {
+               ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
+               return -EIO;
+       }
+#endif
+
+       AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+           ee_ant_gain);
+
+       if (ah->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 (ah->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_MODE_11G][0] = val & 0x7;
+               ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+       }
+
+       /*
+        * Get conformance test limit values
+        */
+       offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
+       ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
+
+       for (i = 0; i < ee->ee_ctls; i++) {
+               AR5K_EEPROM_READ(offset++, val);
+               ee->ee_ctl[i] = (val >> 8) & 0xff;
+               ee->ee_ctl[i + 1] = val & 0xff;
+       }
+
+       /*
+        * Get values for 802.11a (5GHz)
+        */
+       mode = AR5K_EEPROM_MODE_11A;
+
+       ee->ee_turbo_max_power[mode] =
+                       AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+       offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+
+       ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+       if (ret)
+               return ret;
+
+       AR5K_EEPROM_READ(offset++, val);
+       ee->ee_adc_desired_size[mode]   = (s8)((val >> 8) & 0xff);
+       ee->ee_ob[mode][3]              = (val >> 5) & 0x7;
+       ee->ee_db[mode][3]              = (val >> 2) & 0x7;
+       ee->ee_ob[mode][2]              = (val << 1) & 0x7;
+
+       AR5K_EEPROM_READ(offset++, val);
+       ee->ee_ob[mode][2]              |= (val >> 15) & 0x1;
+       ee->ee_db[mode][2]              = (val >> 12) & 0x7;
+       ee->ee_ob[mode][1]              = (val >> 9) & 0x7;
+       ee->ee_db[mode][1]              = (val >> 6) & 0x7;
+       ee->ee_ob[mode][0]              = (val >> 3) & 0x7;
+       ee->ee_db[mode][0]              = val & 0x7;
+
+       ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+       if (ret)
+               return ret;
+
+       if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
+               AR5K_EEPROM_READ(offset++, val);
+               ee->ee_margin_tx_rx[mode] = val & 0x3f;
+       }
+
+       /*
+        * Get values for 802.11b (2.4GHz)
+        */
+       mode = AR5K_EEPROM_MODE_11B;
+       offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+
+       ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+       if (ret)
+               return ret;
+
+       AR5K_EEPROM_READ(offset++, val);
+       ee->ee_adc_desired_size[mode]   = (s8)((val >> 8) & 0xff);
+       ee->ee_ob[mode][1]              = (val >> 4) & 0x7;
+       ee->ee_db[mode][1]              = val & 0x7;
+
+       ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+       if (ret)
+               return ret;
+
+       if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+               AR5K_EEPROM_READ(offset++, val);
+               ee->ee_cal_pier[mode][0] =
+                       ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+               ee->ee_cal_pier[mode][1] =
+                       ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+
+               AR5K_EEPROM_READ(offset++, val);
+               ee->ee_cal_pier[mode][2] =
+                       ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+       }
+
+       if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+               ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+       /*
+        * Get values for 802.11g (2.4GHz)
+        */
+       mode = AR5K_EEPROM_MODE_11G;
+       offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+       ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+       if (ret)
+               return ret;
+
+       AR5K_EEPROM_READ(offset++, val);
+       ee->ee_adc_desired_size[mode]   = (s8)((val >> 8) & 0xff);
+       ee->ee_ob[mode][1]              = (val >> 4) & 0x7;
+       ee->ee_db[mode][1]              = val & 0x7;
+
+       ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+       if (ret)
+               return ret;
+
+       if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+               AR5K_EEPROM_READ(offset++, val);
+               ee->ee_cal_pier[mode][0] =
+                       ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+               ee->ee_cal_pier[mode][1] =
+                       ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+
+               AR5K_EEPROM_READ(offset++, val);
+               ee->ee_turbo_max_power[mode] = val & 0x7f;
+               ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+               AR5K_EEPROM_READ(offset++, val);
+               ee->ee_cal_pier[mode][2] =
+                       ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+
+               if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+                       ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+               AR5K_EEPROM_READ(offset++, val);
+               ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+               ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+               if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+                       AR5K_EEPROM_READ(offset++, val);
+                       ee->ee_cck_ofdm_gain_delta = val & 0xff;
+               }
+       }
+
+       /*
+        * Read 5GHz EEPROM channels
+        */
+
+       return 0;
+}
+
+/*
+ * Read the MAC address from eeprom
+ */
+static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+       u8 mac_d[ETH_ALEN];
+       u32 total, offset;
+       u16 data;
+       int octet, ret;
+
+       memset(mac, 0, ETH_ALEN);
+       memset(mac_d, 0, ETH_ALEN);
+
+       ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
+       if (ret)
+               return ret;
+
+       for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+               ret = ath5k_hw_eeprom_read(ah, offset, &data);
+               if (ret)
+                       return ret;
+
+               total += data;
+               mac_d[octet + 1] = data & 0xff;
+               mac_d[octet] = data >> 8;
+               octet += 2;
+       }
+
+       memcpy(mac, mac_d, ETH_ALEN);
+
+       if (!total || total == 3 * 0xffff)
+               return -EINVAL;
+
+       return 0;
+}
+
+/*
+ * Read/Write regulatory domain
+ */
+static bool ath5k_eeprom_regulation_domain(struct ath5k_hw *ah, bool write,
+       enum ath5k_regdom *regdomain)
+{
+       u16 ee_regdomain;
+
+       /* Read current value */
+       if (write != true) {
+               ee_regdomain = ah->ah_capabilities.cap_eeprom.ee_regdomain;
+               *regdomain = ath5k_regdom_to_ieee(ee_regdomain);
+               return true;
+       }
+
+       ee_regdomain = ath5k_regdom_from_ieee(*regdomain);
+
+       /* Try to write a new value */
+       if (ah->ah_capabilities.cap_eeprom.ee_protect &
+                       AR5K_EEPROM_PROTECT_WR_128_191)
+               return false;
+       if (ath5k_hw_eeprom_write(ah, AR5K_EEPROM_REG_DOMAIN, ee_regdomain)!=0)
+               return false;
+
+       ah->ah_capabilities.cap_eeprom.ee_regdomain = ee_regdomain;
+
+       return true;
+}
+
+/*
+ * Use the above to write a new regulatory domain
+ */
+int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain)
+{
+       enum ath5k_regdom ieee_regdomain;
+
+       ieee_regdomain = ath5k_regdom_to_ieee(regdomain);
+
+       if (ath5k_eeprom_regulation_domain(ah, true, &ieee_regdomain) == true)
+               return 0;
+
+       return -EIO;
+}
+
+/*
+ * Fill the capabilities struct
+ */
+static int ath5k_hw_get_capabilities(struct ath5k_hw *ah)
+{
+       u16 ee_header;
+
+       ATH5K_TRACE(ah->ah_sc);
+       /* Capabilities stored in the EEPROM */
+       ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
+
+       if (ah->ah_version == AR5K_AR5210) {
+               /*
+                * Set radio capabilities
+                * (The AR5110 only supports the middle 5GHz band)
+                */
+               ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
+               ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
+               ah->ah_capabilities.cap_range.range_2ghz_min = 0;
+               ah->ah_capabilities.cap_range.range_2ghz_max = 0;
+
+               /* Set supported modes */
+               __set_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode);
+               __set_bit(MODE_ATHEROS_TURBO, ah->ah_capabilities.cap_mode);
+       } else {
+               /*
+                * XXX The tranceiver supports frequencies from 4920 to 6100GHz
+                * XXX and from 2312 to 2732GHz. There are problems with the
+                * XXX current ieee80211 implementation because the IEEE
+                * XXX channel mapping does not support negative channel
+                * XXX numbers (2312MHz is channel -19). Of course, this
+                * XXX doesn't matter because these channels are out of range
+                * XXX but some regulation domains like MKK (Japan) will
+                * XXX support frequencies somewhere around 4.8GHz.
+                */
+
+               /*
+                * Set radio capabilities
+                */
+
+               if (AR5K_EEPROM_HDR_11A(ee_header)) {
+                       ah->ah_capabilities.cap_range.range_5ghz_min = 5005; /* 4920 */
+                       ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
+
+                       /* Set supported modes */
+                       __set_bit(MODE_IEEE80211A,
+                                       ah->ah_capabilities.cap_mode);
+                       __set_bit(MODE_ATHEROS_TURBO,
+                                       ah->ah_capabilities.cap_mode);
+                       if (ah->ah_version == AR5K_AR5212)
+                               __set_bit(MODE_ATHEROS_TURBOG,
+                                               ah->ah_capabilities.cap_mode);
+               }
+
+               /* Enable  802.11b if a 2GHz capable radio (2111/5112) is
+                * connected */
+               if (AR5K_EEPROM_HDR_11B(ee_header) ||
+                               AR5K_EEPROM_HDR_11G(ee_header)) {
+                       ah->ah_capabilities.cap_range.range_2ghz_min = 2412; /* 2312 */
+                       ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
+
+                       if (AR5K_EEPROM_HDR_11B(ee_header))
+                               __set_bit(MODE_IEEE80211B,
+                                               ah->ah_capabilities.cap_mode);
+
+                       if (AR5K_EEPROM_HDR_11G(ee_header))
+                               __set_bit(MODE_IEEE80211G,
+                                               ah->ah_capabilities.cap_mode);
+               }
+       }
+
+       /* GPIO */
+       ah->ah_gpio_npins = AR5K_NUM_GPIO;
+
+       /* Set number of supported TX queues */
+       if (ah->ah_version == AR5K_AR5210)
+               ah->ah_capabilities.cap_queues.q_tx_num =
+                       AR5K_NUM_TX_QUEUES_NOQCU;
+       else
+               ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
+
+       return 0;
+}
+
+/*********************************\
+  Protocol Control Unit Functions
+\*********************************/
+
+/*
+ * Set Operation mode
+ */
+int ath5k_hw_set_opmode(struct ath5k_hw *ah)
+{
+       u32 pcu_reg, beacon_reg, low_id, high_id;
+
+       pcu_reg = 0;
+       beacon_reg = 0;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       switch (ah->ah_op_mode) {
+       case IEEE80211_IF_TYPE_IBSS:
+               pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
+                       (ah->ah_version == AR5K_AR5210 ?
+                               AR5K_STA_ID1_NO_PSPOLL : 0);
+               beacon_reg |= AR5K_BCR_ADHOC;
+               break;
+
+       case IEEE80211_IF_TYPE_AP:
+               pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
+                       (ah->ah_version == AR5K_AR5210 ?
+                               AR5K_STA_ID1_NO_PSPOLL : 0);
+               beacon_reg |= AR5K_BCR_AP;
+               break;
+
+       case IEEE80211_IF_TYPE_STA:
+               pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
+                       (ah->ah_version == AR5K_AR5210 ?
+                               AR5K_STA_ID1_PWR_SV : 0);
+       case IEEE80211_IF_TYPE_MNTR:
+               pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
+                       (ah->ah_version == AR5K_AR5210 ?
+                               AR5K_STA_ID1_NO_PSPOLL : 0);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * Set PCU registers
+        */
+       low_id = AR5K_LOW_ID(ah->ah_sta_id);
+       high_id = AR5K_HIGH_ID(ah->ah_sta_id);
+       ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+       ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+       /*
+        * Set Beacon Control Register on 5210
+        */
+       if (ah->ah_version == AR5K_AR5210)
+               ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+
+       return 0;
+}
+
+/*
+ * BSSID Functions
+ */
+
+/*
+ * Get station id
+ */
+void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       memcpy(mac, ah->ah_sta_id, ETH_ALEN);
+}
+
+/*
+ * Set station id
+ */
+int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
+{
+       u32 low_id, high_id;
+
+       ATH5K_TRACE(ah->ah_sc);
+       /* Set new station ID */
+       memcpy(ah->ah_sta_id, mac, ETH_ALEN);
+
+       low_id = AR5K_LOW_ID(mac);
+       high_id = AR5K_HIGH_ID(mac);
+
+       ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+       ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1);
+
+       return 0;
+}
+
+/*
+ * Set BSSID
+ */
+void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
+{
+       u32 low_id, high_id;
+       u16 tim_offset = 0;
+
+       /*
+        * Set simple BSSID mask on 5212
+        */
+       if (ah->ah_version == AR5K_AR5212) {
+               ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM0);
+               ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM1);
+       }
+
+       /*
+        * Set BSSID which triggers the "SME Join" operation
+        */
+       low_id = AR5K_LOW_ID(bssid);
+       high_id = AR5K_HIGH_ID(bssid);
+       ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
+       ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
+                               AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
+
+       if (assoc_id == 0) {
+               ath5k_hw_disable_pspoll(ah);
+               return;
+       }
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
+                       tim_offset ? tim_offset + 4 : 0);
+
+       ath5k_hw_enable_pspoll(ah, NULL, 0);
+}
+/**
+ * ath5k_hw_set_bssid_mask - set common bits we should listen to
+ *
+ * The bssid_mask is a utility used by AR5212 hardware to inform the hardware
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode every bit matters. In AP
+ * mode with a single BSS every bit matters as well. In AP mode with
+ * multiple BSSes not every bit matters.
+ *
+ * @ah: the &struct ath5k_hw
+ * @mask: the bssid_mask, a u8 array of size ETH_ALEN
+ *
+ * Note that this is a simple filter and *does* not filter out all
+ * relevant frames. Some non-relevant frames will get through, probability
+ * jocks are welcomed to compute.
+ *
+ * When handling multiple BSSes (or VAPs) you can get the BSSID mask by
+ * computing the set of:
+ *
+ *     ~ ( MAC XOR BSSID )
+ *
+ * When you do this you are essentially computing the common bits. Later it
+ * is assumed the harware will "and" (&) the BSSID mask with the MAC address
+ * to obtain the relevant bits which should match on the destination frame.
+ *
+ * Simple example: on your card you have have two BSSes you have created with
+ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
+ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
+ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
+ *
+ *                  \
+ * MAC:                0001 |
+ * BSSID-01:   0100 | --> Belongs to us
+ * BSSID-02:   1001 |
+ *                  /
+ * -------------------
+ * BSSID-03:   0110  | --> External
+ * -------------------
+ *
+ * Our bssid_mask would then be:
+ *
+ *             On loop iteration for BSSID-01:
+ *             ~(0001 ^ 0100)  -> ~(0101)
+ *                             ->   1010
+ *             bssid_mask      =    1010
+ *
+ *             On loop iteration for BSSID-02:
+ *             bssid_mask &= ~(0001   ^   1001)
+ *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
+ *             bssid_mask =   (1010)  & ~(1001)
+ *             bssid_mask =   (1010)  &  (0110)
+ *             bssid_mask =   0010
+ *
+ * A bssid_mask of 0010 means "only pay attention to the second least
+ * significant bit". This is because its the only bit common
+ * amongst the MAC and all BSSIDs we support. To findout what the real
+ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
+ * or our MAC address (we assume the hardware uses the MAC address).
+ *
+ * Now, suppose there's an incoming frame for BSSID-03:
+ *
+ * IFRAME-01:  0110
+ *
+ * An easy eye-inspeciton of this already should tell you that this frame
+ * will not pass our check. This is beacuse the bssid_mask tells the
+ * hardware to only look at the second least significant bit and the
+ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
+ * as 1, which does not match 0.
+ *
+ * So with IFRAME-01 we *assume* the hardware will do:
+ *
+ *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
+ *  --> allow = (0010) == 0000 ? 1 : 0;
+ *  --> allow = 0
+ *
+ *  Lets now test a frame that should work:
+ *
+ * IFRAME-02:  0001 (we should allow)
+ *
+ *     allow = (0001 & 1010) == 1010
+ *
+ *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
+ *  --> allow = (0010) == (0010)
+ *  --> allow = 1
+ *
+ * Other examples:
+ *
+ * IFRAME-03:  0100 --> allowed
+ * IFRAME-04:  1001 --> allowed
+ * IFRAME-05:  1101 --> allowed but its not for us!!!
+ *
+ */
+int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
+{
+       u32 low_id, high_id;
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (ah->ah_version == AR5K_AR5212) {
+               low_id = AR5K_LOW_ID(mask);
+               high_id = AR5K_HIGH_ID(mask);
+
+               ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
+               ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
+
+               return 0;
+       }
+
+       return -EIO;
+}
+
+/*
+ * Receive start/stop functions
+ */
+
+/*
+ * Start receive on PCU
+ */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/*
+ * Stop receive on PCU
+ */
+void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/*
+ * RX Filter functions
+ */
+
+/*
+ * Set multicast filter
+ */
+void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       /* Set the multicat filter */
+       ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
+       ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
+}
+
+/*
+ * Set multicast filter by index
+ */
+int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index)
+{
+
+       ATH5K_TRACE(ah->ah_sc);
+       if (index >= 64)
+               return -EINVAL;
+       else if (index >= 32)
+               AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1,
+                               (1 << (index - 32)));
+       else
+               AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
+
+       return 0;
+}
+
+/*
+ * Clear Multicast filter by index
+ */
+int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
+{
+
+       ATH5K_TRACE(ah->ah_sc);
+       if (index >= 64)
+               return -EINVAL;
+       else if (index >= 32)
+               AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1,
+                               (1 << (index - 32)));
+       else
+               AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
+
+       return 0;
+}
+
+/*
+ * Get current rx filter
+ */
+u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
+{
+       u32 data, filter = 0;
+
+       ATH5K_TRACE(ah->ah_sc);
+       filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
+
+       /*Radar detection for 5212*/
+       if (ah->ah_version == AR5K_AR5212) {
+               data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
+
+               if (data & AR5K_PHY_ERR_FIL_RADAR)
+                       filter |= AR5K_RX_FILTER_RADARERR;
+               if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
+                       filter |= AR5K_RX_FILTER_PHYERR;
+       }
+
+       return filter;
+}
+
+/*
+ * Set rx filter
+ */
+void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
+{
+       u32 data = 0;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /* Set PHY error filter register on 5212*/
+       if (ah->ah_version == AR5K_AR5212) {
+               if (filter & AR5K_RX_FILTER_RADARERR)
+                       data |= AR5K_PHY_ERR_FIL_RADAR;
+               if (filter & AR5K_RX_FILTER_PHYERR)
+                       data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
+       }
+
+       /*
+        * The AR5210 uses promiscous mode to detect radar activity
+        */
+       if (ah->ah_version == AR5K_AR5210 &&
+                       (filter & AR5K_RX_FILTER_RADARERR)) {
+               filter &= ~AR5K_RX_FILTER_RADARERR;
+               filter |= AR5K_RX_FILTER_PROM;
+       }
+
+       /*Zero length DMA*/
+       if (data)
+               AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+       else
+               AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+
+       /*Write RX Filter register*/
+       ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
+
+       /*Write PHY error filter register on 5212*/
+       if (ah->ah_version == AR5K_AR5212)
+               ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
+
+}
+
+/*
+ * Beacon related functions
+ */
+
+/*
+ * Get a 32bit TSF
+ */
+u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       return ath5k_hw_reg_read(ah, AR5K_TSF_L32);
+}
+
+/*
+ * Get the full 64bit TSF
+ */
+u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
+{
+       u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+       ATH5K_TRACE(ah->ah_sc);
+
+       return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
+}
+
+/*
+ * Force a TSF reset
+ */
+void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF);
+}
+
+/*
+ * Initialize beacon timers
+ */
+void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
+{
+       u32 timer1, timer2, timer3;
+
+       ATH5K_TRACE(ah->ah_sc);
+       /*
+        * Set the additional timers by mode
+        */
+       switch (ah->ah_op_mode) {
+       case IEEE80211_IF_TYPE_STA:
+               if (ah->ah_version == AR5K_AR5210) {
+                       timer1 = 0xffffffff;
+                       timer2 = 0xffffffff;
+               } else {
+                       timer1 = 0x0000ffff;
+                       timer2 = 0x0007ffff;
+               }
+               break;
+
+       default:
+               timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) <<
+                   0x00000003;
+               timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) <<
+                   0x00000003;
+       }
+
+       timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
+
+       /*
+        * Set the beacon register and enable all timers.
+        * (next beacon, DMA beacon, software beacon, ATIM window time)
+        */
+       ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
+       ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
+       ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
+       ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
+
+       ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
+                       AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
+               AR5K_BEACON);
+}
+
+#if 0
+/*
+ * Set beacon timers
+ */
+int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah,
+               const struct ath5k_beacon_state *state)
+{
+       u32 cfp_period, next_cfp, dtim, interval, next_beacon;
+
+       /*
+        * TODO: should be changed through *state
+        * review struct ath5k_beacon_state struct
+        *
+        * XXX: These are used for cfp period bellow, are they
+        * ok ? Is it O.K. for tsf here to be 0 or should we use
+        * get_tsf ?
+        */
+       u32 dtim_count = 0; /* XXX */
+       u32 cfp_count = 0; /* XXX */
+       u32 tsf = 0; /* XXX */
+
+       ATH5K_TRACE(ah->ah_sc);
+       /* Return on an invalid beacon state */
+       if (state->bs_interval < 1)
+               return -EINVAL;
+
+       interval = state->bs_interval;
+       dtim = state->bs_dtim_period;
+
+       /*
+        * PCF support?
+        */
+       if (state->bs_cfp_period > 0) {
+               /*
+                * Enable PCF mode and set the CFP
+                * (Contention Free Period) and timer registers
+                */
+               cfp_period = state->bs_cfp_period * state->bs_dtim_period *
+                       state->bs_interval;
+               next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) *
+                       state->bs_interval;
+
+               AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
+                               AR5K_STA_ID1_DEFAULT_ANTENNA |
+                               AR5K_STA_ID1_PCF);
+               ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD);
+               ath5k_hw_reg_write(ah, state->bs_cfp_max_duration,
+                               AR5K_CFP_DUR);
+               ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period :
+                                               next_cfp)) << 3, AR5K_TIMER2);
+       } else {
+               /* Disable PCF mode */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+                               AR5K_STA_ID1_DEFAULT_ANTENNA |
+                               AR5K_STA_ID1_PCF);
+       }
+
+       /*
+        * Enable the beacon timer register
+        */
+       ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0);
+
+       /*
+        * Start the beacon timers
+        */
+       ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &~
+               (AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) |
+               AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0,
+               AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval,
+               AR5K_BEACON_PERIOD), AR5K_BEACON);
+
+       /*
+        * Write new beacon miss threshold, if it appears to be valid
+        * XXX: Figure out right values for min <= bs_bmiss_threshold <= max
+        * and return if its not in range. We can test this by reading value and
+        * setting value to a largest value and seeing which values register.
+        */
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS,
+                       state->bs_bmiss_threshold);
+
+       /*
+        * Set sleep control register
+        * XXX: Didn't find this in 5210 code but since this register
+        * exists also in ar5k's 5210 headers i leave it as common code.
+        */
+       AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR,
+                       (state->bs_sleep_duration - 3) << 3);
+
+       /*
+        * Set enhanced sleep registers on 5212
+        */
+       if (ah->ah_version == AR5K_AR5212) {
+               if (state->bs_sleep_duration > state->bs_interval &&
+                               roundup(state->bs_sleep_duration, interval) ==
+                               state->bs_sleep_duration)
+                       interval = state->bs_sleep_duration;
+
+               if (state->bs_sleep_duration > dtim && (dtim == 0 ||
+                               roundup(state->bs_sleep_duration, dtim) ==
+                               state->bs_sleep_duration))
+                       dtim = state->bs_sleep_duration;
+
+               if (interval > dtim)
+                       return -EINVAL;
+
+               next_beacon = interval == dtim ? state->bs_next_dtim :
+                       state->bs_next_beacon;
+
+               ath5k_hw_reg_write(ah,
+                       AR5K_REG_SM((state->bs_next_dtim - 3) << 3,
+                       AR5K_SLEEP0_NEXT_DTIM) |
+                       AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) |
+                       AR5K_SLEEP0_ENH_SLEEP_EN |
+                       AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0);
+
+               ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3,
+                       AR5K_SLEEP1_NEXT_TIM) |
+                       AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1);
+
+               ath5k_hw_reg_write(ah,
+                       AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) |
+                       AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2);
+       }
+
+       return 0;
+}
+
+/*
+ * Reset beacon timers
+ */
+void ath5k_hw_reset_beacon(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       /*
+        * Disable beacon timer
+        */
+       ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
+
+       /*
+        * Disable some beacon register values
+        */
+       AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+                       AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF);
+       ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON);
+}
+
+/*
+ * Wait for beacon queue to finish
+ */
+int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
+{
+       unsigned int i;
+       int ret;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /* 5210 doesn't have QCU*/
+       if (ah->ah_version == AR5K_AR5210) {
+               /*
+                * Wait for beaconn queue to finish by checking
+                * Control Register and Beacon Status Register.
+                */
+               for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) {
+                       if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F)
+                                       ||
+                           !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F))
+                               break;
+                       udelay(10);
+               }
+
+               /* Timeout... */
+               if (i <= 0) {
+                       /*
+                        * Re-schedule the beacon queue
+                        */
+                       ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1);
+                       ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
+                                       AR5K_BCR);
+
+                       return -EIO;
+               }
+               ret = 0;
+       } else {
+       /*5211/5212*/
+               ret = ath5k_hw_register_timeout(ah,
+                       AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON),
+                       AR5K_QCU_STS_FRMPENDCNT, 0, false);
+
+               if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON))
+                       return -EIO;
+       }
+
+       return ret;
+}
+#endif
+
+/*
+ * Update mib counters (statistics)
+ */
+void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
+               struct ath5k_mib_stats *statistics)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       /* Read-And-Clear */
+       statistics->ackrcv_bad += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
+       statistics->rts_bad += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
+       statistics->rts_good += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
+       statistics->fcs_bad += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
+       statistics->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
+
+       /* Reset profile count registers on 5212*/
+       if (ah->ah_version == AR5K_AR5212) {
+               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
+               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
+               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
+               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
+       }
+}
+
+/** ath5k_hw_set_ack_bitrate - set bitrate for ACKs
+ *
+ * @ah: the &struct ath5k_hw
+ * @high: determines if to use low bit rate or now
+ */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
+{
+       if (ah->ah_version != AR5K_AR5212)
+               return;
+       else {
+               u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
+               if (high)
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+               else
+                       AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+       }
+}
+
+
+/*
+ * ACK/CTS Timeouts
+ */
+
+/*
+ * Set ACK timeout on PCU
+ */
+int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
+                       ah->ah_turbo) <= timeout)
+               return -EINVAL;
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
+               ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+       return 0;
+}
+
+/*
+ * Read the ACK timeout from PCU
+ */
+unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+
+       return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+                       AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
+}
+
+/*
+ * Set CTS timeout on PCU
+ */
+int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
+                       ah->ah_turbo) <= timeout)
+               return -EINVAL;
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
+                       ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+       return 0;
+}
+
+/*
+ * Read CTS timeout from PCU
+ */
+unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+                       AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
+}
+
+/*
+ * Key table (WEP) functions
+ */
+
+int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
+{
+       unsigned int i;
+
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+       for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
+               ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
+
+       /* Set NULL encryption on non-5210*/
+       if (ah->ah_version != AR5K_AR5210)
+               ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+                               AR5K_KEYTABLE_TYPE(entry));
+
+       return 0;
+}
+
+int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+       /* Check the validation flag at the end of the entry */
+       return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) &
+               AR5K_KEYTABLE_VALID;
+}
+
+int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
+               const struct ieee80211_key_conf *key, const u8 *mac)
+{
+       unsigned int i;
+       __le32 key_v[5] = {};
+       u32 keytype;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /* key->keylen comes in from mac80211 in bytes */
+
+       if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
+               return -EOPNOTSUPP;
+
+       switch (key->keylen) {
+       /* WEP 40-bit   = 40-bit  entered key + 24 bit IV = 64-bit */
+       case 40 / 8:
+               memcpy(&key_v[0], key->key, 5);
+               keytype = AR5K_KEYTABLE_TYPE_40;
+               break;
+
+       /* WEP 104-bit  = 104-bit entered key + 24-bit IV = 128-bit */
+       case 104 / 8:
+               memcpy(&key_v[0], &key->key[0], 6);
+               memcpy(&key_v[2], &key->key[6], 6);
+               memcpy(&key_v[4], &key->key[12], 1);
+               keytype = AR5K_KEYTABLE_TYPE_104;
+               break;
+       /* WEP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
+       case 128 / 8:
+               memcpy(&key_v[0], &key->key[0], 6);
+               memcpy(&key_v[2], &key->key[6], 6);
+               memcpy(&key_v[4], &key->key[12], 4);
+               keytype = AR5K_KEYTABLE_TYPE_128;
+               break;
+
+       default:
+               return -EINVAL; /* shouldn't happen */
+       }
+
+       for (i = 0; i < ARRAY_SIZE(key_v); i++)
+               ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
+                               AR5K_KEYTABLE_OFF(entry, i));
+
+       ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
+
+       return ath5k_hw_set_key_lladdr(ah, entry, mac);
+}
+
+int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
+{
+       u32 low_id, high_id;
+
+       ATH5K_TRACE(ah->ah_sc);
+        /* Invalid entry (key table overflow) */
+       AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+       /* MAC may be NULL if it's a broadcast key. In this case no need to
+        * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */
+       if (unlikely(mac == NULL)) {
+               low_id = 0xffffffff;
+               high_id = 0xffff | AR5K_KEYTABLE_VALID;
+       } else {
+               low_id = AR5K_LOW_ID(mac);
+               high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID;
+       }
+
+       ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
+       ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
+
+       return 0;
+}
+
+
+/********************************************\
+Queue Control Unit, DFS Control Unit Functions
+\********************************************/
+
+/*
+ * Initialize a transmit queue
+ */
+int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
+               struct ath5k_txq_info *queue_info)
+{
+       unsigned int queue;
+       int ret;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /*
+        * Get queue by type
+        */
+       /*5210 only has 2 queues*/
+       if (ah->ah_version == AR5K_AR5210) {
+               switch (queue_type) {
+               case AR5K_TX_QUEUE_DATA:
+                       queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
+                       break;
+               case AR5K_TX_QUEUE_BEACON:
+               case AR5K_TX_QUEUE_CAB:
+                       queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               switch (queue_type) {
+               case AR5K_TX_QUEUE_DATA:
+                       for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
+                               ah->ah_txq[queue].tqi_type !=
+                               AR5K_TX_QUEUE_INACTIVE; queue++) {
+
+                               if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
+                                       return -EINVAL;
+                       }
+                       break;
+               case AR5K_TX_QUEUE_UAPSD:
+                       queue = AR5K_TX_QUEUE_ID_UAPSD;
+                       break;
+               case AR5K_TX_QUEUE_BEACON:
+                       queue = AR5K_TX_QUEUE_ID_BEACON;
+                       break;
+               case AR5K_TX_QUEUE_CAB:
+                       queue = AR5K_TX_QUEUE_ID_CAB;
+                       break;
+               case AR5K_TX_QUEUE_XR_DATA:
+                       if (ah->ah_version != AR5K_AR5212)
+                               ATH5K_ERR(ah->ah_sc,
+                                       "XR data queues only supported in"
+                                       " 5212!\n");
+                       queue = AR5K_TX_QUEUE_ID_XR_DATA;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       /*
+        * Setup internal queue structure
+        */
+       memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
+       ah->ah_txq[queue].tqi_type = queue_type;
+
+       if (queue_info != NULL) {
+               queue_info->tqi_type = queue_type;
+               ret = ath5k_hw_setup_tx_queueprops(ah, queue, queue_info);
+               if (ret)
+                       return ret;
+       }
+       /*
+        * We use ah_txq_status to hold a temp value for
+        * the Secondary interrupt mask registers on 5211+
+        * check out ath5k_hw_reset_tx_queue
+        */
+       AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
+
+       return queue;
+}
+
+/*
+ * Setup a transmit queue
+ */
+int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue,
+                               const struct ath5k_txq_info *queue_info)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+       if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+               return -EIO;
+
+       memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
+
+       /*XXX: Is this supported on 5210 ?*/
+       if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
+                       ((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
+                       (queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
+                       queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
+               ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
+
+       return 0;
+}
+
+/*
+ * Get properties for a specific transmit queue
+ */
+int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
+               struct ath5k_txq_info *queue_info)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
+       return 0;
+}
+
+/*
+ * Set a transmit queue inactive
+ */
+void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
+               return;
+
+       /* This queue will be skipped in further operations */
+       ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
+       /*For SIMR setup*/
+       AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
+}
+
+/*
+ * Set DFS params for a transmit queue
+ */
+int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+       u32 cw_min, cw_max, retry_lg, retry_sh;
+       struct ath5k_txq_info *tq = &ah->ah_txq[queue];
+
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+       tq = &ah->ah_txq[queue];
+
+       if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
+               return 0;
+
+       if (ah->ah_version == AR5K_AR5210) {
+               /* Only handle data queues, others will be ignored */
+               if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
+                       return 0;
+
+               /* Set Slot time */
+               ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+                       AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
+                       AR5K_SLOT_TIME);
+               /* Set ACK_CTS timeout */
+               ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+                       AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
+                       AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
+               /* Set Transmit Latency */
+               ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+                       AR5K_INIT_TRANSMIT_LATENCY_TURBO :
+                       AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
+               /* Set IFS0 */
+               if (ah->ah_turbo == true)
+                        ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
+                               (ah->ah_aifs + tq->tqi_aifs) *
+                               AR5K_INIT_SLOT_TIME_TURBO) <<
+                               AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
+                               AR5K_IFS0);
+               else
+                       ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
+                               (ah->ah_aifs + tq->tqi_aifs) *
+                               AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
+                               AR5K_INIT_SIFS, AR5K_IFS0);
+
+               /* Set IFS1 */
+               ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+                       AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
+                       AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
+               /* Set PHY register 0x9844 (??) */
+               ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+                       (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 :
+                       (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C,
+                       AR5K_PHY(17));
+               /* Set Frame Control Register */
+               ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+                       (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
+                       AR5K_PHY_TURBO_SHORT | 0x2020) :
+                       (AR5K_PHY_FRAME_CTL_INI | 0x1020),
+                       AR5K_PHY_FRAME_CTL_5210);
+       }
+
+       /*
+        * Calculate cwmin/max by channel mode
+        */
+       cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
+       cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
+       ah->ah_aifs = AR5K_TUNE_AIFS;
+       /*XR is only supported on 5212*/
+       if (IS_CHAN_XR(ah->ah_current_channel) &&
+                       ah->ah_version == AR5K_AR5212) {
+               cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
+               cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
+               ah->ah_aifs = AR5K_TUNE_AIFS_XR;
+       /*B mode is not supported on 5210*/
+       } else if (IS_CHAN_B(ah->ah_current_channel) &&
+                       ah->ah_version != AR5K_AR5210) {
+               cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
+               cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
+               ah->ah_aifs = AR5K_TUNE_AIFS_11B;
+       }
+
+       cw_min = 1;
+       while (cw_min < ah->ah_cw_min)
+               cw_min = (cw_min << 1) | 1;
+
+       cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
+               ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
+       cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
+               ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
+
+       /*
+        * Calculate and set retry limits
+        */
+       if (ah->ah_software_retry == true) {
+               /* XXX Need to test this */
+               retry_lg = ah->ah_limit_tx_retries;
+               retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
+                       AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
+       } else {
+               retry_lg = AR5K_INIT_LG_RETRY;
+               retry_sh = AR5K_INIT_SH_RETRY;
+       }
+
+       /*No QCU/DCU [5210]*/
+       if (ah->ah_version == AR5K_AR5210) {
+               ath5k_hw_reg_write(ah,
+                       (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
+                       | AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+                               AR5K_NODCU_RETRY_LMT_SLG_RETRY)
+                       | AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+                               AR5K_NODCU_RETRY_LMT_SSH_RETRY)
+                       | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
+                       | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
+                       AR5K_NODCU_RETRY_LMT);
+       } else {
+               /*QCU/DCU [5211+]*/
+               ath5k_hw_reg_write(ah,
+                       AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+                               AR5K_DCU_RETRY_LMT_SLG_RETRY) |
+                       AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+                               AR5K_DCU_RETRY_LMT_SSH_RETRY) |
+                       AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
+                       AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
+                       AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
+
+       /*===Rest is also for QCU/DCU only [5211+]===*/
+
+               /*
+                * Set initial content window (cw_min/cw_max)
+                * and arbitrated interframe space (aifs)...
+                */
+               ath5k_hw_reg_write(ah,
+                       AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
+                       AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
+                       AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
+                               AR5K_DCU_LCL_IFS_AIFS),
+                       AR5K_QUEUE_DFS_LOCAL_IFS(queue));
+
+               /*
+                * Set misc registers
+                */
+               ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
+                       AR5K_QUEUE_MISC(queue));
+
+               if (tq->tqi_cbr_period) {
+                       ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
+                               AR5K_QCU_CBRCFG_INTVAL) |
+                               AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
+                               AR5K_QCU_CBRCFG_ORN_THRES),
+                               AR5K_QUEUE_CBRCFG(queue));
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                               AR5K_QCU_MISC_FRSHED_CBR);
+                       if (tq->tqi_cbr_overflow_limit)
+                               AR5K_REG_ENABLE_BITS(ah,
+                                       AR5K_QUEUE_MISC(queue),
+                                       AR5K_QCU_MISC_CBR_THRES_ENABLE);
+               }
+
+               if (tq->tqi_ready_time)
+                       ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
+                               AR5K_QCU_RDYTIMECFG_INTVAL) |
+                               AR5K_QCU_RDYTIMECFG_ENABLE,
+                               AR5K_QUEUE_RDYTIMECFG(queue));
+
+               if (tq->tqi_burst_time) {
+                       ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
+                               AR5K_DCU_CHAN_TIME_DUR) |
+                               AR5K_DCU_CHAN_TIME_ENABLE,
+                               AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
+
+                       if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
+                               AR5K_REG_ENABLE_BITS(ah,
+                                       AR5K_QUEUE_MISC(queue),
+                                       AR5K_QCU_MISC_TXE);
+               }
+
+               if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
+                       ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
+                               AR5K_QUEUE_DFS_MISC(queue));
+
+               if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+                       ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
+                               AR5K_QUEUE_DFS_MISC(queue));
+
+               /*
+                * Set registers by queue type
+                */
+               switch (tq->tqi_type) {
+               case AR5K_TX_QUEUE_BEACON:
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                               AR5K_QCU_MISC_FRSHED_DBA_GT |
+                               AR5K_QCU_MISC_CBREXP_BCN |
+                               AR5K_QCU_MISC_BCN_ENABLE);
+
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+                               (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
+                               AR5K_DCU_MISC_ARBLOCK_CTL_S) |
+                               AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
+                               AR5K_DCU_MISC_BCN_ENABLE);
+
+                       ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
+                               (AR5K_TUNE_SW_BEACON_RESP -
+                               AR5K_TUNE_DMA_BEACON_RESP) -
+                               AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
+                               AR5K_QCU_RDYTIMECFG_ENABLE,
+                               AR5K_QUEUE_RDYTIMECFG(queue));
+                       break;
+
+               case AR5K_TX_QUEUE_CAB:
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                               AR5K_QCU_MISC_FRSHED_DBA_GT |
+                               AR5K_QCU_MISC_CBREXP |
+                               AR5K_QCU_MISC_CBREXP_BCN);
+
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+                               (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
+                               AR5K_DCU_MISC_ARBLOCK_CTL_S));
+                       break;
+
+               case AR5K_TX_QUEUE_UAPSD:
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                               AR5K_QCU_MISC_CBREXP);
+                       break;
+
+               case AR5K_TX_QUEUE_DATA:
+               default:
+                       break;
+               }
+
+               /*
+                * Enable interrupts for this tx queue
+                * in the secondary interrupt mask registers
+                */
+               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
+                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
+
+               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
+                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
+
+               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
+                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
+
+               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
+                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
+
+               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
+                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
+
+
+               /* Update secondary interrupt mask registers */
+               ah->ah_txq_imr_txok &= ah->ah_txq_status;
+               ah->ah_txq_imr_txerr &= ah->ah_txq_status;
+               ah->ah_txq_imr_txurn &= ah->ah_txq_status;
+               ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
+               ah->ah_txq_imr_txeol &= ah->ah_txq_status;
+
+               ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
+                       AR5K_SIMR0_QCU_TXOK) |
+                       AR5K_REG_SM(ah->ah_txq_imr_txdesc,
+                       AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
+               ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
+                       AR5K_SIMR1_QCU_TXERR) |
+                       AR5K_REG_SM(ah->ah_txq_imr_txeol,
+                       AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
+               ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
+                       AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
+       }
+
+       return 0;
+}
+
+/*
+ * Get number of pending frames
+ * for a specific queue [5211+]
+ */
+u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) {
+       ATH5K_TRACE(ah->ah_sc);
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+       /* Return if queue is declared inactive */
+       if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+               return false;
+
+       /* XXX: How about AR5K_CFG_TXCNT ? */
+       if (ah->ah_version == AR5K_AR5210)
+               return false;
+
+       return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
+}
+
+/*
+ * Set slot time
+ */
+int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
+               return -EINVAL;
+
+       if (ah->ah_version == AR5K_AR5210)
+               ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
+                               ah->ah_turbo), AR5K_SLOT_TIME);
+       else
+               ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
+
+       return 0;
+}
+
+/*
+ * Get slot time
+ */
+unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       if (ah->ah_version == AR5K_AR5210)
+               return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
+                               AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
+       else
+               return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
+}
+
+
+/******************************\
+ Hardware Descriptor Functions
+\******************************/
+
+/*
+ * TX Descriptor
+ */
+
+/*
+ * Initialize the 2-word tx descriptor on 5210/5211
+ */
+static int
+ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+       unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
+       unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
+       unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
+       unsigned int rtscts_rate, unsigned int rtscts_duration)
+{
+       u32 frame_type;
+       struct ath5k_hw_2w_tx_desc *tx_desc;
+       unsigned int buff_len;
+
+       tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
+
+       /*
+        * Validate input
+        * - Zero retries don't make sense.
+        * - A zero rate will put the HW into a mode where it continously sends
+        *   noise on the channel, so it is important to avoid this.
+        */
+       if (unlikely(tx_tries0 == 0)) {
+               ATH5K_ERR(ah->ah_sc, "zero retries\n");
+               WARN_ON(1);
+               return -EINVAL;
+       }
+       if (unlikely(tx_rate0 == 0)) {
+               ATH5K_ERR(ah->ah_sc, "zero rate\n");
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       /* Clear status descriptor */
+       memset(desc->ds_hw, 0, sizeof(struct ath5k_hw_tx_status));
+
+       /* Initialize control descriptor */
+       tx_desc->tx_control_0 = 0;
+       tx_desc->tx_control_1 = 0;
+
+       /* Setup control descriptor */
+
+       /* Verify and set frame length */
+       if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
+               return -EINVAL;
+
+       tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+
+       /* Verify and set buffer length */
+       buff_len = pkt_len - FCS_LEN;
+
+       /* NB: beacon's BufLen must be a multiple of 4 bytes */
+       if(type == AR5K_PKT_TYPE_BEACON)
+               buff_len = roundup(buff_len, 4);
+
+       if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
+               return -EINVAL;
+
+       tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+
+       /*
+        * Verify and set header length
+        * XXX: I only found that on 5210 code, does it work on 5211 ?
+        */
+       if (ah->ah_version == AR5K_AR5210) {
+               if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
+                       return -EINVAL;
+               tx_desc->tx_control_0 |=
+                       AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
+       }
+
+       /*Diferences between 5210-5211*/
+       if (ah->ah_version == AR5K_AR5210) {
+               switch (type) {
+               case AR5K_PKT_TYPE_BEACON:
+               case AR5K_PKT_TYPE_PROBE_RESP:
+                       frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
+               case AR5K_PKT_TYPE_PIFS:
+                       frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
+               default:
+                       frame_type = type /*<< 2 ?*/;
+               }
+
+               tx_desc->tx_control_0 |=
+                       AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
+                       AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+       } else {
+               tx_desc->tx_control_0 |=
+                       AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
+                       AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
+               tx_desc->tx_control_1 |=
+                       AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
+       }
+#define _TX_FLAGS(_c, _flag)                                           \
+       if (flags & AR5K_TXDESC_##_flag)                                \
+               tx_desc->tx_control_##_c |=                             \
+                       AR5K_2W_TX_DESC_CTL##_c##_##_flag
+
+       _TX_FLAGS(0, CLRDMASK);
+       _TX_FLAGS(0, VEOL);
+       _TX_FLAGS(0, INTREQ);
+       _TX_FLAGS(0, RTSENA);
+       _TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+       /*
+        * WEP crap
+        */
+       if (key_index != AR5K_TXKEYIX_INVALID) {
+               tx_desc->tx_control_0 |=
+                       AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+               tx_desc->tx_control_1 |=
+                       AR5K_REG_SM(key_index,
+                       AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+       }
+
+       /*
+        * RTS/CTS Duration [5210 ?]
+        */
+       if ((ah->ah_version == AR5K_AR5210) &&
+                       (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
+               tx_desc->tx_control_1 |= rtscts_duration &
+                               AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
+
+       return 0;
+}
+
+/*
+ * Initialize the 4-word tx descriptor on 5212
+ */
+static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
+       struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
+       enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
+       unsigned int tx_tries0, unsigned int key_index,
+       unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate,
+       unsigned int rtscts_duration)
+{
+       struct ath5k_hw_4w_tx_desc *tx_desc;
+       struct ath5k_hw_tx_status *tx_status;
+       unsigned int buff_len;
+
+       ATH5K_TRACE(ah->ah_sc);
+       tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
+       tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2];
+
+       /*
+        * Validate input
+        * - Zero retries don't make sense.
+        * - A zero rate will put the HW into a mode where it continously sends
+        *   noise on the channel, so it is important to avoid this.
+        */
+       if (unlikely(tx_tries0 == 0)) {
+               ATH5K_ERR(ah->ah_sc, "zero retries\n");
+               WARN_ON(1);
+               return -EINVAL;
+       }
+       if (unlikely(tx_rate0 == 0)) {
+               ATH5K_ERR(ah->ah_sc, "zero rate\n");
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       /* Clear status descriptor */
+       memset(tx_status, 0, sizeof(struct ath5k_hw_tx_status));
+
+       /* Initialize control descriptor */
+       tx_desc->tx_control_0 = 0;
+       tx_desc->tx_control_1 = 0;
+       tx_desc->tx_control_2 = 0;
+       tx_desc->tx_control_3 = 0;
+
+       /* Setup control descriptor */
+
+       /* Verify and set frame length */
+       if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+               return -EINVAL;
+
+       tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+
+       /* Verify and set buffer length */
+       buff_len = pkt_len - FCS_LEN;
+
+       /* NB: beacon's BufLen must be a multiple of 4 bytes */
+       if(type == AR5K_PKT_TYPE_BEACON)
+               buff_len = roundup(buff_len, 4);
+
+       if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+               return -EINVAL;
+
+       tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+
+       tx_desc->tx_control_0 |=
+               AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+               AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+       tx_desc->tx_control_1 |= AR5K_REG_SM(type,
+                                       AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+       tx_desc->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
+                                       AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+       tx_desc->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+
+#define _TX_FLAGS(_c, _flag)                   \
+       if (flags & AR5K_TXDESC_##_flag)        \
+               tx_desc->tx_control_##_c |=     \
+                       AR5K_4W_TX_DESC_CTL##_c##_##_flag
+
+       _TX_FLAGS(0, CLRDMASK);
+       _TX_FLAGS(0, VEOL);
+       _TX_FLAGS(0, INTREQ);
+       _TX_FLAGS(0, RTSENA);
+       _TX_FLAGS(0, CTSENA);
+       _TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+       /*
+        * WEP crap
+        */
+       if (key_index != AR5K_TXKEYIX_INVALID) {
+               tx_desc->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+               tx_desc->tx_control_1 |= AR5K_REG_SM(key_index,
+                               AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+       }
+
+       /*
+        * RTS/CTS
+        */
+       if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
+               if ((flags & AR5K_TXDESC_RTSENA) &&
+                               (flags & AR5K_TXDESC_CTSENA))
+                       return -EINVAL;
+               tx_desc->tx_control_2 |= rtscts_duration &
+                               AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+               tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+                               AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
+       }
+
+       return 0;
+}
+
+/*
+ * Initialize a 4-word multirate tx descriptor on 5212
+ */
+static bool
+ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+       unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2,
+       unsigned int tx_rate3, u_int tx_tries3)
+{
+       struct ath5k_hw_4w_tx_desc *tx_desc;
+
+       /*
+        * Rates can be 0 as long as the retry count is 0 too.
+        * A zero rate and nonzero retry count will put the HW into a mode where
+        * it continously sends noise on the channel, so it is important to
+        * avoid this.
+        */
+       if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) ||
+                    (tx_rate2 == 0 && tx_tries2 != 0) ||
+                    (tx_rate3 == 0 && tx_tries3 != 0))) {
+               ATH5K_ERR(ah->ah_sc, "zero rate\n");
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       if (ah->ah_version == AR5K_AR5212) {
+               tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
+
+#define _XTX_TRIES(_n)                                                 \
+       if (tx_tries##_n) {                                             \
+               tx_desc->tx_control_2 |=                                \
+                   AR5K_REG_SM(tx_tries##_n,                           \
+                   AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n);               \
+               tx_desc->tx_control_3 |=                                \
+                   AR5K_REG_SM(tx_rate##_n,                            \
+                   AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n);                \
+       }
+
+               _XTX_TRIES(1);
+               _XTX_TRIES(2);
+               _XTX_TRIES(3);
+
+#undef _XTX_TRIES
+
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * Proccess the tx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
+               struct ath5k_desc *desc)
+{
+       struct ath5k_hw_tx_status *tx_status;
+       struct ath5k_hw_2w_tx_desc *tx_desc;
+
+       tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
+       tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[0];
+
+       /* No frame has been send or error */
+       if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
+               return -EINPROGRESS;
+
+       /*
+        * Get descriptor status
+        */
+       desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+               AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+       desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+               AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+       desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+               AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+       /*TODO: desc->ds_us.tx.ts_virtcol + test*/
+       desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+               AR5K_DESC_TX_STATUS1_SEQ_NUM);
+       desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+               AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+       desc->ds_us.tx.ts_antenna = 1;
+       desc->ds_us.tx.ts_status = 0;
+       desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0,
+               AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+
+       if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
+               if (tx_status->tx_status_0 &
+                               AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+                       desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY;
+
+               if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+                       desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO;
+
+               if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+                       desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT;
+       }
+
+       return 0;
+}
+
+/*
+ * Proccess a tx descriptor on 5212
+ */
+static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
+               struct ath5k_desc *desc)
+{
+       struct ath5k_hw_tx_status *tx_status;
+       struct ath5k_hw_4w_tx_desc *tx_desc;
+
+       ATH5K_TRACE(ah->ah_sc);
+       tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
+       tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2];
+
+       /* No frame has been send or error */
+       if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
+               return -EINPROGRESS;
+
+       /*
+        * Get descriptor status
+        */
+       desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+               AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+       desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+               AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+       desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+               AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+       desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+               AR5K_DESC_TX_STATUS1_SEQ_NUM);
+       desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+               AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+       desc->ds_us.tx.ts_antenna = (tx_status->tx_status_1 &
+               AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+       desc->ds_us.tx.ts_status = 0;
+
+       switch (AR5K_REG_MS(tx_status->tx_status_1,
+                       AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) {
+       case 0:
+               desc->ds_us.tx.ts_rate = tx_desc->tx_control_3 &
+                       AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+               break;
+       case 1:
+               desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+                       AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
+               desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+                       AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+               break;
+       case 2:
+               desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+                       AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
+               desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+                       AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
+               break;
+       case 3:
+               desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+                       AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
+               desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+                       AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
+               break;
+       }
+
+       if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
+               if (tx_status->tx_status_0 &
+                               AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+                       desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY;
+
+               if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+                       desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO;
+
+               if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+                       desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT;
+       }
+
+       return 0;
+}
+
+/*
+ * RX Descriptor
+ */
+
+/*
+ * Initialize an rx descriptor
+ */
+int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+                       u32 size, unsigned int flags)
+{
+       struct ath5k_rx_desc *rx_desc;
+
+       ATH5K_TRACE(ah->ah_sc);
+       rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0;
+
+       /*
+        *Clear ds_hw
+        * If we don't clean the status descriptor,
+        * while scanning we get too many results,
+        * most of them virtual, after some secs
+        * of scanning system hangs. M.F.
+       */
+       memset(desc->ds_hw, 0, sizeof(desc->ds_hw));
+
+       /*Initialize rx descriptor*/
+       rx_desc->rx_control_0 = 0;
+       rx_desc->rx_control_1 = 0;
+
+       /* Setup descriptor */
+       rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
+       if (unlikely(rx_desc->rx_control_1 != size))
+               return -EINVAL;
+
+       if (flags & AR5K_RXDESC_INTREQ)
+               rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
+
+       return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah,
+               struct ath5k_desc *desc)
+{
+       struct ath5k_hw_old_rx_status *rx_status;
+
+       rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0];
+
+       /* No frame received / not ready */
+       if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE)
+                               == 0))
+               return -EINPROGRESS;
+
+       /*
+        * Frame receive status
+        */
+       desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 &
+               AR5K_OLD_RX_DESC_STATUS0_DATA_LEN;
+       desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+               AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+       desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+               AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE);
+       desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 &
+               AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA;
+       desc->ds_us.rx.rs_more = rx_status->rx_status_0 &
+               AR5K_OLD_RX_DESC_STATUS0_MORE;
+       desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+               AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+       desc->ds_us.rx.rs_status = 0;
+
+       /*
+        * Key table status
+        */
+       if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID)
+               desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+                       AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX);
+       else
+               desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
+
+       /*
+        * Receive/descriptor errors
+        */
+       if ((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK)
+                       == 0) {
+               if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR)
+                       desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC;
+
+               if (rx_status->rx_status_1 &
+                               AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN)
+                       desc->ds_us.rx.rs_status |= AR5K_RXERR_FIFO;
+
+               if (rx_status->rx_status_1 &
+                               AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR) {
+                       desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY;
+                       desc->ds_us.rx.rs_phyerr =
+                               AR5K_REG_MS(rx_status->rx_status_1,
+                                       AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR);
+               }
+
+               if (rx_status->rx_status_1 &
+                               AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+                       desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT;
+       }
+
+       return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5212
+ */
+static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah,
+               struct ath5k_desc *desc)
+{
+       struct ath5k_hw_new_rx_status *rx_status;
+       struct ath5k_hw_rx_error *rx_err;
+
+       ATH5K_TRACE(ah->ah_sc);
+       rx_status = (struct ath5k_hw_new_rx_status *)&desc->ds_hw[0];
+
+       /* Overlay on error */
+       rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0];
+
+       /* No frame received / not ready */
+       if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE)
+                               == 0))
+               return -EINPROGRESS;
+
+       /*
+        * Frame receive status
+        */
+       desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 &
+               AR5K_NEW_RX_DESC_STATUS0_DATA_LEN;
+       desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+               AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+       desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+               AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE);
+       desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 &
+               AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA;
+       desc->ds_us.rx.rs_more = rx_status->rx_status_0 &
+               AR5K_NEW_RX_DESC_STATUS0_MORE;
+       desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+               AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+       desc->ds_us.rx.rs_status = 0;
+
+       /*
+        * Key table status
+        */
+       if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID)
+               desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+                               AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX);
+       else
+               desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
+
+       /*
+        * Receive/descriptor errors
+        */
+       if ((rx_status->rx_status_1 &
+                       AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
+               if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR)
+                       desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC;
+
+               if (rx_status->rx_status_1 &
+                               AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) {
+                       desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY;
+                       desc->ds_us.rx.rs_phyerr =
+                               AR5K_REG_MS(rx_err->rx_error_1,
+                                       AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
+               }
+
+               if (rx_status->rx_status_1 &
+                               AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+                       desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT;
+
+               if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR)
+                       desc->ds_us.rx.rs_status |= AR5K_RXERR_MIC;
+       }
+
+       return 0;
+}
+
+
+/****************\
+  GPIO Functions
+\****************/
+
+/*
+ * Set led state
+ */
+void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
+{
+       u32 led;
+       /*5210 has different led mode handling*/
+       u32 led_5210;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /*Reset led status*/
+       if (ah->ah_version != AR5K_AR5210)
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
+                       AR5K_PCICFG_LEDMODE |  AR5K_PCICFG_LED);
+       else
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED);
+
+       /*
+        * Some blinking values, define at your wish
+        */
+       switch (state) {
+       case AR5K_LED_SCAN:
+       case AR5K_LED_AUTH:
+               led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND;
+               led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL;
+               break;
+
+       case AR5K_LED_INIT:
+               led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE;
+               led_5210 = AR5K_PCICFG_LED_PEND;
+               break;
+
+       case AR5K_LED_ASSOC:
+       case AR5K_LED_RUN:
+               led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC;
+               led_5210 = AR5K_PCICFG_LED_ASSOC;
+               break;
+
+       default:
+               led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE;
+               led_5210 = AR5K_PCICFG_LED_PEND;
+               break;
+       }
+
+       /*Write new status to the register*/
+       if (ah->ah_version != AR5K_AR5210)
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led);
+       else
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
+}
+
+/*
+ * Set GPIO outputs
+ */
+int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       if (gpio > AR5K_NUM_GPIO)
+               return -EINVAL;
+
+       ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~
+               AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
+
+       return 0;
+}
+
+/*
+ * Set GPIO inputs
+ */
+int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       if (gpio > AR5K_NUM_GPIO)
+               return -EINVAL;
+
+       ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~
+               AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
+
+       return 0;
+}
+
+/*
+ * Get GPIO state
+ */
+u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       if (gpio > AR5K_NUM_GPIO)
+               return 0xffffffff;
+
+       /* GPIO input magic */
+       return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
+               0x1;
+}
+
+/*
+ * Set GPIO state
+ */
+int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
+{
+       u32 data;
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (gpio > AR5K_NUM_GPIO)
+               return -EINVAL;
+
+       /* GPIO output magic */
+       data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+       data &= ~(1 << gpio);
+       data |= (val & 1) << gpio;
+
+       ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
+
+       return 0;
+}
+
+/*
+ * Initialize the GPIO interrupt (RFKill switch)
+ */
+void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
+               u32 interrupt_level)
+{
+       u32 data;
+
+       ATH5K_TRACE(ah->ah_sc);
+       if (gpio > AR5K_NUM_GPIO)
+               return;
+
+       /*
+        * Set the GPIO interrupt
+        */
+       data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
+               ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
+               AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
+               (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
+
+       ath5k_hw_reg_write(ah, interrupt_level ? data :
+               (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
+
+       ah->ah_imr |= AR5K_IMR_GPIO;
+
+       /* Enable GPIO interrupts */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
+}
+
+
+/*********************************\
+ Regulatory Domain/Channels Setup
+\*********************************/
+
+u16 ath5k_get_regdomain(struct ath5k_hw *ah)
+{
+       u16 regdomain;
+       enum ath5k_regdom ieee_regdomain;
+#ifdef COUNTRYCODE
+       u16 code;
+#endif
+
+       ath5k_eeprom_regulation_domain(ah, false, &ieee_regdomain);
+       ah->ah_capabilities.cap_regdomain.reg_hw = ieee_regdomain;
+
+#ifdef COUNTRYCODE
+       /*
+        * Get the regulation domain by country code. This will ignore
+        * the settings found in the EEPROM.
+        */
+       code = ieee80211_name2countrycode(COUNTRYCODE);
+       ieee_regdomain = ieee80211_countrycode2regdomain(code);
+#endif
+
+       regdomain = ath5k_regdom_from_ieee(ieee_regdomain);
+       ah->ah_capabilities.cap_regdomain.reg_current = regdomain;
+
+       return regdomain;
+}
+
+
+/****************\
+  Misc functions
+\****************/
+
+int ath5k_hw_get_capability(struct ath5k_hw *ah,
+               enum ath5k_capability_type cap_type,
+               u32 capability, u32 *result)
+{
+       ATH5K_TRACE(ah->ah_sc);
+
+       switch (cap_type) {
+       case AR5K_CAP_NUM_TXQUEUES:
+               if (result) {
+                       if (ah->ah_version == AR5K_AR5210)
+                               *result = AR5K_NUM_TX_QUEUES_NOQCU;
+                       else
+                               *result = AR5K_NUM_TX_QUEUES;
+                       goto yes;
+               }
+       case AR5K_CAP_VEOL:
+               goto yes;
+       case AR5K_CAP_COMPRESSION:
+               if (ah->ah_version == AR5K_AR5212)
+                       goto yes;
+               else
+                       goto no;
+       case AR5K_CAP_BURST:
+               goto yes;
+       case AR5K_CAP_TPC:
+               goto yes;
+       case AR5K_CAP_BSSIDMASK:
+               if (ah->ah_version == AR5K_AR5212)
+                       goto yes;
+               else
+                       goto no;
+       case AR5K_CAP_XR:
+               if (ah->ah_version == AR5K_AR5212)
+                       goto yes;
+               else
+                       goto no;
+       default:
+               goto no;
+       }
+
+no:
+       return -EINVAL;
+yes:
+       return 0;
+}
+
+static int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
+               u16 assoc_id)
+{
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (ah->ah_version == AR5K_AR5210) {
+               AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+                       AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
+               return 0;
+       }
+
+       return -EIO;
+}
+
+static int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (ah->ah_version == AR5K_AR5210) {
+               AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
+                       AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
+               return 0;
+       }
+
+       return -EIO;
+}
diff --git a/drivers/net/wireless/ath5k/hw.h b/drivers/net/wireless/ath5k/hw.h
new file mode 100644 (file)
index 0000000..d9a7c09
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Matthew W. S. Bell  <mentor@madwifi.org>
+ * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+
+/*
+ * Gain settings
+ */
+
+enum ath5k_rfgain {
+       AR5K_RFGAIN_INACTIVE = 0,
+       AR5K_RFGAIN_READ_REQUESTED,
+       AR5K_RFGAIN_NEED_CHANGE,
+};
+
+#define AR5K_GAIN_CRN_FIX_BITS_5111            4
+#define AR5K_GAIN_CRN_FIX_BITS_5112            7
+#define AR5K_GAIN_CRN_MAX_FIX_BITS             AR5K_GAIN_CRN_FIX_BITS_5112
+#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN         15
+#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN         20
+#define AR5K_GAIN_CCK_PROBE_CORR               5
+#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA          15
+#define AR5K_GAIN_STEP_COUNT                   10
+#define AR5K_GAIN_PARAM_TX_CLIP                        0
+#define AR5K_GAIN_PARAM_PD_90                  1
+#define AR5K_GAIN_PARAM_PD_84                  2
+#define AR5K_GAIN_PARAM_GAIN_SEL               3
+#define AR5K_GAIN_PARAM_MIX_ORN                        0
+#define AR5K_GAIN_PARAM_PD_138                 1
+#define AR5K_GAIN_PARAM_PD_137                 2
+#define AR5K_GAIN_PARAM_PD_136                 3
+#define AR5K_GAIN_PARAM_PD_132                 4
+#define AR5K_GAIN_PARAM_PD_131                 5
+#define AR5K_GAIN_PARAM_PD_130                 6
+#define AR5K_GAIN_CHECK_ADJUST(_g)             \
+       ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
+
+struct ath5k_gain_opt_step {
+       s16                             gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
+       s32                             gos_gain;
+};
+
+struct ath5k_gain {
+       u32                     g_step_idx;
+       u32                     g_current;
+       u32                     g_target;
+       u32                     g_low;
+       u32                     g_high;
+       u32                     g_f_corr;
+       u32                     g_active;
+       const struct ath5k_gain_opt_step        *g_step;
+};
+
+
+/*
+ * HW SPECIFIC STRUCTS
+ */
+
+/* Some EEPROM defines */
+#define AR5K_EEPROM_EEP_SCALE          100
+#define AR5K_EEPROM_EEP_DELTA          10
+#define AR5K_EEPROM_N_MODES            3
+#define AR5K_EEPROM_N_5GHZ_CHAN                10
+#define AR5K_EEPROM_N_2GHZ_CHAN                3
+#define AR5K_EEPROM_MAX_CHAN           10
+#define AR5K_EEPROM_N_PCDAC            11
+#define AR5K_EEPROM_N_TEST_FREQ                8
+#define AR5K_EEPROM_N_EDGES            8
+#define AR5K_EEPROM_N_INTERCEPTS       11
+#define AR5K_EEPROM_FREQ_M(_v)         AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
+#define AR5K_EEPROM_PCDAC_M            0x3f
+#define AR5K_EEPROM_PCDAC_START                1
+#define AR5K_EEPROM_PCDAC_STOP         63
+#define AR5K_EEPROM_PCDAC_STEP         1
+#define AR5K_EEPROM_NON_EDGE_M         0x40
+#define AR5K_EEPROM_CHANNEL_POWER      8
+#define AR5K_EEPROM_N_OBDB             4
+#define AR5K_EEPROM_OBDB_DIS           0xffff
+#define AR5K_EEPROM_CHANNEL_DIS                0xff
+#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10)
+#define AR5K_EEPROM_N_CTLS(_v)         AR5K_EEPROM_OFF(_v, 16, 32)
+#define AR5K_EEPROM_MAX_CTLS           32
+#define AR5K_EEPROM_N_XPD_PER_CHANNEL  4
+#define AR5K_EEPROM_N_XPD0_POINTS      4
+#define AR5K_EEPROM_N_XPD3_POINTS      3
+#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ        35
+#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ        55
+#define AR5K_EEPROM_POWER_M            0x3f
+#define AR5K_EEPROM_POWER_MIN          0
+#define AR5K_EEPROM_POWER_MAX          3150
+#define AR5K_EEPROM_POWER_STEP         50
+#define AR5K_EEPROM_POWER_TABLE_SIZE   64
+#define AR5K_EEPROM_N_POWER_LOC_11B    4
+#define AR5K_EEPROM_N_POWER_LOC_11G    6
+#define AR5K_EEPROM_I_GAIN             10
+#define AR5K_EEPROM_CCK_OFDM_DELTA     15
+#define AR5K_EEPROM_N_IQ_CAL           2
+
+/* Struct to hold EEPROM calibration data */
+struct ath5k_eeprom_info {
+       u16     ee_magic;
+       u16     ee_protect;
+       u16     ee_regdomain;
+       u16     ee_version;
+       u16     ee_header;
+       u16     ee_ant_gain;
+       u16     ee_misc0;
+       u16     ee_misc1;
+       u16     ee_cck_ofdm_gain_delta;
+       u16     ee_cck_ofdm_power_delta;
+       u16     ee_scaled_cck_delta;
+
+       /* Used for tx thermal adjustment (eeprom_init, rfregs) */
+       u16     ee_tx_clip;
+       u16     ee_pwd_84;
+       u16     ee_pwd_90;
+       u16     ee_gain_select;
+
+       /* RF Calibration settings (reset, rfregs) */
+       u16     ee_i_cal[AR5K_EEPROM_N_MODES];
+       u16     ee_q_cal[AR5K_EEPROM_N_MODES];
+       u16     ee_fixed_bias[AR5K_EEPROM_N_MODES];
+       u16     ee_turbo_max_power[AR5K_EEPROM_N_MODES];
+       u16     ee_xr_power[AR5K_EEPROM_N_MODES];
+       u16     ee_switch_settling[AR5K_EEPROM_N_MODES];
+       u16     ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
+       u16     ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
+       u16     ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+       u16     ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+       u16     ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
+       u16     ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
+       u16     ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
+       u16     ee_thr_62[AR5K_EEPROM_N_MODES];
+       u16     ee_xlna_gain[AR5K_EEPROM_N_MODES];
+       u16     ee_xpd[AR5K_EEPROM_N_MODES];
+       u16     ee_x_gain[AR5K_EEPROM_N_MODES];
+       u16     ee_i_gain[AR5K_EEPROM_N_MODES];
+       u16     ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+
+       /* Unused */
+       u16     ee_false_detect[AR5K_EEPROM_N_MODES];
+       u16     ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
+       u16     ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
+
+       /* Conformance test limits (Unused) */
+       u16     ee_ctls;
+       u16     ee_ctl[AR5K_EEPROM_MAX_CTLS];
+
+       /* Noise Floor Calibration settings */
+       s16     ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
+       s8      ee_adc_desired_size[AR5K_EEPROM_N_MODES];
+       s8      ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+};
+
+/*
+ * Internal RX/TX descriptor structures
+ * (rX: reserved fields possibily used by future versions of the ar5k chipset)
+ */
+
+struct ath5k_rx_desc {
+       u32     rx_control_0; /* RX control word 0 */
+
+#define AR5K_DESC_RX_CTL0                      0x00000000
+
+       u32     rx_control_1; /* RX control word 1 */
+
+#define AR5K_DESC_RX_CTL1_BUF_LEN              0x00000fff
+#define AR5K_DESC_RX_CTL1_INTREQ               0x00002000
+} __packed;
+
+/*
+ * 5210/5211 rx status descriptor
+ */
+struct ath5k_hw_old_rx_status {
+       u32     rx_status_0; /* RX status word 0 */
+
+#define AR5K_OLD_RX_DESC_STATUS0_DATA_LEN              0x00000fff
+#define AR5K_OLD_RX_DESC_STATUS0_MORE                  0x00001000
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE          0x00078000
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE_S                15
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL                0x07f80000
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL_S      19
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA       0x38000000
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA_S     27
+
+       u32     rx_status_1; /* RX status word 1 */
+
+#define AR5K_OLD_RX_DESC_STATUS1_DONE                  0x00000001
+#define AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK      0x00000002
+#define AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR             0x00000004
+#define AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN          0x00000008
+#define AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR     0x00000010
+#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR             0x000000e0
+#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR_S           5
+#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID       0x00000100
+#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX             0x00007e00
+#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_S           9
+#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP     0x0fff8000
+#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S   15
+#define AR5K_OLD_RX_DESC_STATUS1_KEY_CACHE_MISS                0x10000000
+} __packed;
+
+/*
+ * 5212 rx status descriptor
+ */
+struct ath5k_hw_new_rx_status {
+       u32     rx_status_0; /* RX status word 0 */
+
+#define AR5K_NEW_RX_DESC_STATUS0_DATA_LEN              0x00000fff
+#define AR5K_NEW_RX_DESC_STATUS0_MORE                  0x00001000
+#define AR5K_NEW_RX_DESC_STATUS0_DECOMP_CRC_ERROR      0x00002000
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE          0x000f8000
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE_S                15
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL                0x0ff00000
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL_S      20
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA       0xf0000000
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA_S     28
+
+       u32     rx_status_1; /* RX status word 1 */
+
+#define AR5K_NEW_RX_DESC_STATUS1_DONE                  0x00000001
+#define AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK      0x00000002
+#define AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR             0x00000004
+#define AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR     0x00000008
+#define AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR             0x00000010
+#define AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR             0x00000020
+#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID       0x00000100
+#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX             0x0000fe00
+#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_S           9
+#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP     0x7fff0000
+#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S   16
+#define AR5K_NEW_RX_DESC_STATUS1_KEY_CACHE_MISS                0x80000000
+} __packed;
+
+struct ath5k_hw_rx_error {
+       u32     rx_error_0; /* RX error word 0 */
+
+#define AR5K_RX_DESC_ERROR0                    0x00000000
+
+       u32     rx_error_1; /* RX error word 1 */
+
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE     0x0000ff00
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S   8
+} __packed;
+
+#define AR5K_DESC_RX_PHY_ERROR_NONE            0x00
+#define AR5K_DESC_RX_PHY_ERROR_TIMING          0x20
+#define AR5K_DESC_RX_PHY_ERROR_PARITY          0x40
+#define AR5K_DESC_RX_PHY_ERROR_RATE            0x60
+#define AR5K_DESC_RX_PHY_ERROR_LENGTH          0x80
+#define AR5K_DESC_RX_PHY_ERROR_64QAM           0xa0
+#define AR5K_DESC_RX_PHY_ERROR_SERVICE         0xc0
+#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR     0xe0
+
+struct ath5k_hw_2w_tx_desc {
+       u32     tx_control_0; /* TX control word 0 */
+
+#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN         0x00000fff
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN                0x0003f000 /*[5210 ?]*/
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S      12
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE         0x003c0000
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S       18
+#define AR5K_2W_TX_DESC_CTL0_RTSENA            0x00400000
+#define AR5K_2W_TX_DESC_CTL0_CLRDMASK          0x01000000
+#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET       0x00800000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_VEOL              0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE                0x1c000000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S      26
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210        0x02000000
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211        0x1e000000
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT     (ah->ah_version == AR5K_AR5210 ? \
+                                               AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \
+                                               AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S   25
+#define AR5K_2W_TX_DESC_CTL0_INTREQ            0x20000000
+#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000
+
+       u32     tx_control_1; /* TX control word 1 */
+
+#define AR5K_2W_TX_DESC_CTL1_BUF_LEN           0x00000fff
+#define AR5K_2W_TX_DESC_CTL1_MORE              0x00001000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210    0x0007e000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211    0x000fe000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX (ah->ah_version == AR5K_AR5210 ? \
+                                               AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \
+                                               AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S       13
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE                0x00700000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S      20
+#define AR5K_2W_TX_DESC_CTL1_NOACK             0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION      0xfff80000 /*[5210 ?]*/
+} __packed;
+
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
+
+/*
+ * 5212 4-word tx control descriptor
+ */
+struct ath5k_hw_4w_tx_desc {
+       u32     tx_control_0; /* TX control word 0 */
+
+#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN         0x00000fff
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER                0x003f0000
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S      16
+#define AR5K_4W_TX_DESC_CTL0_RTSENA            0x00400000
+#define AR5K_4W_TX_DESC_CTL0_VEOL              0x00800000
+#define AR5K_4W_TX_DESC_CTL0_CLRDMASK          0x01000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT     0x1e000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S   25
+#define AR5K_4W_TX_DESC_CTL0_INTREQ            0x20000000
+#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000
+#define AR5K_4W_TX_DESC_CTL0_CTSENA            0x80000000
+
+       u32     tx_control_1; /* TX control word 1 */
+
+#define AR5K_4W_TX_DESC_CTL1_BUF_LEN           0x00000fff
+#define AR5K_4W_TX_DESC_CTL1_MORE              0x00001000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S       13
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE                0x00f00000
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S      20
+#define AR5K_4W_TX_DESC_CTL1_NOACK             0x01000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC         0x06000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S       25
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN       0x18000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S     27
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN      0x60000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S    29
+
+       u32     tx_control_2; /* TX control word 2 */
+
+#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION              0x00007fff
+#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE    0x00008000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0               0x000f0000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S             16
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1               0x00f00000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S             20
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2               0x0f000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S             24
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3               0xf0000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S             28
+
+       u32     tx_control_3; /* TX control word 3 */
+
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0                0x0000001f
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1                0x000003e0
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S      5
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2                0x00007c00
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S      10
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3                0x000f8000
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S      15
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE      0x01f00000
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S    20
+} __packed;
+
+/*
+ * Common tx status descriptor
+ */
+struct ath5k_hw_tx_status {
+       u32     tx_status_0; /* TX status word 0 */
+
+#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK     0x00000001
+#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002
+#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN     0x00000004
+#define AR5K_DESC_TX_STATUS0_FILTERED          0x00000008
+/*???
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT    0x000000f0
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S  4
+*/
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S       4
+/*???
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT   0x00000f00
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8
+*/
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT  0x00000f00
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S        8
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT   0x0000f000
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP    0xffff0000
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S  16
+
+       u32     tx_status_1; /* TX status word 1 */
+
+#define AR5K_DESC_TX_STATUS1_DONE              0x00000001
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM           0x00001ffe
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S         1
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH  0x001fe000
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S        13
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX    0x00600000
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S  21
+#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS      0x00800000
+#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA      0x01000000
+} __packed;
+
+
+/*
+ * AR5K REGISTER ACCESS
+ */
+
+/*Swap RX/TX Descriptor for big endian archs*/
+#if defined(__BIG_ENDIAN)
+#define AR5K_INIT_CFG  (               \
+       AR5K_CFG_SWTD | AR5K_CFG_SWRD   \
+)
+#else
+#define AR5K_INIT_CFG  0x00000000
+#endif
+
+/*#define AR5K_REG_READ(_reg)  ath5k_hw_reg_read(ah, _reg)
+
+#define AR5K_REG_WRITE(_reg, _val)     ath5k_hw_reg_write(ah, _val, _reg)*/
+
+#define AR5K_REG_SM(_val, _flags)                                      \
+       (((_val) << _flags##_S) & (_flags))
+
+#define AR5K_REG_MS(_val, _flags)                                      \
+       (((_val) & (_flags)) >> _flags##_S)
+
+/* Some registers can hold multiple values of interest. For this
+ * reason when we want to write to these registers we must first
+ * retrieve the values which we do not want to clear (lets call this
+ * old_data) and then set the register with this and our new_value:
+ * ( old_data | new_value) */
+#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val)                    \
+       ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
+           (((_val) << _flags##_S) & (_flags)), _reg)
+
+#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask)                  \
+       ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) &           \
+                       (_mask)) | (_flags), _reg)
+
+#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)                         \
+       ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
+
+#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)                        \
+       ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
+
+#define AR5K_PHY_WRITE(ah, _reg, _val)                                 \
+       ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
+
+#define AR5K_PHY_READ(ah, _reg)                                        \
+       ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
+
+#define AR5K_REG_WAIT(_i) do {                                         \
+       if (_i % 64)                                                    \
+               udelay(1);                                              \
+} while (0)
+
+#define AR5K_EEPROM_READ(_o, _v) do {                                  \
+       if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0) \
+               return (ret);                                           \
+} while (0)
+
+#define AR5K_EEPROM_READ_HDR(_o, _v)                                   \
+       AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);        \
+
+/* Read status of selected queue */
+#define AR5K_REG_READ_Q(ah, _reg, _queue)                              \
+       (ath5k_hw_reg_read(ah, _reg) & (1 << _queue))                   \
+
+#define AR5K_REG_WRITE_Q(ah, _reg, _queue)                             \
+       ath5k_hw_reg_write(ah, (1 << _queue), _reg)
+
+#define AR5K_Q_ENABLE_BITS(_reg, _queue) do {                          \
+       _reg |= 1 << _queue;                                            \
+} while (0)
+
+#define AR5K_Q_DISABLE_BITS(_reg, _queue) do {                         \
+       _reg &= ~(1 << _queue);                                         \
+} while (0)
+
+#define AR5K_LOW_ID(_a)(                               \
+(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \
+)
+
+#define AR5K_HIGH_ID(_a)       ((_a)[4] | (_a)[5] << 8)
+
+/*
+ * Initial register values
+ */
+
+/*
+ * Common initial register values
+ */
+#define AR5K_INIT_MODE                         CHANNEL_B
+
+#define AR5K_INIT_TX_LATENCY                   502
+#define AR5K_INIT_USEC                         39
+#define AR5K_INIT_USEC_TURBO                   79
+#define AR5K_INIT_USEC_32                      31
+#define AR5K_INIT_CARR_SENSE_EN                        1
+#define AR5K_INIT_PROG_IFS                     920
+#define AR5K_INIT_PROG_IFS_TURBO               960
+#define AR5K_INIT_EIFS                         3440
+#define AR5K_INIT_EIFS_TURBO                   6880
+#define AR5K_INIT_SLOT_TIME                    396
+#define AR5K_INIT_SLOT_TIME_TURBO              480
+#define AR5K_INIT_ACK_CTS_TIMEOUT              1024
+#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO                0x08000800
+#define AR5K_INIT_SIFS                         560
+#define AR5K_INIT_SIFS_TURBO                   480
+#define AR5K_INIT_SH_RETRY                     10
+#define AR5K_INIT_LG_RETRY                     AR5K_INIT_SH_RETRY
+#define AR5K_INIT_SSH_RETRY                    32
+#define AR5K_INIT_SLG_RETRY                    AR5K_INIT_SSH_RETRY
+#define AR5K_INIT_TX_RETRY                     10
+#define AR5K_INIT_TOPS                         8
+#define AR5K_INIT_RXNOFRM                      8
+#define AR5K_INIT_RPGTO                                0
+#define AR5K_INIT_TXNOFRM                      0
+#define AR5K_INIT_BEACON_PERIOD                        65535
+#define AR5K_INIT_TIM_OFFSET                   0
+#define AR5K_INIT_BEACON_EN                    0
+#define AR5K_INIT_RESET_TSF                    0
+
+#define AR5K_INIT_TRANSMIT_LATENCY             (                       \
+       (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |       \
+       (AR5K_INIT_USEC)                                                \
+)
+#define AR5K_INIT_TRANSMIT_LATENCY_TURBO       (                       \
+       (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |       \
+       (AR5K_INIT_USEC_TURBO)                                          \
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL             (                       \
+       (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |      \
+       (AR5K_INIT_PROG_IFS)                                            \
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO       (                       \
+       (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
+       (AR5K_INIT_PROG_IFS_TURBO)                                      \
+)
+#define AR5K_INIT_BEACON_CONTROL               (                       \
+       (AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) |     \
+       (AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD)        \
+)
+
+/*
+ * Non-common initial register values which have to be loaded into the
+ * card at boot time and after each reset.
+ */
+
+/* Register dumps are done per operation mode */
+#define AR5K_INI_RFGAIN_5GHZ           0
+#define AR5K_INI_RFGAIN_2GHZ           1
+
+#define AR5K_INI_VAL_11A               0
+#define AR5K_INI_VAL_11A_TURBO         1
+#define AR5K_INI_VAL_11B               2
+#define AR5K_INI_VAL_11G               3
+#define AR5K_INI_VAL_11G_TURBO         4
+#define AR5K_INI_VAL_XR                        0
+#define AR5K_INI_VAL_MAX               5
+
+#define AR5K_RF5111_INI_RF_MAX_BANKS   AR5K_MAX_RF_BANKS
+#define AR5K_RF5112_INI_RF_MAX_BANKS   AR5K_MAX_RF_BANKS
+
+static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
+{
+       u32 retval = 0, bit, i;
+
+       for (i = 0; i < bits; i++) {
+               bit = (val >> i) & 1;
+               retval = (retval << 1) | bit;
+       }
+
+       return retval;
+}
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c
new file mode 100644 (file)
index 0000000..2c22f1d
--- /dev/null
@@ -0,0 +1,1347 @@
+/*
+ * Initial register settings functions
+ *
+ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#include "ath5k.h"
+#include "base.h"
+#include "reg.h"
+
+/*
+ * MAC/PHY REGISTERS
+ */
+
+
+/*
+ * Mode-independent initial register writes
+ */
+
+struct ath5k_ini {
+       u16     ini_register;
+       u32     ini_value;
+
+       enum {
+               AR5K_INI_WRITE = 0,     /* Default */
+               AR5K_INI_READ = 1,      /* Cleared on read */
+       } ini_mode;
+};
+
+/*
+ * Mode specific initial register values
+ */
+
+struct ath5k_ini_mode {
+       u16     mode_register;
+       u32     mode_value[5];
+};
+
+/* Initial register settings for AR5210 */
+static const struct ath5k_ini ar5210_ini[] = {
+       /* PCU and MAC registers */
+       { AR5K_NOQCU_TXDP0,     0 },
+       { AR5K_NOQCU_TXDP1,     0 },
+       { AR5K_RXDP,            0 },
+       { AR5K_CR,              0 },
+       { AR5K_ISR,             0, AR5K_INI_READ },
+       { AR5K_IMR,             0 },
+       { AR5K_IER,             AR5K_IER_DISABLE },
+       { AR5K_BSR,             0, AR5K_INI_READ },
+       { AR5K_TXCFG,           AR5K_DMASIZE_128B },
+       { AR5K_RXCFG,           AR5K_DMASIZE_128B },
+       { AR5K_CFG,             AR5K_INIT_CFG },
+       { AR5K_TOPS,            AR5K_INIT_TOPS },
+       { AR5K_RXNOFRM,         AR5K_INIT_RXNOFRM },
+       { AR5K_RPGTO,           AR5K_INIT_RPGTO },
+       { AR5K_TXNOFRM,         AR5K_INIT_TXNOFRM },
+       { AR5K_SFR,             0 },
+       { AR5K_MIBC,            0 },
+       { AR5K_MISC,            0 },
+       { AR5K_RX_FILTER_5210,  0 },
+       { AR5K_MCAST_FILTER0_5210, 0 },
+       { AR5K_MCAST_FILTER1_5210, 0 },
+       { AR5K_TX_MASK0,        0 },
+       { AR5K_TX_MASK1,        0 },
+       { AR5K_CLR_TMASK,       0 },
+       { AR5K_TRIG_LVL,        AR5K_TUNE_MIN_TX_FIFO_THRES },
+       { AR5K_DIAG_SW_5210,    0 },
+       { AR5K_RSSI_THR,        AR5K_TUNE_RSSI_THRES },
+       { AR5K_TSF_L32_5210,    0 },
+       { AR5K_TIMER0_5210,     0 },
+       { AR5K_TIMER1_5210,     0xffffffff },
+       { AR5K_TIMER2_5210,     0xffffffff },
+       { AR5K_TIMER3_5210,     1 },
+       { AR5K_CFP_DUR_5210,    0 },
+       { AR5K_CFP_PERIOD_5210, 0 },
+       /* PHY registers */
+       { AR5K_PHY(0),  0x00000047 },
+       { AR5K_PHY_AGC, 0x00000000 },
+       { AR5K_PHY(3),  0x09848ea6 },
+       { AR5K_PHY(4),  0x3d32e000 },
+       { AR5K_PHY(5),  0x0000076b },
+       { AR5K_PHY_ACT, AR5K_PHY_ACT_DISABLE },
+       { AR5K_PHY(8),  0x02020200 },
+       { AR5K_PHY(9),  0x00000e0e },
+       { AR5K_PHY(10), 0x0a020201 },
+       { AR5K_PHY(11), 0x00036ffc },
+       { AR5K_PHY(12), 0x00000000 },
+       { AR5K_PHY(13), 0x00000e0e },
+       { AR5K_PHY(14), 0x00000007 },
+       { AR5K_PHY(15), 0x00020100 },
+       { AR5K_PHY(16), 0x89630000 },
+       { AR5K_PHY(17), 0x1372169c },
+       { AR5K_PHY(18), 0x0018b633 },
+       { AR5K_PHY(19), 0x1284613c },
+       { AR5K_PHY(20), 0x0de8b8e0 },
+       { AR5K_PHY(21), 0x00074859 },
+       { AR5K_PHY(22), 0x7e80beba },
+       { AR5K_PHY(23), 0x313a665e },
+       { AR5K_PHY_AGCCTL, 0x00001d08 },
+       { AR5K_PHY(25), 0x0001ce00 },
+       { AR5K_PHY(26), 0x409a4190 },
+       { AR5K_PHY(28), 0x0000000f },
+       { AR5K_PHY(29), 0x00000080 },
+       { AR5K_PHY(30), 0x00000004 },
+       { AR5K_PHY(31), 0x00000018 },   /* 0x987c */
+       { AR5K_PHY(64), 0x00000000 },   /* 0x9900 */
+       { AR5K_PHY(65), 0x00000000 },
+       { AR5K_PHY(66), 0x00000000 },
+       { AR5K_PHY(67), 0x00800000 },
+       { AR5K_PHY(68), 0x00000003 },
+       /* BB gain table (64bytes) */
+       { AR5K_BB_GAIN(0), 0x00000000 },
+       { AR5K_BB_GAIN(1), 0x00000020 },
+       { AR5K_BB_GAIN(2), 0x00000010 },
+       { AR5K_BB_GAIN(3), 0x00000030 },
+       { AR5K_BB_GAIN(4), 0x00000008 },
+       { AR5K_BB_GAIN(5), 0x00000028 },
+       { AR5K_BB_GAIN(6), 0x00000028 },
+       { AR5K_BB_GAIN(7), 0x00000004 },
+       { AR5K_BB_GAIN(8), 0x00000024 },
+       { AR5K_BB_GAIN(9), 0x00000014 },
+       { AR5K_BB_GAIN(10), 0x00000034 },
+       { AR5K_BB_GAIN(11), 0x0000000c },
+       { AR5K_BB_GAIN(12), 0x0000002c },
+       { AR5K_BB_GAIN(13), 0x00000002 },
+       { AR5K_BB_GAIN(14), 0x00000022 },
+       { AR5K_BB_GAIN(15), 0x00000012 },
+       { AR5K_BB_GAIN(16), 0x00000032 },
+       { AR5K_BB_GAIN(17), 0x0000000a },
+       { AR5K_BB_GAIN(18), 0x0000002a },
+       { AR5K_BB_GAIN(19), 0x00000001 },
+       { AR5K_BB_GAIN(20), 0x00000021 },
+       { AR5K_BB_GAIN(21), 0x00000011 },
+       { AR5K_BB_GAIN(22), 0x00000031 },
+       { AR5K_BB_GAIN(23), 0x00000009 },
+       { AR5K_BB_GAIN(24), 0x00000029 },
+       { AR5K_BB_GAIN(25), 0x00000005 },
+       { AR5K_BB_GAIN(26), 0x00000025 },
+       { AR5K_BB_GAIN(27), 0x00000015 },
+       { AR5K_BB_GAIN(28), 0x00000035 },
+       { AR5K_BB_GAIN(29), 0x0000000d },
+       { AR5K_BB_GAIN(30), 0x0000002d },
+       { AR5K_BB_GAIN(31), 0x00000003 },
+       { AR5K_BB_GAIN(32), 0x00000023 },
+       { AR5K_BB_GAIN(33), 0x00000013 },
+       { AR5K_BB_GAIN(34), 0x00000033 },
+       { AR5K_BB_GAIN(35), 0x0000000b },
+       { AR5K_BB_GAIN(36), 0x0000002b },
+       { AR5K_BB_GAIN(37), 0x00000007 },
+       { AR5K_BB_GAIN(38), 0x00000027 },
+       { AR5K_BB_GAIN(39), 0x00000017 },
+       { AR5K_BB_GAIN(40), 0x00000037 },
+       { AR5K_BB_GAIN(41), 0x0000000f },
+       { AR5K_BB_GAIN(42), 0x0000002f },
+       { AR5K_BB_GAIN(43), 0x0000002f },
+       { AR5K_BB_GAIN(44), 0x0000002f },
+       { AR5K_BB_GAIN(45), 0x0000002f },
+       { AR5K_BB_GAIN(46), 0x0000002f },
+       { AR5K_BB_GAIN(47), 0x0000002f },
+       { AR5K_BB_GAIN(48), 0x0000002f },
+       { AR5K_BB_GAIN(49), 0x0000002f },
+       { AR5K_BB_GAIN(50), 0x0000002f },
+       { AR5K_BB_GAIN(51), 0x0000002f },
+       { AR5K_BB_GAIN(52), 0x0000002f },
+       { AR5K_BB_GAIN(53), 0x0000002f },
+       { AR5K_BB_GAIN(54), 0x0000002f },
+       { AR5K_BB_GAIN(55), 0x0000002f },
+       { AR5K_BB_GAIN(56), 0x0000002f },
+       { AR5K_BB_GAIN(57), 0x0000002f },
+       { AR5K_BB_GAIN(58), 0x0000002f },
+       { AR5K_BB_GAIN(59), 0x0000002f },
+       { AR5K_BB_GAIN(60), 0x0000002f },
+       { AR5K_BB_GAIN(61), 0x0000002f },
+       { AR5K_BB_GAIN(62), 0x0000002f },
+       { AR5K_BB_GAIN(63), 0x0000002f },
+       /* 5110 RF gain table (64btes) */
+       { AR5K_RF_GAIN(0), 0x0000001d },
+       { AR5K_RF_GAIN(1), 0x0000005d },
+       { AR5K_RF_GAIN(2), 0x0000009d },
+       { AR5K_RF_GAIN(3), 0x000000dd },
+       { AR5K_RF_GAIN(4), 0x0000011d },
+       { AR5K_RF_GAIN(5), 0x00000021 },
+       { AR5K_RF_GAIN(6), 0x00000061 },
+       { AR5K_RF_GAIN(7), 0x000000a1 },
+       { AR5K_RF_GAIN(8), 0x000000e1 },
+       { AR5K_RF_GAIN(9), 0x00000031 },
+       { AR5K_RF_GAIN(10), 0x00000071 },
+       { AR5K_RF_GAIN(11), 0x000000b1 },
+       { AR5K_RF_GAIN(12), 0x0000001c },
+       { AR5K_RF_GAIN(13), 0x0000005c },
+       { AR5K_RF_GAIN(14), 0x00000029 },
+       { AR5K_RF_GAIN(15), 0x00000069 },
+       { AR5K_RF_GAIN(16), 0x000000a9 },
+       { AR5K_RF_GAIN(17), 0x00000020 },
+       { AR5K_RF_GAIN(18), 0x00000019 },
+       { AR5K_RF_GAIN(19), 0x00000059 },
+       { AR5K_RF_GAIN(20), 0x00000099 },
+       { AR5K_RF_GAIN(21), 0x00000030 },
+       { AR5K_RF_GAIN(22), 0x00000005 },
+       { AR5K_RF_GAIN(23), 0x00000025 },
+       { AR5K_RF_GAIN(24), 0x00000065 },
+       { AR5K_RF_GAIN(25), 0x000000a5 },
+       { AR5K_RF_GAIN(26), 0x00000028 },
+       { AR5K_RF_GAIN(27), 0x00000068 },
+       { AR5K_RF_GAIN(28), 0x0000001f },
+       { AR5K_RF_GAIN(29), 0x0000001e },
+       { AR5K_RF_GAIN(30), 0x00000018 },
+       { AR5K_RF_GAIN(31), 0x00000058 },
+       { AR5K_RF_GAIN(32), 0x00000098 },
+       { AR5K_RF_GAIN(33), 0x00000003 },
+       { AR5K_RF_GAIN(34), 0x00000004 },
+       { AR5K_RF_GAIN(35), 0x00000044 },
+       { AR5K_RF_GAIN(36), 0x00000084 },
+       { AR5K_RF_GAIN(37), 0x00000013 },
+       { AR5K_RF_GAIN(38), 0x00000012 },
+       { AR5K_RF_GAIN(39), 0x00000052 },
+       { AR5K_RF_GAIN(40), 0x00000092 },
+       { AR5K_RF_GAIN(41), 0x000000d2 },
+       { AR5K_RF_GAIN(42), 0x0000002b },
+       { AR5K_RF_GAIN(43), 0x0000002a },
+       { AR5K_RF_GAIN(44), 0x0000006a },
+       { AR5K_RF_GAIN(45), 0x000000aa },
+       { AR5K_RF_GAIN(46), 0x0000001b },
+       { AR5K_RF_GAIN(47), 0x0000001a },
+       { AR5K_RF_GAIN(48), 0x0000005a },
+       { AR5K_RF_GAIN(49), 0x0000009a },
+       { AR5K_RF_GAIN(50), 0x000000da },
+       { AR5K_RF_GAIN(51), 0x00000006 },
+       { AR5K_RF_GAIN(52), 0x00000006 },
+       { AR5K_RF_GAIN(53), 0x00000006 },
+       { AR5K_RF_GAIN(54), 0x00000006 },
+       { AR5K_RF_GAIN(55), 0x00000006 },
+       { AR5K_RF_GAIN(56), 0x00000006 },
+       { AR5K_RF_GAIN(57), 0x00000006 },
+       { AR5K_RF_GAIN(58), 0x00000006 },
+       { AR5K_RF_GAIN(59), 0x00000006 },
+       { AR5K_RF_GAIN(60), 0x00000006 },
+       { AR5K_RF_GAIN(61), 0x00000006 },
+       { AR5K_RF_GAIN(62), 0x00000006 },
+       { AR5K_RF_GAIN(63), 0x00000006 },
+       /* PHY activation */
+       { AR5K_PHY(53), 0x00000020 },
+       { AR5K_PHY(51), 0x00000004 },
+       { AR5K_PHY(50), 0x00060106 },
+       { AR5K_PHY(39), 0x0000006d },
+       { AR5K_PHY(48), 0x00000000 },
+       { AR5K_PHY(52), 0x00000014 },
+       { AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE },
+};
+
+/* Initial register settings for AR5211 */
+static const struct ath5k_ini ar5211_ini[] = {
+       { AR5K_RXDP,            0x00000000 },
+       { AR5K_RTSD0,           0x84849c9c },
+       { AR5K_RTSD1,           0x7c7c7c7c },
+       { AR5K_RXCFG,           0x00000005 },
+       { AR5K_MIBC,            0x00000000 },
+       { AR5K_TOPS,            0x00000008 },
+       { AR5K_RXNOFRM,         0x00000008 },
+       { AR5K_TXNOFRM,         0x00000010 },
+       { AR5K_RPGTO,           0x00000000 },
+       { AR5K_RFCNT,           0x0000001f },
+       { AR5K_QUEUE_TXDP(0),   0x00000000 },
+       { AR5K_QUEUE_TXDP(1),   0x00000000 },
+       { AR5K_QUEUE_TXDP(2),   0x00000000 },
+       { AR5K_QUEUE_TXDP(3),   0x00000000 },
+       { AR5K_QUEUE_TXDP(4),   0x00000000 },
+       { AR5K_QUEUE_TXDP(5),   0x00000000 },
+       { AR5K_QUEUE_TXDP(6),   0x00000000 },
+       { AR5K_QUEUE_TXDP(7),   0x00000000 },
+       { AR5K_QUEUE_TXDP(8),   0x00000000 },
+       { AR5K_QUEUE_TXDP(9),   0x00000000 },
+       { AR5K_DCU_FP,          0x00000000 },
+       { AR5K_STA_ID1,         0x00000000 },
+       { AR5K_BSS_ID0,         0x00000000 },
+       { AR5K_BSS_ID1,         0x00000000 },
+       { AR5K_RSSI_THR,        0x00000000 },
+       { AR5K_CFP_PERIOD_5211, 0x00000000 },
+       { AR5K_TIMER0_5211,     0x00000030 },
+       { AR5K_TIMER1_5211,     0x0007ffff },
+       { AR5K_TIMER2_5211,     0x01ffffff },
+       { AR5K_TIMER3_5211,     0x00000031 },
+       { AR5K_CFP_DUR_5211,    0x00000000 },
+       { AR5K_RX_FILTER_5211,  0x00000000 },
+       { AR5K_MCAST_FILTER0_5211, 0x00000000 },
+       { AR5K_MCAST_FILTER1_5211, 0x00000002 },
+       { AR5K_DIAG_SW_5211,    0x00000000 },
+       { AR5K_ADDAC_TEST,      0x00000000 },
+       { AR5K_DEFAULT_ANTENNA, 0x00000000 },
+       /* PHY registers */
+       { AR5K_PHY_AGC, 0x00000000 },
+       { AR5K_PHY(3),  0x2d849093 },
+       { AR5K_PHY(4),  0x7d32e000 },
+       { AR5K_PHY(5),  0x00000f6b },
+       { AR5K_PHY_ACT, 0x00000000 },
+       { AR5K_PHY(11), 0x00026ffe },
+       { AR5K_PHY(12), 0x00000000 },
+       { AR5K_PHY(15), 0x00020100 },
+       { AR5K_PHY(16), 0x206a017a },
+       { AR5K_PHY(19), 0x1284613c },
+       { AR5K_PHY(21), 0x00000859 },
+       { AR5K_PHY(26), 0x409a4190 },   /* 0x9868 */
+       { AR5K_PHY(27), 0x050cb081 },
+       { AR5K_PHY(28), 0x0000000f },
+       { AR5K_PHY(29), 0x00000080 },
+       { AR5K_PHY(30), 0x0000000c },
+       { AR5K_PHY(64), 0x00000000 },
+       { AR5K_PHY(65), 0x00000000 },
+       { AR5K_PHY(66), 0x00000000 },
+       { AR5K_PHY(67), 0x00800000 },
+       { AR5K_PHY(68), 0x00000001 },
+       { AR5K_PHY(71), 0x0000092a },
+       { AR5K_PHY_IQ,  0x00000000 },
+       { AR5K_PHY(73), 0x00058a05 },
+       { AR5K_PHY(74), 0x00000001 },
+       { AR5K_PHY(75), 0x00000000 },
+       { AR5K_PHY_PAPD_PROBE, 0x00000000 },
+       { AR5K_PHY(77), 0x00000000 },   /* 0x9934 */
+       { AR5K_PHY(78), 0x00000000 },   /* 0x9938 */
+       { AR5K_PHY(79), 0x0000003f },   /* 0x993c */
+       { AR5K_PHY(80), 0x00000004 },
+       { AR5K_PHY(82), 0x00000000 },
+       { AR5K_PHY(83), 0x00000000 },
+       { AR5K_PHY(84), 0x00000000 },
+       { AR5K_PHY_RADAR, 0x5d50f14c },
+       { AR5K_PHY(86), 0x00000018 },
+       { AR5K_PHY(87), 0x004b6a8e },
+       /* Initial Power table (32bytes)
+        * common on all cards/modes.
+        * Note: Table is rewritten during
+        * txpower setup later using calibration
+        * data etc. so next write is non-common
+       { AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff },
+       { AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff },
+       { AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff },
+       { AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff },
+       { AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff },
+       { AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff },
+       { AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff },
+       { AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff },
+       { AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff },
+       { AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff },
+       { AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff },
+       { AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff },
+       { AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff },
+       { AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff },
+       { AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff },
+       { AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff },
+       { AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff },
+       { AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff },
+       { AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff },
+       { AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff },
+       { AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff },
+       { AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff },*/
+       { AR5K_PHY_CCKTXCTL, 0x00000000 },
+       { AR5K_PHY(642), 0x503e4646 },
+       { AR5K_PHY_GAIN_2GHZ, 0x6480416c },
+       { AR5K_PHY(644), 0x0199a003 },
+       { AR5K_PHY(645), 0x044cd610 },
+       { AR5K_PHY(646), 0x13800040 },
+       { AR5K_PHY(647), 0x1be00060 },
+       { AR5K_PHY(648), 0x0c53800a },
+       { AR5K_PHY(649), 0x0014df3b },
+       { AR5K_PHY(650), 0x000001b5 },
+       { AR5K_PHY(651), 0x00000020 },
+};
+
+/* Initial mode-specific settings for AR5211
+ * XXX: how about g / gTurbo ? RF5111 supports it, how about AR5211 ?
+ * Maybe 5211 supports OFDM-only g but we need to test it !
+ */
+static const struct ath5k_ini_mode ar5211_ini_mode[] = {
+       { AR5K_TXCFG,
+       /*        a           aTurbo      b             */
+               { 0x00000015, 0x00000015, 0x0000001d } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(0),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(1),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(2),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(3),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(4),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(5),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(6),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(7),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(8),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(9),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+       { AR5K_DCU_GBL_IFS_SLOT,
+               { 0x00000168, 0x000001e0, 0x000001b8 } },
+       { AR5K_DCU_GBL_IFS_SIFS,
+               { 0x00000230, 0x000001e0, 0x000000b0 } },
+       { AR5K_DCU_GBL_IFS_EIFS,
+               { 0x00000d98, 0x00001180, 0x00001f48 } },
+       { AR5K_DCU_GBL_IFS_MISC,
+               { 0x0000a0e0, 0x00014068, 0x00005880 } },
+       { AR5K_TIME_OUT,
+               { 0x04000400, 0x08000800, 0x20003000 } },
+       { AR5K_USEC_5211,
+               { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95 } },
+       { AR5K_PHY_TURBO,
+               { 0x00000000, 0x00000003, 0x00000000 } },
+       { AR5K_PHY(8),
+               { 0x02020200, 0x02020200, 0x02010200 } },
+       { AR5K_PHY(9),
+               { 0x00000e0e, 0x00000e0e, 0x00000707 } },
+       { AR5K_PHY(10),
+               { 0x0a020001, 0x0a020001, 0x05010000 } },
+       { AR5K_PHY(13),
+               { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+       { AR5K_PHY(14),
+               { 0x00000007, 0x00000007, 0x0000000b } },
+       { AR5K_PHY(17),
+               { 0x1372169c, 0x137216a5, 0x137216a8 } },
+       { AR5K_PHY(18),
+               { 0x0018ba67, 0x0018ba67, 0x0018ba69 } },
+       { AR5K_PHY(20),
+               { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
+       { AR5K_PHY_SIG,
+               { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e } },
+       { AR5K_PHY_AGCCOARSE,
+               { 0x31375d5e, 0x31375d5e, 0x313a5d5e } },
+       { AR5K_PHY_AGCCTL,
+               { 0x0000bd10, 0x0000bd10, 0x0000bd38 } },
+       { AR5K_PHY_NF,
+               { 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+       { AR5K_PHY_RX_DELAY,
+               { 0x00002710, 0x00002710, 0x0000157c } },
+       { AR5K_PHY(70),
+               { 0x00000190, 0x00000190, 0x00000084 } },
+       { AR5K_PHY_FRAME_CTL_5211,
+               { 0x6fe01020, 0x6fe01020, 0x6fe00920 } },
+       { AR5K_PHY_PCDAC_TXPOWER_BASE_5211,
+               { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff } },
+       { AR5K_RF_BUFFER_CONTROL_4,
+               { 0x00000010, 0x00000014, 0x00000010 } },
+};
+
+/* Initial register settings for AR5212 */
+static const struct ath5k_ini ar5212_ini[] = {
+       { AR5K_RXDP,            0x00000000 },
+       { AR5K_RXCFG,           0x00000005 },
+       { AR5K_MIBC,            0x00000000 },
+       { AR5K_TOPS,            0x00000008 },
+       { AR5K_RXNOFRM,         0x00000008 },
+       { AR5K_TXNOFRM,         0x00000010 },
+       { AR5K_RPGTO,           0x00000000 },
+       { AR5K_RFCNT,           0x0000001f },
+       { AR5K_QUEUE_TXDP(0),   0x00000000 },
+       { AR5K_QUEUE_TXDP(1),   0x00000000 },
+       { AR5K_QUEUE_TXDP(2),   0x00000000 },
+       { AR5K_QUEUE_TXDP(3),   0x00000000 },
+       { AR5K_QUEUE_TXDP(4),   0x00000000 },
+       { AR5K_QUEUE_TXDP(5),   0x00000000 },
+       { AR5K_QUEUE_TXDP(6),   0x00000000 },
+       { AR5K_QUEUE_TXDP(7),   0x00000000 },
+       { AR5K_QUEUE_TXDP(8),   0x00000000 },
+       { AR5K_QUEUE_TXDP(9),   0x00000000 },
+       { AR5K_DCU_FP,          0x00000000 },
+       { AR5K_DCU_TXP,         0x00000000 },
+       { AR5K_DCU_TX_FILTER,   0x00000000 },
+       /* Unknown table */
+       { 0x1078, 0x00000000 },
+       { 0x10b8, 0x00000000 },
+       { 0x10f8, 0x00000000 },
+       { 0x1138, 0x00000000 },
+       { 0x1178, 0x00000000 },
+       { 0x11b8, 0x00000000 },
+       { 0x11f8, 0x00000000 },
+       { 0x1238, 0x00000000 },
+       { 0x1278, 0x00000000 },
+       { 0x12b8, 0x00000000 },
+       { 0x12f8, 0x00000000 },
+       { 0x1338, 0x00000000 },
+       { 0x1378, 0x00000000 },
+       { 0x13b8, 0x00000000 },
+       { 0x13f8, 0x00000000 },
+       { 0x1438, 0x00000000 },
+       { 0x1478, 0x00000000 },
+       { 0x14b8, 0x00000000 },
+       { 0x14f8, 0x00000000 },
+       { 0x1538, 0x00000000 },
+       { 0x1578, 0x00000000 },
+       { 0x15b8, 0x00000000 },
+       { 0x15f8, 0x00000000 },
+       { 0x1638, 0x00000000 },
+       { 0x1678, 0x00000000 },
+       { 0x16b8, 0x00000000 },
+       { 0x16f8, 0x00000000 },
+       { 0x1738, 0x00000000 },
+       { 0x1778, 0x00000000 },
+       { 0x17b8, 0x00000000 },
+       { 0x17f8, 0x00000000 },
+       { 0x103c, 0x00000000 },
+       { 0x107c, 0x00000000 },
+       { 0x10bc, 0x00000000 },
+       { 0x10fc, 0x00000000 },
+       { 0x113c, 0x00000000 },
+       { 0x117c, 0x00000000 },
+       { 0x11bc, 0x00000000 },
+       { 0x11fc, 0x00000000 },
+       { 0x123c, 0x00000000 },
+       { 0x127c, 0x00000000 },
+       { 0x12bc, 0x00000000 },
+       { 0x12fc, 0x00000000 },
+       { 0x133c, 0x00000000 },
+       { 0x137c, 0x00000000 },
+       { 0x13bc, 0x00000000 },
+       { 0x13fc, 0x00000000 },
+       { 0x143c, 0x00000000 },
+       { 0x147c, 0x00000000 },
+       { AR5K_DCU_TX_FILTER_CLR, 0x00000000 },
+       { AR5K_DCU_TX_FILTER_SET, 0x00000000 },
+       { AR5K_STA_ID1,         0x00000000 },
+       { AR5K_BSS_ID0,         0x00000000 },
+       { AR5K_BSS_ID1,         0x00000000 },
+       /*{ AR5K_RSSI_THR,      0x00000000 },*/ /* Found on SuperAG cards */
+       { AR5K_BEACON_5211,     0x00000000 },   /* Found on SuperAG cards */
+       { AR5K_CFP_PERIOD_5211, 0x00000000 },   /* Found on SuperAG cards */
+       { AR5K_TIMER0_5211,     0x00000030 },   /* Found on SuperAG cards */
+       { AR5K_TIMER1_5211,     0x0007ffff },   /* Found on SuperAG cards */
+       { AR5K_TIMER2_5211,     0x01ffffff },   /* Found on SuperAG cards */
+       { AR5K_TIMER3_5211,     0x00000031 },   /* Found on SuperAG cards */
+       { AR5K_CFP_DUR_5211,    0x00000000 },   /* Found on SuperAG cards */
+       { AR5K_RX_FILTER_5211,  0x00000000 },
+       { AR5K_DIAG_SW_5211,    0x00000000 },
+       { AR5K_ADDAC_TEST,      0x00000000 },
+       { AR5K_DEFAULT_ANTENNA, 0x00000000 },
+       { 0x8080, 0x00000000 },
+       /*{ 0x805c, 0xffffc7ff },*/ /* Old value */
+       { 0x805c, 0x000fc78f },
+       { AR5K_NAV_5211,        0x00000000 },   /* Not found on recent */
+       { AR5K_RTS_OK_5211,     0x00000000 },   /* dumps but it makes  */
+       { AR5K_RTS_FAIL_5211,   0x00000000 },   /* sense to reset counters */
+       { AR5K_ACK_FAIL_5211,   0x00000000 },   /* since pcu registers */
+       { AR5K_FCS_FAIL_5211,   0x00000000 },   /* are skiped during chan*/
+       { AR5K_BEACON_CNT_5211, 0x00000000 },   /* change */
+       { AR5K_XRMODE,          0x2a82301a },
+       { AR5K_XRDELAY,         0x05dc01e0 },
+       { AR5K_XRTIMEOUT,       0x1f402710 },
+       { AR5K_XRCHIRP,         0x01f40000 },
+       { AR5K_XRSTOMP,         0x00001e1c },
+       { AR5K_SLEEP0,          0x0002aaaa },   /* Found on SuperAG cards */
+       { AR5K_SLEEP1,          0x02005555 },   /* Found on SuperAG cards */
+       { AR5K_SLEEP2,          0x00000000 },   /* Found on SuperAG cards */
+       { AR5K_BSS_IDM0,        0xffffffff },
+       { AR5K_BSS_IDM1,        0x0000ffff },
+       { AR5K_TXPC,            0x00000000 },
+       { AR5K_PROFCNT_TX,      0x00000000 },
+       { AR5K_PROFCNT_RX,      0x00000000 },
+       { AR5K_PROFCNT_RXCLR,   0x00000000 },
+       { AR5K_PROFCNT_CYCLE,   0x00000000 },
+       { 0x80fc, 0x00000088 },
+       { AR5K_RATE_DUR(0),     0x00000000 },
+       { AR5K_RATE_DUR(1),     0x0000008c },
+       { AR5K_RATE_DUR(2),     0x000000e4 },
+       { AR5K_RATE_DUR(3),     0x000002d5 },
+       { AR5K_RATE_DUR(4),     0x00000000 },
+       { AR5K_RATE_DUR(5),     0x00000000 },
+       { AR5K_RATE_DUR(6),     0x000000a0 },
+       { AR5K_RATE_DUR(7),     0x000001c9 },
+       { AR5K_RATE_DUR(8),     0x0000002c },
+       { AR5K_RATE_DUR(9),     0x0000002c },
+       { AR5K_RATE_DUR(10),    0x00000030 },
+       { AR5K_RATE_DUR(11),    0x0000003c },
+       { AR5K_RATE_DUR(12),    0x0000002c },
+       { AR5K_RATE_DUR(13),    0x0000002c },
+       { AR5K_RATE_DUR(14),    0x00000030 },
+       { AR5K_RATE_DUR(15),    0x0000003c },
+       { AR5K_RATE_DUR(16),    0x00000000 },
+       { AR5K_RATE_DUR(17),    0x00000000 },
+       { AR5K_RATE_DUR(18),    0x00000000 },
+       { AR5K_RATE_DUR(19),    0x00000000 },
+       { AR5K_RATE_DUR(20),    0x00000000 },
+       { AR5K_RATE_DUR(21),    0x00000000 },
+       { AR5K_RATE_DUR(22),    0x00000000 },
+       { AR5K_RATE_DUR(23),    0x00000000 },
+       { AR5K_RATE_DUR(24),    0x000000d5 },
+       { AR5K_RATE_DUR(25),    0x000000df },
+       { AR5K_RATE_DUR(26),    0x00000102 },
+       { AR5K_RATE_DUR(27),    0x0000013a },
+       { AR5K_RATE_DUR(28),    0x00000075 },
+       { AR5K_RATE_DUR(29),    0x0000007f },
+       { AR5K_RATE_DUR(30),    0x000000a2 },
+       { AR5K_RATE_DUR(31),    0x00000000 },
+       { 0x8100, 0x00010002},
+       { AR5K_TSF_PARM,        0x00000001 },
+       { 0x8108, 0x000000c0 },
+       { AR5K_PHY_ERR_FIL,     0x00000000 },
+       { 0x8110, 0x00000168 },
+       { 0x8114, 0x00000000 },
+       /* Some kind of table
+        * also notice ...03<-02<-01<-00) */
+       { 0x87c0, 0x03020100 },
+       { 0x87c4, 0x07060504 },
+       { 0x87c8, 0x0b0a0908 },
+       { 0x87cc, 0x0f0e0d0c },
+       { 0x87d0, 0x13121110 },
+       { 0x87d4, 0x17161514 },
+       { 0x87d8, 0x1b1a1918 },
+       { 0x87dc, 0x1f1e1d1c },
+       /* loop ? */
+       { 0x87e0, 0x03020100 },
+       { 0x87e4, 0x07060504 },
+       { 0x87e8, 0x0b0a0908 },
+       { 0x87ec, 0x0f0e0d0c },
+       { 0x87f0, 0x13121110 },
+       { 0x87f4, 0x17161514 },
+       { 0x87f8, 0x1b1a1918 },
+       { 0x87fc, 0x1f1e1d1c },
+       /* PHY registers */
+       /*{ AR5K_PHY_AGC, 0x00000000 },*/
+       { AR5K_PHY(3),  0xad848e19 },
+       { AR5K_PHY(4),  0x7d28e000 },
+       { AR5K_PHY_TIMING_3, 0x9c0a9f6b },
+       { AR5K_PHY_ACT, 0x00000000 },
+       /*{ AR5K_PHY(11), 0x00022ffe },*/
+       /*{ AR5K_PHY(15), 0x00020100 },*/
+       { AR5K_PHY(16), 0x206a017a },
+       /*{ AR5K_PHY(19), 0x1284613c },*/
+       { AR5K_PHY(21), 0x00000859 },
+       { AR5K_PHY(64), 0x00000000 },
+       { AR5K_PHY(65), 0x00000000 },
+       { AR5K_PHY(66), 0x00000000 },
+       { AR5K_PHY(67), 0x00800000 },
+       { AR5K_PHY(68), 0x00000001 },
+       /*{ AR5K_PHY(71), 0x0000092a },*/ /* Old value */
+       { AR5K_PHY(71), 0x00000c80 },
+       { AR5K_PHY_IQ,  0x05100000 },
+       { AR5K_PHY(74), 0x00000001 },
+       { AR5K_PHY(75), 0x00000004 },
+       { AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022 },
+       { AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d },
+       { AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f },
+       /*{ AR5K_PHY(80), 0x00000004 },*/
+       { AR5K_PHY(82), 0x9280b212 },
+       { AR5K_PHY_RADAR, 0x5d50e188 },
+       /*{ AR5K_PHY(86), 0x000000ff },*/
+       { AR5K_PHY(87), 0x004b6a8e },
+       { AR5K_PHY(90), 0x000003ce },
+       { AR5K_PHY(92), 0x192fb515 },
+       /*{ AR5K_PHY(93), 0x00000000 },*/
+       { AR5K_PHY(94), 0x00000001 },
+       { AR5K_PHY(95), 0x00000000 },
+       /*{ AR5K_PHY(644), 0x0080a333 },*/ /* Old value */
+       /*{ AR5K_PHY(645), 0x00206c10 },*/ /* Old value */
+       { AR5K_PHY(644), 0x00806333 },
+       { AR5K_PHY(645), 0x00106c10 },
+       { AR5K_PHY(646), 0x009c4060 },
+       /*{ AR5K_PHY(647), 0x1483800a },*/ /* Old value */
+       { AR5K_PHY(647), 0x1483800a },
+       { AR5K_PHY(648), 0x01831061 },
+       { AR5K_PHY(649), 0x00000400 },
+       /*{ AR5K_PHY(650), 0x000001b5 },*/
+       { AR5K_PHY(651), 0x00000000 },
+       { AR5K_PHY_TXPOWER_RATE3, 0x20202020 },
+       { AR5K_PHY_TXPOWER_RATE2, 0x20202020 },
+       /*{ AR5K_PHY(655), 0x13c889af },*/
+       { AR5K_PHY(656), 0x38490a20 },
+       { AR5K_PHY(657), 0x00007bb6 },
+       { AR5K_PHY(658), 0x0fff3ffc },
+       /*{ AR5K_PHY_CCKTXCTL, 0x00000000 },*/
+};
+
+/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */
+static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
+       { AR5K_PHY(640),
+       /*        a/XR        aTurbo      b           g (DYN)     gTurbo */
+               { 0x00000008, 0x00000008, 0x0000000b, 0x0000000e, 0x0000000e } },
+       { AR5K_PHY(0),
+               { 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(0),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(1),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(2),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(3),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(4),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(5),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(6),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(7),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(8),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_QUEUE_DFS_LOCAL_IFS(9),
+               { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       { AR5K_DCU_GBL_IFS_SIFS,
+               { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
+       { AR5K_DCU_GBL_IFS_SLOT,
+               { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
+       { AR5K_DCU_GBL_IFS_EIFS,
+               { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
+       { AR5K_DCU_GBL_IFS_MISC,
+               { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
+       { AR5K_TIME_OUT,
+               { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
+       { AR5K_PHY_TURBO,
+               { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
+       { AR5K_PHY(8),
+               { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
+       { AR5K_PHY(9),
+               { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
+       { AR5K_PHY(17),
+               { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
+       { AR5K_PHY_AGCCTL,
+               { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } },
+       { AR5K_PHY_NF,
+               { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+       { AR5K_PHY(26),
+               { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
+       { AR5K_PHY(70),
+               { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
+       { AR5K_PHY(73),
+               { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
+       { 0xa230,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
+};
+
+/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
+/* New dump pending */
+static const struct ath5k_ini_mode ar5212_rf5111_ini_mode_end[] = {
+       { AR5K_PHY(640), /* This one differs from ar5212_ini_mode_start ! */
+       /*        a/XR        aTurbo      b           g (DYN)     gTurbo */
+               { 0x00000000, 0x00000000, 0x00000003, 0x00000006, 0x00000006 } },
+       { AR5K_TXCFG,
+               { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+       { AR5K_USEC_5211,
+               { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
+       { AR5K_PHY(10),
+               { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
+       { AR5K_PHY(13),
+               { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+       { AR5K_PHY(14),
+               { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+       { AR5K_PHY(18),
+               { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
+       { AR5K_PHY(20),
+               { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+       { AR5K_PHY_SIG,
+               { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
+       { AR5K_PHY_AGCCOARSE,
+               { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
+       { AR5K_PHY(27),
+               { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
+       { AR5K_PHY_RX_DELAY,
+               { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
+       { AR5K_PHY_FRAME_CTL_5211,
+               { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
+       { AR5K_PHY_GAIN_2GHZ,
+               { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
+       { 0xa21c,
+               { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+       { AR5K_DCU_FP,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY_AGC,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY(11),
+               { 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } },
+       { AR5K_PHY(15),
+               { 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } },
+       { AR5K_PHY(19),
+               { 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } },
+       { AR5K_PHY_PAPD_PROBE,
+               { 0x00004883, 0x00004883, 0x00004883, 0x00004883, 0x00004883 } },
+       { AR5K_PHY(80),
+               { 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } },
+       { AR5K_PHY(86),
+               { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
+       { AR5K_PHY(93),
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY_SPENDING,
+               { 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0x00000018 } },
+       { AR5K_PHY_CCKTXCTL,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY(642),
+               { 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+       { 0xa23c,
+               { 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } },
+};
+
+/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
+/* XXX: No dumps for turbog yet, but i found settings from old values so it should be ok */
+static const struct ath5k_ini_mode ar5212_rf5112_ini_mode_end[] = {
+       { AR5K_TXCFG,
+       /*        a/XR        aTurbo      b           g (DYN)     gTurbo */
+               { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+       { AR5K_USEC_5211,
+               { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+       { AR5K_PHY(10),
+               { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+       { AR5K_PHY(13),
+               { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+       { AR5K_PHY(14),
+               { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+       { AR5K_PHY(18),
+               { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
+       { AR5K_PHY(20),
+               { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+       { AR5K_PHY_SIG,
+               { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } },
+       { AR5K_PHY_AGCCOARSE,
+               { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
+       { AR5K_PHY(27),
+               { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+       { AR5K_PHY_RX_DELAY,
+               { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+       { AR5K_PHY_FRAME_CTL_5211,
+               { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
+       { AR5K_PHY_CCKTXCTL,
+               { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
+       { AR5K_PHY(642),
+               { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+       { AR5K_PHY_GAIN_2GHZ,
+               { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
+       { 0xa21c,
+               { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+       { AR5K_DCU_FP,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY_AGC,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY(11),
+               { 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } },
+       { AR5K_PHY(15),
+               { 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } },
+       { AR5K_PHY(19),
+               { 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } },
+       { AR5K_PHY_PAPD_PROBE,
+               { 0x00004882, 0x00004882, 0x00004882, 0x00004882, 0x00004882 } },
+       { AR5K_PHY(80),
+               { 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } },
+       { AR5K_PHY(86),
+               { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
+       { AR5K_PHY(93),
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0xa228,
+               { 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5 } },
+       { 0xa23c,
+               { 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } },
+};
+
+/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
+/* XXX: No dumps for turbog yet, so turbog is the same with g here with some
+ * minor tweaking based on dumps from other chips */
+static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
+       { AR5K_TXCFG,
+       /*        a/XR        aTurbo      b           g           gTurbo */
+               { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+       { AR5K_USEC_5211,
+               { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+       { AR5K_PHY(10),
+               { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+       { AR5K_PHY(13),
+               { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+       { AR5K_PHY(14),
+               { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+       { AR5K_PHY(18),
+               { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
+       { AR5K_PHY(20),
+               { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+       { AR5K_PHY_SIG,
+               { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+       { AR5K_PHY_AGCCOARSE,
+               { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+       { AR5K_PHY(27),
+               { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+       { AR5K_PHY_RX_DELAY,
+               { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+       { AR5K_PHY_FRAME_CTL_5211,
+               { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+       { AR5K_PHY_CCKTXCTL,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY(642),
+               { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+       { AR5K_PHY_GAIN_2GHZ,
+               { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
+       { 0xa21c,
+               { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+       { 0xa300,
+               { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
+       { 0xa304,
+               { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
+       { 0xa308,
+               { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
+       { 0xa30c,
+               { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
+       { 0xa310,
+               { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
+       { 0xa314,
+               { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
+       { 0xa318,
+               { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
+       { 0xa31c,
+               { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
+       { 0xa320,
+               { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
+       { 0xa324,
+               { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
+       { 0xa328,
+               { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
+       { 0xa32c,
+               { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
+       { 0xa330,
+               { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
+       { 0xa334,
+               { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
+       { AR5K_DCU_FP,
+               { 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0 } },
+       { 0x4068,
+               { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
+       { 0x8060,
+               { 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f } },
+       { 0x809c,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x80a0,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x8118,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x811c,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x8120,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x8124,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x8128,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x812c,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x8130,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x8134,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x8138,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x813c,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0x8140,
+               { 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9 } },
+       { 0x8144,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY_AGC,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY(11),
+               { 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } },
+       { AR5K_PHY(15),
+               { 0x00200400, 0x00200400, 0x00200400, 0x00200400, 0x00200400 } },
+       { AR5K_PHY(19),
+               { 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c } },
+       { AR5K_PHY_SCR,
+               { 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f } },
+       { AR5K_PHY_SLMT,
+               { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+       { AR5K_PHY_SCAL,
+               { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+       { AR5K_PHY(86),
+               { 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff } },
+       { AR5K_PHY(96),
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY(97),
+               { 0x02800000, 0x02800000, 0x02800000, 0x02800000, 0x02800000 } },
+       { AR5K_PHY(104),
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY(120),
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { AR5K_PHY(121),
+               { 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } },
+       { AR5K_PHY(122),
+               { 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478 } },
+       { AR5K_PHY(123),
+               { 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa } },
+       { AR5K_PHY_SCLOCK,
+               { 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c } },
+       { AR5K_PHY_SDELAY,
+               { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
+       { AR5K_PHY_SPENDING,
+               { 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000014 } },
+       { 0xa228,
+               { 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5 } },
+       { 0xa23c,
+               { 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af } },
+       { 0xa24c,
+               { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+       { 0xa250,
+               { 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } },
+       { 0xa254,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0xa258,
+               { 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380 } },
+       { 0xa25c,
+               { 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } },
+       { 0xa260,
+               { 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01 } },
+       { 0xa264,
+               { 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11 } },
+       { 0xa268,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0xa26c,
+               { 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } },
+       { 0xa270,
+               { 0x00820820, 0x00820820, 0x00820820, 0x00820820, 0x00820820 } },
+       { 0xa274,
+               { 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa } },
+       { 0xa278,
+               { 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } },
+       { 0xa27c,
+               { 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce } },
+       { 0xa338,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0xa33c,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0xa340,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0xa344,
+               { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0xa348,
+               { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+       { 0xa34c,
+               { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+       { 0xa350,
+               { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+       { 0xa354,
+               { 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff } },
+       { 0xa358,
+               { 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } },
+       { 0xa35c,
+               { 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f } },
+       { 0xa360,
+               { 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207 } },
+       { 0xa364,
+               { 0x17601685, 0x17601685, 0x17601685, 0x17601685, 0x17601685 } },
+       { 0xa368,
+               { 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104 } },
+       { 0xa36c,
+               { 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03 } },
+       { 0xa370,
+               { 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883 } },
+       { 0xa374,
+               { 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803 } },
+       { 0xa378,
+               { 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682 } },
+       { 0xa37c,
+               { 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482 } },
+       { 0xa380,
+               { 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } },
+       { 0xa384,
+               { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
+};
+
+/*
+ * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with
+ * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI)
+ */
+
+/* RF5111 Initial BaseBand Gain settings */
+static const struct ath5k_ini rf5111_ini_bbgain[] = {
+       { AR5K_BB_GAIN(0), 0x00000000 },
+       { AR5K_BB_GAIN(1), 0x00000020 },
+       { AR5K_BB_GAIN(2), 0x00000010 },
+       { AR5K_BB_GAIN(3), 0x00000030 },
+       { AR5K_BB_GAIN(4), 0x00000008 },
+       { AR5K_BB_GAIN(5), 0x00000028 },
+       { AR5K_BB_GAIN(6), 0x00000004 },
+       { AR5K_BB_GAIN(7), 0x00000024 },
+       { AR5K_BB_GAIN(8), 0x00000014 },
+       { AR5K_BB_GAIN(9), 0x00000034 },
+       { AR5K_BB_GAIN(10), 0x0000000c },
+       { AR5K_BB_GAIN(11), 0x0000002c },
+       { AR5K_BB_GAIN(12), 0x00000002 },
+       { AR5K_BB_GAIN(13), 0x00000022 },
+       { AR5K_BB_GAIN(14), 0x00000012 },
+       { AR5K_BB_GAIN(15), 0x00000032 },
+       { AR5K_BB_GAIN(16), 0x0000000a },
+       { AR5K_BB_GAIN(17), 0x0000002a },
+       { AR5K_BB_GAIN(18), 0x00000006 },
+       { AR5K_BB_GAIN(19), 0x00000026 },
+       { AR5K_BB_GAIN(20), 0x00000016 },
+       { AR5K_BB_GAIN(21), 0x00000036 },
+       { AR5K_BB_GAIN(22), 0x0000000e },
+       { AR5K_BB_GAIN(23), 0x0000002e },
+       { AR5K_BB_GAIN(24), 0x00000001 },
+       { AR5K_BB_GAIN(25), 0x00000021 },
+       { AR5K_BB_GAIN(26), 0x00000011 },
+       { AR5K_BB_GAIN(27), 0x00000031 },
+       { AR5K_BB_GAIN(28), 0x00000009 },
+       { AR5K_BB_GAIN(29), 0x00000029 },
+       { AR5K_BB_GAIN(30), 0x00000005 },
+       { AR5K_BB_GAIN(31), 0x00000025 },
+       { AR5K_BB_GAIN(32), 0x00000015 },
+       { AR5K_BB_GAIN(33), 0x00000035 },
+       { AR5K_BB_GAIN(34), 0x0000000d },
+       { AR5K_BB_GAIN(35), 0x0000002d },
+       { AR5K_BB_GAIN(36), 0x00000003 },
+       { AR5K_BB_GAIN(37), 0x00000023 },
+       { AR5K_BB_GAIN(38), 0x00000013 },
+       { AR5K_BB_GAIN(39), 0x00000033 },
+       { AR5K_BB_GAIN(40), 0x0000000b },
+       { AR5K_BB_GAIN(41), 0x0000002b },
+       { AR5K_BB_GAIN(42), 0x0000002b },
+       { AR5K_BB_GAIN(43), 0x0000002b },
+       { AR5K_BB_GAIN(44), 0x0000002b },
+       { AR5K_BB_GAIN(45), 0x0000002b },
+       { AR5K_BB_GAIN(46), 0x0000002b },
+       { AR5K_BB_GAIN(47), 0x0000002b },
+       { AR5K_BB_GAIN(48), 0x0000002b },
+       { AR5K_BB_GAIN(49), 0x0000002b },
+       { AR5K_BB_GAIN(50), 0x0000002b },
+       { AR5K_BB_GAIN(51), 0x0000002b },
+       { AR5K_BB_GAIN(52), 0x0000002b },
+       { AR5K_BB_GAIN(53), 0x0000002b },
+       { AR5K_BB_GAIN(54), 0x0000002b },
+       { AR5K_BB_GAIN(55), 0x0000002b },
+       { AR5K_BB_GAIN(56), 0x0000002b },
+       { AR5K_BB_GAIN(57), 0x0000002b },
+       { AR5K_BB_GAIN(58), 0x0000002b },
+       { AR5K_BB_GAIN(59), 0x0000002b },
+       { AR5K_BB_GAIN(60), 0x0000002b },
+       { AR5K_BB_GAIN(61), 0x0000002b },
+       { AR5K_BB_GAIN(62), 0x00000002 },
+       { AR5K_BB_GAIN(63), 0x00000016 },
+};
+
+/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414) */
+static const struct ath5k_ini rf5112_ini_bbgain[] = {
+       { AR5K_BB_GAIN(0), 0x00000000 },
+       { AR5K_BB_GAIN(1), 0x00000001 },
+       { AR5K_BB_GAIN(2), 0x00000002 },
+       { AR5K_BB_GAIN(3), 0x00000003 },
+       { AR5K_BB_GAIN(4), 0x00000004 },
+       { AR5K_BB_GAIN(5), 0x00000005 },
+       { AR5K_BB_GAIN(6), 0x00000008 },
+       { AR5K_BB_GAIN(7), 0x00000009 },
+       { AR5K_BB_GAIN(8), 0x0000000a },
+       { AR5K_BB_GAIN(9), 0x0000000b },
+       { AR5K_BB_GAIN(10), 0x0000000c },
+       { AR5K_BB_GAIN(11), 0x0000000d },
+       { AR5K_BB_GAIN(12), 0x00000010 },
+       { AR5K_BB_GAIN(13), 0x00000011 },
+       { AR5K_BB_GAIN(14), 0x00000012 },
+       { AR5K_BB_GAIN(15), 0x00000013 },
+       { AR5K_BB_GAIN(16), 0x00000014 },
+       { AR5K_BB_GAIN(17), 0x00000015 },
+       { AR5K_BB_GAIN(18), 0x00000018 },
+       { AR5K_BB_GAIN(19), 0x00000019 },
+       { AR5K_BB_GAIN(20), 0x0000001a },
+       { AR5K_BB_GAIN(21), 0x0000001b },
+       { AR5K_BB_GAIN(22), 0x0000001c },
+       { AR5K_BB_GAIN(23), 0x0000001d },
+       { AR5K_BB_GAIN(24), 0x00000020 },
+       { AR5K_BB_GAIN(25), 0x00000021 },
+       { AR5K_BB_GAIN(26), 0x00000022 },
+       { AR5K_BB_GAIN(27), 0x00000023 },
+       { AR5K_BB_GAIN(28), 0x00000024 },
+       { AR5K_BB_GAIN(29), 0x00000025 },
+       { AR5K_BB_GAIN(30), 0x00000028 },
+       { AR5K_BB_GAIN(31), 0x00000029 },
+       { AR5K_BB_GAIN(32), 0x0000002a },
+       { AR5K_BB_GAIN(33), 0x0000002b },
+       { AR5K_BB_GAIN(34), 0x0000002c },
+       { AR5K_BB_GAIN(35), 0x0000002d },
+       { AR5K_BB_GAIN(36), 0x00000030 },
+       { AR5K_BB_GAIN(37), 0x00000031 },
+       { AR5K_BB_GAIN(38), 0x00000032 },
+       { AR5K_BB_GAIN(39), 0x00000033 },
+       { AR5K_BB_GAIN(40), 0x00000034 },
+       { AR5K_BB_GAIN(41), 0x00000035 },
+       { AR5K_BB_GAIN(42), 0x00000035 },
+       { AR5K_BB_GAIN(43), 0x00000035 },
+       { AR5K_BB_GAIN(44), 0x00000035 },
+       { AR5K_BB_GAIN(45), 0x00000035 },
+       { AR5K_BB_GAIN(46), 0x00000035 },
+       { AR5K_BB_GAIN(47), 0x00000035 },
+       { AR5K_BB_GAIN(48), 0x00000035 },
+       { AR5K_BB_GAIN(49), 0x00000035 },
+       { AR5K_BB_GAIN(50), 0x00000035 },
+       { AR5K_BB_GAIN(51), 0x00000035 },
+       { AR5K_BB_GAIN(52), 0x00000035 },
+       { AR5K_BB_GAIN(53), 0x00000035 },
+       { AR5K_BB_GAIN(54), 0x00000035 },
+       { AR5K_BB_GAIN(55), 0x00000035 },
+       { AR5K_BB_GAIN(56), 0x00000035 },
+       { AR5K_BB_GAIN(57), 0x00000035 },
+       { AR5K_BB_GAIN(58), 0x00000035 },
+       { AR5K_BB_GAIN(59), 0x00000035 },
+       { AR5K_BB_GAIN(60), 0x00000035 },
+       { AR5K_BB_GAIN(61), 0x00000035 },
+       { AR5K_BB_GAIN(62), 0x00000010 },
+       { AR5K_BB_GAIN(63), 0x0000001a },
+};
+
+
+/*
+ * Write initial register dump
+ */
+static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
+               const struct ath5k_ini *ini_regs, bool change_channel)
+{
+       unsigned int i;
+
+       /* Write initial registers */
+       for (i = 0; i < size; i++) {
+               /* On channel change there is
+                * no need to mess with PCU */
+               if (change_channel &&
+                               ini_regs[i].ini_register >= AR5K_PCU_MIN &&
+                               ini_regs[i].ini_register <= AR5K_PCU_MAX)
+                       continue;
+
+               switch (ini_regs[i].ini_mode) {
+               case AR5K_INI_READ:
+                       /* Cleared on read */
+                       ath5k_hw_reg_read(ah, ini_regs[i].ini_register);
+                       break;
+               case AR5K_INI_WRITE:
+               default:
+                       AR5K_REG_WAIT(i);
+                       ath5k_hw_reg_write(ah, ini_regs[i].ini_value,
+                                       ini_regs[i].ini_register);
+               }
+       }
+}
+
+static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
+               unsigned int size, const struct ath5k_ini_mode *ini_mode,
+               u8 mode)
+{
+       unsigned int i;
+
+       for (i = 0; i < size; i++) {
+               AR5K_REG_WAIT(i);
+               ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode],
+                       (u32)ini_mode[i].mode_register);
+       }
+
+}
+
+int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
+{
+       /*
+        * Write initial register settings
+        */
+
+       /* For AR5212 and combatible */
+       if (ah->ah_version == AR5K_AR5212){
+
+               /* First set of mode-specific settings */
+               ath5k_hw_ini_mode_registers(ah,
+                       ARRAY_SIZE(ar5212_ini_mode_start),
+                       ar5212_ini_mode_start, mode);
+
+               /*
+                * Write initial settings common for all modes
+                */
+               ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini),
+                                       ar5212_ini, change_channel);
+
+               /* Second set of mode-specific settings */
+               if (ah->ah_radio == AR5K_RF5111){
+                       ath5k_hw_ini_mode_registers(ah,
+                                       ARRAY_SIZE(ar5212_rf5111_ini_mode_end),
+                                       ar5212_rf5111_ini_mode_end, mode);
+                       /* Baseband gain table */
+                       ath5k_hw_ini_registers(ah,
+                                       ARRAY_SIZE(rf5111_ini_bbgain),
+                                       rf5111_ini_bbgain, change_channel);
+               } else if (ah->ah_radio == AR5K_RF5112){
+                       ath5k_hw_ini_mode_registers(ah,
+                                       ARRAY_SIZE(ar5212_rf5112_ini_mode_end),
+                                       ar5212_rf5112_ini_mode_end, mode);
+                       /* Baseband gain table */
+                       ath5k_hw_ini_registers(ah,
+                                       ARRAY_SIZE(rf5112_ini_bbgain),
+                                       rf5112_ini_bbgain, change_channel);
+               } else if (ah->ah_radio == AR5K_RF5413){
+                       ath5k_hw_ini_mode_registers(ah,
+                                       ARRAY_SIZE(rf5413_ini_mode_end),
+                                       rf5413_ini_mode_end, mode);
+                       /* Baseband gain table */
+                       ath5k_hw_ini_registers(ah,
+                                       ARRAY_SIZE(rf5112_ini_bbgain),
+                                       rf5112_ini_bbgain, change_channel);
+               }
+       /* For AR5211 */
+       } else if (ah->ah_version == AR5K_AR5211) {
+
+               if(mode > 2){ /* AR5K_INI_VAL_11B */
+                       ATH5K_ERR(ah->ah_sc,"unsupported channel mode: %d\n", mode);
+                       return -EINVAL;
+               }
+
+               /* Mode-specific settings */
+               ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode),
+                               ar5211_ini_mode, mode);
+
+               /*
+                * Write initial settings common for all modes
+                */
+               ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini),
+                               ar5211_ini, change_channel);
+
+               /* AR5211 only comes with 5111 */
+
+               /* Baseband gain table */
+               ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain),
+                               rf5111_ini_bbgain, change_channel);
+       /* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */
+       } else if (ah->ah_version == AR5K_AR5210) {
+               ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini),
+                               ar5210_ini, change_channel);
+       }
+
+       return 0;
+}
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
new file mode 100644 (file)
index 0000000..b959417
--- /dev/null
@@ -0,0 +1,2071 @@
+/*
+ * PHY functions
+ *
+ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/* Struct to hold initial RF register values (RF Banks) */
+struct ath5k_ini_rf {
+       u8      rf_bank;        /* check out ath5k_reg.h */
+       u16     rf_register;    /* register address */
+       u32     rf_value[5];    /* register value for different modes (above) */
+};
+
+/*
+ * Mode-specific RF Gain table (64bytes) for RF5111/5112
+ * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
+ * RF Gain values are included in AR5K_AR5210_INI)
+ */
+struct ath5k_ini_rfgain {
+       u16     rfg_register;   /* RF Gain register address */
+       u32     rfg_value[2];   /* [freq (see below)] */
+};
+
+struct ath5k_gain_opt {
+       u32                     go_default;
+       u32                     go_steps_count;
+       const struct ath5k_gain_opt_step        go_step[AR5K_GAIN_STEP_COUNT];
+};
+
+/* RF5111 mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_5111[] = {
+       { 0, 0x989c,
+       /*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c,
+           { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } },
+       { 0, 0x989c,
+           { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } },
+       { 0, 0x98d4,
+           { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } },
+       { 1, 0x98d4,
+           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d4,
+           { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } },
+       { 3, 0x98d8,
+           { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+       { 6, 0x989c,
+           { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } },
+       { 6, 0x989c,
+           { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } },
+       { 6, 0x989c,
+           { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } },
+       { 6, 0x989c,
+           { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } },
+       { 6, 0x989c,
+           { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } },
+       { 6, 0x98d4,
+           { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } },
+       { 7, 0x989c,
+           { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } },
+       { 7, 0x989c,
+           { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
+       { 7, 0x989c,
+           { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
+       { 7, 0x989c,
+           { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } },
+       { 7, 0x989c,
+           { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } },
+       { 7, 0x989c,
+           { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } },
+       { 7, 0x989c,
+           { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } },
+       { 7, 0x98cc,
+           { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } },
+};
+
+/* Initial RF Gain settings for RF5111 */
+static const struct ath5k_ini_rfgain rfgain_5111[] = {
+       /*                            5Ghz      2Ghz    */
+       { AR5K_RF_GAIN(0),      { 0x000001a9, 0x00000000 } },
+       { AR5K_RF_GAIN(1),      { 0x000001e9, 0x00000040 } },
+       { AR5K_RF_GAIN(2),      { 0x00000029, 0x00000080 } },
+       { AR5K_RF_GAIN(3),      { 0x00000069, 0x00000150 } },
+       { AR5K_RF_GAIN(4),      { 0x00000199, 0x00000190 } },
+       { AR5K_RF_GAIN(5),      { 0x000001d9, 0x000001d0 } },
+       { AR5K_RF_GAIN(6),      { 0x00000019, 0x00000010 } },
+       { AR5K_RF_GAIN(7),      { 0x00000059, 0x00000044 } },
+       { AR5K_RF_GAIN(8),      { 0x00000099, 0x00000084 } },
+       { AR5K_RF_GAIN(9),      { 0x000001a5, 0x00000148 } },
+       { AR5K_RF_GAIN(10),     { 0x000001e5, 0x00000188 } },
+       { AR5K_RF_GAIN(11),     { 0x00000025, 0x000001c8 } },
+       { AR5K_RF_GAIN(12),     { 0x000001c8, 0x00000014 } },
+       { AR5K_RF_GAIN(13),     { 0x00000008, 0x00000042 } },
+       { AR5K_RF_GAIN(14),     { 0x00000048, 0x00000082 } },
+       { AR5K_RF_GAIN(15),     { 0x00000088, 0x00000178 } },
+       { AR5K_RF_GAIN(16),     { 0x00000198, 0x000001b8 } },
+       { AR5K_RF_GAIN(17),     { 0x000001d8, 0x000001f8 } },
+       { AR5K_RF_GAIN(18),     { 0x00000018, 0x00000012 } },
+       { AR5K_RF_GAIN(19),     { 0x00000058, 0x00000052 } },
+       { AR5K_RF_GAIN(20),     { 0x00000098, 0x00000092 } },
+       { AR5K_RF_GAIN(21),     { 0x000001a4, 0x0000017c } },
+       { AR5K_RF_GAIN(22),     { 0x000001e4, 0x000001bc } },
+       { AR5K_RF_GAIN(23),     { 0x00000024, 0x000001fc } },
+       { AR5K_RF_GAIN(24),     { 0x00000064, 0x0000000a } },
+       { AR5K_RF_GAIN(25),     { 0x000000a4, 0x0000004a } },
+       { AR5K_RF_GAIN(26),     { 0x000000e4, 0x0000008a } },
+       { AR5K_RF_GAIN(27),     { 0x0000010a, 0x0000015a } },
+       { AR5K_RF_GAIN(28),     { 0x0000014a, 0x0000019a } },
+       { AR5K_RF_GAIN(29),     { 0x0000018a, 0x000001da } },
+       { AR5K_RF_GAIN(30),     { 0x000001ca, 0x0000000e } },
+       { AR5K_RF_GAIN(31),     { 0x0000000a, 0x0000004e } },
+       { AR5K_RF_GAIN(32),     { 0x0000004a, 0x0000008e } },
+       { AR5K_RF_GAIN(33),     { 0x0000008a, 0x0000015e } },
+       { AR5K_RF_GAIN(34),     { 0x000001ba, 0x0000019e } },
+       { AR5K_RF_GAIN(35),     { 0x000001fa, 0x000001de } },
+       { AR5K_RF_GAIN(36),     { 0x0000003a, 0x00000009 } },
+       { AR5K_RF_GAIN(37),     { 0x0000007a, 0x00000049 } },
+       { AR5K_RF_GAIN(38),     { 0x00000186, 0x00000089 } },
+       { AR5K_RF_GAIN(39),     { 0x000001c6, 0x00000179 } },
+       { AR5K_RF_GAIN(40),     { 0x00000006, 0x000001b9 } },
+       { AR5K_RF_GAIN(41),     { 0x00000046, 0x000001f9 } },
+       { AR5K_RF_GAIN(42),     { 0x00000086, 0x00000039 } },
+       { AR5K_RF_GAIN(43),     { 0x000000c6, 0x00000079 } },
+       { AR5K_RF_GAIN(44),     { 0x000000c6, 0x000000b9 } },
+       { AR5K_RF_GAIN(45),     { 0x000000c6, 0x000001bd } },
+       { AR5K_RF_GAIN(46),     { 0x000000c6, 0x000001fd } },
+       { AR5K_RF_GAIN(47),     { 0x000000c6, 0x0000003d } },
+       { AR5K_RF_GAIN(48),     { 0x000000c6, 0x0000007d } },
+       { AR5K_RF_GAIN(49),     { 0x000000c6, 0x000000bd } },
+       { AR5K_RF_GAIN(50),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(51),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(52),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(53),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(54),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(55),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(56),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(57),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(58),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(59),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(60),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(61),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(62),     { 0x000000c6, 0x000000fd } },
+       { AR5K_RF_GAIN(63),     { 0x000000c6, 0x000000fd } },
+};
+
+static const struct ath5k_gain_opt rfgain_opt_5111 = {
+       4,
+       9,
+       {
+               { { 4, 1, 1, 1 }, 6 },
+               { { 4, 0, 1, 1 }, 4 },
+               { { 3, 1, 1, 1 }, 3 },
+               { { 4, 0, 0, 1 }, 1 },
+               { { 4, 1, 1, 0 }, 0 },
+               { { 4, 0, 1, 0 }, -2 },
+               { { 3, 1, 1, 0 }, -3 },
+               { { 4, 0, 0, 0 }, -4 },
+               { { 2, 1, 1, 0 }, -6 }
+       }
+};
+
+/* RF5112 mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_5112[] = {
+       { 1, 0x98d4,
+       /*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
+           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0,
+           { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
+       { 3, 0x98dc,
+           { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
+       { 6, 0x989c,
+           { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } },
+       { 6, 0x989c,
+           { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } },
+       { 6, 0x989c,
+           { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } },
+       { 6, 0x989c,
+           { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } },
+       { 6, 0x989c,
+           { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+       { 6, 0x989c,
+           { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+       { 6, 0x989c,
+           { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+       { 6, 0x989c,
+           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c,
+           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c,
+           { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } },
+       { 6, 0x989c,
+           { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } },
+       { 6, 0x989c,
+           { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+       { 6, 0x989c,
+           { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
+       { 6, 0x989c,
+           { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } },
+       { 6, 0x989c,
+           { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } },
+       { 6, 0x989c,
+           { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
+       { 6, 0x989c,
+           { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } },
+       { 6, 0x989c,
+           { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+       { 6, 0x989c,
+           { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+       { 6, 0x989c,
+           { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } },
+       { 6, 0x989c,
+           { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } },
+       { 6, 0x989c,
+           { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
+       { 6, 0x989c,
+           { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } },
+       { 6, 0x989c,
+           { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } },
+       { 6, 0x989c,
+           { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } },
+       { 6, 0x989c,
+           { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } },
+       { 6, 0x989c,
+           { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } },
+       { 6, 0x989c,
+           { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } },
+       { 6, 0x989c,
+           { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } },
+       { 6, 0x989c,
+           { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } },
+       { 6, 0x989c,
+           { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } },
+       { 6, 0x989c,
+           { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } },
+       { 6, 0x98d0,
+           { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } },
+       { 7, 0x989c,
+           { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
+       { 7, 0x989c,
+           { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
+       { 7, 0x989c,
+           { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } },
+       { 7, 0x989c,
+           { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+       { 7, 0x989c,
+           { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } },
+       { 7, 0x989c,
+           { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+       { 7, 0x989c,
+           { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
+       { 7, 0x989c,
+           { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } },
+       { 7, 0x989c,
+           { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } },
+       { 7, 0x989c,
+           { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
+       { 7, 0x989c,
+           { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
+       { 7, 0x989c,
+           { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
+       { 7, 0x98c4,
+           { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+/* RF5112A mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_5112a[] = {
+       { 1, 0x98d4,
+       /*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
+           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0,
+           { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
+       { 3, 0x98dc,
+           { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
+       { 6, 0x989c,
+           { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } },
+       { 6, 0x989c,
+           { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, 0x989c,
+           { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } },
+       { 6, 0x989c,
+           { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } },
+       { 6, 0x989c,
+           { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } },
+       { 6, 0x989c,
+           { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } },
+       { 6, 0x989c,
+           { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } },
+       { 6, 0x989c,
+           { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
+       { 6, 0x989c,
+           { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
+       { 6, 0x989c,
+           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c,
+           { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } },
+       { 6, 0x989c,
+           { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+       { 6, 0x989c,
+           { 0x00190000, 0x00190000, 0x00190000, 0x00190000, 0x00190000 } },
+       { 6, 0x989c,
+           { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
+       { 6, 0x989c,
+           { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } },
+       { 6, 0x989c,
+           { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } },
+       { 6, 0x989c,
+           { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } },
+       { 6, 0x989c,
+           { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, 0x989c,
+           { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+       { 6, 0x989c,
+           { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } },
+       { 6, 0x989c,
+           { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } },
+       { 6, 0x989c,
+           { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+       { 6, 0x989c,
+           { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } },
+       { 6, 0x989c,
+           { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } },
+       { 6, 0x989c,
+           { 0x00020080, 0x00020080, 0x00020080, 0x00020080, 0x00020080 } },
+       { 6, 0x989c,
+           { 0x00080009, 0x00080009, 0x00080009, 0x00080009, 0x00080009 } },
+       { 6, 0x989c,
+           { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } },
+       { 6, 0x989c,
+           { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } },
+       { 6, 0x989c,
+           { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } },
+       { 6, 0x989c,
+           { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } },
+       { 6, 0x989c,
+           { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } },
+       { 6, 0x98d8,
+           { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } },
+       { 7, 0x989c,
+           { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
+       { 7, 0x989c,
+           { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
+       { 7, 0x989c,
+           { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } },
+       { 7, 0x989c,
+           { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+       { 7, 0x989c,
+           { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } },
+       { 7, 0x989c,
+           { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+       { 7, 0x989c,
+           { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
+       { 7, 0x989c,
+           { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } },
+       { 7, 0x989c,
+           { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } },
+       { 7, 0x989c,
+           { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
+       { 7, 0x989c,
+           { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
+       { 7, 0x989c,
+           { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
+       { 7, 0x98c4,
+           { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+
+static const struct ath5k_ini_rf rfregs_2112a[] = {
+       { 1, AR5K_RF_BUFFER_CONTROL_4,
+       /*         mode b       mode g    mode gTurbo */
+               { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, AR5K_RF_BUFFER_CONTROL_3,
+               { 0x03060408, 0x03060408, 0x03070408 } },
+       { 3, AR5K_RF_BUFFER_CONTROL_6,
+               { 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x0a000000, 0x0a000000, 0x0a000000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00800000, 0x00800000, 0x00800000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00010000, 0x00010000, 0x00010000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00180000, 0x00180000, 0x00180000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x006e0000, 0x006e0000, 0x006e0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00c70000, 0x00c70000, 0x00c70000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x004b0000, 0x004b0000, 0x004b0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x04480000, 0x04480000, 0x04480000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00e40000, 0x00e40000, 0x00e40000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x043f0000, 0x043f0000, 0x043f0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x0c0c0000, 0x0c0c0000, 0x0c0c0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x02190000, 0x02190000, 0x02190000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00240000, 0x00240000, 0x00240000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00b40000, 0x00b40000, 0x00b40000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00990000, 0x00990000, 0x00990000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00500000, 0x00500000, 0x00500000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00120000, 0x00120000, 0x00120000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0xc0320000, 0xc0320000, 0xc0320000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x01740000, 0x01740000, 0x01740000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00110000, 0x00110000, 0x00110000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x86280000, 0x86280000, 0x86280000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x31840000, 0x31840000, 0x31840000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00f20080, 0x00f20080, 0x00f20080 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00070019, 0x00070019, 0x00070019 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x000000b2, 0x000000b2, 0x000000b2 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00b02184, 0x00b02184, 0x00b02184 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x004125a4, 0x004125a4, 0x004125a4 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x00119220, 0x00119220, 0x00119220 } },
+       { 6, AR5K_RF_BUFFER,
+               { 0x001a4800, 0x001a4800, 0x001a4800 } },
+       { 6, AR5K_RF_BUFFER_CONTROL_5,
+               { 0x000b0230, 0x000b0230, 0x000b0230 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x00000094, 0x00000094, 0x00000094 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x00000091, 0x00000091, 0x00000091 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x00000012, 0x00000012, 0x00000012 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x00000080, 0x00000080, 0x00000080 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x000000d9, 0x000000d9, 0x000000d9 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x00000060, 0x00000060, 0x00000060 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x000000f0, 0x000000f0, 0x000000f0 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x000000a2, 0x000000a2, 0x000000a2 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x00000052, 0x00000052, 0x00000052 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x000000d4, 0x000000d4, 0x000000d4 } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x000014cc, 0x000014cc, 0x000014cc } },
+       { 7, AR5K_RF_BUFFER,
+               { 0x0000048c, 0x0000048c, 0x0000048c } },
+       { 7, AR5K_RF_BUFFER_CONTROL_1,
+               { 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+/* RF5413/5414 mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_5413[] = {
+       { 1, 0x98d4,
+       /*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
+           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0,
+           { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
+       { 3, 0x98dc,
+           { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } },
+       { 6, 0x989c,
+           { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } },
+       { 6, 0x989c,
+           { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } },
+       { 6, 0x989c,
+           { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } },
+       { 6, 0x989c,
+           { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
+       { 6, 0x989c,
+           { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
+       { 6, 0x989c,
+           { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } },
+       { 6, 0x989c,
+           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c,
+           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c,
+           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c,
+           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c,
+           { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } },
+       { 6, 0x989c,
+           { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } },
+       { 6, 0x989c,
+           { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
+       { 6, 0x989c,
+           { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } },
+       { 6, 0x989c,
+           { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } },
+       { 6, 0x989c,
+           { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } },
+       { 6, 0x989c,
+           { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
+       { 6, 0x989c,
+           { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } },
+       { 6, 0x989c,
+           { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
+       { 6, 0x989c,
+           { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } },
+       { 6, 0x989c,
+           { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } },
+       { 6, 0x989c,
+           { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } },
+       { 6, 0x989c,
+           { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } },
+       { 6, 0x989c,
+           { 0x00510040, 0x00510040, 0x005100a0, 0x005100a0, 0x005100a0 } },
+       { 6, 0x989c,
+           { 0x0050006a, 0x0050006a, 0x005000dd, 0x005000dd, 0x005000dd } },
+       { 6, 0x989c,
+           { 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } },
+       { 6, 0x989c,
+           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c,
+           { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } },
+       { 6, 0x989c,
+           { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00003600 } },
+       { 6, 0x98c8,
+           { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } },
+       { 7, 0x989c,
+           { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+       { 7, 0x989c,
+           { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+       { 7, 0x98cc,
+           { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+/* Initial RF Gain settings for RF5112 */
+static const struct ath5k_ini_rfgain rfgain_5112[] = {
+       /*                            5Ghz      2Ghz    */
+       { AR5K_RF_GAIN(0),      { 0x00000007, 0x00000007 } },
+       { AR5K_RF_GAIN(1),      { 0x00000047, 0x00000047 } },
+       { AR5K_RF_GAIN(2),      { 0x00000087, 0x00000087 } },
+       { AR5K_RF_GAIN(3),      { 0x000001a0, 0x000001a0 } },
+       { AR5K_RF_GAIN(4),      { 0x000001e0, 0x000001e0 } },
+       { AR5K_RF_GAIN(5),      { 0x00000020, 0x00000020 } },
+       { AR5K_RF_GAIN(6),      { 0x00000060, 0x00000060 } },
+       { AR5K_RF_GAIN(7),      { 0x000001a1, 0x000001a1 } },
+       { AR5K_RF_GAIN(8),      { 0x000001e1, 0x000001e1 } },
+       { AR5K_RF_GAIN(9),      { 0x00000021, 0x00000021 } },
+       { AR5K_RF_GAIN(10),     { 0x00000061, 0x00000061 } },
+       { AR5K_RF_GAIN(11),     { 0x00000162, 0x00000162 } },
+       { AR5K_RF_GAIN(12),     { 0x000001a2, 0x000001a2 } },
+       { AR5K_RF_GAIN(13),     { 0x000001e2, 0x000001e2 } },
+       { AR5K_RF_GAIN(14),     { 0x00000022, 0x00000022 } },
+       { AR5K_RF_GAIN(15),     { 0x00000062, 0x00000062 } },
+       { AR5K_RF_GAIN(16),     { 0x00000163, 0x00000163 } },
+       { AR5K_RF_GAIN(17),     { 0x000001a3, 0x000001a3 } },
+       { AR5K_RF_GAIN(18),     { 0x000001e3, 0x000001e3 } },
+       { AR5K_RF_GAIN(19),     { 0x00000023, 0x00000023 } },
+       { AR5K_RF_GAIN(20),     { 0x00000063, 0x00000063 } },
+       { AR5K_RF_GAIN(21),     { 0x00000184, 0x00000184 } },
+       { AR5K_RF_GAIN(22),     { 0x000001c4, 0x000001c4 } },
+       { AR5K_RF_GAIN(23),     { 0x00000004, 0x00000004 } },
+       { AR5K_RF_GAIN(24),     { 0x000001ea, 0x0000000b } },
+       { AR5K_RF_GAIN(25),     { 0x0000002a, 0x0000004b } },
+       { AR5K_RF_GAIN(26),     { 0x0000006a, 0x0000008b } },
+       { AR5K_RF_GAIN(27),     { 0x000000aa, 0x000001ac } },
+       { AR5K_RF_GAIN(28),     { 0x000001ab, 0x000001ec } },
+       { AR5K_RF_GAIN(29),     { 0x000001eb, 0x0000002c } },
+       { AR5K_RF_GAIN(30),     { 0x0000002b, 0x00000012 } },
+       { AR5K_RF_GAIN(31),     { 0x0000006b, 0x00000052 } },
+       { AR5K_RF_GAIN(32),     { 0x000000ab, 0x00000092 } },
+       { AR5K_RF_GAIN(33),     { 0x000001ac, 0x00000193 } },
+       { AR5K_RF_GAIN(34),     { 0x000001ec, 0x000001d3 } },
+       { AR5K_RF_GAIN(35),     { 0x0000002c, 0x00000013 } },
+       { AR5K_RF_GAIN(36),     { 0x0000003a, 0x00000053 } },
+       { AR5K_RF_GAIN(37),     { 0x0000007a, 0x00000093 } },
+       { AR5K_RF_GAIN(38),     { 0x000000ba, 0x00000194 } },
+       { AR5K_RF_GAIN(39),     { 0x000001bb, 0x000001d4 } },
+       { AR5K_RF_GAIN(40),     { 0x000001fb, 0x00000014 } },
+       { AR5K_RF_GAIN(41),     { 0x0000003b, 0x0000003a } },
+       { AR5K_RF_GAIN(42),     { 0x0000007b, 0x0000007a } },
+       { AR5K_RF_GAIN(43),     { 0x000000bb, 0x000000ba } },
+       { AR5K_RF_GAIN(44),     { 0x000001bc, 0x000001bb } },
+       { AR5K_RF_GAIN(45),     { 0x000001fc, 0x000001fb } },
+       { AR5K_RF_GAIN(46),     { 0x0000003c, 0x0000003b } },
+       { AR5K_RF_GAIN(47),     { 0x0000007c, 0x0000007b } },
+       { AR5K_RF_GAIN(48),     { 0x000000bc, 0x000000bb } },
+       { AR5K_RF_GAIN(49),     { 0x000000fc, 0x000001bc } },
+       { AR5K_RF_GAIN(50),     { 0x000000fc, 0x000001fc } },
+       { AR5K_RF_GAIN(51),     { 0x000000fc, 0x0000003c } },
+       { AR5K_RF_GAIN(52),     { 0x000000fc, 0x0000007c } },
+       { AR5K_RF_GAIN(53),     { 0x000000fc, 0x000000bc } },
+       { AR5K_RF_GAIN(54),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(55),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(56),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(57),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(58),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(59),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(60),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(61),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(62),     { 0x000000fc, 0x000000fc } },
+       { AR5K_RF_GAIN(63),     { 0x000000fc, 0x000000fc } },
+};
+
+/* Initial RF Gain settings for RF5413 */
+static const struct ath5k_ini_rfgain rfgain_5413[] = {
+       /*                            5Ghz      2Ghz    */
+       { AR5K_RF_GAIN(0),      { 0x00000000, 0x00000000 } },
+       { AR5K_RF_GAIN(1),      { 0x00000040, 0x00000040 } },
+       { AR5K_RF_GAIN(2),      { 0x00000080, 0x00000080 } },
+       { AR5K_RF_GAIN(3),      { 0x000001a1, 0x00000161 } },
+       { AR5K_RF_GAIN(4),      { 0x000001e1, 0x000001a1 } },
+       { AR5K_RF_GAIN(5),      { 0x00000021, 0x000001e1 } },
+       { AR5K_RF_GAIN(6),      { 0x00000061, 0x00000021 } },
+       { AR5K_RF_GAIN(7),      { 0x00000188, 0x00000061 } },
+       { AR5K_RF_GAIN(8),      { 0x000001c8, 0x00000188 } },
+       { AR5K_RF_GAIN(9),      { 0x00000008, 0x000001c8 } },
+       { AR5K_RF_GAIN(10),     { 0x00000048, 0x00000008 } },
+       { AR5K_RF_GAIN(11),     { 0x00000088, 0x00000048 } },
+       { AR5K_RF_GAIN(12),     { 0x000001a9, 0x00000088 } },
+       { AR5K_RF_GAIN(13),     { 0x000001e9, 0x00000169 } },
+       { AR5K_RF_GAIN(14),     { 0x00000029, 0x000001a9 } },
+       { AR5K_RF_GAIN(15),     { 0x00000069, 0x000001e9 } },
+       { AR5K_RF_GAIN(16),     { 0x000001d0, 0x00000029 } },
+       { AR5K_RF_GAIN(17),     { 0x00000010, 0x00000069 } },
+       { AR5K_RF_GAIN(18),     { 0x00000050, 0x00000190 } },
+       { AR5K_RF_GAIN(19),     { 0x00000090, 0x000001d0 } },
+       { AR5K_RF_GAIN(20),     { 0x000001b1, 0x00000010 } },
+       { AR5K_RF_GAIN(21),     { 0x000001f1, 0x00000050 } },
+       { AR5K_RF_GAIN(22),     { 0x00000031, 0x00000090 } },
+       { AR5K_RF_GAIN(23),     { 0x00000071, 0x00000171 } },
+       { AR5K_RF_GAIN(24),     { 0x000001b8, 0x000001b1 } },
+       { AR5K_RF_GAIN(25),     { 0x000001f8, 0x000001f1 } },
+       { AR5K_RF_GAIN(26),     { 0x00000038, 0x00000031 } },
+       { AR5K_RF_GAIN(27),     { 0x00000078, 0x00000071 } },
+       { AR5K_RF_GAIN(28),     { 0x00000199, 0x00000198 } },
+       { AR5K_RF_GAIN(29),     { 0x000001d9, 0x000001d8 } },
+       { AR5K_RF_GAIN(30),     { 0x00000019, 0x00000018 } },
+       { AR5K_RF_GAIN(31),     { 0x00000059, 0x00000058 } },
+       { AR5K_RF_GAIN(32),     { 0x00000099, 0x00000098 } },
+       { AR5K_RF_GAIN(33),     { 0x000000d9, 0x00000179 } },
+       { AR5K_RF_GAIN(34),     { 0x000000f9, 0x000001b9 } },
+       { AR5K_RF_GAIN(35),     { 0x000000f9, 0x000001f9 } },
+       { AR5K_RF_GAIN(36),     { 0x000000f9, 0x00000039 } },
+       { AR5K_RF_GAIN(37),     { 0x000000f9, 0x00000079 } },
+       { AR5K_RF_GAIN(38),     { 0x000000f9, 0x000000b9 } },
+       { AR5K_RF_GAIN(39),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(40),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(41),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(42),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(43),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(44),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(45),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(46),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(47),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(48),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(49),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(50),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(51),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(52),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(53),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(54),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(55),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(56),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(57),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(58),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(59),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(60),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(61),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(62),     { 0x000000f9, 0x000000f9 } },
+       { AR5K_RF_GAIN(63),     { 0x000000f9, 0x000000f9 } },
+};
+
+static const struct ath5k_gain_opt rfgain_opt_5112 = {
+       1,
+       8,
+       {
+               { { 3, 0, 0, 0, 0, 0, 0 }, 6 },
+               { { 2, 0, 0, 0, 0, 0, 0 }, 0 },
+               { { 1, 0, 0, 0, 0, 0, 0 }, -3 },
+               { { 0, 0, 0, 0, 0, 0, 0 }, -6 },
+               { { 0, 1, 1, 0, 0, 0, 0 }, -8 },
+               { { 0, 1, 1, 0, 1, 1, 0 }, -10 },
+               { { 0, 1, 0, 1, 1, 1, 0 }, -13 },
+               { { 0, 1, 0, 1, 1, 0, 1 }, -16 },
+       }
+};
+
+/*
+ * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
+ */
+static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits,
+               u32 first, u32 col, bool set)
+{
+       u32 mask, entry, last, data, shift, position;
+       s32 left;
+       int i;
+
+       data = 0;
+
+       if (rf == NULL)
+               /* should not happen */
+               return 0;
+
+       if (!(col <= 3 && bits <= 32 && first + bits <= 319)) {
+               ATH5K_PRINTF("invalid values at offset %u\n", offset);
+               return 0;
+       }
+
+       entry = ((first - 1) / 8) + offset;
+       position = (first - 1) % 8;
+
+       if (set == true)
+               data = ath5k_hw_bitswap(reg, bits);
+
+       for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) {
+               last = (position + left > 8) ? 8 : position + left;
+               mask = (((1 << last) - 1) ^ ((1 << position) - 1)) << (col * 8);
+
+               if (set == true) {
+                       rf[entry] &= ~mask;
+                       rf[entry] |= ((data << position) << (col * 8)) & mask;
+                       data >>= (8 - position);
+               } else {
+                       data = (((rf[entry] & mask) >> (col * 8)) >> position)
+                               << shift;
+                       shift += last - position;
+               }
+
+               left -= 8 - position;
+       }
+
+       data = set == true ? 1 : ath5k_hw_bitswap(data, bits);
+
+       return data;
+}
+
+static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
+{
+       u32 mix, step;
+       u32 *rf;
+
+       if (ah->ah_rf_banks == NULL)
+               return 0;
+
+       rf = ah->ah_rf_banks;
+       ah->ah_gain.g_f_corr = 0;
+
+       if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1)
+               return 0;
+
+       step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false);
+       mix = ah->ah_gain.g_step->gos_param[0];
+
+       switch (mix) {
+       case 3:
+               ah->ah_gain.g_f_corr = step * 2;
+               break;
+       case 2:
+               ah->ah_gain.g_f_corr = (step - 5) * 2;
+               break;
+       case 1:
+               ah->ah_gain.g_f_corr = step;
+               break;
+       default:
+               ah->ah_gain.g_f_corr = 0;
+               break;
+       }
+
+       return ah->ah_gain.g_f_corr;
+}
+
+static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
+{
+       u32 step, mix, level[4];
+       u32 *rf;
+
+       if (ah->ah_rf_banks == NULL)
+               return false;
+
+       rf = ah->ah_rf_banks;
+
+       if (ah->ah_radio == AR5K_RF5111) {
+               step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0,
+                               false);
+               level[0] = 0;
+               level[1] = (step == 0x3f) ? 0x32 : step + 4;
+               level[2] = (step != 0x3f) ? 0x40 : level[0];
+               level[3] = level[2] + 0x32;
+
+               ah->ah_gain.g_high = level[3] -
+                       (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
+               ah->ah_gain.g_low = level[0] +
+                       (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
+       } else {
+               mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0,
+                               false);
+               level[0] = level[2] = 0;
+
+               if (mix == 1) {
+                       level[1] = level[3] = 83;
+               } else {
+                       level[1] = level[3] = 107;
+                       ah->ah_gain.g_high = 55;
+               }
+       }
+
+       return (ah->ah_gain.g_current >= level[0] &&
+                       ah->ah_gain.g_current <= level[1]) ||
+               (ah->ah_gain.g_current >= level[2] &&
+                       ah->ah_gain.g_current <= level[3]);
+}
+
+static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah)
+{
+       const struct ath5k_gain_opt *go;
+       int ret = 0;
+
+       switch (ah->ah_radio) {
+       case AR5K_RF5111:
+               go = &rfgain_opt_5111;
+               break;
+       case AR5K_RF5112:
+       case AR5K_RF5413: /* ??? */
+               go = &rfgain_opt_5112;
+               break;
+       default:
+               return 0;
+       }
+
+       ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+       if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
+               if (ah->ah_gain.g_step_idx == 0)
+                       return -1;
+               for (ah->ah_gain.g_target = ah->ah_gain.g_current;
+                               ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
+                               ah->ah_gain.g_step_idx > 0;
+                               ah->ah_gain.g_step =
+                                       &go->go_step[ah->ah_gain.g_step_idx])
+                       ah->ah_gain.g_target -= 2 *
+                           (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
+                           ah->ah_gain.g_step->gos_gain);
+
+               ret = 1;
+               goto done;
+       }
+
+       if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
+               if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
+                       return -2;
+               for (ah->ah_gain.g_target = ah->ah_gain.g_current;
+                               ah->ah_gain.g_target <= ah->ah_gain.g_low &&
+                               ah->ah_gain.g_step_idx < go->go_steps_count-1;
+                               ah->ah_gain.g_step =
+                                       &go->go_step[ah->ah_gain.g_step_idx])
+                       ah->ah_gain.g_target -= 2 *
+                           (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
+                           ah->ah_gain.g_step->gos_gain);
+
+               ret = 2;
+               goto done;
+       }
+
+done:
+       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+               "ret %d, gain step %u, current gain %u, target gain %u\n",
+               ret, ah->ah_gain.g_step_idx, ah->ah_gain.g_current,
+               ah->ah_gain.g_target);
+
+       return ret;
+}
+
+/*
+ * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111
+ */
+static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel, unsigned int mode)
+{
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+       u32 *rf;
+       const unsigned int rf_size = ARRAY_SIZE(rfregs_5111);
+       unsigned int i;
+       int obdb = -1, bank = -1;
+       u32 ee_mode;
+
+       AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+
+       rf = ah->ah_rf_banks;
+
+       /* Copy values to modify them */
+       for (i = 0; i < rf_size; i++) {
+               if (rfregs_5111[i].rf_bank >= AR5K_RF5111_INI_RF_MAX_BANKS) {
+                       ATH5K_ERR(ah->ah_sc, "invalid bank\n");
+                       return -EINVAL;
+               }
+
+               if (bank != rfregs_5111[i].rf_bank) {
+                       bank = rfregs_5111[i].rf_bank;
+                       ah->ah_offset[bank] = i;
+               }
+
+               rf[i] = rfregs_5111[i].rf_value[mode];
+       }
+
+       /* Modify bank 0 */
+       if (channel->val & CHANNEL_2GHZ) {
+               if (channel->val & CHANNEL_CCK)
+                       ee_mode = AR5K_EEPROM_MODE_11B;
+               else
+                       ee_mode = AR5K_EEPROM_MODE_11G;
+               obdb = 0;
+
+               if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0],
+                               ee->ee_ob[ee_mode][obdb], 3, 119, 0, true))
+                       return -EINVAL;
+
+               if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0],
+                               ee->ee_ob[ee_mode][obdb], 3, 122, 0, true))
+                       return -EINVAL;
+
+               obdb = 1;
+       /* Modify bank 6 */
+       } else {
+               /* For 11a, Turbo and XR */
+               ee_mode = AR5K_EEPROM_MODE_11A;
+               obdb =   channel->freq >= 5725 ? 3 :
+                       (channel->freq >= 5500 ? 2 :
+                       (channel->freq >= 5260 ? 1 :
+                        (channel->freq > 4000 ? 0 : -1)));
+
+               if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                               ee->ee_pwd_84, 1, 51, 3, true))
+                       return -EINVAL;
+
+               if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                               ee->ee_pwd_90, 1, 45, 3, true))
+                       return -EINVAL;
+       }
+
+       if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                       !ee->ee_xpd[ee_mode], 1, 95, 0, true))
+               return -EINVAL;
+
+       if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                       ee->ee_x_gain[ee_mode], 4, 96, 0, true))
+               return -EINVAL;
+
+       if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ?
+                       ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0, true))
+               return -EINVAL;
+
+       if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ?
+                       ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0, true))
+               return -EINVAL;
+
+       /* Modify bank 7 */
+       if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
+                       ee->ee_i_gain[ee_mode], 6, 29, 0, true))
+               return -EINVAL;
+
+       if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
+                       ee->ee_xpd[ee_mode], 1, 4, 0, true))
+               return -EINVAL;
+
+       /* Write RF values */
+       for (i = 0; i < rf_size; i++) {
+               AR5K_REG_WAIT(i);
+               ath5k_hw_reg_write(ah, rf[i], rfregs_5111[i].rf_register);
+       }
+
+       return 0;
+}
+
+/*
+ * Read EEPROM Calibration data, modify RF Banks and Initialize RF5112
+ */
+static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel, unsigned int mode)
+{
+       const struct ath5k_ini_rf *rf_ini;
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+       u32 *rf;
+       unsigned int rf_size, i;
+       int obdb = -1, bank = -1;
+       u32 ee_mode;
+
+       AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+
+       rf = ah->ah_rf_banks;
+
+       if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_2112A
+               && !test_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode)){
+               rf_ini = rfregs_2112a;
+               rf_size = ARRAY_SIZE(rfregs_5112a);
+               if (mode < 2) {
+                       ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode);
+                       return -EINVAL;
+               }
+               mode = mode - 2; /*no a/turboa modes for 2112*/
+       } else if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+               rf_ini = rfregs_5112a;
+               rf_size = ARRAY_SIZE(rfregs_5112a);
+       } else {
+               rf_ini = rfregs_5112;
+               rf_size = ARRAY_SIZE(rfregs_5112);
+       }
+
+       /* Copy values to modify them */
+       for (i = 0; i < rf_size; i++) {
+               if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) {
+                       ATH5K_ERR(ah->ah_sc, "invalid bank\n");
+                       return -EINVAL;
+               }
+
+               if (bank != rf_ini[i].rf_bank) {
+                       bank = rf_ini[i].rf_bank;
+                       ah->ah_offset[bank] = i;
+               }
+
+               rf[i] = rf_ini[i].rf_value[mode];
+       }
+
+       /* Modify bank 6 */
+       if (channel->val & CHANNEL_2GHZ) {
+               if (channel->val & CHANNEL_OFDM)
+                       ee_mode = AR5K_EEPROM_MODE_11G;
+               else
+                       ee_mode = AR5K_EEPROM_MODE_11B;
+               obdb = 0;
+
+               if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                               ee->ee_ob[ee_mode][obdb], 3, 287, 0, true))
+                       return -EINVAL;
+
+               if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                               ee->ee_ob[ee_mode][obdb], 3, 290, 0, true))
+                       return -EINVAL;
+       } else {
+               /* For 11a, Turbo and XR */
+               ee_mode = AR5K_EEPROM_MODE_11A;
+               obdb = channel->freq >= 5725 ? 3 :
+                   (channel->freq >= 5500 ? 2 :
+                       (channel->freq >= 5260 ? 1 :
+                           (channel->freq > 4000 ? 0 : -1)));
+
+               if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                               ee->ee_ob[ee_mode][obdb], 3, 279, 0, true))
+                       return -EINVAL;
+
+               if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                               ee->ee_ob[ee_mode][obdb], 3, 282, 0, true))
+                       return -EINVAL;
+       }
+
+       ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+           ee->ee_x_gain[ee_mode], 2, 270, 0, true);
+       ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+           ee->ee_x_gain[ee_mode], 2, 257, 0, true);
+
+       if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+                       ee->ee_xpd[ee_mode], 1, 302, 0, true))
+               return -EINVAL;
+
+       /* Modify bank 7 */
+       if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
+                       ee->ee_i_gain[ee_mode], 6, 14, 0, true))
+               return -EINVAL;
+
+       /* Write RF values */
+       for (i = 0; i < rf_size; i++)
+               ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register);
+
+       return 0;
+}
+
+/*
+ * Initialize RF5413/5414
+ */
+static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel, unsigned int mode)
+{
+       const struct ath5k_ini_rf *rf_ini;
+       u32 *rf;
+       unsigned int rf_size, i;
+       int bank = -1;
+
+       AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+
+       rf = ah->ah_rf_banks;
+
+       rf_ini = rfregs_5413;
+       rf_size = ARRAY_SIZE(rfregs_5413);
+
+       /* Copy values to modify them */
+       for (i = 0; i < rf_size; i++) {
+               if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) {
+                       ATH5K_ERR(ah->ah_sc, "invalid bank\n");
+                       return -EINVAL;
+               }
+
+               if (bank != rf_ini[i].rf_bank) {
+                       bank = rf_ini[i].rf_bank;
+                       ah->ah_offset[bank] = i;
+               }
+
+               rf[i] = rf_ini[i].rf_value[mode];
+       }
+
+       /*
+        * After compairing dumps from different cards
+        * we get the same RF_BUFFER settings (diff returns
+        * 0 lines). It seems that RF_BUFFER settings are static
+        * and are written unmodified (no EEPROM stuff
+        * is used because calibration data would be
+        * different between different cards and would result
+        * different RF_BUFFER settings)
+        */
+
+       /* Write RF values */
+       for (i = 0; i < rf_size; i++)
+               ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register);
+
+       return 0;
+}
+
+/*
+ * Initialize RF
+ */
+int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+               unsigned int mode)
+{
+       int (*func)(struct ath5k_hw *, struct ieee80211_channel *, unsigned int);
+       int ret;
+
+       switch (ah->ah_radio) {
+       case AR5K_RF5111:
+               ah->ah_rf_banks_size = sizeof(rfregs_5111);
+               func = ath5k_hw_rf5111_rfregs;
+               break;
+       case AR5K_RF5112:
+               if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
+                       ah->ah_rf_banks_size = sizeof(rfregs_5112a);
+               else
+                       ah->ah_rf_banks_size = sizeof(rfregs_5112);
+               func = ath5k_hw_rf5112_rfregs;
+               break;
+       case AR5K_RF5413:
+               ah->ah_rf_banks_size = sizeof(rfregs_5413);
+               func = ath5k_hw_rf5413_rfregs;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (ah->ah_rf_banks == NULL) {
+               /* XXX do extra checks? */
+               ah->ah_rf_banks = kmalloc(ah->ah_rf_banks_size, GFP_KERNEL);
+               if (ah->ah_rf_banks == NULL) {
+                       ATH5K_ERR(ah->ah_sc, "out of memory\n");
+                       return -ENOMEM;
+               }
+       }
+
+       ret = func(ah, channel, mode);
+       if (!ret)
+               ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE;
+
+       return ret;
+}
+
+int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
+{
+       const struct ath5k_ini_rfgain *ath5k_rfg;
+       unsigned int i, size;
+
+       switch (ah->ah_radio) {
+       case AR5K_RF5111:
+               ath5k_rfg = rfgain_5111;
+               size = ARRAY_SIZE(rfgain_5111);
+               break;
+       case AR5K_RF5112:
+               ath5k_rfg = rfgain_5112;
+               size = ARRAY_SIZE(rfgain_5112);
+               break;
+       case AR5K_RF5413:
+               ath5k_rfg = rfgain_5413;
+               size = ARRAY_SIZE(rfgain_5413);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (freq) {
+       case AR5K_INI_RFGAIN_2GHZ:
+       case AR5K_INI_RFGAIN_5GHZ:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < size; i++) {
+               AR5K_REG_WAIT(i);
+               ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
+                       (u32)ath5k_rfg[i].rfg_register);
+       }
+
+       return 0;
+}
+
+enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah)
+{
+       u32 data, type;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active ||
+                       ah->ah_version <= AR5K_AR5211)
+               return AR5K_RFGAIN_INACTIVE;
+
+       if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED)
+               goto done;
+
+       data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
+
+       if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
+               ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
+               type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
+
+               if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK)
+                       ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR;
+
+               if (ah->ah_radio >= AR5K_RF5112) {
+                       ath5k_hw_rfregs_gainf_corr(ah);
+                       ah->ah_gain.g_current =
+                               ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ?
+                               (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
+                               0;
+               }
+
+               if (ath5k_hw_rfregs_gain_readback(ah) &&
+                               AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
+                               ath5k_hw_rfregs_gain_adjust(ah))
+                       ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE;
+       }
+
+done:
+       return ah->ah_rf_gain;
+}
+
+int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah)
+{
+       /* Initialize the gain optimization values */
+       switch (ah->ah_radio) {
+       case AR5K_RF5111:
+               ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
+               ah->ah_gain.g_step =
+                   &rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx];
+               ah->ah_gain.g_low = 20;
+               ah->ah_gain.g_high = 35;
+               ah->ah_gain.g_active = 1;
+               break;
+       case AR5K_RF5112:
+       case AR5K_RF5413: /* ??? */
+               ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
+               ah->ah_gain.g_step =
+                   &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx];
+               ah->ah_gain.g_low = 20;
+               ah->ah_gain.g_high = 85;
+               ah->ah_gain.g_active = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**************************\
+  PHY/RF channel functions
+\**************************/
+
+/*
+ * Check if a channel is supported
+ */
+bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
+{
+       /* Check if the channel is in our supported range */
+       if (flags & CHANNEL_2GHZ) {
+               if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
+                   (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
+                       return true;
+       } else if (flags & CHANNEL_5GHZ)
+               if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
+                   (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
+                       return true;
+
+       return false;
+}
+
+/*
+ * Convertion needed for RF5110
+ */
+static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel)
+{
+       u32 athchan;
+
+       /*
+        * Convert IEEE channel/MHz to an internal channel value used
+        * by the AR5210 chipset. This has not been verified with
+        * newer chipsets like the AR5212A who have a completely
+        * different RF/PHY part.
+        */
+       athchan = (ath5k_hw_bitswap((channel->chan - 24) / 2, 5) << 1) |
+               (1 << 6) | 0x1;
+
+       return athchan;
+}
+
+/*
+ * Set channel on RF5110
+ */
+static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel)
+{
+       u32 data;
+
+       /*
+        * Set the channel and wait
+        */
+       data = ath5k_hw_rf5110_chan2athchan(channel);
+       ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
+       ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
+       mdelay(1);
+
+       return 0;
+}
+
+/*
+ * Convertion needed for 5111
+ */
+static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
+               struct ath5k_athchan_2ghz *athchan)
+{
+       int channel;
+
+       /* Cast this value to catch negative channel numbers (>= -19) */
+       channel = (int)ieee;
+
+       /*
+        * Map 2GHz IEEE channel to 5GHz Atheros channel
+        */
+       if (channel <= 13) {
+               athchan->a2_athchan = 115 + channel;
+               athchan->a2_flags = 0x46;
+       } else if (channel == 14) {
+               athchan->a2_athchan = 124;
+               athchan->a2_flags = 0x44;
+       } else if (channel >= 15 && channel <= 26) {
+               athchan->a2_athchan = ((channel - 14) * 4) + 132;
+               athchan->a2_flags = 0x46;
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+/*
+ * Set channel on 5111
+ */
+static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel)
+{
+       struct ath5k_athchan_2ghz ath5k_channel_2ghz;
+       unsigned int ath5k_channel = channel->chan;
+       u32 data0, data1, clock;
+       int ret;
+
+       /*
+        * Set the channel on the RF5111 radio
+        */
+       data0 = data1 = 0;
+
+       if (channel->val & CHANNEL_2GHZ) {
+               /* Map 2GHz channel to 5GHz Atheros channel ID */
+               ret = ath5k_hw_rf5111_chan2athchan(channel->chan,
+                               &ath5k_channel_2ghz);
+               if (ret)
+                       return ret;
+
+               ath5k_channel = ath5k_channel_2ghz.a2_athchan;
+               data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff)
+                   << 5) | (1 << 4);
+       }
+
+       if (ath5k_channel < 145 || !(ath5k_channel & 1)) {
+               clock = 1;
+               data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) |
+                       (clock << 1) | (1 << 10) | 1;
+       } else {
+               clock = 0;
+               data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff)
+                       << 2) | (clock << 1) | (1 << 10) | 1;
+       }
+
+       ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8),
+                       AR5K_RF_BUFFER);
+       ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00),
+                       AR5K_RF_BUFFER_CONTROL_3);
+
+       return 0;
+}
+
+/*
+ * Set channel on 5112 and newer
+ */
+static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel)
+{
+       u32 data, data0, data1, data2;
+       u16 c;
+
+       data = data0 = data1 = data2 = 0;
+       c = channel->freq;
+
+       /*
+        * Set the channel on the RF5112 or newer
+        */
+       if (c < 4800) {
+               if (!((c - 2224) % 5)) {
+                       data0 = ((2 * (c - 704)) - 3040) / 10;
+                       data1 = 1;
+               } else if (!((c - 2192) % 5)) {
+                       data0 = ((2 * (c - 672)) - 3040) / 10;
+                       data1 = 0;
+               } else
+                       return -EINVAL;
+
+               data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
+       } else {
+               if (!(c % 20) && c >= 5120) {
+                       data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
+                       data2 = ath5k_hw_bitswap(3, 2);
+               } else if (!(c % 10)) {
+                       data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
+                       data2 = ath5k_hw_bitswap(2, 2);
+               } else if (!(c % 5)) {
+                       data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
+                       data2 = ath5k_hw_bitswap(1, 2);
+               } else
+                       return -EINVAL;
+       }
+
+       data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
+
+       ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
+       ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
+
+       return 0;
+}
+
+/*
+ * Set a channel on the radio chip
+ */
+int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
+{
+       int ret;
+
+       /*
+        * Check bounds supported by the PHY
+        * (don't care about regulation restrictions at this point)
+        */
+       if ((channel->freq < ah->ah_capabilities.cap_range.range_2ghz_min ||
+           channel->freq > ah->ah_capabilities.cap_range.range_2ghz_max) &&
+           (channel->freq < ah->ah_capabilities.cap_range.range_5ghz_min ||
+           channel->freq > ah->ah_capabilities.cap_range.range_5ghz_max)) {
+               ATH5K_ERR(ah->ah_sc,
+                       "channel out of supported range (%u MHz)\n",
+                       channel->freq);
+               return -EINVAL;
+       }
+
+       /*
+        * Set the channel and wait
+        */
+       switch (ah->ah_radio) {
+       case AR5K_RF5110:
+               ret = ath5k_hw_rf5110_channel(ah, channel);
+               break;
+       case AR5K_RF5111:
+               ret = ath5k_hw_rf5111_channel(ah, channel);
+               break;
+       default:
+               ret = ath5k_hw_rf5112_channel(ah, channel);
+               break;
+       }
+
+       if (ret)
+               return ret;
+
+       ah->ah_current_channel.freq = channel->freq;
+       ah->ah_current_channel.val = channel->val;
+       ah->ah_turbo = channel->val == CHANNEL_T ? true : false;
+
+       return 0;
+}
+
+/*****************\
+  PHY calibration
+\*****************/
+
+/**
+ * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
+ *
+ * @ah: struct ath5k_hw pointer we are operating on
+ * @freq: the channel frequency, just used for error logging
+ *
+ * This function performs a noise floor calibration of the PHY and waits for
+ * it to complete. Then the noise floor value is compared to some maximum
+ * noise floor we consider valid.
+ *
+ * Note that this is different from what the madwifi HAL does: it reads the
+ * noise floor and afterwards initiates the calibration. Since the noise floor
+ * calibration can take some time to finish, depending on the current channel
+ * use, that avoids the occasional timeout warnings we are seeing now.
+ *
+ * See the following link for an Atheros patent on noise floor calibration:
+ * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
+ * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
+ *
+ */
+int
+ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
+{
+       int ret;
+       unsigned int i;
+       s32 noise_floor;
+
+       /*
+        * Enable noise floor calibration and wait until completion
+        */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+                               AR5K_PHY_AGCCTL_NF);
+
+       ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+                       AR5K_PHY_AGCCTL_NF, 0, false);
+       if (ret) {
+               ATH5K_ERR(ah->ah_sc,
+                       "noise floor calibration timeout (%uMHz)\n", freq);
+               return ret;
+       }
+
+       /* Wait until the noise floor is calibrated and read the value */
+       for (i = 20; i > 0; i--) {
+               mdelay(1);
+               noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
+               noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
+               if (noise_floor & AR5K_PHY_NF_ACTIVE) {
+                       noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
+
+                       if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
+                               break;
+               }
+       }
+
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+               "noise floor %d\n", noise_floor);
+
+       if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
+               ATH5K_ERR(ah->ah_sc,
+                       "noise floor calibration failed (%uMHz)\n", freq);
+               return -EIO;
+       }
+
+       ah->ah_noise_floor = noise_floor;
+
+       return 0;
+}
+
+/*
+ * Perform a PHY calibration on RF5110
+ * -Fix BPSK/QAM Constellation (I/Q correction)
+ * -Calculate Noise Floor
+ */
+static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel)
+{
+       u32 phy_sig, phy_agc, phy_sat, beacon;
+       int ret;
+
+       /*
+        * Disable beacons and RX/TX queues, wait
+        */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
+               AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+       beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
+       ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
+
+       udelay(2300);
+
+       /*
+        * Set the channel (with AGC turned off)
+        */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+       udelay(10);
+       ret = ath5k_hw_channel(ah, channel);
+
+       /*
+        * Activate PHY and wait
+        */
+       ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+       mdelay(1);
+
+       AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+
+       if (ret)
+               return ret;
+
+       /*
+        * Calibrate the radio chip
+        */
+
+       /* Remember normal state */
+       phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG);
+       phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE);
+       phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT);
+
+       /* Update radio registers */
+       ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) |
+               AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG);
+
+       ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI |
+                       AR5K_PHY_AGCCOARSE_LO)) |
+               AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) |
+               AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE);
+
+       ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT |
+                       AR5K_PHY_ADCSAT_THR)) |
+               AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) |
+               AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT);
+
+       udelay(20);
+
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+       udelay(10);
+       ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
+       AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+
+       mdelay(1);
+
+       /*
+        * Enable calibration and wait until completion
+        */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL);
+
+       ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+                       AR5K_PHY_AGCCTL_CAL, 0, false);
+
+       /* Reset to normal state */
+       ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG);
+       ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE);
+       ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT);
+
+       if (ret) {
+               ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
+                               channel->freq);
+               return ret;
+       }
+
+       ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
+       if (ret)
+               return ret;
+
+       /*
+        * Re-enable RX/TX and beacons
+        */
+       AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
+               AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+       ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
+
+       return 0;
+}
+
+/*
+ * Perform a PHY calibration on RF5111/5112
+ */
+static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel)
+{
+       u32 i_pwr, q_pwr;
+       s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (ah->ah_calibration == false ||
+                       ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
+               goto done;
+
+       ah->ah_calibration = false;
+
+       iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
+       i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
+       q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
+       i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
+       q_coffd = q_pwr >> 6;
+
+       if (i_coffd == 0 || q_coffd == 0)
+               goto done;
+
+       i_coff = ((-iq_corr) / i_coffd) & 0x3f;
+       q_coff = (((s32)i_pwr / q_coffd) - 64) & 0x1f;
+
+       /* Commit new IQ value */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
+               ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
+
+done:
+       ath5k_hw_noise_floor_calibration(ah, channel->freq);
+
+       /* Request RF gain */
+       if (channel->val & CHANNEL_5GHZ) {
+               ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
+                       AR5K_PHY_PAPD_PROBE_TXPOWER) |
+                       AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
+               ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED;
+       }
+
+       return 0;
+}
+
+/*
+ * Perform a PHY calibration
+ */
+int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel)
+{
+       int ret;
+
+       if (ah->ah_radio == AR5K_RF5110)
+               ret = ath5k_hw_rf5110_calibrate(ah, channel);
+       else
+               ret = ath5k_hw_rf511x_calibrate(ah, channel);
+
+       return ret;
+}
+
+int ath5k_hw_phy_disable(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       /*Just a try M.F.*/
+       ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+
+       return 0;
+}
+
+/********************\
+  Misc PHY functions
+\********************/
+
+/*
+ * Get the PHY Chip revision
+ */
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
+{
+       unsigned int i;
+       u32 srev;
+       u16 ret;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       /*
+        * Set the radio chip access register
+        */
+       switch (chan) {
+       case CHANNEL_2GHZ:
+               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
+               break;
+       case CHANNEL_5GHZ:
+               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+               break;
+       default:
+               return 0;
+       }
+
+       mdelay(2);
+
+       /* ...wait until PHY is ready and read the selected radio revision */
+       ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
+
+       for (i = 0; i < 8; i++)
+               ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
+
+       if (ah->ah_version == AR5K_AR5210) {
+               srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
+               ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
+       } else {
+               srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
+               ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
+                               ((srev & 0x0f) << 4), 8);
+       }
+
+       /* Reset to the 5GHz mode */
+       ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+       return ret;
+}
+
+void /*TODO:Boundary check*/
+ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       /*Just a try M.F.*/
+       if (ah->ah_version != AR5K_AR5210)
+               ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA);
+}
+
+unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah)
+{
+       ATH5K_TRACE(ah->ah_sc);
+       /*Just a try M.F.*/
+       if (ah->ah_version != AR5K_AR5210)
+               return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+
+       return false; /*XXX: What do we return for 5210 ?*/
+}
+
+/*
+ * TX power setup
+ */
+
+/*
+ * Initialize the tx power table (not fully implemented)
+ */
+static void ath5k_txpower_table(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel, s16 max_power)
+{
+       unsigned int i, min, max, n;
+       u16 txpower, *rates;
+
+       rates = ah->ah_txpower.txp_rates;
+
+       txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2;
+       if (max_power > txpower)
+               txpower = max_power > AR5K_TUNE_MAX_TXPOWER ?
+                   AR5K_TUNE_MAX_TXPOWER : max_power;
+
+       for (i = 0; i < AR5K_MAX_RATES; i++)
+               rates[i] = txpower;
+
+       /* XXX setup target powers by rate */
+
+       ah->ah_txpower.txp_min = rates[7];
+       ah->ah_txpower.txp_max = rates[0];
+       ah->ah_txpower.txp_ofdm = rates[0];
+
+       /* Calculate the power table */
+       n = ARRAY_SIZE(ah->ah_txpower.txp_pcdac);
+       min = AR5K_EEPROM_PCDAC_START;
+       max = AR5K_EEPROM_PCDAC_STOP;
+       for (i = 0; i < n; i += AR5K_EEPROM_PCDAC_STEP)
+               ah->ah_txpower.txp_pcdac[i] =
+#ifdef notyet
+               min + ((i * (max - min)) / n);
+#else
+               min;
+#endif
+}
+
+/*
+ * Set transmition power
+ */
+int /*O.K. - txpower_table is unimplemented so this doesn't work*/
+ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+               unsigned int txpower)
+{
+       bool tpc = ah->ah_txpower.txp_tpc;
+       unsigned int i;
+
+       ATH5K_TRACE(ah->ah_sc);
+       if (txpower > AR5K_TUNE_MAX_TXPOWER) {
+               ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
+               return -EINVAL;
+       }
+
+       /* Reset TX power values */
+       memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
+       ah->ah_txpower.txp_tpc = tpc;
+
+       /* Initialize TX power table */
+       ath5k_txpower_table(ah, channel, txpower);
+
+       /*
+        * Write TX power values
+        */
+       for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
+               ath5k_hw_reg_write(ah,
+                       ((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | 0xff) & 0xffff) << 16) |
+                       (((ah->ah_txpower.txp_pcdac[(i << 1)    ] << 8) | 0xff) & 0xffff),
+                       AR5K_PHY_PCDAC_TXPOWER(i));
+       }
+
+       ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) |
+               AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) |
+               AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1);
+
+       ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) |
+               AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) |
+               AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2);
+
+       ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) |
+               AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) |
+               AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3);
+
+       ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) |
+               AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
+               AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
+
+       if (ah->ah_txpower.txp_tpc == true)
+               ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
+                       AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+       else
+               ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
+                       AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+
+       return 0;
+}
+
+int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power)
+{
+       /*Just a try M.F.*/
+       struct ieee80211_channel *channel = &ah->ah_current_channel;
+
+       ATH5K_TRACE(ah->ah_sc);
+       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER,
+               "changing txpower to %d\n", power);
+
+       return ath5k_hw_txpower(ah, channel, power);
+}
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
new file mode 100644 (file)
index 0000000..2f41c83
--- /dev/null
@@ -0,0 +1,1987 @@
+/*
+ * Copyright (c) 2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2007 Michael Taylor <mike.taylor@apprion.com>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k
+ * maintained by Reyk Floeter
+ *
+ * I tried to document those registers by looking at ar5k code, some
+ * 802.11 (802.11e mostly) papers and by reading various public available
+ * Atheros presentations and papers like these:
+ *
+ * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf
+ *        http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf
+ *
+ * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf
+ */
+
+
+
+/*====MAC DMA REGISTERS====*/
+
+/*
+ * AR5210-Specific TXDP registers
+ * 5210 has only 2 transmit queues so no DCU/QCU, just
+ * 2 transmit descriptor pointers...
+ */
+#define AR5K_NOQCU_TXDP0       0x0000          /* Queue 0 - data */
+#define AR5K_NOQCU_TXDP1       0x0004          /* Queue 1 - beacons */
+
+/*
+ * Mac Control Register
+ */
+#define        AR5K_CR         0x0008                  /* Register Address */
+#define AR5K_CR_TXE0   0x00000001      /* TX Enable for queue 0 on 5210 */
+#define AR5K_CR_TXE1   0x00000002      /* TX Enable for queue 1 on 5210 */
+#define        AR5K_CR_RXE     0x00000004      /* RX Enable */
+#define AR5K_CR_TXD0   0x00000008      /* TX Disable for queue 0 on 5210 */
+#define AR5K_CR_TXD1   0x00000010      /* TX Disable for queue 1 on 5210 */
+#define        AR5K_CR_RXD     0x00000020      /* RX Disable */
+#define        AR5K_CR_SWI     0x00000040
+
+/*
+ * RX Descriptor Pointer register
+ */
+#define        AR5K_RXDP       0x000c
+
+/*
+ * Configuration and status register
+ */
+#define        AR5K_CFG                0x0014                  /* Register Address */
+#define        AR5K_CFG_SWTD           0x00000001      /* Byte-swap TX descriptor (for big endian archs) */
+#define        AR5K_CFG_SWTB           0x00000002      /* Byte-swap TX buffer (?) */
+#define        AR5K_CFG_SWRD           0x00000004      /* Byte-swap RX descriptor */
+#define        AR5K_CFG_SWRB           0x00000008      /* Byte-swap RX buffer (?) */
+#define        AR5K_CFG_SWRG           0x00000010      /* Byte-swap Register values (?) */
+#define AR5K_CFG_ADHOC         0x00000020      /* [5211+] */
+#define AR5K_CFG_PHY_OK                0x00000100      /* [5211+] */
+#define AR5K_CFG_EEBS          0x00000200      /* EEPROM is busy */
+#define        AR5K_CFG_CLKGD          0x00000400      /* Clock gated (?) */
+#define AR5K_CFG_TXCNT         0x00007800      /* Tx frame count (?) [5210] */
+#define AR5K_CFG_TXCNT_S       11
+#define AR5K_CFG_TXFSTAT       0x00008000      /* Tx frame status (?) [5210] */
+#define AR5K_CFG_TXFSTRT       0x00010000      /* [5210] */
+#define        AR5K_CFG_PCI_THRES      0x00060000      /* [5211+] */
+#define        AR5K_CFG_PCI_THRES_S    17
+
+/*
+ * Interrupt enable register
+ */
+#define AR5K_IER               0x0024          /* Register Address */
+#define AR5K_IER_DISABLE       0x00000000      /* Disable card interrupts */
+#define AR5K_IER_ENABLE                0x00000001      /* Enable card interrupts */
+
+
+/*
+ * 0x0028 is Beacon Control Register on 5210
+ * and first RTS duration register on 5211
+ */
+
+/*
+ * Beacon control register [5210]
+ */
+#define AR5K_BCR               0x0028          /* Register Address */
+#define AR5K_BCR_AP            0x00000000      /* AP mode */
+#define AR5K_BCR_ADHOC         0x00000001      /* Ad-Hoc mode */
+#define AR5K_BCR_BDMAE         0x00000002      /* DMA enable */
+#define AR5K_BCR_TQ1FV         0x00000004      /* Use Queue1 for CAB traffic */
+#define AR5K_BCR_TQ1V          0x00000008      /* Use Queue1 for Beacon traffic */
+#define AR5K_BCR_BCGET         0x00000010
+
+/*
+ * First RTS duration register [5211]
+ */
+#define AR5K_RTSD0             0x0028          /* Register Address */
+#define        AR5K_RTSD0_6            0x000000ff      /* 6Mb RTS duration mask (?) */
+#define        AR5K_RTSD0_6_S          0               /* 6Mb RTS duration shift (?) */
+#define        AR5K_RTSD0_9            0x0000ff00      /* 9Mb*/
+#define        AR5K_RTSD0_9_S          8
+#define        AR5K_RTSD0_12           0x00ff0000      /* 12Mb*/
+#define        AR5K_RTSD0_12_S         16
+#define        AR5K_RTSD0_18           0xff000000      /* 16Mb*/
+#define        AR5K_RTSD0_18_S         24
+
+
+/*
+ * 0x002c is Beacon Status Register on 5210
+ * and second RTS duration register on 5211
+ */
+
+/*
+ * Beacon status register [5210]
+ *
+ * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR
+ * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning
+ * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR).
+ * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i
+ * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what
+ * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR.
+ */
+#define AR5K_BSR               0x002c                  /* Register Address */
+#define AR5K_BSR_BDLYSW                0x00000001      /* SW Beacon delay (?) */
+#define AR5K_BSR_BDLYDMA       0x00000002      /* DMA Beacon delay (?) */
+#define AR5K_BSR_TXQ1F         0x00000004      /* Beacon queue (1) finished */
+#define AR5K_BSR_ATIMDLY       0x00000008      /* ATIM delay (?) */
+#define AR5K_BSR_SNPADHOC      0x00000100      /* Ad-hoc mode set (?) */
+#define AR5K_BSR_SNPBDMAE      0x00000200      /* Beacon DMA enabled (?) */
+#define AR5K_BSR_SNPTQ1FV      0x00000400      /* Queue1 is used for CAB traffic (?) */
+#define AR5K_BSR_SNPTQ1V       0x00000800      /* Queue1 is used for Beacon traffic (?) */
+#define AR5K_BSR_SNAPSHOTSVALID        0x00001000      /* BCR snapshots are valid (?) */
+#define AR5K_BSR_SWBA_CNT      0x00ff0000
+
+/*
+ * Second RTS duration register [5211]
+ */
+#define AR5K_RTSD1             0x002c                  /* Register Address */
+#define        AR5K_RTSD1_24           0x000000ff      /* 24Mb */
+#define        AR5K_RTSD1_24_S         0
+#define        AR5K_RTSD1_36           0x0000ff00      /* 36Mb */
+#define        AR5K_RTSD1_36_S         8
+#define        AR5K_RTSD1_48           0x00ff0000      /* 48Mb */
+#define        AR5K_RTSD1_48_S         16
+#define        AR5K_RTSD1_54           0xff000000      /* 54Mb */
+#define        AR5K_RTSD1_54_S         24
+
+
+/*
+ * Transmit configuration register
+ */
+#define AR5K_TXCFG             0x0030                  /* Register Address */
+#define AR5K_TXCFG_SDMAMR      0x00000007      /* DMA size */
+#define AR5K_TXCFG_SDMAMR_S    0
+#define AR5K_TXCFG_B_MODE      0x00000008      /* Set b mode for 5111 (enable 2111) */
+#define AR5K_TXCFG_TXFSTP      0x00000008      /* TX DMA full Stop [5210] */
+#define AR5K_TXCFG_TXFULL      0x000003f0      /* TX Triger level mask */
+#define AR5K_TXCFG_TXFULL_S    4
+#define AR5K_TXCFG_TXFULL_0B   0x00000000
+#define AR5K_TXCFG_TXFULL_64B  0x00000010
+#define AR5K_TXCFG_TXFULL_128B 0x00000020
+#define AR5K_TXCFG_TXFULL_192B 0x00000030
+#define AR5K_TXCFG_TXFULL_256B 0x00000040
+#define AR5K_TXCFG_TXCONT_EN   0x00000080
+#define AR5K_TXCFG_DMASIZE     0x00000100      /* Flag for passing DMA size [5210] */
+#define AR5K_TXCFG_JUMBO_TXE   0x00000400      /* Enable jumbo frames transmition (?) [5211+] */
+#define AR5K_TXCFG_RTSRND      0x00001000      /* [5211+] */
+#define AR5K_TXCFG_FRMPAD_DIS  0x00002000      /* [5211+] */
+#define AR5K_TXCFG_RDY_DIS     0x00004000      /* [5211+] */
+
+/*
+ * Receive configuration register
+ */
+#define AR5K_RXCFG             0x0034                  /* Register Address */
+#define AR5K_RXCFG_SDMAMW      0x00000007      /* DMA size */
+#define AR5K_RXCFG_SDMAMW_S    0
+#define        AR5K_RXCFG_DEF_ANTENNA  0x00000008      /* Default antenna */
+#define AR5K_RXCFG_ZLFDMA      0x00000010      /* Zero-length DMA */
+#define AR5K_RXCFG_JUMBO_RXE   0x00000020      /* Enable jumbo frames reception (?) [5211+] */
+#define AR5K_RXCFG_JUMBO_WRAP  0x00000040      /* Wrap jumbo frames (?) [5211+] */
+
+/*
+ * Receive jumbo descriptor last address register
+ * Only found in 5211 (?)
+ */
+#define AR5K_RXJLA             0x0038
+
+/*
+ * MIB control register
+ */
+#define AR5K_MIBC              0x0040                  /* Register Address */
+#define AR5K_MIBC_COW          0x00000001
+#define AR5K_MIBC_FMC          0x00000002      /* Freeze Mib Counters (?) */
+#define AR5K_MIBC_CMC          0x00000004      /* Clean Mib Counters (?) */
+#define AR5K_MIBC_MCS          0x00000008
+
+/*
+ * Timeout prescale register
+ */
+#define AR5K_TOPS              0x0044
+#define        AR5K_TOPS_M             0x0000ffff      /* [5211+] (?) */
+
+/*
+ * Receive timeout register (no frame received)
+ */
+#define AR5K_RXNOFRM           0x0048
+#define        AR5K_RXNOFRM_M          0x000003ff      /* [5211+] (?) */
+
+/*
+ * Transmit timeout register (no frame sent)
+ */
+#define AR5K_TXNOFRM           0x004c
+#define        AR5K_TXNOFRM_M          0x000003ff      /* [5211+] (?) */
+#define        AR5K_TXNOFRM_QCU        0x000ffc00      /* [5211+] (?) */
+
+/*
+ * Receive frame gap timeout register
+ */
+#define AR5K_RPGTO             0x0050
+#define AR5K_RPGTO_M           0x000003ff      /* [5211+] (?) */
+
+/*
+ * Receive frame count limit register
+ */
+#define AR5K_RFCNT             0x0054
+#define AR5K_RFCNT_M           0x0000001f      /* [5211+] (?) */
+#define AR5K_RFCNT_RFCL                0x0000000f      /* [5210] */
+
+/*
+ * Misc settings register
+ */
+#define AR5K_MISC              0x0058                  /* Register Address */
+#define        AR5K_MISC_DMA_OBS_M     0x000001e0
+#define        AR5K_MISC_DMA_OBS_S     5
+#define        AR5K_MISC_MISC_OBS_M    0x00000e00
+#define        AR5K_MISC_MISC_OBS_S    9
+#define        AR5K_MISC_MAC_OBS_LSB_M 0x00007000
+#define        AR5K_MISC_MAC_OBS_LSB_S 12
+#define        AR5K_MISC_MAC_OBS_MSB_M 0x00038000
+#define        AR5K_MISC_MAC_OBS_MSB_S 15
+#define AR5K_MISC_LED_DECAY    0x001c0000      /* [5210] */
+#define AR5K_MISC_LED_BLINK    0x00e00000      /* [5210] */
+
+/*
+ * QCU/DCU clock gating register (5311)
+ */
+#define        AR5K_QCUDCU_CLKGT       0x005c                  /* Register Address (?) */
+#define        AR5K_QCUDCU_CLKGT_QCU   0x0000ffff      /* Mask for QCU clock */
+#define        AR5K_QCUDCU_CLKGT_DCU   0x07ff0000      /* Mask for DCU clock */
+
+/*
+ * Interrupt Status Registers
+ *
+ * For 5210 there is only one status register but for
+ * 5211/5212 we have one primary and 4 secondary registers.
+ * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212.
+ * Most of these bits are common for all chipsets.
+ */
+#define AR5K_ISR               0x001c                  /* Register Address [5210] */
+#define AR5K_PISR              0x0080                  /* Register Address [5211+] */
+#define AR5K_ISR_RXOK          0x00000001      /* Frame successfuly recieved */
+#define AR5K_ISR_RXDESC                0x00000002      /* RX descriptor request */
+#define AR5K_ISR_RXERR         0x00000004      /* Receive error */
+#define AR5K_ISR_RXNOFRM       0x00000008      /* No frame received (receive timeout) */
+#define AR5K_ISR_RXEOL         0x00000010      /* Empty RX descriptor */
+#define AR5K_ISR_RXORN         0x00000020      /* Receive FIFO overrun */
+#define AR5K_ISR_TXOK          0x00000040      /* Frame successfuly transmited */
+#define AR5K_ISR_TXDESC                0x00000080      /* TX descriptor request */
+#define AR5K_ISR_TXERR         0x00000100      /* Transmit error */
+#define AR5K_ISR_TXNOFRM       0x00000200      /* No frame transmited (transmit timeout) */
+#define AR5K_ISR_TXEOL         0x00000400      /* Empty TX descriptor */
+#define AR5K_ISR_TXURN         0x00000800      /* Transmit FIFO underrun */
+#define AR5K_ISR_MIB           0x00001000      /* Update MIB counters */
+#define AR5K_ISR_SWI           0x00002000      /* Software interrupt (?) */
+#define AR5K_ISR_RXPHY         0x00004000      /* PHY error */
+#define AR5K_ISR_RXKCM         0x00008000
+#define AR5K_ISR_SWBA          0x00010000      /* Software beacon alert */
+#define AR5K_ISR_BRSSI         0x00020000
+#define AR5K_ISR_BMISS         0x00040000      /* Beacon missed */
+#define AR5K_ISR_HIUERR                0x00080000      /* Host Interface Unit error [5211+] */
+#define AR5K_ISR_BNR           0x00100000      /* Beacon not ready [5211+] */
+#define AR5K_ISR_MCABT         0x00100000      /* [5210] */
+#define AR5K_ISR_RXCHIRP       0x00200000      /* [5212+] */
+#define AR5K_ISR_SSERR         0x00200000      /* [5210] */
+#define AR5K_ISR_DPERR         0x00400000      /* [5210] */
+#define AR5K_ISR_TIM           0x00800000      /* [5210] */
+#define AR5K_ISR_BCNMISC       0x00800000      /* [5212+] */
+#define AR5K_ISR_GPIO          0x01000000      /* GPIO (rf kill)*/
+#define AR5K_ISR_QCBRORN       0x02000000      /* CBR overrun (?)  [5211+] */
+#define AR5K_ISR_QCBRURN       0x04000000      /* CBR underrun (?) [5211+] */
+#define AR5K_ISR_QTRIG         0x08000000      /* [5211+] */
+
+/*
+ * Secondary status registers [5211+] (0 - 4)
+ *
+ * I guess from the names that these give the status for each
+ * queue, that's why only masks are defined here, haven't got
+ * any info about them (couldn't find them anywhere in ar5k code).
+ */
+#define AR5K_SISR0             0x0084                  /* Register Address [5211+] */
+#define AR5K_SISR0_QCU_TXOK    0x000003ff      /* Mask for QCU_TXOK */
+#define AR5K_SISR0_QCU_TXDESC  0x03ff0000      /* Mask for QCU_TXDESC */
+
+#define AR5K_SISR1             0x0088                  /* Register Address [5211+] */
+#define AR5K_SISR1_QCU_TXERR   0x000003ff      /* Mask for QCU_TXERR */
+#define AR5K_SISR1_QCU_TXEOL   0x03ff0000      /* Mask for QCU_TXEOL */
+
+#define AR5K_SISR2             0x008c                  /* Register Address [5211+] */
+#define AR5K_SISR2_QCU_TXURN   0x000003ff      /* Mask for QCU_TXURN */
+#define        AR5K_SISR2_MCABT        0x00100000
+#define        AR5K_SISR2_SSERR        0x00200000
+#define        AR5K_SISR2_DPERR        0x00400000
+#define        AR5K_SISR2_TIM          0x01000000      /* [5212+] */
+#define        AR5K_SISR2_CAB_END      0x02000000      /* [5212+] */
+#define        AR5K_SISR2_DTIM_SYNC    0x04000000      /* [5212+] */
+#define        AR5K_SISR2_BCN_TIMEOUT  0x08000000      /* [5212+] */
+#define        AR5K_SISR2_CAB_TIMEOUT  0x10000000      /* [5212+] */
+#define        AR5K_SISR2_DTIM         0x20000000      /* [5212+] */
+
+#define AR5K_SISR3             0x0090                  /* Register Address [5211+] */
+#define AR5K_SISR3_QCBRORN     0x000003ff      /* Mask for QCBRORN */
+#define AR5K_SISR3_QCBRURN     0x03ff0000      /* Mask for QCBRURN */
+
+#define AR5K_SISR4             0x0094                  /* Register Address [5211+] */
+#define AR5K_SISR4_QTRIG       0x000003ff      /* Mask for QTRIG */
+
+/*
+ * Shadow read-and-clear interrupt status registers [5211+]
+ */
+#define AR5K_RAC_PISR          0x00c0          /* Read and clear PISR */
+#define AR5K_RAC_SISR0         0x00c4          /* Read and clear SISR0 */
+#define AR5K_RAC_SISR1         0x00c8          /* Read and clear SISR1 */
+#define AR5K_RAC_SISR2         0x00cc          /* Read and clear SISR2 */
+#define AR5K_RAC_SISR3         0x00d0          /* Read and clear SISR3 */
+#define AR5K_RAC_SISR4         0x00d4          /* Read and clear SISR4 */
+
+/*
+ * Interrupt Mask Registers
+ *
+ * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary
+ * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match.
+ */
+#define        AR5K_IMR                0x0020                  /* Register Address [5210] */
+#define AR5K_PIMR              0x00a0                  /* Register Address [5211+] */
+#define AR5K_IMR_RXOK          0x00000001      /* Frame successfuly recieved*/
+#define AR5K_IMR_RXDESC                0x00000002      /* RX descriptor request*/
+#define AR5K_IMR_RXERR         0x00000004      /* Receive error*/
+#define AR5K_IMR_RXNOFRM       0x00000008      /* No frame received (receive timeout)*/
+#define AR5K_IMR_RXEOL         0x00000010      /* Empty RX descriptor*/
+#define AR5K_IMR_RXORN         0x00000020      /* Receive FIFO overrun*/
+#define AR5K_IMR_TXOK          0x00000040      /* Frame successfuly transmited*/
+#define AR5K_IMR_TXDESC                0x00000080      /* TX descriptor request*/
+#define AR5K_IMR_TXERR         0x00000100      /* Transmit error*/
+#define AR5K_IMR_TXNOFRM       0x00000200      /* No frame transmited (transmit timeout)*/
+#define AR5K_IMR_TXEOL         0x00000400      /* Empty TX descriptor*/
+#define AR5K_IMR_TXURN         0x00000800      /* Transmit FIFO underrun*/
+#define AR5K_IMR_MIB           0x00001000      /* Update MIB counters*/
+#define AR5K_IMR_SWI           0x00002000
+#define AR5K_IMR_RXPHY         0x00004000      /* PHY error*/
+#define AR5K_IMR_RXKCM         0x00008000
+#define AR5K_IMR_SWBA          0x00010000      /* Software beacon alert*/
+#define AR5K_IMR_BRSSI         0x00020000
+#define AR5K_IMR_BMISS         0x00040000      /* Beacon missed*/
+#define AR5K_IMR_HIUERR                0x00080000      /* Host Interface Unit error [5211+] */
+#define AR5K_IMR_BNR           0x00100000      /* Beacon not ready [5211+] */
+#define AR5K_IMR_MCABT         0x00100000      /* [5210] */
+#define AR5K_IMR_RXCHIRP       0x00200000      /* [5212+]*/
+#define AR5K_IMR_SSERR         0x00200000      /* [5210] */
+#define AR5K_IMR_DPERR         0x00400000      /* [5210] */
+#define AR5K_IMR_TIM           0x00800000      /* [5211+] */
+#define AR5K_IMR_BCNMISC       0x00800000      /* [5212+] */
+#define AR5K_IMR_GPIO          0x01000000      /* GPIO (rf kill)*/
+#define AR5K_IMR_QCBRORN       0x02000000      /* CBR overrun (?) [5211+] */
+#define AR5K_IMR_QCBRURN       0x04000000      /* CBR underrun (?) [5211+] */
+#define AR5K_IMR_QTRIG         0x08000000      /* [5211+] */
+
+/*
+ * Secondary interrupt mask registers [5211+] (0 - 4)
+ */
+#define AR5K_SIMR0             0x00a4                  /* Register Address [5211+] */
+#define AR5K_SIMR0_QCU_TXOK    0x000003ff      /* Mask for QCU_TXOK */
+#define AR5K_SIMR0_QCU_TXOK_S  0
+#define AR5K_SIMR0_QCU_TXDESC  0x03ff0000      /* Mask for QCU_TXDESC */
+#define AR5K_SIMR0_QCU_TXDESC_S        16
+
+#define AR5K_SIMR1             0x00a8                  /* Register Address [5211+] */
+#define AR5K_SIMR1_QCU_TXERR   0x000003ff      /* Mask for QCU_TXERR */
+#define AR5K_SIMR1_QCU_TXERR_S 0
+#define AR5K_SIMR1_QCU_TXEOL   0x03ff0000      /* Mask for QCU_TXEOL */
+#define AR5K_SIMR1_QCU_TXEOL_S 16
+
+#define AR5K_SIMR2             0x00ac                  /* Register Address [5211+] */
+#define AR5K_SIMR2_QCU_TXURN   0x000003ff      /* Mask for QCU_TXURN */
+#define AR5K_SIMR2_QCU_TXURN_S 0
+#define        AR5K_SIMR2_MCABT        0x00100000
+#define        AR5K_SIMR2_SSERR        0x00200000
+#define        AR5K_SIMR2_DPERR        0x00400000
+#define        AR5K_SIMR2_TIM          0x01000000      /* [5212+] */
+#define        AR5K_SIMR2_CAB_END      0x02000000      /* [5212+] */
+#define        AR5K_SIMR2_DTIM_SYNC    0x04000000      /* [5212+] */
+#define        AR5K_SIMR2_BCN_TIMEOUT  0x08000000      /* [5212+] */
+#define        AR5K_SIMR2_CAB_TIMEOUT  0x10000000      /* [5212+] */
+#define        AR5K_SIMR2_DTIM         0x20000000      /* [5212+] */
+
+#define AR5K_SIMR3             0x00b0                  /* Register Address [5211+] */
+#define AR5K_SIMR3_QCBRORN     0x000003ff      /* Mask for QCBRORN */
+#define AR5K_SIMR3_QCBRORN_S   0
+#define AR5K_SIMR3_QCBRURN     0x03ff0000      /* Mask for QCBRURN */
+#define AR5K_SIMR3_QCBRURN_S   16
+
+#define AR5K_SIMR4             0x00b4                  /* Register Address [5211+] */
+#define AR5K_SIMR4_QTRIG       0x000003ff      /* Mask for QTRIG */
+#define AR5K_SIMR4_QTRIG_S     0
+
+
+/*
+ * Decompression mask registers [5212+]
+ */
+#define AR5K_DCM_ADDR          0x0400          /*Decompression mask address (?)*/
+#define AR5K_DCM_DATA          0x0404          /*Decompression mask data (?)*/
+
+/*
+ * Decompression configuration registers [5212+]
+ */
+#define AR5K_DCCFG             0x0420
+
+/*
+ * Compression configuration registers [5212+]
+ */
+#define AR5K_CCFG              0x0600
+#define AR5K_CCFG_CUP          0x0604
+
+/*
+ * Compression performance counter registers [5212+]
+ */
+#define AR5K_CPC0              0x0610          /* Compression performance counter 0 */
+#define AR5K_CPC1              0x0614          /* Compression performance counter 1*/
+#define AR5K_CPC2              0x0618          /* Compression performance counter 2 */
+#define AR5K_CPC3              0x061c          /* Compression performance counter 3 */
+#define AR5K_CPCORN            0x0620          /* Compression performance overrun (?) */
+
+
+/*
+ * Queue control unit (QCU) registers [5211+]
+ *
+ * Card has 12 TX Queues but i see that only 0-9 are used (?)
+ * both in binary HAL (see ah.h) and ar5k. Each queue has it's own
+ * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate)
+ * configuration register (0x08c0 - 0x08ec), a ready time configuration
+ * register (0x0900 - 0x092c), a misc configuration register (0x09c0 -
+ * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some
+ * global registers, QCU transmit enable/disable and "one shot arm (?)"
+ * set/clear, which contain status for all queues (we shift by 1 for each
+ * queue). To access these registers easily we define some macros here
+ * that are used inside HAL. For more infos check out *_tx_queue functs.
+ *
+ * TODO: Boundary checking on macros (here?)
+ */
+
+/*
+ * Generic QCU Register access macros
+ */
+#define        AR5K_QUEUE_REG(_r, _q)          (((_q) << 2) + _r)
+#define AR5K_QCU_GLOBAL_READ(_r, _q)   (AR5K_REG_READ(_r) & (1 << _q))
+#define AR5K_QCU_GLOBAL_WRITE(_r, _q)  AR5K_REG_WRITE(_r, (1 << _q))
+
+/*
+ * QCU Transmit descriptor pointer registers
+ */
+#define AR5K_QCU_TXDP_BASE     0x0800          /* Register Address - Queue0 TXDP */
+#define AR5K_QUEUE_TXDP(_q)    AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q)
+
+/*
+ * QCU Transmit enable register
+ */
+#define AR5K_QCU_TXE           0x0840
+#define AR5K_ENABLE_QUEUE(_q)  AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q)
+#define AR5K_QUEUE_ENABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q)
+
+/*
+ * QCU Transmit disable register
+ */
+#define AR5K_QCU_TXD           0x0880
+#define AR5K_DISABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q)
+#define AR5K_QUEUE_DISABLED(_q)        AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q)
+
+/*
+ * QCU Constant Bit Rate configuration registers
+ */
+#define        AR5K_QCU_CBRCFG_BASE            0x08c0  /* Register Address - Queue0 CBRCFG */
+#define        AR5K_QCU_CBRCFG_INTVAL          0x00ffffff      /* CBR Interval mask */
+#define AR5K_QCU_CBRCFG_INTVAL_S       0
+#define        AR5K_QCU_CBRCFG_ORN_THRES       0xff000000      /* CBR overrun threshold mask */
+#define AR5K_QCU_CBRCFG_ORN_THRES_S    24
+#define        AR5K_QUEUE_CBRCFG(_q)           AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q)
+
+/*
+ * QCU Ready time configuration registers
+ */
+#define        AR5K_QCU_RDYTIMECFG_BASE        0x0900  /* Register Address - Queue0 RDYTIMECFG */
+#define        AR5K_QCU_RDYTIMECFG_INTVAL      0x00ffffff      /* Ready time interval mask */
+#define AR5K_QCU_RDYTIMECFG_INTVAL_S   0
+#define        AR5K_QCU_RDYTIMECFG_DURATION    0x00ffffff      /* Ready time duration mask */
+#define        AR5K_QCU_RDYTIMECFG_ENABLE      0x01000000      /* Ready time enable mask */
+#define AR5K_QUEUE_RDYTIMECFG(_q)      AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q)
+
+/*
+ * QCU one shot arm set registers
+ */
+#define        AR5K_QCU_ONESHOTARM_SET         0x0940  /* Register Address -QCU "one shot arm set (?)" */
+#define        AR5K_QCU_ONESHOTARM_SET_M       0x0000ffff
+
+/*
+ * QCU one shot arm clear registers
+ */
+#define        AR5K_QCU_ONESHOTARM_CLEAR       0x0980  /* Register Address -QCU "one shot arm clear (?)" */
+#define        AR5K_QCU_ONESHOTARM_CLEAR_M     0x0000ffff
+
+/*
+ * QCU misc registers
+ */
+#define AR5K_QCU_MISC_BASE             0x09c0                  /* Register Address -Queue0 MISC */
+#define        AR5K_QCU_MISC_FRSHED_M          0x0000000f      /* Frame sheduling mask */
+#define        AR5K_QCU_MISC_FRSHED_ASAP       0               /* ASAP */
+#define        AR5K_QCU_MISC_FRSHED_CBR        1               /* Constant Bit Rate */
+#define        AR5K_QCU_MISC_FRSHED_DBA_GT     2               /* DMA Beacon alert gated (?) */
+#define        AR5K_QCU_MISC_FRSHED_TIM_GT     3               /* Time gated (?) */
+#define        AR5K_QCU_MISC_FRSHED_BCN_SENT_GT        4       /* Beacon sent gated (?) */
+#define        AR5K_QCU_MISC_ONESHOT_ENABLE    0x00000010      /* Oneshot enable */
+#define        AR5K_QCU_MISC_CBREXP            0x00000020      /* CBR expired (normal queue) */
+#define        AR5K_QCU_MISC_CBREXP_BCN        0x00000040      /* CBR expired (beacon queue) */
+#define        AR5K_QCU_MISC_BCN_ENABLE        0x00000080      /* Beacons enabled */
+#define        AR5K_QCU_MISC_CBR_THRES_ENABLE  0x00000100      /* CBR threshold enabled (?) */
+#define        AR5K_QCU_MISC_TXE               0x00000200      /* TXE reset when RDYTIME enalbed (?) */
+#define        AR5K_QCU_MISC_CBR               0x00000400      /* CBR threshold reset (?) */
+#define        AR5K_QCU_MISC_DCU_EARLY         0x00000800      /* DCU reset (?) */
+#define AR5K_QUEUE_MISC(_q)            AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q)
+
+
+/*
+ * QCU status registers
+ */
+#define AR5K_QCU_STS_BASE      0x0a00                  /* Register Address - Queue0 STS */
+#define        AR5K_QCU_STS_FRMPENDCNT 0x00000003      /* Frames pending counter */
+#define        AR5K_QCU_STS_CBREXPCNT  0x0000ff00      /* CBR expired counter (?) */
+#define        AR5K_QUEUE_STATUS(_q)   AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q)
+
+/*
+ * QCU ready time shutdown register
+ */
+#define AR5K_QCU_RDYTIMESHDN   0x0a40
+#define AR5K_QCU_RDYTIMESHDN_M 0x000003ff
+
+/*
+ * QCU compression buffer base registers [5212+]
+ */
+#define AR5K_QCU_CBB_SELECT    0x0b00
+#define AR5K_QCU_CBB_ADDR      0x0b04
+
+/*
+ * QCU compression buffer configuration register [5212+]
+ */
+#define AR5K_QCU_CBCFG         0x0b08
+
+
+
+/*
+ * Distributed Coordination Function (DCF) control unit (DCU)
+ * registers [5211+]
+ *
+ * These registers control the various characteristics of each queue
+ * for 802.11e (WME) combatibility so they go together with
+ * QCU registers in pairs. For each queue we have a QCU mask register,
+ * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c),
+ * a retry limit register (0x1080 - 0x10ac), a channel time register
+ * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and
+ * a sequence number register (0x1140 - 0x116c). It seems that "global"
+ * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k).
+ * We use the same macros here for easier register access.
+ *
+ */
+
+/*
+ * DCU QCU mask registers
+ */
+#define AR5K_DCU_QCUMASK_BASE  0x1000          /* Register Address -Queue0 DCU_QCUMASK */
+#define AR5K_DCU_QCUMASK_M     0x000003ff
+#define AR5K_QUEUE_QCUMASK(_q) AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q)
+
+/*
+ * DCU local Inter Frame Space settings register
+ */
+#define AR5K_DCU_LCL_IFS_BASE          0x1040                  /* Register Address -Queue0 DCU_LCL_IFS */
+#define        AR5K_DCU_LCL_IFS_CW_MIN         0x000003ff      /* Minimum Contention Window */
+#define        AR5K_DCU_LCL_IFS_CW_MIN_S       0
+#define        AR5K_DCU_LCL_IFS_CW_MAX         0x000ffc00      /* Maximum Contention Window */
+#define        AR5K_DCU_LCL_IFS_CW_MAX_S       10
+#define        AR5K_DCU_LCL_IFS_AIFS           0x0ff00000      /* Arbitrated Interframe Space */
+#define        AR5K_DCU_LCL_IFS_AIFS_S         20
+#define        AR5K_QUEUE_DFS_LOCAL_IFS(_q)    AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q)
+
+/*
+ * DCU retry limit registers
+ */
+#define AR5K_DCU_RETRY_LMT_BASE                0x1080                  /* Register Address -Queue0 DCU_RETRY_LMT */
+#define AR5K_DCU_RETRY_LMT_SH_RETRY    0x0000000f      /* Short retry limit mask */
+#define AR5K_DCU_RETRY_LMT_SH_RETRY_S  0
+#define AR5K_DCU_RETRY_LMT_LG_RETRY    0x000000f0      /* Long retry limit mask */
+#define AR5K_DCU_RETRY_LMT_LG_RETRY_S  4
+#define AR5K_DCU_RETRY_LMT_SSH_RETRY   0x00003f00      /* Station short retry limit mask (?) */
+#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8
+#define AR5K_DCU_RETRY_LMT_SLG_RETRY   0x000fc000      /* Station long retry limit mask (?) */
+#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14
+#define        AR5K_QUEUE_DFS_RETRY_LIMIT(_q)  AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q)
+
+/*
+ * DCU channel time registers
+ */
+#define AR5K_DCU_CHAN_TIME_BASE                0x10c0                  /* Register Address -Queue0 DCU_CHAN_TIME */
+#define        AR5K_DCU_CHAN_TIME_DUR          0x000fffff      /* Channel time duration */
+#define        AR5K_DCU_CHAN_TIME_DUR_S        0
+#define        AR5K_DCU_CHAN_TIME_ENABLE       0x00100000      /* Enable channel time */
+#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q)        AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q)
+
+/*
+ * DCU misc registers [5211+]
+ *
+ * For some of the registers i couldn't find in the code
+ * (only backoff stuff is there realy) i tried to match the
+ * names with 802.11e parameters etc, so i guess VIRTCOL here
+ * means Virtual Collision and HCFPOLL means Hybrid Coordination
+ * factor Poll (CF- Poll). Arbiter lockout control controls the
+ * behaviour on low priority queues when we have multiple queues
+ * with pending frames. Intra-frame lockout means we wait until
+ * the queue's current frame transmits (with post frame backoff and bursting)
+ * before we transmit anything else and global lockout means we
+ * wait for the whole queue to finish before higher priority queues
+ * can transmit (this is used on beacon and CAB queues).
+ * No lockout means there is no special handling.
+ */
+#define AR5K_DCU_MISC_BASE             0x1100                  /* Register Address -Queue0 DCU_MISC */
+#define        AR5K_DCU_MISC_BACKOFF           0x000007ff      /* Mask for backoff setting (?) */
+#define AR5K_DCU_MISC_BACKOFF_FRAG     0x00000200      /* Enable backoff while bursting */
+#define        AR5K_DCU_MISC_HCFPOLL_ENABLE    0x00000800      /* CF - Poll (?) */
+#define        AR5K_DCU_MISC_BACKOFF_PERSIST   0x00001000      /* Persistent backoff (?) */
+#define        AR5K_DCU_MISC_FRMPRFTCH_ENABLE  0x00002000      /* Enable frame pre-fetch (?) */
+#define        AR5K_DCU_MISC_VIRTCOL           0x0000c000      /* Mask for Virtual Collision (?) */
+#define        AR5K_DCU_MISC_VIRTCOL_NORMAL    0
+#define        AR5K_DCU_MISC_VIRTCOL_MODIFIED  1
+#define        AR5K_DCU_MISC_VIRTCOL_IGNORE    2
+#define        AR5K_DCU_MISC_BCN_ENABLE        0x00010000      /* Beacon enable (?) */
+#define        AR5K_DCU_MISC_ARBLOCK_CTL       0x00060000      /* Arbiter lockout control mask */
+#define        AR5K_DCU_MISC_ARBLOCK_CTL_S     17
+#define        AR5K_DCU_MISC_ARBLOCK_CTL_NONE  0               /* No arbiter lockout */
+#define        AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM        1       /* Intra-frame lockout */
+#define        AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL        2       /* Global lockout */
+#define        AR5K_DCU_MISC_ARBLOCK_IGNORE    0x00080000
+#define        AR5K_DCU_MISC_SEQ_NUM_INCR_DIS  0x00100000      /* Disable sequence number increment (?) */
+#define        AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000      /* Disable post-frame backoff (?) */
+#define        AR5K_DCU_MISC_VIRT_COLL_POLICY  0x00400000      /* Virtual Collision policy (?) */
+#define        AR5K_DCU_MISC_BLOWN_IFS_POLICY  0x00800000
+#define        AR5K_DCU_MISC_SEQNUM_CTL        0x01000000      /* Sequence number control (?) */
+#define AR5K_QUEUE_DFS_MISC(_q)                AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q)
+
+/*
+ * DCU frame sequence number registers
+ */
+#define AR5K_DCU_SEQNUM_BASE   0x1140
+#define        AR5K_DCU_SEQNUM_M       0x00000fff
+#define        AR5K_QUEUE_DFS_SEQNUM(_q)       AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
+
+/*
+ * DCU global IFS SIFS registers
+ */
+#define AR5K_DCU_GBL_IFS_SIFS  0x1030
+#define AR5K_DCU_GBL_IFS_SIFS_M        0x0000ffff
+
+/*
+ * DCU global IFS slot interval registers
+ */
+#define AR5K_DCU_GBL_IFS_SLOT  0x1070
+#define AR5K_DCU_GBL_IFS_SLOT_M        0x0000ffff
+
+/*
+ * DCU global IFS EIFS registers
+ */
+#define AR5K_DCU_GBL_IFS_EIFS  0x10b0
+#define AR5K_DCU_GBL_IFS_EIFS_M        0x0000ffff
+
+/*
+ * DCU global IFS misc registers
+ */
+#define AR5K_DCU_GBL_IFS_MISC                  0x10f0                  /* Register Address */
+#define        AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE        0x00000007
+#define        AR5K_DCU_GBL_IFS_MISC_TURBO_MODE        0x00000008      /* Turbo mode (?) */
+#define        AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC     0x000003f0      /* SIFS Duration mask (?) */
+#define        AR5K_DCU_GBL_IFS_MISC_USEC_DUR          0x000ffc00
+#define        AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY     0x00300000
+
+/*
+ * DCU frame prefetch control register
+ */
+#define AR5K_DCU_FP            0x1230
+
+/*
+ * DCU transmit pause control/status register
+ */
+#define AR5K_DCU_TXP           0x1270                  /* Register Address */
+#define        AR5K_DCU_TXP_M          0x000003ff      /* Tx pause mask (?) */
+#define        AR5K_DCU_TXP_STATUS     0x00010000      /* Tx pause status (?) */
+
+/*
+ * DCU transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER     0x1038
+
+/*
+ * DCU clear transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER_CLR 0x143c
+
+/*
+ * DCU set transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER_SET 0x147c
+
+/*
+ * Reset control register
+ *
+ * 4 and 8 are not used in 5211/5212 and
+ * 2 means "baseband reset" on 5211/5212.
+ */
+#define AR5K_RESET_CTL         0x4000                  /* Register Address */
+#define AR5K_RESET_CTL_PCU     0x00000001      /* Protocol Control Unit reset */
+#define AR5K_RESET_CTL_DMA     0x00000002      /* DMA (Rx/Tx) reset [5210] */
+#define        AR5K_RESET_CTL_BASEBAND 0x00000002      /* Baseband reset [5211+] */
+#define AR5K_RESET_CTL_MAC     0x00000004      /* MAC reset (PCU+Baseband ?) [5210] */
+#define AR5K_RESET_CTL_PHY     0x00000008      /* PHY reset [5210] */
+#define AR5K_RESET_CTL_PCI     0x00000010      /* PCI Core reset (interrupts etc) */
+#define AR5K_RESET_CTL_CHIP    (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA |      \
+                               AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY)
+
+/*
+ * Sleep control register
+ */
+#define AR5K_SLEEP_CTL                 0x4004                  /* Register Address */
+#define AR5K_SLEEP_CTL_SLDUR           0x0000ffff      /* Sleep duration mask */
+#define AR5K_SLEEP_CTL_SLDUR_S         0
+#define AR5K_SLEEP_CTL_SLE             0x00030000      /* Sleep enable mask */
+#define AR5K_SLEEP_CTL_SLE_S           16
+#define AR5K_SLEEP_CTL_SLE_WAKE                0x00000000      /* Force chip awake */
+#define AR5K_SLEEP_CTL_SLE_SLP         0x00010000      /* Force chip sleep */
+#define AR5K_SLEEP_CTL_SLE_ALLOW       0x00020000
+#define AR5K_SLEEP_CTL_SLE_UNITS       0x00000008      /* [5211+] */
+
+/*
+ * Interrupt pending register
+ */
+#define AR5K_INTPEND   0x4008
+#define AR5K_INTPEND_M 0x00000001
+
+/*
+ * Sleep force register
+ */
+#define AR5K_SFR       0x400c
+#define AR5K_SFR_M     0x00000001
+
+/*
+ * PCI configuration register
+ */
+#define AR5K_PCICFG                    0x4010                  /* Register Address */
+#define AR5K_PCICFG_EEAE               0x00000001      /* Eeprom access enable [5210] */
+#define AR5K_PCICFG_CLKRUNEN           0x00000004      /* CLKRUN enable [5211+] */
+#define AR5K_PCICFG_EESIZE             0x00000018      /* Mask for EEPROM size [5211+] */
+#define AR5K_PCICFG_EESIZE_S           3
+#define AR5K_PCICFG_EESIZE_4K          0               /* 4K */
+#define AR5K_PCICFG_EESIZE_8K          1               /* 8K */
+#define AR5K_PCICFG_EESIZE_16K         2               /* 16K */
+#define AR5K_PCICFG_EESIZE_FAIL                3               /* Failed to get size (?) [5211+] */
+#define AR5K_PCICFG_LED                        0x00000060      /* Led status [5211+] */
+#define AR5K_PCICFG_LED_NONE           0x00000000      /* Default [5211+] */
+#define AR5K_PCICFG_LED_PEND           0x00000020      /* Scan / Auth pending */
+#define AR5K_PCICFG_LED_ASSOC          0x00000040      /* Associated */
+#define        AR5K_PCICFG_BUS_SEL             0x00000380      /* Mask for "bus select" [5211+] (?) */
+#define        AR5K_PCICFG_CBEFIX_DIS          0x00000400      /* Disable CBE fix (?) */
+#define AR5K_PCICFG_SL_INTEN           0x00000800      /* Enable interrupts when asleep (?) */
+#define AR5K_PCICFG_LED_BCTL           0x00001000      /* Led blink (?) [5210] */
+#define AR5K_PCICFG_SL_INPEN           0x00002800      /* Sleep even whith pending interrupts (?) */
+#define AR5K_PCICFG_SPWR_DN            0x00010000      /* Mask for power status */
+#define AR5K_PCICFG_LEDMODE            0x000e0000      /* Ledmode [5211+] */
+#define AR5K_PCICFG_LEDMODE_PROP       0x00000000      /* Blink on standard traffic [5211+] */
+#define AR5K_PCICFG_LEDMODE_PROM       0x00020000      /* Default mode (blink on any traffic) [5211+] */
+#define AR5K_PCICFG_LEDMODE_PWR                0x00040000      /* Some other blinking mode  (?) [5211+] */
+#define AR5K_PCICFG_LEDMODE_RAND       0x00060000      /* Random blinking (?) [5211+] */
+#define AR5K_PCICFG_LEDBLINK           0x00700000
+#define AR5K_PCICFG_LEDBLINK_S         20
+#define AR5K_PCICFG_LEDSLOW            0x00800000      /* Slow led blink rate (?) [5211+] */
+#define AR5K_PCICFG_LEDSTATE                           \
+       (AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE |        \
+       AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW)
+
+/*
+ * "General Purpose Input/Output" (GPIO) control register
+ *
+ * I'm not sure about this but after looking at the code
+ * for all chipsets here is what i got.
+ *
+ * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits)
+ * Mode 0 -> always input
+ * Mode 1 -> output when GPIODO for this GPIO is set to 0
+ * Mode 2 -> output when GPIODO for this GPIO is set to 1
+ * Mode 3 -> always output
+ *
+ * For more infos check out get_gpio/set_gpio and
+ * set_gpio_input/set_gpio_output functs.
+ * For more infos on gpio interrupt check out set_gpio_intr.
+ */
+#define AR5K_NUM_GPIO  6
+
+#define AR5K_GPIOCR            0x4014                          /* Register Address */
+#define AR5K_GPIOCR_INT_ENA    0x00008000              /* Enable GPIO interrupt */
+#define AR5K_GPIOCR_INT_SELL   0x00000000              /* Generate interrupt when pin is off (?) */
+#define AR5K_GPIOCR_INT_SELH   0x00010000              /* Generate interrupt when pin is on */
+#define AR5K_GPIOCR_IN(n)      (0 << ((n) * 2))        /* Mode 0 for pin n */
+#define AR5K_GPIOCR_OUT0(n)    (1 << ((n) * 2))        /* Mode 1 for pin n */
+#define AR5K_GPIOCR_OUT1(n)    (2 << ((n) * 2))        /* Mode 2 for pin n */
+#define AR5K_GPIOCR_OUT(n)     (3 << ((n) * 2))        /* Mode 3 for pin n */
+#define AR5K_GPIOCR_INT_SEL(n) ((n) << 12)             /* Interrupt for GPIO pin n */
+
+/*
+ * "General Purpose Input/Output" (GPIO) data output register
+ */
+#define AR5K_GPIODO    0x4018
+
+/*
+ * "General Purpose Input/Output" (GPIO) data input register
+ */
+#define AR5K_GPIODI    0x401c
+#define AR5K_GPIODI_M  0x0000002f
+
+
+/*
+ * Silicon revision register
+ */
+#define AR5K_SREV              0x4020                  /* Register Address */
+#define AR5K_SREV_REV          0x0000000f      /* Mask for revision */
+#define AR5K_SREV_REV_S                0
+#define AR5K_SREV_VER          0x000000ff      /* Mask for version */
+#define AR5K_SREV_VER_S                4
+
+
+
+/*====EEPROM REGISTERS====*/
+
+/*
+ * EEPROM access registers
+ *
+ * Here we got a difference between 5210/5211-12
+ * read data register for 5210 is at 0x6800 and
+ * status register is at 0x6c00. There is also
+ * no eeprom command register on 5210 and the
+ * offsets are different.
+ *
+ * To read eeprom data for a specific offset:
+ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
+ *        read AR5K_EEPROM_BASE +(4 * offset)
+ *        check the eeprom status register
+ *        and read eeprom data register.
+ *
+ * 5211 - write offset to AR5K_EEPROM_BASE
+ * 5212   write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD
+ *        check the eeprom status register
+ *        and read eeprom data register.
+ *
+ * To write eeprom data for a specific offset:
+ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
+ *        write data to AR5K_EEPROM_BASE +(4 * offset)
+ *        check the eeprom status register
+ * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD
+ * 5212   write offset to AR5K_EEPROM_BASE
+ *        write data to data register
+ *       write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD
+ *        check the eeprom status register
+ *
+ * For more infos check eeprom_* functs and the ar5k.c
+ * file posted in madwifi-devel mailing list.
+ * http://sourceforge.net/mailarchive/message.php?msg_id=8966525
+ *
+ */
+#define AR5K_EEPROM_BASE       0x6000
+
+/*
+ * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
+ */
+#define AR5K_EEPROM_MAGIC              0x003d  /* EEPROM Magic number */
+#define AR5K_EEPROM_MAGIC_VALUE                0x5aa5  /* Default - found on EEPROM */
+#define AR5K_EEPROM_MAGIC_5212         0x0000145c /* 5212 */
+#define AR5K_EEPROM_MAGIC_5211         0x0000145b /* 5211 */
+#define AR5K_EEPROM_MAGIC_5210         0x0000145a /* 5210 */
+
+#define AR5K_EEPROM_PROTECT            0x003f  /* EEPROM protect status */
+#define AR5K_EEPROM_PROTECT_RD_0_31    0x0001  /* Read protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_WR_0_31    0x0002  /* Write protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_RD_32_63   0x0004  /* 0x20 - 0x3f */
+#define AR5K_EEPROM_PROTECT_WR_32_63   0x0008
+#define AR5K_EEPROM_PROTECT_RD_64_127  0x0010  /* 0x40 - 0x7f */
+#define AR5K_EEPROM_PROTECT_WR_64_127  0x0020
+#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040  /* 0x80 - 0xbf (regdom) */
+#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080
+#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100  /* 0xc0 - 0xcf */
+#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200
+#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400  /* 0xd0 - 0xdf */
+#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800
+#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000  /* 0xe0 - 0xef */
+#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
+#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000  /* 0xf0 - 0xff */
+#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
+#define AR5K_EEPROM_REG_DOMAIN         0x00bf  /* EEPROM regdom */
+#define AR5K_EEPROM_INFO_BASE          0x00c0  /* EEPROM header */
+#define AR5K_EEPROM_INFO_MAX           (0x400 - AR5K_EEPROM_INFO_BASE)
+#define AR5K_EEPROM_INFO_CKSUM         0xffff
+#define AR5K_EEPROM_INFO(_n)           (AR5K_EEPROM_INFO_BASE + (_n))
+
+#define AR5K_EEPROM_VERSION            AR5K_EEPROM_INFO(1)     /* EEPROM Version */
+#define AR5K_EEPROM_VERSION_3_0                0x3000  /* No idea what's going on before this version */
+#define AR5K_EEPROM_VERSION_3_1                0x3001  /* ob/db values for 2Ghz (ar5211_rfregs) */
+#define AR5K_EEPROM_VERSION_3_2                0x3002  /* different frequency representation (eeprom_bin2freq) */
+#define AR5K_EEPROM_VERSION_3_3                0x3003  /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_3_4                0x3004  /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0                0x4000  /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_1                0x4001  /* has ee_margin_tx_rx (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_2                0x4002  /* has ee_cck_ofdm_gain_delta (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_3                0x4003
+#define AR5K_EEPROM_VERSION_4_4                0x4004
+#define AR5K_EEPROM_VERSION_4_5                0x4005
+#define AR5K_EEPROM_VERSION_4_6                0x4006  /* has ee_scaled_cck_delta */
+#define AR5K_EEPROM_VERSION_4_7                0x3007
+
+#define AR5K_EEPROM_MODE_11A           0
+#define AR5K_EEPROM_MODE_11B           1
+#define AR5K_EEPROM_MODE_11G           2
+
+#define AR5K_EEPROM_HDR                        AR5K_EEPROM_INFO(2)     /* Header that contains the device caps */
+#define AR5K_EEPROM_HDR_11A(_v)                (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
+#define AR5K_EEPROM_HDR_11B(_v)                (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
+#define AR5K_EEPROM_HDR_11G(_v)                (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
+#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1)     /* Disable turbo for 2Ghz (?) */
+#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f)    /* Max turbo power for a/XR mode (eeprom_init) */
+#define AR5K_EEPROM_HDR_DEVICE(_v)     (((_v) >> 11) & 0x7)
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1)    /* Disable turbo for 5Ghz (?) */
+#define AR5K_EEPROM_HDR_RFKILL(_v)     (((_v) >> 14) & 0x1)    /* Device has RFKill support */
+
+#define AR5K_EEPROM_RFKILL_GPIO_SEL    0x0000001c
+#define AR5K_EEPROM_RFKILL_GPIO_SEL_S  2
+#define AR5K_EEPROM_RFKILL_POLARITY    0x00000002
+#define AR5K_EEPROM_RFKILL_POLARITY_S  1
+
+/* Newer EEPROMs are using a different offset */
+#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
+       (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
+
+#define AR5K_EEPROM_ANT_GAIN(_v)       AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)  ((int8_t)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)  ((int8_t)((_v) & 0xff))
+
+/* calibration settings */
+#define AR5K_EEPROM_MODES_11A(_v)      AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
+#define AR5K_EEPROM_MODES_11B(_v)      AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
+#define AR5K_EEPROM_MODES_11G(_v)      AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
+#define AR5K_EEPROM_CTL(_v)            AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)     /* Conformance test limits */
+
+/* [3.1 - 3.3] */
+#define AR5K_EEPROM_OBDB0_2GHZ         0x00ec
+#define AR5K_EEPROM_OBDB1_2GHZ         0x00ed
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0              0x00c4
+#define AR5K_EEPROM_EARSTART(_v)       ((_v) & 0xfff)
+#define AR5K_EEPROM_EEMAP(_v)          (((_v) >> 14) & 0x3)
+#define AR5K_EEPROM_MISC1              0x00c5
+#define AR5K_EEPROM_TARGET_PWRSTART(_v)        ((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)        (((_v) >> 14) & 0x1)
+
+/*
+ * EEPROM data register
+ */
+#define AR5K_EEPROM_DATA_5211  0x6004
+#define AR5K_EEPROM_DATA_5210  0x6800
+#define        AR5K_EEPROM_DATA        (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
+
+/*
+ * EEPROM command register
+ */
+#define AR5K_EEPROM_CMD                0x6008                  /* Register Addres */
+#define AR5K_EEPROM_CMD_READ   0x00000001      /* EEPROM read */
+#define AR5K_EEPROM_CMD_WRITE  0x00000002      /* EEPROM write */
+#define AR5K_EEPROM_CMD_RESET  0x00000004      /* EEPROM reset */
+
+/*
+ * EEPROM status register
+ */
+#define AR5K_EEPROM_STAT_5210  0x6c00                  /* Register Address [5210] */
+#define AR5K_EEPROM_STAT_5211  0x600c                  /* Register Address [5211+] */
+#define        AR5K_EEPROM_STATUS      (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
+#define AR5K_EEPROM_STAT_RDERR 0x00000001      /* EEPROM read failed */
+#define AR5K_EEPROM_STAT_RDDONE        0x00000002      /* EEPROM read successful */
+#define AR5K_EEPROM_STAT_WRERR 0x00000004      /* EEPROM write failed */
+#define AR5K_EEPROM_STAT_WRDONE        0x00000008      /* EEPROM write successful */
+
+/*
+ * EEPROM config register (?)
+ */
+#define AR5K_EEPROM_CFG        0x6010
+
+
+
+/*
+ * Protocol Control Unit (PCU) registers
+ */
+/*
+ * Used for checking initial register writes
+ * during channel reset (see reset func)
+ */
+#define AR5K_PCU_MIN   0x8000
+#define AR5K_PCU_MAX   0x8fff
+
+/*
+ * First station id register (MAC address in lower 32 bits)
+ */
+#define AR5K_STA_ID0   0x8000
+
+/*
+ * Second station id register (MAC address in upper 16 bits)
+ */
+#define AR5K_STA_ID1                   0x8004                  /* Register Address */
+#define AR5K_STA_ID1_AP                        0x00010000      /* Set AP mode */
+#define AR5K_STA_ID1_ADHOC             0x00020000      /* Set Ad-Hoc mode */
+#define AR5K_STA_ID1_PWR_SV            0x00040000      /* Power save reporting (?) */
+#define AR5K_STA_ID1_NO_KEYSRCH                0x00080000      /* No key search */
+#define AR5K_STA_ID1_NO_PSPOLL         0x00100000      /* No power save polling [5210] */
+#define AR5K_STA_ID1_PCF_5211          0x00100000      /* Enable PCF on [5211+] */
+#define AR5K_STA_ID1_PCF_5210          0x00200000      /* Enable PCF on [5210]*/
+#define        AR5K_STA_ID1_PCF                (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211)
+#define AR5K_STA_ID1_DEFAULT_ANTENNA   0x00200000      /* Use default antenna */
+#define AR5K_STA_ID1_DESC_ANTENNA      0x00400000      /* Update antenna from descriptor */
+#define AR5K_STA_ID1_RTS_DEF_ANTENNA   0x00800000      /* Use default antenna for RTS (?) */
+#define AR5K_STA_ID1_ACKCTS_6MB                0x01000000      /* Use 6Mbit/s for ACK/CTS (?) */
+#define AR5K_STA_ID1_BASE_RATE_11B     0x02000000      /* Use 11b base rate (for ACK/CTS ?) [5211+] */
+
+/*
+ * First BSSID register (MAC address, lower 32bits)
+ */
+#define AR5K_BSS_ID0   0x8008
+
+/*
+ * Second BSSID register (MAC address in upper 16 bits)
+ *
+ * AID: Association ID
+ */
+#define AR5K_BSS_ID1           0x800c
+#define AR5K_BSS_ID1_AID       0xffff0000
+#define AR5K_BSS_ID1_AID_S     16
+
+/*
+ * Backoff slot time register
+ */
+#define AR5K_SLOT_TIME 0x8010
+
+/*
+ * ACK/CTS timeout register
+ */
+#define AR5K_TIME_OUT          0x8014                  /* Register Address */
+#define AR5K_TIME_OUT_ACK      0x00001fff      /* ACK timeout mask */
+#define AR5K_TIME_OUT_ACK_S    0
+#define AR5K_TIME_OUT_CTS      0x1fff0000      /* CTS timeout mask */
+#define AR5K_TIME_OUT_CTS_S    16
+
+/*
+ * RSSI threshold register
+ */
+#define AR5K_RSSI_THR                  0x8018          /* Register Address */
+#define AR5K_RSSI_THR_M                        0x000000ff      /* Mask for RSSI threshold [5211+] */
+#define AR5K_RSSI_THR_BMISS_5210       0x00000700      /* Mask for Beacon Missed threshold [5210] */
+#define AR5K_RSSI_THR_BMISS_5210_S     8
+#define AR5K_RSSI_THR_BMISS_5211       0x0000ff00      /* Mask for Beacon Missed threshold [5211+] */
+#define AR5K_RSSI_THR_BMISS_5211_S     8
+#define        AR5K_RSSI_THR_BMISS             (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211)
+#define        AR5K_RSSI_THR_BMISS_S           8
+
+/*
+ * 5210 has more PCU registers because there is no QCU/DCU
+ * so queue parameters are set here, this way a lot common
+ * registers have different address for 5210. To make things
+ * easier we define a macro based on ah->ah_version for common
+ * registers with different addresses and common flags.
+ */
+
+/*
+ * Retry limit register
+ *
+ * Retry limit register for 5210 (no QCU/DCU so it's done in PCU)
+ */
+#define AR5K_NODCU_RETRY_LMT           0x801c                  /*Register Address */
+#define AR5K_NODCU_RETRY_LMT_SH_RETRY  0x0000000f      /* Short retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S        0
+#define AR5K_NODCU_RETRY_LMT_LG_RETRY  0x000000f0      /* Long retry mask */
+#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S        4
+#define AR5K_NODCU_RETRY_LMT_SSH_RETRY 0x00003f00      /* Station short retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S       8
+#define AR5K_NODCU_RETRY_LMT_SLG_RETRY 0x000fc000      /* Station long retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S       14
+#define AR5K_NODCU_RETRY_LMT_CW_MIN    0x3ff00000      /* Minimum contention window mask */
+#define AR5K_NODCU_RETRY_LMT_CW_MIN_S  20
+
+/*
+ * Transmit latency register
+ */
+#define AR5K_USEC_5210                 0x8020                  /* Register Address [5210] */
+#define AR5K_USEC_5211                 0x801c                  /* Register Address [5211+] */
+#define AR5K_USEC                      (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_USEC_5210 : AR5K_USEC_5211)
+#define AR5K_USEC_1                    0x0000007f
+#define AR5K_USEC_1_S                  0
+#define AR5K_USEC_32                   0x00003f80
+#define AR5K_USEC_32_S                 7
+#define AR5K_USEC_TX_LATENCY_5211      0x007fc000
+#define AR5K_USEC_TX_LATENCY_5211_S    14
+#define AR5K_USEC_RX_LATENCY_5211      0x1f800000
+#define AR5K_USEC_RX_LATENCY_5211_S    23
+#define AR5K_USEC_TX_LATENCY_5210      0x000fc000      /* also for 5311 */
+#define AR5K_USEC_TX_LATENCY_5210_S    14
+#define AR5K_USEC_RX_LATENCY_5210      0x03f00000      /* also for 5311 */
+#define AR5K_USEC_RX_LATENCY_5210_S    20
+
+/*
+ * PCU beacon control register
+ */
+#define AR5K_BEACON_5210       0x8024
+#define AR5K_BEACON_5211       0x8020
+#define AR5K_BEACON            (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_BEACON_5210 : AR5K_BEACON_5211)
+#define AR5K_BEACON_PERIOD     0x0000ffff
+#define AR5K_BEACON_PERIOD_S   0
+#define AR5K_BEACON_TIM                0x007f0000
+#define AR5K_BEACON_TIM_S      16
+#define AR5K_BEACON_ENABLE     0x00800000
+#define AR5K_BEACON_RESET_TSF  0x01000000
+
+/*
+ * CFP period register
+ */
+#define AR5K_CFP_PERIOD_5210   0x8028
+#define AR5K_CFP_PERIOD_5211   0x8024
+#define AR5K_CFP_PERIOD                (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211)
+
+/*
+ * Next beacon time register
+ */
+#define AR5K_TIMER0_5210       0x802c
+#define AR5K_TIMER0_5211       0x8028
+#define AR5K_TIMER0            (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
+
+/*
+ * Next DMA beacon alert register
+ */
+#define AR5K_TIMER1_5210       0x8030
+#define AR5K_TIMER1_5211       0x802c
+#define AR5K_TIMER1            (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
+
+/*
+ * Next software beacon alert register
+ */
+#define AR5K_TIMER2_5210       0x8034
+#define AR5K_TIMER2_5211       0x8030
+#define AR5K_TIMER2            (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
+
+/*
+ * Next ATIM window time register
+ */
+#define AR5K_TIMER3_5210       0x8038
+#define AR5K_TIMER3_5211       0x8034
+#define AR5K_TIMER3            (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
+
+
+/*
+ * 5210 First inter frame spacing register (IFS)
+ */
+#define AR5K_IFS0              0x8040
+#define AR5K_IFS0_SIFS         0x000007ff
+#define AR5K_IFS0_SIFS_S       0
+#define AR5K_IFS0_DIFS         0x007ff800
+#define AR5K_IFS0_DIFS_S       11
+
+/*
+ * 5210 Second inter frame spacing register (IFS)
+ */
+#define AR5K_IFS1              0x8044
+#define AR5K_IFS1_PIFS         0x00000fff
+#define AR5K_IFS1_PIFS_S       0
+#define AR5K_IFS1_EIFS         0x03fff000
+#define AR5K_IFS1_EIFS_S       12
+#define AR5K_IFS1_CS_EN                0x04000000
+
+
+/*
+ * CFP duration register
+ */
+#define AR5K_CFP_DUR_5210      0x8048
+#define AR5K_CFP_DUR_5211      0x8038
+#define AR5K_CFP_DUR           (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211)
+
+/*
+ * Receive filter register
+ * TODO: Get these out of ar5xxx.h on ath5k
+ */
+#define AR5K_RX_FILTER_5210    0x804c                  /* Register Address [5210] */
+#define AR5K_RX_FILTER_5211    0x803c                  /* Register Address [5211+] */
+#define AR5K_RX_FILTER         (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211)
+#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 [5212+] */
+#define        AR5K_RX_FILTER_PROBEREQ 0x00000080      /* Don't filter probe requests [5212+] */
+#define        AR5K_RX_FILTER_PHYERR_5212      0x00000100      /* Don't filter phy errors [5212+] */
+#define        AR5K_RX_FILTER_RADARERR_5212    0x00000200      /* Don't filter phy radar errors [5212+] */
+#define AR5K_RX_FILTER_PHYERR_5211     0x00000040      /* [5211] */
+#define AR5K_RX_FILTER_RADARERR_5211   0x00000080      /* [5211] */
+#define AR5K_RX_FILTER_PHYERR  \
+       ((ah->ah_version == AR5K_AR5211 ? \
+       AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212))
+#define        AR5K_RX_FILTER_RADARERR \
+       ((ah->ah_version == AR5K_AR5211 ? \
+       AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212))
+
+/*
+ * Multicast filter register (lower 32 bits)
+ */
+#define AR5K_MCAST_FILTER0_5210        0x8050
+#define AR5K_MCAST_FILTER0_5211        0x8040
+#define AR5K_MCAST_FILTER0     (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211)
+
+/*
+ * Multicast filter register (higher 16 bits)
+ */
+#define AR5K_MCAST_FILTER1_5210        0x8054
+#define AR5K_MCAST_FILTER1_5211        0x8044
+#define AR5K_MCAST_FILTER1     (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211)
+
+
+/*
+ * Transmit mask register (lower 32 bits) [5210]
+ */
+#define AR5K_TX_MASK0  0x8058
+
+/*
+ * Transmit mask register (higher 16 bits) [5210]
+ */
+#define AR5K_TX_MASK1  0x805c
+
+/*
+ * Clear transmit mask [5210]
+ */
+#define AR5K_CLR_TMASK 0x8060
+
+/*
+ * Trigger level register (before transmission) [5210]
+ */
+#define AR5K_TRIG_LVL  0x8064
+
+
+/*
+ * PCU control register
+ *
+ * Only DIS_RX is used in the code, the rest i guess are
+ * for tweaking/diagnostics.
+ */
+#define AR5K_DIAG_SW_5210              0x8068                  /* Register Address [5210] */
+#define AR5K_DIAG_SW_5211              0x8048                  /* Register Address [5211+] */
+#define AR5K_DIAG_SW                   (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211)
+#define AR5K_DIAG_SW_DIS_WEP_ACK       0x00000001
+#define AR5K_DIAG_SW_DIS_ACK           0x00000002      /* Disable ACKs (?) */
+#define AR5K_DIAG_SW_DIS_CTS           0x00000004      /* Disable CTSs (?) */
+#define AR5K_DIAG_SW_DIS_ENC           0x00000008      /* Disable encryption (?) */
+#define AR5K_DIAG_SW_DIS_DEC           0x00000010      /* Disable decryption (?) */
+#define AR5K_DIAG_SW_DIS_TX            0x00000020      /* Disable transmit [5210] */
+#define AR5K_DIAG_SW_DIS_RX_5210       0x00000040      /* Disable recieve */
+#define AR5K_DIAG_SW_DIS_RX_5211       0x00000020
+#define        AR5K_DIAG_SW_DIS_RX             (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211)
+#define AR5K_DIAG_SW_LOOP_BACK_5210    0x00000080      /* Loopback (i guess it goes with DIS_TX) [5210] */
+#define AR5K_DIAG_SW_LOOP_BACK_5211    0x00000040
+#define AR5K_DIAG_SW_LOOP_BACK         (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211)
+#define AR5K_DIAG_SW_CORR_FCS_5210     0x00000100
+#define AR5K_DIAG_SW_CORR_FCS_5211     0x00000080
+#define AR5K_DIAG_SW_CORR_FCS          (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211)
+#define AR5K_DIAG_SW_CHAN_INFO_5210    0x00000200
+#define AR5K_DIAG_SW_CHAN_INFO_5211    0x00000100
+#define AR5K_DIAG_SW_CHAN_INFO         (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211        0x00000200      /* Scrambler seed (?) */
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210        0x00000400
+#define AR5K_DIAG_SW_EN_SCRAM_SEED     (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211)
+#define AR5K_DIAG_SW_ECO_ENABLE                0x00000400      /* [5211+] */
+#define AR5K_DIAG_SW_SCVRAM_SEED       0x0003f800      /* [5210] */
+#define AR5K_DIAG_SW_SCRAM_SEED_M      0x0001fc00      /* Scrambler seed mask (?) */
+#define AR5K_DIAG_SW_SCRAM_SEED_S      10
+#define AR5K_DIAG_SW_DIS_SEQ_INC       0x00040000      /* Disable seqnum increment (?)[5210] */
+#define AR5K_DIAG_SW_FRAME_NV0_5210    0x00080000
+#define AR5K_DIAG_SW_FRAME_NV0_5211    0x00020000
+#define        AR5K_DIAG_SW_FRAME_NV0          (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
+#define AR5K_DIAG_SW_OBSPT_M           0x000c0000
+#define AR5K_DIAG_SW_OBSPT_S           18
+
+/*
+ * TSF (clock) register (lower 32 bits)
+ */
+#define AR5K_TSF_L32_5210      0x806c
+#define AR5K_TSF_L32_5211      0x804c
+#define        AR5K_TSF_L32            (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
+
+/*
+ * TSF (clock) register (higher 32 bits)
+ */
+#define AR5K_TSF_U32_5210      0x8070
+#define AR5K_TSF_U32_5211      0x8050
+#define        AR5K_TSF_U32            (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
+
+/*
+ * Last beacon timestamp register
+ */
+#define AR5K_LAST_TSTP 0x8080
+
+/*
+ * ADDAC test register [5211+]
+ */
+#define AR5K_ADDAC_TEST        0x8054
+#define AR5K_ADDAC_TEST_TXCONT 0x00000001
+
+/*
+ * Default antenna register [5211+]
+ */
+#define AR5K_DEFAULT_ANTENNA   0x8058
+
+
+
+/*
+ * Retry count register [5210]
+ */
+#define AR5K_RETRY_CNT         0x8084                  /* Register Address [5210] */
+#define AR5K_RETRY_CNT_SSH     0x0000003f      /* Station short retry count (?) */
+#define AR5K_RETRY_CNT_SLG     0x00000fc0      /* Station long retry count (?) */
+
+/*
+ * Back-off status register [5210]
+ */
+#define AR5K_BACKOFF           0x8088                  /* Register Address [5210] */
+#define AR5K_BACKOFF_CW                0x000003ff      /* Backoff Contention Window (?) */
+#define AR5K_BACKOFF_CNT       0x03ff0000      /* Backoff count (?) */
+
+
+
+/*
+ * NAV register (current)
+ */
+#define AR5K_NAV_5210          0x808c
+#define AR5K_NAV_5211          0x8084
+#define        AR5K_NAV                (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_NAV_5210 : AR5K_NAV_5211)
+
+/*
+ * RTS success register
+ */
+#define AR5K_RTS_OK_5210       0x8090
+#define AR5K_RTS_OK_5211       0x8088
+#define        AR5K_RTS_OK             (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)
+
+/*
+ * RTS failure register
+ */
+#define AR5K_RTS_FAIL_5210     0x8094
+#define AR5K_RTS_FAIL_5211     0x808c
+#define        AR5K_RTS_FAIL           (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)
+
+/*
+ * ACK failure register
+ */
+#define AR5K_ACK_FAIL_5210     0x8098
+#define AR5K_ACK_FAIL_5211     0x8090
+#define        AR5K_ACK_FAIL           (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)
+
+/*
+ * FCS failure register
+ */
+#define AR5K_FCS_FAIL_5210     0x809c
+#define AR5K_FCS_FAIL_5211     0x8094
+#define        AR5K_FCS_FAIL           (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211)
+
+/*
+ * Beacon count register
+ */
+#define AR5K_BEACON_CNT_5210   0x80a0
+#define AR5K_BEACON_CNT_5211   0x8098
+#define        AR5K_BEACON_CNT         (ah->ah_version == AR5K_AR5210 ? \
+                               AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211)
+
+
+/*===5212 Specific PCU registers===*/
+
+/*
+ * XR (eXtended Range) mode register
+ */
+#define AR5K_XRMODE                    0x80c0
+#define        AR5K_XRMODE_POLL_TYPE_M         0x0000003f
+#define        AR5K_XRMODE_POLL_TYPE_S         0
+#define        AR5K_XRMODE_POLL_SUBTYPE_M      0x0000003c
+#define        AR5K_XRMODE_POLL_SUBTYPE_S      2
+#define        AR5K_XRMODE_POLL_WAIT_ALL       0x00000080
+#define        AR5K_XRMODE_SIFS_DELAY          0x000fff00
+#define        AR5K_XRMODE_FRAME_HOLD_M        0xfff00000
+#define        AR5K_XRMODE_FRAME_HOLD_S        20
+
+/*
+ * XR delay register
+ */
+#define AR5K_XRDELAY                   0x80c4
+#define AR5K_XRDELAY_SLOT_DELAY_M      0x0000ffff
+#define AR5K_XRDELAY_SLOT_DELAY_S      0
+#define AR5K_XRDELAY_CHIRP_DELAY_M     0xffff0000
+#define AR5K_XRDELAY_CHIRP_DELAY_S     16
+
+/*
+ * XR timeout register
+ */
+#define AR5K_XRTIMEOUT                 0x80c8
+#define AR5K_XRTIMEOUT_CHIRP_M         0x0000ffff
+#define AR5K_XRTIMEOUT_CHIRP_S         0
+#define AR5K_XRTIMEOUT_POLL_M          0xffff0000
+#define AR5K_XRTIMEOUT_POLL_S          16
+
+/*
+ * XR chirp register
+ */
+#define AR5K_XRCHIRP                   0x80cc
+#define AR5K_XRCHIRP_SEND              0x00000001
+#define AR5K_XRCHIRP_GAP               0xffff0000
+
+/*
+ * XR stomp register
+ */
+#define AR5K_XRSTOMP                   0x80d0
+#define AR5K_XRSTOMP_TX                        0x00000001
+#define AR5K_XRSTOMP_RX_ABORT          0x00000002
+#define AR5K_XRSTOMP_RSSI_THRES                0x0000ff00
+
+/*
+ * First enhanced sleep register
+ */
+#define AR5K_SLEEP0                    0x80d4
+#define AR5K_SLEEP0_NEXT_DTIM          0x0007ffff
+#define AR5K_SLEEP0_NEXT_DTIM_S                0
+#define AR5K_SLEEP0_ASSUME_DTIM                0x00080000
+#define AR5K_SLEEP0_ENH_SLEEP_EN       0x00100000
+#define AR5K_SLEEP0_CABTO              0xff000000
+#define AR5K_SLEEP0_CABTO_S            24
+
+/*
+ * Second enhanced sleep register
+ */
+#define AR5K_SLEEP1                    0x80d8
+#define AR5K_SLEEP1_NEXT_TIM           0x0007ffff
+#define AR5K_SLEEP1_NEXT_TIM_S         0
+#define AR5K_SLEEP1_BEACON_TO          0xff000000
+#define AR5K_SLEEP1_BEACON_TO_S                24
+
+/*
+ * Third enhanced sleep register
+ */
+#define AR5K_SLEEP2                    0x80dc
+#define AR5K_SLEEP2_TIM_PER            0x0000ffff
+#define AR5K_SLEEP2_TIM_PER_S          0
+#define AR5K_SLEEP2_DTIM_PER           0xffff0000
+#define AR5K_SLEEP2_DTIM_PER_S         16
+
+/*
+ * BSSID mask registers
+ */
+#define AR5K_BSS_IDM0                  0x80e0
+#define AR5K_BSS_IDM1                  0x80e4
+
+/*
+ * TX power control (TPC) register
+ */
+#define AR5K_TXPC                      0x80e8
+#define AR5K_TXPC_ACK_M                        0x0000003f
+#define AR5K_TXPC_ACK_S                        0
+#define AR5K_TXPC_CTS_M                        0x00003f00
+#define AR5K_TXPC_CTS_S                        8
+#define AR5K_TXPC_CHIRP_M              0x003f0000
+#define AR5K_TXPC_CHIRP_S              22
+
+/*
+ * Profile count registers
+ */
+#define AR5K_PROFCNT_TX                        0x80ec
+#define AR5K_PROFCNT_RX                        0x80f0
+#define AR5K_PROFCNT_RXCLR             0x80f4
+#define AR5K_PROFCNT_CYCLE             0x80f8
+
+/*
+ * TSF parameter register
+ */
+#define AR5K_TSF_PARM                  0x8104
+#define AR5K_TSF_PARM_INC_M            0x000000ff
+#define AR5K_TSF_PARM_INC_S            0
+
+/*
+ * PHY error filter register
+ */
+#define AR5K_PHY_ERR_FIL               0x810c
+#define AR5K_PHY_ERR_FIL_RADAR         0x00000020
+#define AR5K_PHY_ERR_FIL_OFDM          0x00020000
+#define AR5K_PHY_ERR_FIL_CCK           0x02000000
+
+/*
+ * Rate duration register
+ */
+#define AR5K_RATE_DUR_BASE             0x8700
+#define AR5K_RATE_DUR(_n)              (AR5K_RATE_DUR_BASE + ((_n) << 2))
+
+/*===5212 end===*/
+
+/*
+ * Key table (WEP) register
+ */
+#define AR5K_KEYTABLE_0_5210           0x9000
+#define AR5K_KEYTABLE_0_5211           0x8800
+#define AR5K_KEYTABLE_5210(_n)         (AR5K_KEYTABLE_0_5210 + ((_n) << 5))
+#define AR5K_KEYTABLE_5211(_n)         (AR5K_KEYTABLE_0_5211 + ((_n) << 5))
+#define        AR5K_KEYTABLE(_n)               (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
+#define AR5K_KEYTABLE_OFF(_n, x)       (AR5K_KEYTABLE(_n) + (x << 2))
+#define AR5K_KEYTABLE_TYPE(_n)         AR5K_KEYTABLE_OFF(_n, 5)
+#define AR5K_KEYTABLE_TYPE_40          0x00000000
+#define AR5K_KEYTABLE_TYPE_104         0x00000001
+#define AR5K_KEYTABLE_TYPE_128         0x00000003
+#define AR5K_KEYTABLE_TYPE_TKIP                0x00000004      /* [5212+] */
+#define AR5K_KEYTABLE_TYPE_AES         0x00000005      /* [5211+] */
+#define AR5K_KEYTABLE_TYPE_CCM         0x00000006      /* [5212+] */
+#define AR5K_KEYTABLE_TYPE_NULL                0x00000007      /* [5211+] */
+#define AR5K_KEYTABLE_ANTENNA          0x00000008      /* [5212+] */
+#define AR5K_KEYTABLE_MAC0(_n)         AR5K_KEYTABLE_OFF(_n, 6)
+#define AR5K_KEYTABLE_MAC1(_n)         AR5K_KEYTABLE_OFF(_n, 7)
+#define AR5K_KEYTABLE_VALID            0x00008000
+
+/* WEP 40-bit  = 40-bit  entered key + 24 bit IV = 64-bit
+ * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit
+ * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit
+ *
+ * Some vendors have introduced bigger WEP keys to address
+ * security vulnerabilities in WEP. This includes:
+ *
+ * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
+ *
+ * We can expand this if we find ar5k Atheros cards with a larger
+ * key table size.
+ */
+#define AR5K_KEYTABLE_SIZE_5210                64
+#define AR5K_KEYTABLE_SIZE_5211                128
+#define        AR5K_KEYTABLE_SIZE              (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
+
+
+/*===PHY REGISTERS===*/
+
+/*
+ * PHY register
+ */
+#define        AR5K_PHY_BASE                   0x9800
+#define        AR5K_PHY(_n)                    (AR5K_PHY_BASE + ((_n) << 2))
+#define AR5K_PHY_SHIFT_2GHZ            0x00004007
+#define AR5K_PHY_SHIFT_5GHZ            0x00000007
+
+/*
+ * PHY frame control register [5110] /turbo mode register [5111+]
+ *
+ * There is another frame control register for [5111+]
+ * at address 0x9944 (see below) but the 2 first flags
+ * are common here between 5110 frame control register
+ * and [5111+] turbo mode register, so this also works as
+ * a "turbo mode register" for 5110. We treat this one as
+ * a frame control register for 5110 below.
+ */
+#define        AR5K_PHY_TURBO                  0x9804
+#define        AR5K_PHY_TURBO_MODE             0x00000001
+#define        AR5K_PHY_TURBO_SHORT            0x00000002
+
+/*
+ * PHY agility command register
+ */
+#define        AR5K_PHY_AGC                    0x9808
+#define        AR5K_PHY_AGC_DISABLE            0x08000000
+
+/*
+ * PHY timing register [5112+]
+ */
+#define        AR5K_PHY_TIMING_3               0x9814
+#define        AR5K_PHY_TIMING_3_DSC_MAN       0xfffe0000
+#define        AR5K_PHY_TIMING_3_DSC_MAN_S     17
+#define        AR5K_PHY_TIMING_3_DSC_EXP       0x0001e000
+#define        AR5K_PHY_TIMING_3_DSC_EXP_S     13
+
+/*
+ * PHY chip revision register
+ */
+#define        AR5K_PHY_CHIP_ID                0x9818
+
+/*
+ * PHY activation register
+ */
+#define        AR5K_PHY_ACT                    0x981c
+#define        AR5K_PHY_ACT_ENABLE             0x00000001
+#define        AR5K_PHY_ACT_DISABLE            0x00000002
+
+/*
+ * PHY signal register
+ */
+#define        AR5K_PHY_SIG                    0x9858
+#define        AR5K_PHY_SIG_FIRSTEP            0x0003f000
+#define        AR5K_PHY_SIG_FIRSTEP_S          12
+#define        AR5K_PHY_SIG_FIRPWR             0x03fc0000
+#define        AR5K_PHY_SIG_FIRPWR_S           18
+
+/*
+ * PHY coarse agility control register
+ */
+#define        AR5K_PHY_AGCCOARSE              0x985c
+#define        AR5K_PHY_AGCCOARSE_LO           0x00007f80
+#define        AR5K_PHY_AGCCOARSE_LO_S         7
+#define        AR5K_PHY_AGCCOARSE_HI           0x003f8000
+#define        AR5K_PHY_AGCCOARSE_HI_S         15
+
+/*
+ * PHY agility control register
+ */
+#define        AR5K_PHY_AGCCTL                 0x9860                  /* Register address */
+#define        AR5K_PHY_AGCCTL_CAL             0x00000001      /* Enable PHY calibration */
+#define        AR5K_PHY_AGCCTL_NF              0x00000002      /* Enable Noise Floor calibration */
+
+/*
+ * PHY noise floor status register
+ */
+#define AR5K_PHY_NF                    0x9864
+#define AR5K_PHY_NF_M                  0x000001ff
+#define AR5K_PHY_NF_ACTIVE             0x00000100
+#define AR5K_PHY_NF_RVAL(_n)           (((_n) >> 19) & AR5K_PHY_NF_M)
+#define AR5K_PHY_NF_AVAL(_n)           (-((_n) ^ AR5K_PHY_NF_M) + 1)
+#define AR5K_PHY_NF_SVAL(_n)           (((_n) & AR5K_PHY_NF_M) | (1 << 9))
+
+/*
+ * PHY ADC saturation register [5110]
+ */
+#define        AR5K_PHY_ADCSAT                 0x9868
+#define        AR5K_PHY_ADCSAT_ICNT            0x0001f800
+#define        AR5K_PHY_ADCSAT_ICNT_S          11
+#define        AR5K_PHY_ADCSAT_THR             0x000007e0
+#define        AR5K_PHY_ADCSAT_THR_S           5
+
+/*
+ * PHY sleep registers [5112+]
+ */
+#define AR5K_PHY_SCR                   0x9870
+#define AR5K_PHY_SCR_32MHZ             0x0000001f
+#define AR5K_PHY_SLMT                  0x9874
+#define AR5K_PHY_SLMT_32MHZ            0x0000007f
+#define AR5K_PHY_SCAL                  0x9878
+#define AR5K_PHY_SCAL_32MHZ            0x0000000e
+
+/*
+ * PHY PLL (Phase Locked Loop) control register
+ */
+#define        AR5K_PHY_PLL                    0x987c
+#define        AR5K_PHY_PLL_20MHZ              0x13    /* For half rate (?) [5111+] */
+#define        AR5K_PHY_PLL_40MHZ_5211         0x18    /* For 802.11a */
+#define        AR5K_PHY_PLL_40MHZ_5212         0x000000aa
+#define        AR5K_PHY_PLL_40MHZ              (ah->ah_version == AR5K_AR5211 ? \
+                                       AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212)
+#define        AR5K_PHY_PLL_44MHZ_5211         0x19    /* For 802.11b/g */
+#define        AR5K_PHY_PLL_44MHZ_5212         0x000000ab
+#define        AR5K_PHY_PLL_44MHZ              (ah->ah_version == AR5K_AR5211 ? \
+                                       AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212)
+#define AR5K_PHY_PLL_RF5111            0x00000000
+#define AR5K_PHY_PLL_RF5112            0x00000040
+
+/*
+ * RF Buffer register
+ *
+ * There are some special control registers on the RF chip
+ * that hold various operation settings related mostly to
+ * the analog parts (channel, gain adjustment etc).
+ *
+ * We don't write on those registers directly but
+ * we send a data packet on the buffer register and
+ * then write on another special register to notify hw
+ * to apply the settings. This is done so that control registers
+ * can be dynamicaly programmed during operation and the settings
+ * are applied faster on the hw.
+ *
+ * We sent such data packets during rf initialization and channel change
+ * through ath5k_hw_rf*_rfregs and ath5k_hw_rf*_channel functions.
+ *
+ * The data packets we send during initializadion are inside ath5k_ini_rf
+ * struct (see ath5k_hw.h) and each one is related to an "rf register bank".
+ * We use *rfregs functions to modify them  acording to current operation
+ * mode and eeprom values and pass them all together to the chip.
+ *
+ * It's obvious from the code that 0x989c is the buffer register but
+ * for the other special registers that we write to after sending each
+ * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers
+ * for now. It's interesting that they are also used for some other operations.
+ *
+ * Also check out hw.h and U.S. Patent 6677779 B1 (about buffer
+ * registers and control registers):
+ *
+ * http://www.google.com/patents?id=qNURAAAAEBAJ
+ */
+
+#define AR5K_RF_BUFFER                 0x989c
+#define AR5K_RF_BUFFER_CONTROL_0       0x98c0  /* Channel on 5110 */
+#define AR5K_RF_BUFFER_CONTROL_1       0x98c4  /* Bank 7 on 5112 */
+#define AR5K_RF_BUFFER_CONTROL_2       0x98cc  /* Bank 7 on 5111 */
+
+#define AR5K_RF_BUFFER_CONTROL_3       0x98d0  /* Bank 2 on 5112 */
+                                               /* Channel set on 5111 */
+                                               /* Used to read radio revision*/
+
+#define AR5K_RF_BUFFER_CONTROL_4       0x98d4  /* RF Stage register on 5110 */
+                                               /* Bank 0,1,2,6 on 5111 */
+                                               /* Bank 1 on 5112 */
+                                               /* Used during activation on 5111 */
+
+#define AR5K_RF_BUFFER_CONTROL_5       0x98d8  /* Bank 3 on 5111 */
+                                               /* Used during activation on 5111 */
+                                               /* Channel on 5112 */
+                                               /* Bank 6 on 5112 */
+
+#define AR5K_RF_BUFFER_CONTROL_6       0x98dc  /* Bank 3 on 5112 */
+
+/*
+ * PHY RF stage register [5210]
+ */
+#define AR5K_PHY_RFSTG                 0x98d4
+#define AR5K_PHY_RFSTG_DISABLE         0x00000021
+
+/*
+ * PHY receiver delay register [5111+]
+ */
+#define        AR5K_PHY_RX_DELAY               0x9914
+#define        AR5K_PHY_RX_DELAY_M             0x00003fff
+
+/*
+ * PHY timing I(nphase) Q(adrature) control register [5111+]
+ */
+#define        AR5K_PHY_IQ                     0x9920          /* Register address */
+#define        AR5K_PHY_IQ_CORR_Q_Q_COFF       0x0000001f      /* Mask for q correction info */
+#define        AR5K_PHY_IQ_CORR_Q_I_COFF       0x000007e0      /* Mask for i correction info */
+#define        AR5K_PHY_IQ_CORR_Q_I_COFF_S     5
+#define        AR5K_PHY_IQ_CORR_ENABLE         0x00000800      /* Enable i/q correction */
+#define        AR5K_PHY_IQ_CAL_NUM_LOG_MAX     0x0000f000
+#define        AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S   12
+#define        AR5K_PHY_IQ_RUN                 0x00010000      /* Run i/q calibration */
+
+
+/*
+ * PHY PAPD probe register [5111+ (?)]
+ * Is this only present in 5212 ?
+ * Because it's always 0 in 5211 initialization code
+ */
+#define        AR5K_PHY_PAPD_PROBE             0x9930
+#define        AR5K_PHY_PAPD_PROBE_TXPOWER     0x00007e00
+#define        AR5K_PHY_PAPD_PROBE_TXPOWER_S   9
+#define        AR5K_PHY_PAPD_PROBE_TX_NEXT     0x00008000
+#define        AR5K_PHY_PAPD_PROBE_TYPE        0x01800000      /* [5112+] */
+#define        AR5K_PHY_PAPD_PROBE_TYPE_S      23
+#define        AR5K_PHY_PAPD_PROBE_TYPE_OFDM   0
+#define        AR5K_PHY_PAPD_PROBE_TYPE_XR     1
+#define        AR5K_PHY_PAPD_PROBE_TYPE_CCK    2
+#define        AR5K_PHY_PAPD_PROBE_GAINF       0xfe000000
+#define        AR5K_PHY_PAPD_PROBE_GAINF_S     25
+#define        AR5K_PHY_PAPD_PROBE_INI_5111    0x00004883      /* [5212+] */
+#define        AR5K_PHY_PAPD_PROBE_INI_5112    0x00004882      /* [5212+] */
+
+
+/*
+ * PHY TX rate power registers [5112+]
+ */
+#define        AR5K_PHY_TXPOWER_RATE1                  0x9934
+#define        AR5K_PHY_TXPOWER_RATE2                  0x9938
+#define        AR5K_PHY_TXPOWER_RATE_MAX               0x993c
+#define        AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE    0x00000040
+#define        AR5K_PHY_TXPOWER_RATE3                  0xa234
+#define        AR5K_PHY_TXPOWER_RATE4                  0xa238
+
+/*
+ * PHY frame control register [5111+]
+ */
+#define        AR5K_PHY_FRAME_CTL_5210         0x9804
+#define        AR5K_PHY_FRAME_CTL_5211         0x9944
+#define        AR5K_PHY_FRAME_CTL              (ah->ah_version == AR5K_AR5210 ? \
+                                       AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
+/*---[5111+]---*/
+#define        AR5K_PHY_FRAME_CTL_TX_CLIP      0x00000038
+#define        AR5K_PHY_FRAME_CTL_TX_CLIP_S    3
+/*---[5110/5111]---*/
+#define        AR5K_PHY_FRAME_CTL_TIMING_ERR   0x01000000
+#define        AR5K_PHY_FRAME_CTL_PARITY_ERR   0x02000000
+#define        AR5K_PHY_FRAME_CTL_ILLRATE_ERR  0x04000000      /* illegal rate */
+#define        AR5K_PHY_FRAME_CTL_ILLLEN_ERR   0x08000000      /* illegal length */
+#define        AR5K_PHY_FRAME_CTL_SERVICE_ERR  0x20000000
+#define        AR5K_PHY_FRAME_CTL_TXURN_ERR    0x40000000      /* tx underrun */
+#define AR5K_PHY_FRAME_CTL_INI         AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
+                       AR5K_PHY_FRAME_CTL_TXURN_ERR | \
+                       AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
+                       AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \
+                       AR5K_PHY_FRAME_CTL_PARITY_ERR | \
+                       AR5K_PHY_FRAME_CTL_TIMING_ERR
+
+/*
+ * PHY radar detection register [5111+]
+ */
+#define        AR5K_PHY_RADAR                  0x9954
+
+/* Radar enable                        ........ ........ ........ .......1 */
+#define        AR5K_PHY_RADAR_ENABLE           0x00000001
+#define        AR5K_PHY_RADAR_DISABLE          0x00000000
+#define        AR5K_PHY_RADAR_ENABLE_S         0
+
+/* This is the value found on the card  .1.111.1 .1.1.... 111....1 1...1...
+at power on. */
+#define        AR5K_PHY_RADAR_PWONDEF_AR5213   0x5d50e188
+
+/* This is the value found on the card         .1.1.111 ..11...1 .1...1.1 1...11.1
+after DFS is enabled */
+#define        AR5K_PHY_RADAR_ENABLED_AR5213   0x5731458d
+
+/* Finite Impulse Response (FIR) filter .1111111 ........ ........ ........
+ * power out threshold.
+ * 7-bits, standard power range {0..127} in 1/2 dBm units. */
+#define AR5K_PHY_RADAR_FIRPWROUTTHR            0x7f000000
+#define AR5K_PHY_RADAR_FIRPWROUTTHR_S  24
+
+/* Radar RSSI/SNR threshold.           ........ 111111.. ........ ........
+ * 6-bits, dBm range {0..63} in dBm units. */
+#define AR5K_PHY_RADAR_RADARRSSITHR            0x00fc0000
+#define AR5K_PHY_RADAR_RADARRSSITHR_S  18
+
+/* Pulse height threshold              ........ ......11 1111.... ........
+ * 6-bits, dBm range {0..63} in dBm units. */
+#define AR5K_PHY_RADAR_PULSEHEIGHTTHR   0x0003f000
+#define AR5K_PHY_RADAR_PULSEHEIGHTTHR_S        12
+
+/* Pulse RSSI/SNR threshold            ........ ........ ....1111 11......
+ * 6-bits, dBm range {0..63} in dBm units. */
+#define AR5K_PHY_RADAR_PULSERSSITHR            0x00000fc0
+#define AR5K_PHY_RADAR_PULSERSSITHR_S  6
+
+/* Inband threshold                    ........ ........ ........ ..11111.
+ * 5-bits, units unknown {0..31} (? MHz ?) */
+#define AR5K_PHY_RADAR_INBANDTHR       0x0000003e
+#define AR5K_PHY_RADAR_INBANDTHR_S     1
+
+/*
+ * PHY antenna switch table registers [5110]
+ */
+#define AR5K_PHY_ANT_SWITCH_TABLE_0    0x9960
+#define AR5K_PHY_ANT_SWITCH_TABLE_1    0x9964
+
+/*
+ * PHY clock sleep registers [5112+]
+ */
+#define AR5K_PHY_SCLOCK                        0x99f0
+#define AR5K_PHY_SCLOCK_32MHZ          0x0000000c
+#define AR5K_PHY_SDELAY                        0x99f4
+#define AR5K_PHY_SDELAY_32MHZ          0x000000ff
+#define AR5K_PHY_SPENDING              0x99f8
+#define AR5K_PHY_SPENDING_RF5111       0x00000018
+#define AR5K_PHY_SPENDING_RF5112       0x00000014
+
+/*
+ * Misc PHY/radio registers [5110 - 5111]
+ */
+#define        AR5K_BB_GAIN_BASE               0x9b00 /* BaseBand Amplifier Gain table base address */
+#define AR5K_BB_GAIN(_n)               (AR5K_BB_GAIN_BASE + ((_n) << 2))
+#define        AR5K_RF_GAIN_BASE               0x9a00 /* RF Amplrifier Gain table base address */
+#define AR5K_RF_GAIN(_n)               (AR5K_RF_GAIN_BASE + ((_n) << 2))
+
+/*
+ * PHY timing IQ calibration result register [5111+]
+ */
+#define        AR5K_PHY_IQRES_CAL_PWR_I        0x9c10 /* I (Inphase) power value */
+#define        AR5K_PHY_IQRES_CAL_PWR_Q        0x9c14 /* Q (Quadrature) power value */
+#define        AR5K_PHY_IQRES_CAL_CORR         0x9c18  /* I/Q Correlation */
+
+/*
+ * PHY current RSSI register [5111+]
+ */
+#define        AR5K_PHY_CURRENT_RSSI           0x9c1c
+
+/*
+ * PHY PCDAC TX power table
+ */
+#define        AR5K_PHY_PCDAC_TXPOWER_BASE_5211        0xa180
+#define AR5K_PHY_PCDAC_TXPOWER_BASE_5413       0xa280
+#define AR5K_PHY_PCDAC_TXPOWER_BASE    (ah->ah_radio >= AR5K_RF5413 ? \
+                                       AR5K_PHY_PCDAC_TXPOWER_BASE_5413 :\
+                                       AR5K_PHY_PCDAC_TXPOWER_BASE_5211)
+#define        AR5K_PHY_PCDAC_TXPOWER(_n)      (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
+
+/*
+ * PHY mode register [5111+]
+ */
+#define        AR5K_PHY_MODE                   0x0a200         /* Register address */
+#define        AR5K_PHY_MODE_MOD               0x00000001      /* PHY Modulation mask*/
+#define AR5K_PHY_MODE_MOD_OFDM         0
+#define AR5K_PHY_MODE_MOD_CCK          1
+#define AR5K_PHY_MODE_FREQ             0x00000002      /* Freq mode mask */
+#define        AR5K_PHY_MODE_FREQ_5GHZ         0
+#define        AR5K_PHY_MODE_FREQ_2GHZ         2
+#define AR5K_PHY_MODE_MOD_DYN          0x00000004      /* Dynamic OFDM/CCK mode mask [5112+] */
+#define AR5K_PHY_MODE_RAD              0x00000008      /* [5212+] */
+#define AR5K_PHY_MODE_RAD_RF5111       0
+#define AR5K_PHY_MODE_RAD_RF5112       8
+#define AR5K_PHY_MODE_XR               0x00000010      /* [5112+] */
+
+/*
+ * PHY CCK transmit control register [5111+ (?)]
+ */
+#define AR5K_PHY_CCKTXCTL              0xa204
+#define AR5K_PHY_CCKTXCTL_WORLD                0x00000000
+#define AR5K_PHY_CCKTXCTL_JAPAN                0x00000010
+
+/*
+ * PHY 2GHz gain register [5111+]
+ */
+#define        AR5K_PHY_GAIN_2GHZ              0xa20c
+#define        AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX  0x00fc0000
+#define        AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S        18
+#define        AR5K_PHY_GAIN_2GHZ_INI_5111     0x6480416c
diff --git a/drivers/net/wireless/ath5k/regdom.c b/drivers/net/wireless/ath5k/regdom.c
new file mode 100644 (file)
index 0000000..e851957
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net>
+ *
+ * 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.
+ */
+
+/*
+ * Basic regulation domain extensions for the IEEE 802.11 stack
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include "regdom.h"
+
+static const struct ath5k_regdommap {
+       enum ath5k_regdom dmn;
+       enum ath5k_regdom dmn5;
+       enum ath5k_regdom dmn2;
+} r_map[] = {
+       { DMN_DEFAULT,          DMN_DEBUG,      DMN_DEBUG },
+       { DMN_NULL_WORLD,       DMN_NULL,       DMN_WORLD },
+       { DMN_NULL_ETSIB,       DMN_NULL,       DMN_ETSIB },
+       { DMN_NULL_ETSIC,       DMN_NULL,       DMN_ETSIC },
+       { DMN_FCC1_FCCA,        DMN_FCC1,       DMN_FCCA },
+       { DMN_FCC1_WORLD,       DMN_FCC1,       DMN_WORLD },
+       { DMN_FCC2_FCCA,        DMN_FCC2,       DMN_FCCA },
+       { DMN_FCC2_WORLD,       DMN_FCC2,       DMN_WORLD },
+       { DMN_FCC2_ETSIC,       DMN_FCC2,       DMN_ETSIC },
+       { DMN_FRANCE_NULL,      DMN_ETSI3,      DMN_ETSI3 },
+       { DMN_FCC3_FCCA,        DMN_FCC3,       DMN_WORLD },
+       { DMN_ETSI1_WORLD,      DMN_ETSI1,      DMN_WORLD },
+       { DMN_ETSI3_ETSIA,      DMN_ETSI3,      DMN_WORLD },
+       { DMN_ETSI2_WORLD,      DMN_ETSI2,      DMN_WORLD },
+       { DMN_ETSI3_WORLD,      DMN_ETSI3,      DMN_WORLD },
+       { DMN_ETSI4_WORLD,      DMN_ETSI4,      DMN_WORLD },
+       { DMN_ETSI4_ETSIC,      DMN_ETSI4,      DMN_ETSIC },
+       { DMN_ETSI5_WORLD,      DMN_ETSI5,      DMN_WORLD },
+       { DMN_ETSI6_WORLD,      DMN_ETSI6,      DMN_WORLD },
+       { DMN_ETSI_NULL,        DMN_ETSI1,      DMN_ETSI1 },
+       { DMN_MKK1_MKKA,        DMN_MKK1,       DMN_MKKA },
+       { DMN_MKK1_MKKB,        DMN_MKK1,       DMN_MKKA },
+       { DMN_APL4_WORLD,       DMN_APL4,       DMN_WORLD },
+       { DMN_MKK2_MKKA,        DMN_MKK2,       DMN_MKKA },
+       { DMN_APL_NULL,         DMN_APL1,       DMN_NULL },
+       { DMN_APL2_WORLD,       DMN_APL2,       DMN_WORLD },
+       { DMN_APL2_APLC,        DMN_APL2,       DMN_WORLD },
+       { DMN_APL3_WORLD,       DMN_APL3,       DMN_WORLD },
+       { DMN_MKK1_FCCA,        DMN_MKK1,       DMN_FCCA },
+       { DMN_APL2_APLD,        DMN_APL2,       DMN_APLD },
+       { DMN_MKK1_MKKA1,       DMN_MKK1,       DMN_MKKA },
+       { DMN_MKK1_MKKA2,       DMN_MKK1,       DMN_MKKA },
+       { DMN_APL1_WORLD,       DMN_APL1,       DMN_WORLD },
+       { DMN_APL1_FCCA,        DMN_APL1,       DMN_FCCA },
+       { DMN_APL1_APLA,        DMN_APL1,       DMN_WORLD },
+       { DMN_APL1_ETSIC,       DMN_APL1,       DMN_ETSIC },
+       { DMN_APL2_ETSIC,       DMN_APL2,       DMN_ETSIC },
+       { DMN_APL5_WORLD,       DMN_APL5,       DMN_WORLD },
+       { DMN_WOR0_WORLD,       DMN_WORLD,      DMN_WORLD },
+       { DMN_WOR1_WORLD,       DMN_WORLD,      DMN_WORLD },
+       { DMN_WOR2_WORLD,       DMN_WORLD,      DMN_WORLD },
+       { DMN_WOR3_WORLD,       DMN_WORLD,      DMN_WORLD },
+       { DMN_WOR4_WORLD,       DMN_WORLD,      DMN_WORLD },
+       { DMN_WOR5_ETSIC,       DMN_WORLD,      DMN_WORLD },
+       { DMN_WOR01_WORLD,      DMN_WORLD,      DMN_WORLD },
+       { DMN_WOR02_WORLD,      DMN_WORLD,      DMN_WORLD },
+       { DMN_EU1_WORLD,        DMN_ETSI1,      DMN_WORLD },
+       { DMN_WOR9_WORLD,       DMN_WORLD,      DMN_WORLD },
+       { DMN_WORA_WORLD,       DMN_WORLD,      DMN_WORLD },
+};
+
+enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom dmn, u16 mhz)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(r_map); i++) {
+               if (r_map[i].dmn == dmn) {
+                       if (mhz >= 2000 && mhz <= 3000)
+                               return r_map[i].dmn2;
+                       if (mhz >= IEEE80211_CHANNELS_5GHZ_MIN &&
+                                       mhz <= IEEE80211_CHANNELS_5GHZ_MAX)
+                               return r_map[i].dmn5;
+               }
+       }
+
+       return DMN_DEBUG;
+}
+
+u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee)
+{
+       u32 regdomain = (u32)ieee;
+
+       /*
+        * Use the default regulation domain if the value is empty
+        * or not supported by the net80211 regulation code.
+        */
+       if (ath5k_regdom2flag(regdomain, IEEE80211_CHANNELS_5GHZ_MIN) ==
+                       DMN_DEBUG)
+               return (u16)AR5K_TUNE_REGDOMAIN;
+
+       /* It is supported, just return the value */
+       return regdomain;
+}
+
+enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain)
+{
+       enum ath5k_regdom ieee = (enum ath5k_regdom)regdomain;
+
+       return ieee;
+}
+
diff --git a/drivers/net/wireless/ath5k/regdom.h b/drivers/net/wireless/ath5k/regdom.h
new file mode 100644 (file)
index 0000000..f7d3c66
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
+ *
+ * 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.
+ */
+
+#ifndef _IEEE80211_REGDOMAIN_H_
+#define _IEEE80211_REGDOMAIN_H_
+
+#include <linux/types.h>
+
+/* Default regulation domain if stored value EEPROM value is invalid */
+#define AR5K_TUNE_REGDOMAIN    DMN_FCC2_FCCA   /* Canada */
+#define AR5K_TUNE_CTRY         CTRY_DEFAULT
+
+
+enum ath5k_regdom {
+       DMN_DEFAULT             = 0x00,
+       DMN_NULL_WORLD          = 0x03,
+       DMN_NULL_ETSIB          = 0x07,
+       DMN_NULL_ETSIC          = 0x08,
+       DMN_FCC1_FCCA           = 0x10,
+       DMN_FCC1_WORLD          = 0x11,
+       DMN_FCC2_FCCA           = 0x20,
+       DMN_FCC2_WORLD          = 0x21,
+       DMN_FCC2_ETSIC          = 0x22,
+       DMN_FRANCE_NULL         = 0x31,
+       DMN_FCC3_FCCA           = 0x3A,
+       DMN_ETSI1_WORLD         = 0x37,
+       DMN_ETSI3_ETSIA         = 0x32,
+       DMN_ETSI2_WORLD         = 0x35,
+       DMN_ETSI3_WORLD         = 0x36,
+       DMN_ETSI4_WORLD         = 0x30,
+       DMN_ETSI4_ETSIC         = 0x38,
+       DMN_ETSI5_WORLD         = 0x39,
+       DMN_ETSI6_WORLD         = 0x34,
+       DMN_ETSI_NULL           = 0x33,
+       DMN_MKK1_MKKA           = 0x40,
+       DMN_MKK1_MKKB           = 0x41,
+       DMN_APL4_WORLD          = 0x42,
+       DMN_MKK2_MKKA           = 0x43,
+       DMN_APL_NULL            = 0x44,
+       DMN_APL2_WORLD          = 0x45,
+       DMN_APL2_APLC           = 0x46,
+       DMN_APL3_WORLD          = 0x47,
+       DMN_MKK1_FCCA           = 0x48,
+       DMN_APL2_APLD           = 0x49,
+       DMN_MKK1_MKKA1          = 0x4A,
+       DMN_MKK1_MKKA2          = 0x4B,
+       DMN_APL1_WORLD          = 0x52,
+       DMN_APL1_FCCA           = 0x53,
+       DMN_APL1_APLA           = 0x54,
+       DMN_APL1_ETSIC          = 0x55,
+       DMN_APL2_ETSIC          = 0x56,
+       DMN_APL5_WORLD          = 0x58,
+       DMN_WOR0_WORLD          = 0x60,
+       DMN_WOR1_WORLD          = 0x61,
+       DMN_WOR2_WORLD          = 0x62,
+       DMN_WOR3_WORLD          = 0x63,
+       DMN_WOR4_WORLD          = 0x64,
+       DMN_WOR5_ETSIC          = 0x65,
+       DMN_WOR01_WORLD         = 0x66,
+       DMN_WOR02_WORLD         = 0x67,
+       DMN_EU1_WORLD           = 0x68,
+       DMN_WOR9_WORLD          = 0x69,
+       DMN_WORA_WORLD          = 0x6A,
+
+       DMN_APL1                = 0xf0000001,
+       DMN_APL2                = 0xf0000002,
+       DMN_APL3                = 0xf0000004,
+       DMN_APL4                = 0xf0000008,
+       DMN_APL5                = 0xf0000010,
+       DMN_ETSI1               = 0xf0000020,
+       DMN_ETSI2               = 0xf0000040,
+       DMN_ETSI3               = 0xf0000080,
+       DMN_ETSI4               = 0xf0000100,
+       DMN_ETSI5               = 0xf0000200,
+       DMN_ETSI6               = 0xf0000400,
+       DMN_ETSIA               = 0xf0000800,
+       DMN_ETSIB               = 0xf0001000,
+       DMN_ETSIC               = 0xf0002000,
+       DMN_FCC1                = 0xf0004000,
+       DMN_FCC2                = 0xf0008000,
+       DMN_FCC3                = 0xf0010000,
+       DMN_FCCA                = 0xf0020000,
+       DMN_APLD                = 0xf0040000,
+       DMN_MKK1                = 0xf0080000,
+       DMN_MKK2                = 0xf0100000,
+       DMN_MKKA                = 0xf0200000,
+       DMN_NULL                = 0xf0400000,
+       DMN_WORLD               = 0xf0800000,
+       DMN_DEBUG               = 0xf1000000    /* used for debugging */
+};
+
+#define IEEE80211_DMN(_d)      ((_d) & ~0xf0000000)
+
+enum ath5k_countrycode {
+       CTRY_DEFAULT            = 0,   /* Default domain (NA) */
+       CTRY_ALBANIA            = 8,   /* Albania */
+       CTRY_ALGERIA            = 12,  /* Algeria */
+       CTRY_ARGENTINA          = 32,  /* Argentina */
+       CTRY_ARMENIA            = 51,  /* Armenia */
+       CTRY_AUSTRALIA          = 36,  /* Australia */
+       CTRY_AUSTRIA            = 40,  /* Austria */
+       CTRY_AZERBAIJAN         = 31,  /* Azerbaijan */
+       CTRY_BAHRAIN            = 48,  /* Bahrain */
+       CTRY_BELARUS            = 112, /* Belarus */
+       CTRY_BELGIUM            = 56,  /* Belgium */
+       CTRY_BELIZE             = 84,  /* Belize */
+       CTRY_BOLIVIA            = 68,  /* Bolivia */
+       CTRY_BRAZIL             = 76,  /* Brazil */
+       CTRY_BRUNEI_DARUSSALAM  = 96,  /* Brunei Darussalam */
+       CTRY_BULGARIA           = 100, /* Bulgaria */
+       CTRY_CANADA             = 124, /* Canada */
+       CTRY_CHILE              = 152, /* Chile */
+       CTRY_CHINA              = 156, /* People's Republic of China */
+       CTRY_COLOMBIA           = 170, /* Colombia */
+       CTRY_COSTA_RICA         = 188, /* Costa Rica */
+       CTRY_CROATIA            = 191, /* Croatia */
+       CTRY_CYPRUS             = 196, /* Cyprus */
+       CTRY_CZECH              = 203, /* Czech Republic */
+       CTRY_DENMARK            = 208, /* Denmark */
+       CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */
+       CTRY_ECUADOR            = 218, /* Ecuador */
+       CTRY_EGYPT              = 818, /* Egypt */
+       CTRY_EL_SALVADOR        = 222, /* El Salvador */
+       CTRY_ESTONIA            = 233, /* Estonia */
+       CTRY_FAEROE_ISLANDS     = 234, /* Faeroe Islands */
+       CTRY_FINLAND            = 246, /* Finland */
+       CTRY_FRANCE             = 250, /* France */
+       CTRY_FRANCE2            = 255, /* France2 */
+       CTRY_GEORGIA            = 268, /* Georgia */
+       CTRY_GERMANY            = 276, /* Germany */
+       CTRY_GREECE             = 300, /* Greece */
+       CTRY_GUATEMALA          = 320, /* Guatemala */
+       CTRY_HONDURAS           = 340, /* Honduras */
+       CTRY_HONG_KONG          = 344, /* Hong Kong S.A.R., P.R.C. */
+       CTRY_HUNGARY            = 348, /* Hungary */
+       CTRY_ICELAND            = 352, /* Iceland */
+       CTRY_INDIA              = 356, /* India */
+       CTRY_INDONESIA          = 360, /* Indonesia */
+       CTRY_IRAN               = 364, /* Iran */
+       CTRY_IRAQ               = 368, /* Iraq */
+       CTRY_IRELAND            = 372, /* Ireland */
+       CTRY_ISRAEL             = 376, /* Israel */
+       CTRY_ITALY              = 380, /* Italy */
+       CTRY_JAMAICA            = 388, /* Jamaica */
+       CTRY_JAPAN              = 392, /* Japan */
+       CTRY_JAPAN1             = 393, /* Japan (JP1) */
+       CTRY_JAPAN2             = 394, /* Japan (JP0) */
+       CTRY_JAPAN3             = 395, /* Japan (JP1-1) */
+       CTRY_JAPAN4             = 396, /* Japan (JE1) */
+       CTRY_JAPAN5             = 397, /* Japan (JE2) */
+       CTRY_JORDAN             = 400, /* Jordan */
+       CTRY_KAZAKHSTAN         = 398, /* Kazakhstan */
+       CTRY_KENYA              = 404, /* Kenya */
+       CTRY_KOREA_NORTH        = 408, /* North Korea */
+       CTRY_KOREA_ROC          = 410, /* South Korea */
+       CTRY_KOREA_ROC2         = 411, /* South Korea */
+       CTRY_KUWAIT             = 414, /* Kuwait */
+       CTRY_LATVIA             = 428, /* Latvia */
+       CTRY_LEBANON            = 422, /* Lebanon */
+       CTRY_LIBYA              = 434, /* Libya */
+       CTRY_LIECHTENSTEIN      = 438, /* Liechtenstein */
+       CTRY_LITHUANIA          = 440, /* Lithuania */
+       CTRY_LUXEMBOURG         = 442, /* Luxembourg */
+       CTRY_MACAU              = 446, /* Macau */
+       CTRY_MACEDONIA          = 807, /* Republic of Macedonia */
+       CTRY_MALAYSIA           = 458, /* Malaysia */
+       CTRY_MEXICO             = 484, /* Mexico */
+       CTRY_MONACO             = 492, /* Principality of Monaco */
+       CTRY_MOROCCO            = 504, /* Morocco */
+       CTRY_NETHERLANDS        = 528, /* Netherlands */
+       CTRY_NEW_ZEALAND        = 554, /* New Zealand */
+       CTRY_NICARAGUA          = 558, /* Nicaragua */
+       CTRY_NORWAY             = 578, /* Norway */
+       CTRY_OMAN               = 512, /* Oman */
+       CTRY_PAKISTAN           = 586, /* Islamic Republic of Pakistan */
+       CTRY_PANAMA             = 591, /* Panama */
+       CTRY_PARAGUAY           = 600, /* Paraguay */
+       CTRY_PERU               = 604, /* Peru */
+       CTRY_PHILIPPINES        = 608, /* Republic of the Philippines */
+       CTRY_POLAND             = 616, /* Poland */
+       CTRY_PORTUGAL           = 620, /* Portugal */
+       CTRY_PUERTO_RICO        = 630, /* Puerto Rico */
+       CTRY_QATAR              = 634, /* Qatar */
+       CTRY_ROMANIA            = 642, /* Romania */
+       CTRY_RUSSIA             = 643, /* Russia */
+       CTRY_SAUDI_ARABIA       = 682, /* Saudi Arabia */
+       CTRY_SINGAPORE          = 702, /* Singapore */
+       CTRY_SLOVAKIA           = 703, /* Slovak Republic */
+       CTRY_SLOVENIA           = 705, /* Slovenia */
+       CTRY_SOUTH_AFRICA       = 710, /* South Africa */
+       CTRY_SPAIN              = 724, /* Spain */
+       CTRY_SRI_LANKA          = 728, /* Sri Lanka */
+       CTRY_SWEDEN             = 752, /* Sweden */
+       CTRY_SWITZERLAND        = 756, /* Switzerland */
+       CTRY_SYRIA              = 760, /* Syria */
+       CTRY_TAIWAN             = 158, /* Taiwan */
+       CTRY_THAILAND           = 764, /* Thailand */
+       CTRY_TRINIDAD_Y_TOBAGO  = 780, /* Trinidad y Tobago */
+       CTRY_TUNISIA            = 788, /* Tunisia */
+       CTRY_TURKEY             = 792, /* Turkey */
+       CTRY_UAE                = 784, /* U.A.E. */
+       CTRY_UKRAINE            = 804, /* Ukraine */
+       CTRY_UNITED_KINGDOM     = 826, /* United Kingdom */
+       CTRY_UNITED_STATES      = 840, /* United States */
+       CTRY_URUGUAY            = 858, /* Uruguay */
+       CTRY_UZBEKISTAN         = 860, /* Uzbekistan */
+       CTRY_VENEZUELA          = 862, /* Venezuela */
+       CTRY_VIET_NAM           = 704, /* Viet Nam */
+       CTRY_YEMEN              = 887, /* Yemen */
+       CTRY_ZIMBABWE           = 716, /* Zimbabwe */
+};
+
+#define IEEE80211_CHANNELS_2GHZ_MIN    2412    /* 2GHz channel 1 */
+#define IEEE80211_CHANNELS_2GHZ_MAX    2732    /* 2GHz channel 26 */
+#define IEEE80211_CHANNELS_5GHZ_MIN    5005    /* 5GHz channel 1 */
+#define IEEE80211_CHANNELS_5GHZ_MAX    6100    /* 5GHz channel 220 */
+
+struct ath5k_regchannel {
+       u16 chan;
+       enum ath5k_regdom domain;
+       u32 mode;
+};
+
+#define IEEE80211_CHANNELS_2GHZ {                                      \
+/*2412*/ {   1, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2417*/ {   2, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2422*/ {   3, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2427*/ {   4, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2432*/ {   5, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2437*/ {   6, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2442*/ {   7, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2447*/ {   8, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2452*/ {   9, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2457*/ {  10, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2462*/ {  11, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2467*/ {  12, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2472*/ {  13, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },                  \
+                                                                       \
+/*2432*/ {   5, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2437*/ {   6, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },   \
+/*2442*/ {   7, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM },                 \
+                                                                       \
+/*2412*/ {   1, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2417*/ {   2, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2422*/ {   3, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2427*/ {   4, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2432*/ {   5, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2437*/ {   6, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },   \
+/*2442*/ {   7, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2447*/ {   8, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2452*/ {   9, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2457*/ {  10, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2462*/ {  11, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2467*/ {  12, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2472*/ {  13, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },                 \
+                                                                       \
+/*2412*/ {   1, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2417*/ {   2, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2422*/ {   3, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2427*/ {   4, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2432*/ {   5, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2437*/ {   6, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },    \
+/*2442*/ {   7, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2447*/ {   8, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2452*/ {   9, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2457*/ {  10, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2462*/ {  11, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+                                                                       \
+/*2412*/ {   1, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2417*/ {   2, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2422*/ {   3, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2427*/ {   4, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2432*/ {   5, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2437*/ {   6, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2442*/ {   7, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2447*/ {   8, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2452*/ {   9, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2457*/ {  10, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2462*/ {  11, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2467*/ {  12, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2472*/ {  13, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },                  \
+/*2484*/ {  14, DMN_MKKA, CHANNEL_CCK },                               \
+                                                                       \
+/*2412*/ {   1, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2417*/ {   2, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2422*/ {   3, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2427*/ {   4, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2432*/ {   5, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2437*/ {   6, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },   \
+/*2442*/ {   7, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2447*/ {   8, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2452*/ {   9, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2457*/ {  10, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2462*/ {  11, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2467*/ {  12, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+/*2472*/ {  13, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },                 \
+}
+
+#define IEEE80211_CHANNELS_5GHZ {                      \
+/*5745*/ { 149, DMN_APL1, CHANNEL_OFDM },              \
+/*5765*/ { 153, DMN_APL1, CHANNEL_OFDM },              \
+/*5785*/ { 157, DMN_APL1, CHANNEL_OFDM },              \
+/*5805*/ { 161, DMN_APL1, CHANNEL_OFDM },              \
+/*5825*/ { 165, DMN_APL1, CHANNEL_OFDM },              \
+                                                       \
+/*5745*/ { 149, DMN_APL2, CHANNEL_OFDM },              \
+/*5765*/ { 153, DMN_APL2, CHANNEL_OFDM },              \
+/*5785*/ { 157, DMN_APL2, CHANNEL_OFDM },              \
+/*5805*/ { 161, DMN_APL2, CHANNEL_OFDM },              \
+                                                       \
+/*5280*/ {  56, DMN_APL3, CHANNEL_OFDM },              \
+/*5300*/ {  60, DMN_APL3, CHANNEL_OFDM },              \
+/*5320*/ {  64, DMN_APL3, CHANNEL_OFDM },              \
+/*5745*/ { 149, DMN_APL3, CHANNEL_OFDM },              \
+/*5765*/ { 153, DMN_APL3, CHANNEL_OFDM },              \
+/*5785*/ { 157, DMN_APL3, CHANNEL_OFDM },              \
+/*5805*/ { 161, DMN_APL3, CHANNEL_OFDM },              \
+                                                       \
+/*5180*/ {  36, DMN_APL4, CHANNEL_OFDM },              \
+/*5200*/ {  40, DMN_APL4, CHANNEL_OFDM },              \
+/*5220*/ {  44, DMN_APL4, CHANNEL_OFDM },              \
+/*5240*/ {  48, DMN_APL4, CHANNEL_OFDM },              \
+/*5745*/ { 149, DMN_APL4, CHANNEL_OFDM },              \
+/*5765*/ { 153, DMN_APL4, CHANNEL_OFDM },              \
+/*5785*/ { 157, DMN_APL4, CHANNEL_OFDM },              \
+/*5805*/ { 161, DMN_APL4, CHANNEL_OFDM },              \
+/*5825*/ { 165, DMN_APL4, CHANNEL_OFDM },              \
+                                                       \
+/*5745*/ { 149, DMN_APL5, CHANNEL_OFDM },              \
+/*5765*/ { 153, DMN_APL5, CHANNEL_OFDM },              \
+/*5785*/ { 157, DMN_APL5, CHANNEL_OFDM },              \
+/*5805*/ { 161, DMN_APL5, CHANNEL_OFDM },              \
+/*5825*/ { 165, DMN_APL5, CHANNEL_OFDM },              \
+                                                       \
+/*5180*/ {  36, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5200*/ {  40, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5220*/ {  44, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5240*/ {  48, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5260*/ {  52, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5280*/ {  56, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5300*/ {  60, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5320*/ {  64, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5500*/ { 100, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5520*/ { 104, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5540*/ { 108, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5560*/ { 112, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5580*/ { 116, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5600*/ { 120, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5620*/ { 124, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5640*/ { 128, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5660*/ { 132, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5680*/ { 136, DMN_ETSI1, CHANNEL_OFDM },             \
+/*5700*/ { 140, DMN_ETSI1, CHANNEL_OFDM },             \
+                                                       \
+/*5180*/ {  36, DMN_ETSI2, CHANNEL_OFDM },             \
+/*5200*/ {  40, DMN_ETSI2, CHANNEL_OFDM },             \
+/*5220*/ {  44, DMN_ETSI2, CHANNEL_OFDM },             \
+/*5240*/ {  48, DMN_ETSI2, CHANNEL_OFDM },             \
+                                                       \
+/*5180*/ {  36, DMN_ETSI3, CHANNEL_OFDM },             \
+/*5200*/ {  40, DMN_ETSI3, CHANNEL_OFDM },             \
+/*5220*/ {  44, DMN_ETSI3, CHANNEL_OFDM },             \
+/*5240*/ {  48, DMN_ETSI3, CHANNEL_OFDM },             \
+/*5260*/ {  52, DMN_ETSI3, CHANNEL_OFDM },             \
+/*5280*/ {  56, DMN_ETSI3, CHANNEL_OFDM },             \
+/*5300*/ {  60, DMN_ETSI3, CHANNEL_OFDM },             \
+/*5320*/ {  64, DMN_ETSI3, CHANNEL_OFDM },             \
+                                                       \
+/*5180*/ {  36, DMN_ETSI4, CHANNEL_OFDM },             \
+/*5200*/ {  40, DMN_ETSI4, CHANNEL_OFDM },             \
+/*5220*/ {  44, DMN_ETSI4, CHANNEL_OFDM },             \
+/*5240*/ {  48, DMN_ETSI4, CHANNEL_OFDM },             \
+/*5260*/ {  52, DMN_ETSI4, CHANNEL_OFDM },             \
+/*5280*/ {  56, DMN_ETSI4, CHANNEL_OFDM },             \
+/*5300*/ {  60, DMN_ETSI4, CHANNEL_OFDM },             \
+/*5320*/ {  64, DMN_ETSI4, CHANNEL_OFDM },             \
+                                                       \
+/*5180*/ {  36, DMN_ETSI5, CHANNEL_OFDM },             \
+/*5200*/ {  40, DMN_ETSI5, CHANNEL_OFDM },             \
+/*5220*/ {  44, DMN_ETSI5, CHANNEL_OFDM },             \
+/*5240*/ {  48, DMN_ETSI5, CHANNEL_OFDM },             \
+                                                       \
+/*5180*/ {  36, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5200*/ {  40, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5220*/ {  44, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5240*/ {  48, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5260*/ {  52, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5280*/ {  56, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5500*/ { 100, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5520*/ { 104, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5540*/ { 108, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5560*/ { 112, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5580*/ { 116, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5600*/ { 120, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5620*/ { 124, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5640*/ { 128, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5660*/ { 132, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5680*/ { 136, DMN_ETSI6, CHANNEL_OFDM },             \
+/*5700*/ { 140, DMN_ETSI6, CHANNEL_OFDM },             \
+                                                       \
+/*5180*/ {  36, DMN_FCC1, CHANNEL_OFDM },              \
+/*5200*/ {  40, DMN_FCC1, CHANNEL_OFDM },              \
+/*5210*/ {  42, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5220*/ {  44, DMN_FCC1, CHANNEL_OFDM },              \
+/*5240*/ {  48, DMN_FCC1, CHANNEL_OFDM },              \
+/*5250*/ {  50, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5260*/ {  52, DMN_FCC1, CHANNEL_OFDM },              \
+/*5280*/ {  56, DMN_FCC1, CHANNEL_OFDM },              \
+/*5290*/ {  58, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5300*/ {  60, DMN_FCC1, CHANNEL_OFDM },              \
+/*5320*/ {  64, DMN_FCC1, CHANNEL_OFDM },              \
+/*5745*/ { 149, DMN_FCC1, CHANNEL_OFDM },              \
+/*5760*/ { 152, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5765*/ { 153, DMN_FCC1, CHANNEL_OFDM },              \
+/*5785*/ { 157, DMN_FCC1, CHANNEL_OFDM },              \
+/*5800*/ { 160, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5805*/ { 161, DMN_FCC1, CHANNEL_OFDM },              \
+/*5825*/ { 165, DMN_FCC1, CHANNEL_OFDM },              \
+                                                       \
+/*5180*/ {  36, DMN_FCC2, CHANNEL_OFDM },              \
+/*5200*/ {  40, DMN_FCC2, CHANNEL_OFDM },              \
+/*5220*/ {  44, DMN_FCC2, CHANNEL_OFDM },              \
+/*5240*/ {  48, DMN_FCC2, CHANNEL_OFDM },              \
+/*5260*/ {  52, DMN_FCC2, CHANNEL_OFDM },              \
+/*5280*/ {  56, DMN_FCC2, CHANNEL_OFDM },              \
+/*5300*/ {  60, DMN_FCC2, CHANNEL_OFDM },              \
+/*5320*/ {  64, DMN_FCC2, CHANNEL_OFDM },              \
+/*5745*/ { 149, DMN_FCC2, CHANNEL_OFDM },              \
+/*5765*/ { 153, DMN_FCC2, CHANNEL_OFDM },              \
+/*5785*/ { 157, DMN_FCC2, CHANNEL_OFDM },              \
+/*5805*/ { 161, DMN_FCC2, CHANNEL_OFDM },              \
+/*5825*/ { 165, DMN_FCC2, CHANNEL_OFDM },              \
+                                                       \
+/*5180*/ {  36, DMN_FCC3, CHANNEL_OFDM },              \
+/*5200*/ {  40, DMN_FCC3, CHANNEL_OFDM },              \
+/*5210*/ {  42, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5220*/ {  44, DMN_FCC3, CHANNEL_OFDM },              \
+/*5240*/ {  48, DMN_FCC3, CHANNEL_OFDM },              \
+/*5250*/ {  50, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5260*/ {  52, DMN_FCC3, CHANNEL_OFDM },              \
+/*5280*/ {  56, DMN_FCC3, CHANNEL_OFDM },              \
+/*5290*/ {  58, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5300*/ {  60, DMN_FCC3, CHANNEL_OFDM },              \
+/*5320*/ {  64, DMN_FCC3, CHANNEL_OFDM },              \
+/*5500*/ { 100, DMN_FCC3, CHANNEL_OFDM },              \
+/*5520*/ { 104, DMN_FCC3, CHANNEL_OFDM },              \
+/*5540*/ { 108, DMN_FCC3, CHANNEL_OFDM },              \
+/*5560*/ { 112, DMN_FCC3, CHANNEL_OFDM },              \
+/*5580*/ { 116, DMN_FCC3, CHANNEL_OFDM },              \
+/*5600*/ { 120, DMN_FCC3, CHANNEL_OFDM },              \
+/*5620*/ { 124, DMN_FCC3, CHANNEL_OFDM },              \
+/*5640*/ { 128, DMN_FCC3, CHANNEL_OFDM },              \
+/*5660*/ { 132, DMN_FCC3, CHANNEL_OFDM },              \
+/*5680*/ { 136, DMN_FCC3, CHANNEL_OFDM },              \
+/*5700*/ { 140, DMN_FCC3, CHANNEL_OFDM },              \
+/*5745*/ { 149, DMN_FCC3, CHANNEL_OFDM },              \
+/*5760*/ { 152, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5765*/ { 153, DMN_FCC3, CHANNEL_OFDM },              \
+/*5785*/ { 157, DMN_FCC3, CHANNEL_OFDM },              \
+/*5800*/ { 160, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },        \
+/*5805*/ { 161, DMN_FCC3, CHANNEL_OFDM },              \
+/*5825*/ { 165, DMN_FCC3, CHANNEL_OFDM },              \
+                                                       \
+/*5170*/ {  34, DMN_MKK1, CHANNEL_OFDM },              \
+/*5190*/ {  38, DMN_MKK1, CHANNEL_OFDM },              \
+/*5210*/ {  42, DMN_MKK1, CHANNEL_OFDM },              \
+/*5230*/ {  46, DMN_MKK1, CHANNEL_OFDM },              \
+                                                       \
+/*5040*/ {   8, DMN_MKK2, CHANNEL_OFDM },              \
+/*5060*/ {  12, DMN_MKK2, CHANNEL_OFDM },              \
+/*5080*/ {  16, DMN_MKK2, CHANNEL_OFDM },              \
+/*5170*/ {  34, DMN_MKK2, CHANNEL_OFDM },              \
+/*5190*/ {  38, DMN_MKK2, CHANNEL_OFDM },              \
+/*5210*/ {  42, DMN_MKK2, CHANNEL_OFDM },              \
+/*5230*/ {  46, DMN_MKK2, CHANNEL_OFDM },              \
+                                                       \
+/*5180*/ {  36, DMN_WORLD, CHANNEL_OFDM },             \
+/*5200*/ {  40, DMN_WORLD, CHANNEL_OFDM },             \
+/*5220*/ {  44, DMN_WORLD, CHANNEL_OFDM },             \
+/*5240*/ {  48, DMN_WORLD, CHANNEL_OFDM },             \
+}
+
+enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom, u16);
+u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee);
+enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain);
+
+#endif