Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index 0eda785..b9af2b8 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -165,9 +165,6 @@
 #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
-
 /* Used for BSSID etc manipulation */
 #define AR5K_LOW_ID(_a)(				\
 (_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24	\
@@ -225,6 +222,7 @@
 #endif
 
 /* Initial values */
+#define	AR5K_INIT_CYCRSSI_THR1			2
 #define AR5K_INIT_TX_LATENCY			502
 #define AR5K_INIT_USEC				39
 #define AR5K_INIT_USEC_TURBO			79
@@ -316,7 +314,7 @@
 #define AR5K_SREV_AR5424	0x90 /* Condor */
 #define AR5K_SREV_AR5413	0xa4 /* Eagle lite */
 #define AR5K_SREV_AR5414	0xa0 /* Eagle */
-#define AR5K_SREV_AR2415	0xb0 /* Cobra */
+#define AR5K_SREV_AR2415	0xb0 /* Talon */
 #define AR5K_SREV_AR5416	0xc0 /* PCI-E */
 #define AR5K_SREV_AR5418	0xca /* PCI-E */
 #define AR5K_SREV_AR2425	0xe0 /* Swan */
@@ -334,7 +332,7 @@
 #define	AR5K_SREV_RAD_2112B	0x46
 #define AR5K_SREV_RAD_2413	0x50
 #define AR5K_SREV_RAD_5413	0x60
-#define AR5K_SREV_RAD_2316	0x70
+#define AR5K_SREV_RAD_2316	0x70 /* Cobra SoC */
 #define AR5K_SREV_RAD_2317	0x80
 #define AR5K_SREV_RAD_5424	0xa0 /* Mostly same as 5413 */
 #define AR5K_SREV_RAD_2425	0xa2
@@ -342,7 +340,8 @@
 
 #define AR5K_SREV_PHY_5211	0x30
 #define AR5K_SREV_PHY_5212	0x41
-#define AR5K_SREV_PHY_2112B	0x43
+#define	AR5K_SREV_PHY_5212A	0x42
+#define AR5K_SREV_PHY_5212B	0x43
 #define AR5K_SREV_PHY_2413	0x45
 #define AR5K_SREV_PHY_5413	0x61
 #define AR5K_SREV_PHY_2425	0x70
@@ -649,49 +648,21 @@
 
 enum ath5k_rfgain {
 	AR5K_RFGAIN_INACTIVE = 0,
+	AR5K_RFGAIN_ACTIVE,
 	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;
+	u8			g_step_idx;
+	u8			g_current;
+	u8			g_target;
+	u8			g_low;
+	u8			g_high;
+	u8			g_f_corr;
+	u8			g_state;
 };
 
-
 /********************\
   COMMON DEFINITIONS
 \********************/
@@ -1053,7 +1024,6 @@
 	bool			ah_running;
 	bool			ah_single_chip;
 	bool			ah_combined_mic;
-	enum ath5k_rfgain	ah_rf_gain;
 
 	u32			ah_mac_srev;
 	u16			ah_mac_version;
@@ -1061,7 +1031,6 @@
 	u16			ah_phy_revision;
 	u16			ah_radio_5ghz_revision;
 	u16			ah_radio_2ghz_revision;
-	u32			ah_phy_spending;
 
 	enum ath5k_version	ah_version;
 	enum ath5k_radio	ah_radio;
@@ -1112,8 +1081,9 @@
 	u32			ah_txq_isr;
 	u32			*ah_rf_banks;
 	size_t			ah_rf_banks_size;
+	size_t			ah_rf_regs_count;
 	struct ath5k_gain	ah_gain;
-	u32			ah_offset[AR5K_MAX_RF_BANKS];
+	u8			ah_offset[AR5K_MAX_RF_BANKS];
 
 	struct {
 		u16		txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE];
@@ -1186,6 +1156,7 @@
 /* EEPROM access functions */
 extern int ath5k_eeprom_init(struct ath5k_hw *ah);
 extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
+extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
 
 /* Protocol Control Unit Functions */
 extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
@@ -1261,10 +1232,12 @@
 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);
+extern int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
+				struct ieee80211_channel *channel,
+				unsigned int mode);
+extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
+extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
+extern int ath5k_hw_rfgain_opt_init(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);
@@ -1286,6 +1259,7 @@
 
 /*
  * Translate usec to hw clock units
+ * TODO: Half/quarter rate
  */
 static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
 {
@@ -1294,6 +1268,7 @@
 
 /*
  * Translate hw clock units to usec
+ * TODO: Half/quarter rate
  */
 static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
 {
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c
index dea378f..05bc5cb 100644
--- a/drivers/net/wireless/ath5k/attach.c
+++ b/drivers/net/wireless/ath5k/attach.c
@@ -169,7 +169,6 @@
 		ah->ah_single_chip = false;
 		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
 							CHANNEL_2GHZ);
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
 		break;
 	case AR5K_SREV_RAD_5112:
 	case AR5K_SREV_RAD_2112:
@@ -177,38 +176,31 @@
 		ah->ah_single_chip = false;
 		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
 							CHANNEL_2GHZ);
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
 		break;
 	case AR5K_SREV_RAD_2413:
 		ah->ah_radio = AR5K_RF2413;
 		ah->ah_single_chip = true;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
 		break;
 	case AR5K_SREV_RAD_5413:
 		ah->ah_radio = AR5K_RF5413;
 		ah->ah_single_chip = true;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
 		break;
 	case AR5K_SREV_RAD_2316:
 		ah->ah_radio = AR5K_RF2316;
 		ah->ah_single_chip = true;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316;
 		break;
 	case AR5K_SREV_RAD_2317:
 		ah->ah_radio = AR5K_RF2317;
 		ah->ah_single_chip = true;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2317;
 		break;
 	case AR5K_SREV_RAD_5424:
 		if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
 		ah->ah_mac_version == AR5K_SREV_AR2417){
 			ah->ah_radio = AR5K_RF2425;
 			ah->ah_single_chip = true;
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
 		} else {
 			ah->ah_radio = AR5K_RF5413;
 			ah->ah_single_chip = true;
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
 		}
 		break;
 	default:
@@ -227,29 +219,25 @@
 			ah->ah_radio = AR5K_RF2425;
 			ah->ah_single_chip = true;
 			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
 		} else if (srev == AR5K_SREV_AR5213A &&
-		ah->ah_phy_revision == AR5K_SREV_PHY_2112B) {
+		ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
 			ah->ah_radio = AR5K_RF5112;
 			ah->ah_single_chip = false;
-			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2112B;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
 		} else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
 			ah->ah_radio = AR5K_RF2316;
 			ah->ah_single_chip = true;
 			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316;
 		} else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
 		ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
 			ah->ah_radio = AR5K_RF5413;
 			ah->ah_single_chip = true;
 			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
 		} else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
 		ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
 			ah->ah_radio = AR5K_RF2413;
 			ah->ah_single_chip = true;
 			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
 		} else {
 			ATH5K_ERR(sc, "Couldn't identify radio revision.\n");
 			ret = -ENODEV;
@@ -331,7 +319,7 @@
 	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
 	ath5k_hw_set_opmode(ah);
 
-	ath5k_hw_set_rfgain_opt(ah);
+	ath5k_hw_rfgain_opt_init(ah);
 
 	return ah;
 err_free:
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index f9d486f..6837ca9 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -2209,10 +2209,6 @@
  *
  * @sc: struct ath5k_softc pointer we are operating on
  *
- * 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 use a self-linked tx descriptor if possible. We enable SWBA
  * interrupts to detect TSF updates only.
  */
@@ -2225,9 +2221,7 @@
 	sc->bmisscount = 0;
 	sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
 
-	if (sc->opmode == NL80211_IFTYPE_STATION) {
-		sc->imask |= AR5K_INT_BMISS;
-	} else if (sc->opmode == NL80211_IFTYPE_ADHOC ||
+	if (sc->opmode == NL80211_IFTYPE_ADHOC ||
 			sc->opmode == NL80211_IFTYPE_MESH_POINT ||
 			sc->opmode == NL80211_IFTYPE_AP) {
 		/*
@@ -2479,6 +2473,7 @@
 					| AR5K_INT_TXERR | AR5K_INT_TXEOL))
 				tasklet_schedule(&sc->txtq);
 			if (status & AR5K_INT_BMISS) {
+				/* TODO */
 			}
 			if (status & AR5K_INT_MIB) {
 				/*
@@ -2518,7 +2513,7 @@
 		ieee80211_frequency_to_channel(sc->curchan->center_freq),
 		sc->curchan->hw_value);
 
-	if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) {
+	if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
 		/*
 		 * Rfgain is out of bounds, reset the chip
 		 * to load new gain values.
@@ -2889,7 +2884,7 @@
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_hw *ah = sc->ah;
-	int ret;
+	int ret = 0;
 
 	mutex_lock(&sc->lock);
 	if (sc->vif != vif) {
@@ -2915,9 +2910,7 @@
 		}
 		ath5k_beacon_update(sc, beacon);
 	}
-	mutex_unlock(&sc->lock);
 
-	return ath5k_reset_wake(sc);
 unlock:
 	mutex_unlock(&sc->lock);
 	return ret;
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c
index b4ec539..a54ee7e 100644
--- a/drivers/net/wireless/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath5k/eeprom.c
@@ -204,7 +204,7 @@
 
 	/* Get antenna modes */
 	ah->ah_antenna[mode][0] =
-	    (ee->ee_ant_control[mode][0] << 4) | 0x1;
+	    (ee->ee_ant_control[mode][0] << 4);
 	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
 	     ee->ee_ant_control[mode][1] 	|
 	    (ee->ee_ant_control[mode][2] << 6) 	|
@@ -517,9 +517,9 @@
 static inline void
 ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
 {
-	const static u16 intercepts3[] =
+	static const u16 intercepts3[] =
 		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
-	const static u16 intercepts3_2[] =
+	static const u16 intercepts3_2[] =
 		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
 	const u16 *ip;
 	int i;
@@ -1412,6 +1412,7 @@
 
 	return 0;
 }
+
 /*
  * Read the MAC address from eeprom
  */
@@ -1448,3 +1449,14 @@
 	return 0;
 }
 
+bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah)
+{
+	u16 data;
+
+	ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data);
+
+	if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data)
+		return true;
+	else
+		return false;
+}
diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h
index 09eb7d0..1deebc0 100644
--- a/drivers/net/wireless/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath5k/eeprom.h
@@ -25,6 +25,7 @@
 #define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
 #define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
 
+#define	AR5K_EEPROM_IS_HB63		0x000b	/* Talon detect */
 #define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
 #define AR5K_EEPROM_CHECKSUM		0x00c0	/* EEPROM checksum */
 #define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c
index 450bd6e..4488643 100644
--- a/drivers/net/wireless/ath5k/initvals.c
+++ b/drivers/net/wireless/ath5k/initvals.c
@@ -2,7 +2,7 @@
  * Initial register settings functions
  *
  * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
  * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -340,7 +340,7 @@
 	 * common on all cards/modes.
 	 * Note: Table is rewritten during
 	 * txpower setup later using calibration
-	 * data etc. so next write is non-common
+	 * 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 },
@@ -371,7 +371,7 @@
 	{ 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_PCDAC_TXPOWER(31), 0x3aff3aff },
 	{ AR5K_PHY_CCKTXCTL, 0x00000000 },
 	{ AR5K_PHY(642), 0x503e4646 },
 	{ AR5K_PHY_GAIN_2GHZ, 0x6480416c },
@@ -386,85 +386,85 @@
 };
 
 /* 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 !
+ * 5211 supports OFDM-only g (draft g) but we
+ * need to test it !
  */
 static const struct ath5k_ini_mode ar5211_ini_mode[] = {
 	{ AR5K_TXCFG,
-	/*	  a	      aTurbo	  b		*/
-		{ 0x00000015, 0x00000015, 0x0000001d } },
+	/*	  a	    aTurbo	  b	  g (OFDM)    */
+	   { 0x00000015, 0x00000015, 0x0000001d, 0x00000015 } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
 	{ AR5K_DCU_GBL_IFS_SLOT,
-		{ 0x00000168, 0x000001e0, 0x000001b8 } },
+	   { 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 } },
 	{ AR5K_DCU_GBL_IFS_SIFS,
-		{ 0x00000230, 0x000001e0, 0x000000b0 } },
+	   { 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 } },
 	{ AR5K_DCU_GBL_IFS_EIFS,
-		{ 0x00000d98, 0x00001180, 0x00001f48 } },
+	   { 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 } },
 	{ AR5K_DCU_GBL_IFS_MISC,
-		{ 0x0000a0e0, 0x00014068, 0x00005880 } },
+	   { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 } },
 	{ AR5K_TIME_OUT,
-		{ 0x04000400, 0x08000800, 0x20003000 } },
+	   { 0x04000400, 0x08000800, 0x20003000, 0x04000400 } },
 	{ AR5K_USEC_5211,
-		{ 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95 } },
+	   { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 } },
 	{ AR5K_PHY_TURBO,
-		{ 0x00000000, 0x00000003, 0x00000000 } },
+	   { 0x00000000, 0x00000003, 0x00000000, 0x00000000 } },
 	{ AR5K_PHY(8),
-		{ 0x02020200, 0x02020200, 0x02010200 } },
+	   { 0x02020200, 0x02020200, 0x02010200, 0x02020200 } },
 	{ AR5K_PHY(9),
-		{ 0x00000e0e, 0x00000e0e, 0x00000707 } },
+	   { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e } },
 	{ AR5K_PHY(10),
-		{ 0x0a020001, 0x0a020001, 0x05010000 } },
+	   { 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 } },
 	{ AR5K_PHY(13),
-		{ 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
 	{ AR5K_PHY(14),
-		{ 0x00000007, 0x00000007, 0x0000000b } },
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b } },
 	{ AR5K_PHY(17),
-		{ 0x1372169c, 0x137216a5, 0x137216a8 } },
+	   { 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c } },
 	{ AR5K_PHY(18),
-		{ 0x0018ba67, 0x0018ba67, 0x0018ba69 } },
+	   { 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 } },
 	{ AR5K_PHY(20),
-		{ 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
+	   { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
 	{ AR5K_PHY_SIG,
-		{ 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e } },
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } },
 	{ AR5K_PHY_AGCCOARSE,
-		{ 0x31375d5e, 0x31375d5e, 0x313a5d5e } },
+	   { 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e } },
 	{ AR5K_PHY_AGCCTL,
-		{ 0x0000bd10, 0x0000bd10, 0x0000bd38 } },
+	   { 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 } },
 	{ AR5K_PHY_NF,
-		{ 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+	   { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
 	{ AR5K_PHY_RX_DELAY,
-		{ 0x00002710, 0x00002710, 0x0000157c } },
+	   { 0x00002710, 0x00002710, 0x0000157c, 0x00002710 } },
 	{ AR5K_PHY(70),
-		{ 0x00000190, 0x00000190, 0x00000084 } },
+	   { 0x00000190, 0x00000190, 0x00000084, 0x00000190 } },
 	{ AR5K_PHY_FRAME_CTL_5211,
-		{ 0x6fe01020, 0x6fe01020, 0x6fe00920 } },
-	{ AR5K_PHY_PCDAC_TXPOWER_BASE_5211,
-		{ 0x05ff14ff, 0x05ff14ff, 0x05ff14ff } },
+	   { 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 } },
+	{ AR5K_PHY_PCDAC_TXPOWER_BASE,
+	   { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } },
 	{ AR5K_RF_BUFFER_CONTROL_4,
-		{ 0x00000010, 0x00000014, 0x00000010 } },
+	   { 0x00000010, 0x00000014, 0x00000010, 0x00000010 } },
 };
 
 /* Initial register settings for AR5212 */
-static const struct ath5k_ini ar5212_ini[] = {
+static const struct ath5k_ini ar5212_ini_common_start[] = {
 	{ AR5K_RXDP,		0x00000000 },
 	{ AR5K_RXCFG,		0x00000005 },
 	{ AR5K_MIBC,		0x00000000 },
@@ -485,91 +485,83 @@
 	{ AR5K_QUEUE_TXDP(9),	0x00000000 },
 	{ AR5K_DCU_FP,		0x00000000 },
 	{ AR5K_DCU_TXP,		0x00000000 },
-	{ AR5K_DCU_TX_FILTER_0_BASE,	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 },
+	/* Tx filter table 0 (32 entries) */
+	{ AR5K_DCU_TX_FILTER_0(0),  0x00000000 }, /* DCU 0 */
+	{ AR5K_DCU_TX_FILTER_0(1),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(2),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(3),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(4),  0x00000000 }, /* DCU 1 */
+	{ AR5K_DCU_TX_FILTER_0(5),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(6),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(7),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(8),  0x00000000 }, /* DCU 2 */
+	{ AR5K_DCU_TX_FILTER_0(9),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(10), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(11), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(12), 0x00000000 }, /* DCU 3 */
+	{ AR5K_DCU_TX_FILTER_0(13), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(14), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(15), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(16), 0x00000000 }, /* DCU 4 */
+	{ AR5K_DCU_TX_FILTER_0(17), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(18), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(19), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(20), 0x00000000 }, /* DCU 5 */
+	{ AR5K_DCU_TX_FILTER_0(21), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(22), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(23), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(24), 0x00000000 }, /* DCU 6 */
+	{ AR5K_DCU_TX_FILTER_0(25), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(26), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(27), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(28), 0x00000000 }, /* DCU 7 */
+	{ AR5K_DCU_TX_FILTER_0(29), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(30), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0(31), 0x00000000 },
+	/* Tx filter table 1 (16 entries) */
+	{ AR5K_DCU_TX_FILTER_1(0),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(1),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(2),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(3),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(4),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(5),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(6),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(7),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(8),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(9),  0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(10), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(11), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(12), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(13), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(14), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_1(15), 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_SET, 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_BEACON_5211,	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_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_FRAME_CTL_QOSM, 	0x000fc78f },
 	{ 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_SLEEP0,		0x0002aaaa },
+	{ AR5K_SLEEP1,		0x02005555 },
+	{ AR5K_SLEEP2,		0x00000000 },
 	{ AR5K_BSS_IDM0,	0xffffffff },
 	{ AR5K_BSS_IDM1,	0x0000ffff },
 	{ AR5K_TXPC,		0x00000000 },
@@ -577,7 +569,8 @@
 	{ AR5K_PROFCNT_RX,	0x00000000 },
 	{ AR5K_PROFCNT_RXCLR,	0x00000000 },
 	{ AR5K_PROFCNT_CYCLE,	0x00000000 },
-	{ 0x80fc, 0x00000088 },
+	{ AR5K_QUIET_CTL1,	0x00000088 },
+	/* Initial rate duration table (32 entries )*/
 	{ AR5K_RATE_DUR(0),	0x00000000 },
 	{ AR5K_RATE_DUR(1),	0x0000008c },
 	{ AR5K_RATE_DUR(2),	0x000000e4 },
@@ -610,881 +603,625 @@
 	{ AR5K_RATE_DUR(29),	0x0000007f },
 	{ AR5K_RATE_DUR(30),	0x000000a2 },
 	{ AR5K_RATE_DUR(31),	0x00000000 },
-	{ 0x8100, 0x00010002},
+	{ AR5K_QUIET_CTL2,	0x00010002 },
 	{ AR5K_TSF_PARM,	0x00000001 },
-	{ 0x8108, 0x000000c0 },
+	{ AR5K_QOS_NOACK,	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_XRLAT_TX,	0x00000168 },
+	{ AR5K_ACKSIFS,		0x00000000 },
+	/* Rate -> db table
+	 * notice ...03<-02<-01<-00 ! */
+	{ AR5K_RATE2DB(0),	0x03020100 },
+	{ AR5K_RATE2DB(1),	0x07060504 },
+	{ AR5K_RATE2DB(2),	0x0b0a0908 },
+	{ AR5K_RATE2DB(3),	0x0f0e0d0c },
+	{ AR5K_RATE2DB(4),	0x13121110 },
+	{ AR5K_RATE2DB(5),	0x17161514 },
+	{ AR5K_RATE2DB(6),	0x1b1a1918 },
+	{ AR5K_RATE2DB(7),	0x1f1e1d1c },
+	/* Db -> Rate table */
+	{ AR5K_DB2RATE(0),	0x03020100 },
+	{ AR5K_DB2RATE(1),	0x07060504 },
+	{ AR5K_DB2RATE(2),	0x0b0a0908 },
+	{ AR5K_DB2RATE(3),	0x0f0e0d0c },
+	{ AR5K_DB2RATE(4),	0x13121110 },
+	{ AR5K_DB2RATE(5),	0x17161514 },
+	{ AR5K_DB2RATE(6),	0x1b1a1918 },
+	{ AR5K_DB2RATE(7),	0x1f1e1d1c },
+	/* PHY registers (Common settings
+	 * for all chips/modes) */
+	{ AR5K_PHY(3),		0xad848e19 },
+	{ AR5K_PHY(4),		0x7d28e000 },
+	{ AR5K_PHY_TIMING_3,	0x9c0a9f6b },
+	{ AR5K_PHY_ACT,		0x00000000 },
+	{ AR5K_PHY(16),		0x206a017a },
+	{ AR5K_PHY(21),		0x00000859 },
+	{ AR5K_PHY_BIN_MASK_1,	0x00000000 },
+	{ AR5K_PHY_BIN_MASK_2,	0x00000000 },
+	{ AR5K_PHY_BIN_MASK_3,	0x00000000 },
+	{ AR5K_PHY_BIN_MASK_CTL, 0x00800000 },
+	{ AR5K_PHY_ANT_CTL,	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_MAX_RX_LEN,	0x00000c80 },
+	{ AR5K_PHY_IQ,		0x05100000 },
+	{ AR5K_PHY_WARM_RESET,	0x00000001 },
+	{ AR5K_PHY_CTL,		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(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(87),		0x004b6a8e },
+	{ AR5K_PHY_NFTHRES,	0x000003ce },
+	{ AR5K_PHY_RESTART,	0x192fb515 },
+	{ AR5K_PHY(94),		0x00000001 },
+	{ AR5K_PHY_RFBUS_REQ,	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 },
-	/* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413/2425 */
-	{ AR5K_PHY(648), 0x01831061 },
-	{ AR5K_PHY(649), 0x00000400 },
+	{ AR5K_PHY(644),	0x00806333 },
+	{ AR5K_PHY(645),	0x00106c10 },
+	{ AR5K_PHY(646),	0x009c4060 },
+	/* { AR5K_PHY(647), 0x1483800a }, */
+	/* { AR5K_PHY(648), 0x01831061 }, */ /* Old value */
+	{ AR5K_PHY(648),	0x018830c6 },
+	{ AR5K_PHY(649),	0x00000400 },
 	/*{ AR5K_PHY(650), 0x000001b5 },*/
-	{ AR5K_PHY(651), 0x00000000 },
+	{ 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 },*/
+	{ AR5K_PHY(656),	0x38490a20 },
+	{ AR5K_PHY(657),	0x00007bb6 },
+	{ AR5K_PHY(658),	0x0fff3ffc },
 };
 
 /* 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 } },
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
-		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
 	{ AR5K_DCU_GBL_IFS_SIFS,
-		{ 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
+	   { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
 	{ AR5K_DCU_GBL_IFS_SLOT,
-		{ 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
+	   { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
 	{ AR5K_DCU_GBL_IFS_EIFS,
-		{ 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
+	   { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
 	{ AR5K_DCU_GBL_IFS_MISC,
-		{ 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
+	   { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
 	{ AR5K_TIME_OUT,
-		{ 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
+	   { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
 	{ AR5K_PHY_TURBO,
-		{ 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
+	   { 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 } },
+	   { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
+	{ AR5K_PHY_RF_CTL2,
+	   { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_SETTLING,
+	   { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
 	{ AR5K_PHY_AGCCTL,
-		{ 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } },
+	   { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } },
 	{ AR5K_PHY_NF,
-		{ 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
-	{ AR5K_PHY(26),
-		{ 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
+	   { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+	{ AR5K_PHY_WEAK_OFDM_HIGH_THR,
+	   { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
 	{ AR5K_PHY(70),
-		{ 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
-	{ AR5K_PHY(73),
-		{ 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
+	   { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
+	{ AR5K_PHY_OFDM_SELFCORR,
+	   { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
 	{ 0xa230,
-		{ 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
+	   { 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 } },
+static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
 	{ AR5K_TXCFG,
-		{ 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 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 } },
+	   { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
 	{ AR5K_PHY_SIG,
-		{ 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
 	{ AR5K_PHY_AGCCOARSE,
-		{ 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
-	{ AR5K_PHY(27),
-		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
 	{ AR5K_PHY_RX_DELAY,
-		{ 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
+	   { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
 	{ AR5K_PHY_FRAME_CTL_5211,
-		{ 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
+	   { 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 } },
-	{ 0xa228,
-		{ 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5 } },
-	{ 0xa23c,
-		{ 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } },
+	   { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf5111_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x00000000 },
+	{ AR5K_PHY_AGC, 	0x00000000 },
+	{ AR5K_PHY_ADC_CTL, 	0x00022ffe },
+	{ 0x983c, 		0x00020100 },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284613c },
+	{ AR5K_PHY_PAPD_PROBE,	0x00004883 },
+	{ 0x9940,		0x00000004 },
+	{ 0x9958,		0x000000ff },
+	{ 0x9974,		0x00000000 },
+	{ AR5K_PHY_SPENDING,	0x00000018 },
+	{ AR5K_PHY_CCKTXCTL,	0x00000000 },
+	{ AR5K_PHY_CCK_CROSSCORR, 0xd03e6788 },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000001b5 },
+	{ 0xa23c,		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[] = {
+static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
 	{ AR5K_TXCFG,
-	/*	  a/XR	      aTurbo	  b	      g (DYN)	  gTurbo */
-		{ 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+	/*	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 } },
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
 	{ AR5K_PHY_SIG,
-		{ 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } },
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } },
 	{ AR5K_PHY_AGCCOARSE,
-		{ 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
-	{ AR5K_PHY(27),
-		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
 	{ AR5K_PHY_RX_DELAY,
-		{ 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
 	{ AR5K_PHY_FRAME_CTL_5211,
-		{ 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
+	   { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
 	{ AR5K_PHY_CCKTXCTL,
-		{ 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
-	{ AR5K_PHY(642),
-		{ 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	   { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 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 } },
+	   { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf5112_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x00000000 },
+	{ AR5K_PHY_AGC,		0x00000000 },
+	{ AR5K_PHY_ADC_CTL,	0x00022ffe },
+	{ 0x983c,		0x00020100 },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284613c },
+	{ AR5K_PHY_PAPD_PROBE,	0x00004882 },
+	{ 0x9940,		0x00000004 },
+	{ 0x9958,		0x000000ff },
+	{ 0x9974,		0x00000000 },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000001b5 },
+	{ 0xa23c,		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 } },
+	/*	a/XR	   aTurbo	  b	   g (DYN)     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 } },
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
 	{ AR5K_PHY_SIG,
-		{ 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+	   { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
 	{ AR5K_PHY_AGCCOARSE,
-		{ 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
-	{ AR5K_PHY(27),
-		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	   { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
 	{ AR5K_PHY_RX_DELAY,
-		{ 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
 	{ AR5K_PHY_FRAME_CTL_5211,
-		{ 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
 	{ AR5K_PHY_CCKTXCTL,
-		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(642),
-		{ 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
 	{ AR5K_PHY_GAIN_2GHZ,
-		{ 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
-	{ 0xa21c,
-		{ 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+	   { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
 	{ 0xa300,
-		{ 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
+	   { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
 	{ 0xa304,
-		{ 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
+	   { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
 	{ 0xa308,
-		{ 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
+	   { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
 	{ 0xa30c,
-		{ 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
+	   { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
 	{ 0xa310,
-		{ 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
+	   { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
 	{ 0xa314,
-		{ 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
+	   { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
 	{ 0xa318,
-		{ 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
+	   { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
 	{ 0xa31c,
-		{ 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
+	   { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
 	{ 0xa320,
-		{ 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
+	   { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
 	{ 0xa324,
-		{ 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
+	   { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
 	{ 0xa328,
-		{ 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
+	   { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
 	{ 0xa32c,
-		{ 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
+	   { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
 	{ 0xa330,
-		{ 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
+	   { 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 } },
+	   { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
+};
+
+static const struct ath5k_ini rf5413_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0 },
+	{ AR5K_5414_CBCFG,	0x00000010 },
+	{ AR5K_SEQ_MASK,	0x0000000f },
+	{ 0x809c,		0x00000000 },
+	{ 0x80a0,		0x00000000 },
+	{ AR5K_MIC_QOS_CTL,	0x00000000 },
+	{ AR5K_MIC_QOS_SEL,	0x00000000 },
+	{ AR5K_MISC_MODE,	0x00000000 },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000 },
+	{ AR5K_CCK_FIL_CNT,	0x00000000 },
+	{ AR5K_PHYERR_CNT1,	0x00000000 },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000 },
+	{ AR5K_PHYERR_CNT2,	0x00000000 },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000 },
+	{ AR5K_TSF_THRES,	0x00000000 },
+	{ 0x8140,		0x800003f9 },
+	{ 0x8144,		0x00000000 },
+	{ AR5K_PHY_AGC,		0x00000000 },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000 },
+	{ 0x983c,		0x00200400 },
+	{ AR5K_PHY_GAIN_OFFSET, 0x1284233c },
+	{ AR5K_PHY_SCR,		0x0000001f },
+	{ AR5K_PHY_SLMT,	0x00000080 },
+	{ AR5K_PHY_SCAL,	0x0000000e },
+	{ 0x9958,		0x00081fff },
+	{ AR5K_PHY_TIMING_7,	0x00000000 },
+	{ AR5K_PHY_TIMING_8,	0x02800000 },
+	{ AR5K_PHY_TIMING_11,	0x00000000 },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 },
+	{ 0x99e4,		0xaaaaaaaa },
+	{ 0x99e8,		0x3c466478 },
+	{ 0x99ec,		0x000000aa },
+	{ AR5K_PHY_SCLOCK,	0x0000000c },
+	{ AR5K_PHY_SDELAY,	0x000000ff },
+	{ AR5K_PHY_SPENDING,	0x00000014 },
+	{ AR5K_PHY_DAG_CCK_CTL, 0x000009b5 },
+	{ 0xa23c,		0x93c889af },
+	{ AR5K_PHY_FAST_ADC,	0x00000001 },
+	{ 0xa250,		0x0000a000 },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000 },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380 },
+	{ 0xa25c,		0x0f0f0f01 },
+	{ 0xa260,		0x5f690f01 },
+	{ 0xa264,		0x00418a11 },
+	{ 0xa268,		0x00000000 },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c16a },
+	{ 0xa270, 0x00820820 },
+	{ 0xa274, 0x081b7caa },
+	{ 0xa278, 0x1ce739ce },
+	{ 0xa27c, 0x051701ce },
+	{ 0xa338, 0x00000000 },
+	{ 0xa33c, 0x00000000 },
+	{ 0xa340, 0x00000000 },
+	{ 0xa344, 0x00000000 },
+	{ 0xa348, 0x3fffffff },
+	{ 0xa34c, 0x3fffffff },
+	{ 0xa350, 0x3fffffff },
+	{ 0xa354, 0x0003ffff },
+	{ 0xa358, 0x79a8aa1f },
+	{ 0xa35c, 0x066c420f },
+	{ 0xa360, 0x0f282207 },
+	{ 0xa364, 0x17601685 },
+	{ 0xa368, 0x1f801104 },
+	{ 0xa36c, 0x37a00c03 },
+	{ 0xa370, 0x3fc40883 },
+	{ 0xa374, 0x57c00803 },
+	{ 0xa378, 0x5fd80682 },
+	{ 0xa37c, 0x7fe00482 },
+	{ 0xa380, 0x7f3c7bba },
+	{ 0xa384, 0xf3307ff0 },
 };
 
 /* Initial mode-specific settings for RF2413/2414 (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 */
+/* XXX: a mode ? */
 static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
 	{ AR5K_TXCFG,
-	/*	      b		g	    gTurbo */
-		{ 0x00000015, 0x00000015, 0x00000015 } },
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
 	{ AR5K_USEC_5211,
-		{ 0x04e01395, 0x12e013ab, 0x098813cf } },
-	{ AR5K_PHY(10),
-		{ 0x05020000, 0x0a020001, 0x0a020001 } },
-	{ AR5K_PHY(13),
-		{ 0x00000e00, 0x00000e00, 0x00000e00 } },
-	{ AR5K_PHY(14),
-		{ 0x0000000a, 0x0000000a, 0x0000000a } },
-	{ AR5K_PHY(18),
-		{ 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
-	{ AR5K_PHY(20),
-		{ 0x0de8b0da, 0x0c98b0da, 0x0c98b0da } },
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da } },
 	{ AR5K_PHY_SIG,
-		{ 0x7ee80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e } },
 	{ AR5K_PHY_AGCCOARSE,
-		{ 0x3137665e, 0x3139605e, 0x3139605e } },
-	{ AR5K_PHY(27),
-		{ 0x050cb081, 0x050cb081, 0x050cb081 } },
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
 	{ AR5K_PHY_RX_DELAY,
-		{ 0x0000044c, 0x00000898, 0x000007d0 } },
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
 	{ AR5K_PHY_FRAME_CTL_5211,
-		{ 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
 	{ AR5K_PHY_CCKTXCTL,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(642),
-		{ 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
 	{ AR5K_PHY_GAIN_2GHZ,
-		{ 0x0042c140, 0x0042c140, 0x0042c140 } },
-	{ 0xa21c,
-		{ 0x1863800a, 0x1883800a, 0x1883800a } },
-	{ AR5K_DCU_FP,
-		{ 0x000003e0, 0x000003e0, 0x000003e0 } },
-	{ 0x8060,
-		{ 0x0000000f, 0x0000000f, 0x0000000f } },
-	{ 0x8118,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x811c,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x8120,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x8124,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x8128,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x812c,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x8130,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x8134,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x8138,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x813c,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0x8140,
-		{ 0x800000a8, 0x800000a8, 0x800000a8 } },
-	{ 0x8144,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY_AGC,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(11),
-		{ 0x0000a000, 0x0000a000, 0x0000a000 } },
-	{ AR5K_PHY(15),
-		{ 0x00200400, 0x00200400, 0x00200400 } },
-	{ AR5K_PHY(19),
-		{ 0x1284233c, 0x1284233c, 0x1284233c } },
-	{ AR5K_PHY_SCR,
-		{ 0x0000001f, 0x0000001f, 0x0000001f } },
-	{ AR5K_PHY_SLMT,
-		{ 0x00000080, 0x00000080, 0x00000080 } },
-	{ AR5K_PHY_SCAL,
-		{ 0x0000000e, 0x0000000e, 0x0000000e } },
-	{ AR5K_PHY(86),
-		{ 0x000000ff, 0x000000ff, 0x000000ff } },
-	{ AR5K_PHY(96),
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(97),
-		{ 0x02800000, 0x02800000, 0x02800000 } },
-	{ AR5K_PHY(104),
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(120),
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(121),
-		{ 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } },
-	{ AR5K_PHY(122),
-		{ 0x3c466478, 0x3c466478, 0x3c466478 } },
-	{ AR5K_PHY(123),
-		{ 0x000000aa, 0x000000aa, 0x000000aa } },
-	{ AR5K_PHY_SCLOCK,
-		{ 0x0000000c, 0x0000000c, 0x0000000c } },
-	{ AR5K_PHY_SDELAY,
-		{ 0x000000ff, 0x000000ff, 0x000000ff } },
-	{ AR5K_PHY_SPENDING,
-		{ 0x00000014, 0x00000014, 0x00000014 } },
-	{ 0xa228,
-		{ 0x000009b5, 0x000009b5, 0x000009b5 } },
-	{ 0xa23c,
-		{ 0x93c889af, 0x93c889af, 0x93c889af } },
-	{ 0xa24c,
-		{ 0x00000001, 0x00000001, 0x00000001 } },
-	{ 0xa250,
-		{ 0x0000a000, 0x0000a000, 0x0000a000 } },
-	{ 0xa254,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0xa258,
-		{ 0x0cc75380, 0x0cc75380, 0x0cc75380 } },
-	{ 0xa25c,
-		{ 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } },
-	{ 0xa260,
-		{ 0x5f690f01, 0x5f690f01, 0x5f690f01 } },
-	{ 0xa264,
-		{ 0x00418a11, 0x00418a11, 0x00418a11 } },
-	{ 0xa268,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0xa26c,
-		{ 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } },
-	{ 0xa270,
-		{ 0x00820820, 0x00820820, 0x00820820 } },
-	{ 0xa274,
-		{ 0x001b7caa, 0x001b7caa, 0x001b7caa } },
-	{ 0xa278,
-		{ 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } },
-	{ 0xa27c,
-		{ 0x051701ce, 0x051701ce, 0x051701ce } },
-	{ 0xa300,
-		{ 0x18010000, 0x18010000, 0x18010000 } },
-	{ 0xa304,
-		{ 0x30032602, 0x30032602, 0x30032602 } },
-	{ 0xa308,
-		{ 0x48073e06, 0x48073e06, 0x48073e06 } },
-	{ 0xa30c,
-		{ 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
-	{ 0xa310,
-		{ 0x641a600f, 0x641a600f, 0x641a600f } },
-	{ 0xa314,
-		{ 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
-	{ 0xa318,
-		{ 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
-	{ 0xa31c,
-		{ 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
-	{ 0xa320,
-		{ 0x9d4f970f, 0x9d4f970f, 0x9d4f970f } },
-	{ 0xa324,
-		{ 0xa5cfa18f, 0xa5cfa18f, 0xa5cfa18f } },
-	{ 0xa328,
-		{ 0xb55faf1f, 0xb55faf1f, 0xb55faf1f } },
-	{ 0xa32c,
-		{ 0xbddfb99f, 0xbddfb99f, 0xbddfb99f } },
-	{ 0xa330,
-		{ 0xcd7fc73f, 0xcd7fc73f, 0xcd7fc73f } },
-	{ 0xa334,
-		{ 0xd5ffd1bf, 0xd5ffd1bf, 0xd5ffd1bf } },
-	{ 0xa338,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0xa33c,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0xa340,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0xa344,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0xa348,
-		{ 0x3fffffff, 0x3fffffff, 0x3fffffff } },
-	{ 0xa34c,
-		{ 0x3fffffff, 0x3fffffff, 0x3fffffff } },
-	{ 0xa350,
-		{ 0x3fffffff, 0x3fffffff, 0x3fffffff } },
-	{ 0xa354,
-		{ 0x0003ffff, 0x0003ffff, 0x0003ffff } },
-	{ 0xa358,
-		{ 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } },
-	{ 0xa35c,
-		{ 0x066c420f, 0x066c420f, 0x066c420f } },
-	{ 0xa360,
-		{ 0x0f282207, 0x0f282207, 0x0f282207 } },
-	{ 0xa364,
-		{ 0x17601685, 0x17601685, 0x17601685 } },
-	{ 0xa368,
-		{ 0x1f801104, 0x1f801104, 0x1f801104 } },
-	{ 0xa36c,
-		{ 0x37a00c03, 0x37a00c03, 0x37a00c03 } },
-	{ 0xa370,
-		{ 0x3fc40883, 0x3fc40883, 0x3fc40883 } },
-	{ 0xa374,
-		{ 0x57c00803, 0x57c00803, 0x57c00803 } },
-	{ 0xa378,
-		{ 0x5fd80682, 0x5fd80682, 0x5fd80682 } },
-	{ 0xa37c,
-		{ 0x7fe00482, 0x7fe00482, 0x7fe00482 } },
-	{ 0xa380,
-		{ 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } },
-	{ 0xa384,
-		{ 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
+	   { 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf2413_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0 },
+	{ AR5K_SEQ_MASK,	0x0000000f },
+	{ AR5K_MIC_QOS_CTL,	0x00000000 },
+	{ AR5K_MIC_QOS_SEL,	0x00000000 },
+	{ AR5K_MISC_MODE,	0x00000000 },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000 },
+	{ AR5K_CCK_FIL_CNT,	0x00000000 },
+	{ AR5K_PHYERR_CNT1,	0x00000000 },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000 },
+	{ AR5K_PHYERR_CNT2,	0x00000000 },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000 },
+	{ AR5K_TSF_THRES,	0x00000000 },
+	{ 0x8140,		0x800000a8 },
+	{ 0x8144,		0x00000000 },
+	{ AR5K_PHY_AGC,		0x00000000 },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000 },
+	{ 0x983c,		0x00200400 },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284233c },
+	{ AR5K_PHY_SCR,		0x0000001f },
+	{ AR5K_PHY_SLMT,	0x00000080 },
+	{ AR5K_PHY_SCAL,	0x0000000e },
+	{ 0x9958,		0x000000ff },
+	{ AR5K_PHY_TIMING_7,	0x00000000 },
+	{ AR5K_PHY_TIMING_8,	0x02800000 },
+	{ AR5K_PHY_TIMING_11,	0x00000000 },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 },
+	{ 0x99e4,		0xaaaaaaaa },
+	{ 0x99e8,		0x3c466478 },
+	{ 0x99ec,		0x000000aa },
+	{ AR5K_PHY_SCLOCK,	0x0000000c },
+	{ AR5K_PHY_SDELAY,	0x000000ff },
+	{ AR5K_PHY_SPENDING,	0x00000014 },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000009b5 },
+	{ 0xa23c,		0x93c889af },
+	{ AR5K_PHY_FAST_ADC,	0x00000001 },
+	{ 0xa250,		0x0000a000 },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000 },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380 },
+	{ 0xa25c,		0x0f0f0f01 },
+	{ 0xa260,		0x5f690f01 },
+	{ 0xa264,		0x00418a11 },
+	{ 0xa268,		0x00000000 },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c16a },
+	{ 0xa270, 0x00820820 },
+	{ 0xa274, 0x001b7caa },
+	{ 0xa278, 0x1ce739ce },
+	{ 0xa27c, 0x051701ce },
+	{ 0xa300, 0x18010000 },
+	{ 0xa304, 0x30032602 },
+	{ 0xa308, 0x48073e06 },
+	{ 0xa30c, 0x560b4c0a },
+	{ 0xa310, 0x641a600f },
+	{ 0xa314, 0x784f6e1b },
+	{ 0xa318, 0x868f7c5a },
+	{ 0xa31c, 0x8ecf865b },
+	{ 0xa320, 0x9d4f970f },
+	{ 0xa324, 0xa5cfa18f },
+	{ 0xa328, 0xb55faf1f },
+	{ 0xa32c, 0xbddfb99f },
+	{ 0xa330, 0xcd7fc73f },
+	{ 0xa334, 0xd5ffd1bf },
+	{ 0xa338, 0x00000000 },
+	{ 0xa33c, 0x00000000 },
+	{ 0xa340, 0x00000000 },
+	{ 0xa344, 0x00000000 },
+	{ 0xa348, 0x3fffffff },
+	{ 0xa34c, 0x3fffffff },
+	{ 0xa350, 0x3fffffff },
+	{ 0xa354, 0x0003ffff },
+	{ 0xa358, 0x79a8aa1f },
+	{ 0xa35c, 0x066c420f },
+	{ 0xa360, 0x0f282207 },
+	{ 0xa364, 0x17601685 },
+	{ 0xa368, 0x1f801104 },
+	{ 0xa36c, 0x37a00c03 },
+	{ 0xa370, 0x3fc40883 },
+	{ 0xa374, 0x57c00803 },
+	{ 0xa378, 0x5fd80682 },
+	{ 0xa37c, 0x7fe00482 },
+	{ 0xa380, 0x7f3c7bba },
+	{ 0xa384, 0xf3307ff0 },
 };
 
 /* Initial mode-specific settings for RF2425 (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 */
+/* XXX: a mode ? */
 static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
 	{ AR5K_TXCFG,
-	/*	       g	gTurbo */
-		{ 0x00000015, 0x00000015 } },
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
 	{ AR5K_USEC_5211,
-		{ 0x12e013ab, 0x098813cf } },
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
 	{ AR5K_PHY_TURBO,
-		{ 0x00000000, 0x00000003 } },
-	{ AR5K_PHY(10),
-		{ 0x0a020001, 0x0a020001 } },
-	{ AR5K_PHY(13),
-		{ 0x00000e0e, 0x00000e0e } },
-	{ AR5K_PHY(14),
-		{ 0x0000000b, 0x0000000b } },
-	{ AR5K_PHY(17),
-		{ 0x13721422, 0x13721422 } },
-	{ AR5K_PHY(18),
-		{ 0x00199a65, 0x00199a65 } },
-	{ AR5K_PHY(20),
-		{ 0x0c98b0da, 0x0c98b0da } },
+	   { 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_SETTLING,
+	   { 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
 	{ AR5K_PHY_SIG,
-		{ 0x7ec80d2e, 0x7ec80d2e } },
+	   { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
 	{ AR5K_PHY_AGCCOARSE,
-		{ 0x3139605e, 0x3139605e } },
-	{ AR5K_PHY(27),
-		{ 0x050cb081, 0x050cb081 } },
+	   { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
 	{ AR5K_PHY_RX_DELAY,
-		{ 0x00000898, 0x000007d0 } },
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
 	{ AR5K_PHY_FRAME_CTL_5211,
-		{ 0xf7b81000, 0xf7b81000 } },
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
 	{ AR5K_PHY_CCKTXCTL,
-		{ 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(642),
-		{ 0xd03e6788, 0xd03e6788 } },
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
 	{ AR5K_PHY_GAIN_2GHZ,
-		{ 0x0052c140, 0x0052c140 } },
-	{ 0xa21c,
-		{ 0x1883800a, 0x1883800a } },
+	   { 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
 	{ 0xa324,
-		{ 0xa7cfa7cf, 0xa7cfa7cf } },
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
 	{ 0xa328,
-		{ 0xa7cfa7cf, 0xa7cfa7cf } },
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
 	{ 0xa32c,
-		{ 0xa7cfa7cf, 0xa7cfa7cf } },
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
 	{ 0xa330,
-		{ 0xa7cfa7cf, 0xa7cfa7cf } },
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
 	{ 0xa334,
-		{ 0xa7cfa7cf, 0xa7cfa7cf } },
-	{ AR5K_DCU_FP,
-		{ 0x000003e0, 0x000003e0 } },
-	{ 0x8060,
-		{ 0x0000000f, 0x0000000f } },
-	{ 0x809c,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x80a0,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x8118,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x811c,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x8120,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x8124,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x8128,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x812c,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x8130,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x8134,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x8138,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x813c,
-		{ 0x00000000, 0x00000000 } },
-	{ 0x8140,
-		{ 0x800003f9, 0x800003f9 } },
-	{ 0x8144,
-		{ 0x00000000, 0x00000000 } },
-	{ AR5K_PHY_AGC,
-		{ 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(11),
-		{ 0x0000a000, 0x0000a000 } },
-	{ AR5K_PHY(15),
-		{ 0x00200400, 0x00200400 } },
-	{ AR5K_PHY(19),
-		{ 0x1284233c, 0x1284233c } },
-	{ AR5K_PHY_SCR,
-		{ 0x0000001f, 0x0000001f } },
-	{ AR5K_PHY_SLMT,
-		{ 0x00000080, 0x00000080 } },
-	{ AR5K_PHY_SCAL,
-		{ 0x0000000e, 0x0000000e } },
-	{ AR5K_PHY(86),
-		{ 0x00081fff, 0x00081fff } },
-	{ AR5K_PHY(96),
-		{ 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(97),
-		{ 0x02800000, 0x02800000 } },
-	{ AR5K_PHY(104),
-		{ 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(119),
-		{ 0xfebadbe8, 0xfebadbe8 } },
-	{ AR5K_PHY(120),
-		{ 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(121),
-		{ 0xaaaaaaaa, 0xaaaaaaaa } },
-	{ AR5K_PHY(122),
-		{ 0x3c466478, 0x3c466478 } },
-	{ AR5K_PHY(123),
-		{ 0x000000aa, 0x000000aa } },
-	{ AR5K_PHY_SCLOCK,
-		{ 0x0000000c, 0x0000000c } },
-	{ AR5K_PHY_SDELAY,
-		{ 0x000000ff, 0x000000ff } },
-	{ AR5K_PHY_SPENDING,
-		{ 0x00000014, 0x00000014 } },
-	{ 0xa228,
-		{ 0x000009b5, 0x000009b5 } },
-	{ AR5K_PHY_TXPOWER_RATE3,
-		{ 0x20202020, 0x20202020 } },
-	{ AR5K_PHY_TXPOWER_RATE4,
-		{ 0x20202020, 0x20202020 } },
-	{ 0xa23c,
-		{ 0x93c889af, 0x93c889af } },
-	{ 0xa24c,
-		{ 0x00000001, 0x00000001 } },
-	{ 0xa250,
-		{ 0x0000a000, 0x0000a000 } },
-	{ 0xa254,
-		{ 0x00000000, 0x00000000 } },
-	{ 0xa258,
-		{ 0x0cc75380, 0x0cc75380 } },
-	{ 0xa25c,
-		{ 0x0f0f0f01, 0x0f0f0f01 } },
-	{ 0xa260,
-		{ 0x5f690f01, 0x5f690f01 } },
-	{ 0xa264,
-		{ 0x00418a11, 0x00418a11 } },
-	{ 0xa268,
-		{ 0x00000000, 0x00000000 } },
-	{ 0xa26c,
-		{ 0x0c30c166, 0x0c30c166 } },
-	{ 0xa270,
-		{ 0x00820820, 0x00820820 } },
-	{ 0xa274,
-		{ 0x081a3caa, 0x081a3caa } },
-	{ 0xa278,
-		{ 0x1ce739ce, 0x1ce739ce } },
-	{ 0xa27c,
-		{ 0x051701ce, 0x051701ce } },
-	{ 0xa300,
-		{ 0x16010000, 0x16010000 } },
-	{ 0xa304,
-		{ 0x2c032402, 0x2c032402 } },
-	{ 0xa308,
-		{ 0x48433e42, 0x48433e42 } },
-	{ 0xa30c,
-		{ 0x5a0f500b, 0x5a0f500b } },
-	{ 0xa310,
-		{ 0x6c4b624a, 0x6c4b624a } },
-	{ 0xa314,
-		{ 0x7e8b748a, 0x7e8b748a } },
-	{ 0xa318,
-		{ 0x96cf8ccb, 0x96cf8ccb } },
-	{ 0xa31c,
-		{ 0xa34f9d0f, 0xa34f9d0f } },
-	{ 0xa320,
-		{ 0xa7cfa58f, 0xa7cfa58f } },
-	{ 0xa348,
-		{ 0x3fffffff, 0x3fffffff } },
-	{ 0xa34c,
-		{ 0x3fffffff, 0x3fffffff } },
-	{ 0xa350,
-		{ 0x3fffffff, 0x3fffffff } },
-	{ 0xa354,
-		{ 0x0003ffff, 0x0003ffff } },
-	{ 0xa358,
-		{ 0x79a8aa1f, 0x79a8aa1f } },
-	{ 0xa35c,
-		{ 0x066c420f, 0x066c420f } },
-	{ 0xa360,
-		{ 0x0f282207, 0x0f282207 } },
-	{ 0xa364,
-		{ 0x17601685, 0x17601685 } },
-	{ 0xa368,
-		{ 0x1f801104, 0x1f801104 } },
-	{ 0xa36c,
-		{ 0x37a00c03, 0x37a00c03 } },
-	{ 0xa370,
-		{ 0x3fc40883, 0x3fc40883 } },
-	{ 0xa374,
-		{ 0x57c00803, 0x57c00803 } },
-	{ 0xa378,
-		{ 0x5fd80682, 0x5fd80682 } },
-	{ 0xa37c,
-		{ 0x7fe00482, 0x7fe00482 } },
-	{ 0xa380,
-		{ 0x7f3c7bba, 0x7f3c7bba } },
-	{ 0xa384,
-		{ 0xf3307ff0, 0xf3307ff0 } },
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+};
+
+static const struct ath5k_ini rf2425_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0 },
+	{ AR5K_SEQ_MASK,	0x0000000f },
+	{ 0x809c,		0x00000000 },
+	{ 0x80a0,		0x00000000 },
+	{ AR5K_MIC_QOS_CTL,	0x00000000 },
+	{ AR5K_MIC_QOS_SEL,	0x00000000 },
+	{ AR5K_MISC_MODE,	0x00000000 },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000 },
+	{ AR5K_CCK_FIL_CNT,	0x00000000 },
+	{ AR5K_PHYERR_CNT1,	0x00000000 },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000 },
+	{ AR5K_PHYERR_CNT2,	0x00000000 },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000 },
+	{ AR5K_TSF_THRES,	0x00000000 },
+	{ 0x8140,		0x800003f9 },
+	{ 0x8144,		0x00000000 },
+	{ AR5K_PHY_AGC,		0x00000000 },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000 },
+	{ 0x983c,		0x00200400 },
+	{ AR5K_PHY_GAIN_OFFSET, 0x1284233c },
+	{ AR5K_PHY_SCR,		0x0000001f },
+	{ AR5K_PHY_SLMT,	0x00000080 },
+	{ AR5K_PHY_SCAL,	0x0000000e },
+	{ 0x9958,		0x00081fff },
+	{ AR5K_PHY_TIMING_7,	0x00000000 },
+	{ AR5K_PHY_TIMING_8,	0x02800000 },
+	{ AR5K_PHY_TIMING_11,	0x00000000 },
+	{ 0x99dc,		0xfebadbe8 },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 },
+	{ 0x99e4,		0xaaaaaaaa },
+	{ 0x99e8,		0x3c466478 },
+	{ 0x99ec,		0x000000aa },
+	{ AR5K_PHY_SCLOCK,	0x0000000c },
+	{ AR5K_PHY_SDELAY,	0x000000ff },
+	{ AR5K_PHY_SPENDING,	0x00000014 },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000009b5 },
+	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020 },
+	{ AR5K_PHY_TXPOWER_RATE4, 0x20202020 },
+	{ 0xa23c,		0x93c889af },
+	{ AR5K_PHY_FAST_ADC,	0x00000001 },
+	{ 0xa250,		0x0000a000 },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000 },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380 },
+	{ 0xa25c,		0x0f0f0f01 },
+	{ 0xa260,		0x5f690f01 },
+	{ 0xa264,		0x00418a11 },
+	{ 0xa268,		0x00000000 },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c166 },
+	{ 0xa270, 0x00820820 },
+	{ 0xa274, 0x081a3caa },
+	{ 0xa278, 0x1ce739ce },
+	{ 0xa27c, 0x051701ce },
+	{ 0xa300, 0x16010000 },
+	{ 0xa304, 0x2c032402 },
+	{ 0xa308, 0x48433e42 },
+	{ 0xa30c, 0x5a0f500b },
+	{ 0xa310, 0x6c4b624a },
+	{ 0xa314, 0x7e8b748a },
+	{ 0xa318, 0x96cf8ccb },
+	{ 0xa31c, 0xa34f9d0f },
+	{ 0xa320, 0xa7cfa58f },
+	{ 0xa348, 0x3fffffff },
+	{ 0xa34c, 0x3fffffff },
+	{ 0xa350, 0x3fffffff },
+	{ 0xa354, 0x0003ffff },
+	{ 0xa358, 0x79a8aa1f },
+	{ 0xa35c, 0x066c420f },
+	{ 0xa360, 0x0f282207 },
+	{ 0xa364, 0x17601685 },
+	{ 0xa368, 0x1f801104 },
+	{ 0xa36c, 0x37a00c03 },
+	{ 0xa370, 0x3fc40883 },
+	{ 0xa374, 0x57c00803 },
+	{ 0xa378, 0x5fd80682 },
+	{ 0xa37c, 0x7fe00482 },
+	{ 0xa380, 0x7f3c7bba },
+	{ 0xa384, 0xf3307ff0 },
 };
 
 /*
@@ -1560,7 +1297,7 @@
 	{ AR5K_BB_GAIN(63), 0x00000016 },
 };
 
-/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414) */
+/* 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 },
@@ -1691,87 +1428,97 @@
 		/*
 		 * Write initial settings common for all modes
 		 */
-		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini),
-					ar5212_ini, change_channel);
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start),
+				ar5212_ini_common_start, change_channel);
 
 		/* Second set of mode-specific settings */
-		if (ah->ah_radio == AR5K_RF5111) {
+		switch (ah->ah_radio) {
+		case AR5K_RF5111:
 
 			ath5k_hw_ini_mode_registers(ah,
-					ARRAY_SIZE(ar5212_rf5111_ini_mode_end),
-					ar5212_rf5111_ini_mode_end, mode);
+					ARRAY_SIZE(rf5111_ini_mode_end),
+					rf5111_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5111_ini_common_end),
+					rf5111_ini_common_end, change_channel);
 
 			/* 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) {
+			break;
+		case AR5K_RF5112:
 
 			ath5k_hw_ini_mode_registers(ah,
-					ARRAY_SIZE(ar5212_rf5112_ini_mode_end),
-					ar5212_rf5112_ini_mode_end, mode);
+					ARRAY_SIZE(rf5112_ini_mode_end),
+					rf5112_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_common_end),
+					rf5112_ini_common_end, change_channel);
 
 			ath5k_hw_ini_registers(ah,
 					ARRAY_SIZE(rf5112_ini_bbgain),
 					rf5112_ini_bbgain, change_channel);
 
-		} else if (ah->ah_radio == AR5K_RF5413) {
+			break;
+		case AR5K_RF5413:
 
 			ath5k_hw_ini_mode_registers(ah,
 					ARRAY_SIZE(rf5413_ini_mode_end),
 					rf5413_ini_mode_end, mode);
 
 			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5413_ini_common_end),
+					rf5413_ini_common_end, change_channel);
+
+			ath5k_hw_ini_registers(ah,
 					ARRAY_SIZE(rf5112_ini_bbgain),
 					rf5112_ini_bbgain, change_channel);
 
-		} else if (ah->ah_radio == AR5K_RF2413) {
-
-			if (mode < 2) {
-				ATH5K_ERR(ah->ah_sc,
-					"unsupported channel mode: %d\n", mode);
-				return -EINVAL;
-			}
-			mode = mode - 2;
-
-			/* Override a setting from ar5212_ini */
-			ath5k_hw_reg_write(ah, 0x018830c6, AR5K_PHY(648));
+			break;
+		case AR5K_RF2316:
+		case AR5K_RF2413:
 
 			ath5k_hw_ini_mode_registers(ah,
 					ARRAY_SIZE(rf2413_ini_mode_end),
 					rf2413_ini_mode_end, mode);
 
-			/* Baseband gain table */
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf2413_ini_common_end),
+					rf2413_ini_common_end, change_channel);
+
+			/* Override settings from rf2413_ini_common_end */
+			if (ah->ah_radio == AR5K_RF2316) {
+				ath5k_hw_reg_write(ah, 0x00004000,
+							AR5K_PHY_AGC);
+				ath5k_hw_reg_write(ah, 0x081b7caa,
+							0xa274);
+			}
+
 			ath5k_hw_ini_registers(ah,
 					ARRAY_SIZE(rf5112_ini_bbgain),
 					rf5112_ini_bbgain, change_channel);
-
-		} else if (ah->ah_radio == AR5K_RF2425) {
-
-			if (mode < 2) {
-				ATH5K_ERR(ah->ah_sc,
-					"unsupported channel mode: %d\n", mode);
-				return -EINVAL;
-			}
-
-			/* Map b to g */
-			if (mode == 2)
-				mode = 0;
-			else
-				mode = mode - 3;
-
-			/* Override a setting from ar5212_ini */
-			ath5k_hw_reg_write(ah, 0x018830c6, AR5K_PHY(648));
+			break;
+		case AR5K_RF2317:
+		case AR5K_RF2425:
 
 			ath5k_hw_ini_mode_registers(ah,
 					ARRAY_SIZE(rf2425_ini_mode_end),
 					rf2425_ini_mode_end, mode);
 
-			/* Baseband gain table */
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf2413_ini_common_end),
+					rf2413_ini_common_end, change_channel);
+
 			ath5k_hw_ini_registers(ah,
 					ARRAY_SIZE(rf5112_ini_bbgain),
 					rf5112_ini_bbgain, change_channel);
+			break;
+		default:
+			return -EINVAL;
 
 		}
 
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
index 7ba18e0..81f5beb 100644
--- a/drivers/net/wireless/ath5k/phy.c
+++ b/drivers/net/wireless/ath5k/phy.c
@@ -2,7 +2,7 @@
  * PHY functions
  *
  * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
  * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -26,1138 +26,191 @@
 #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 } },
-};
-
-/* RF2413/2414 mode-specific init registers */
-static const struct ath5k_ini_rf rfregs_2413[] = {
-	{ 1, AR5K_RF_BUFFER_CONTROL_4,
-	/* 	   mode b      mode g     mode gTurbo */
-		{ 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, AR5K_RF_BUFFER_CONTROL_3,
-		{ 0x02001408, 0x02001408, 0x02001408 } },
-	{ 3, AR5K_RF_BUFFER_CONTROL_6,
-		{ 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0xf0000000, 0xf0000000, 0xf0000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x03000000, 0x03000000, 0x03000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x40400000, 0x40400000, 0x40400000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x65050000, 0x65050000, 0x65050000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00420000, 0x00420000, 0x00420000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00b50000, 0x00b50000, 0x00b50000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00030000, 0x00030000, 0x00030000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00f70000, 0x00f70000, 0x00f70000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x009d0000, 0x009d0000, 0x009d0000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00220000, 0x00220000, 0x00220000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x04220000, 0x04220000, 0x04220000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00230018, 0x00230018, 0x00230018 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00280050, 0x00280050, 0x00280050 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x005000c3, 0x005000c3, 0x005000c3 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x0004007f, 0x0004007f, 0x0004007f } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000458, 0x00000458, 0x00000458 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x0000c000, 0x0000c000, 0x0000c000 } },
-	{ 6, AR5K_RF_BUFFER_CONTROL_5,
-		{ 0x00400230, 0x00400230, 0x00400230 } },
-	{ 7, AR5K_RF_BUFFER,
-		{ 0x00006400, 0x00006400, 0x00006400 } },
-	{ 7, AR5K_RF_BUFFER,
-		{ 0x00000800, 0x00000800, 0x00000800 } },
-	{ 7, AR5K_RF_BUFFER_CONTROL_2,
-		{ 0x0000000e, 0x0000000e, 0x0000000e } },
-};
-
-/* RF2425 mode-specific init registers */
-static const struct ath5k_ini_rf rfregs_2425[] = {
-	{ 1, AR5K_RF_BUFFER_CONTROL_4,
-	/* 	   mode g     mode gTurbo */
-		{ 0x00000020, 0x00000020 } },
-	{ 2, AR5K_RF_BUFFER_CONTROL_3,
-		{ 0x02001408, 0x02001408 } },
-	{ 3, AR5K_RF_BUFFER_CONTROL_6,
-		{ 0x00e020c0, 0x00e020c0 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x10000000, 0x10000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x002a0000, 0x002a0000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00100000, 0x00100000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00020000, 0x00020000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00730000, 0x00730000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00f80000, 0x00f80000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00e70000, 0x00e70000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00140000, 0x00140000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00910040, 0x00910040 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x0007001a, 0x0007001a } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00410000, 0x00410000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00810060, 0x00810060 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00020803, 0x00020803 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00000000, 0x00000000 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00001660, 0x00001660 } },
-	{ 6, AR5K_RF_BUFFER,
-		{ 0x00001688, 0x00001688 } },
-	{ 6, AR5K_RF_BUFFER_CONTROL_1,
-		{ 0x00000001, 0x00000001 } },
-	{ 7, AR5K_RF_BUFFER,
-		{ 0x00006400, 0x00006400 } },
-	{ 7, AR5K_RF_BUFFER,
-		{ 0x00000800, 0x00000800 } },
-	{ 7, AR5K_RF_BUFFER_CONTROL_2,
-		{ 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 } },
-};
-
-/* Initial RF Gain settings for RF2413 */
-static const struct ath5k_ini_rfgain rfgain_2413[] = {
-	{ AR5K_RF_GAIN(0), { 0x00000000 } },
-	{ AR5K_RF_GAIN(1), { 0x00000040 } },
-	{ AR5K_RF_GAIN(2), { 0x00000080 } },
-	{ AR5K_RF_GAIN(3), { 0x00000181 } },
-	{ AR5K_RF_GAIN(4), { 0x000001c1 } },
-	{ AR5K_RF_GAIN(5), { 0x00000001 } },
-	{ AR5K_RF_GAIN(6), { 0x00000041 } },
-	{ AR5K_RF_GAIN(7), { 0x00000081 } },
-	{ AR5K_RF_GAIN(8), { 0x00000168 } },
-	{ AR5K_RF_GAIN(9), { 0x000001a8 } },
-	{ AR5K_RF_GAIN(10), { 0x000001e8 } },
-	{ AR5K_RF_GAIN(11), { 0x00000028 } },
-	{ AR5K_RF_GAIN(12), { 0x00000068 } },
-	{ AR5K_RF_GAIN(13), { 0x00000189 } },
-	{ AR5K_RF_GAIN(14), { 0x000001c9 } },
-	{ AR5K_RF_GAIN(15), { 0x00000009 } },
-	{ AR5K_RF_GAIN(16), { 0x00000049 } },
-	{ AR5K_RF_GAIN(17), { 0x00000089 } },
-	{ AR5K_RF_GAIN(18), { 0x00000190 } },
-	{ AR5K_RF_GAIN(19), { 0x000001d0 } },
-	{ AR5K_RF_GAIN(20), { 0x00000010 } },
-	{ AR5K_RF_GAIN(21), { 0x00000050 } },
-	{ AR5K_RF_GAIN(22), { 0x00000090 } },
-	{ AR5K_RF_GAIN(23), { 0x00000191 } },
-	{ AR5K_RF_GAIN(24), { 0x000001d1 } },
-	{ AR5K_RF_GAIN(25), { 0x00000011 } },
-	{ AR5K_RF_GAIN(26), { 0x00000051 } },
-	{ AR5K_RF_GAIN(27), { 0x00000091 } },
-	{ AR5K_RF_GAIN(28), { 0x00000178 } },
-	{ AR5K_RF_GAIN(29), { 0x000001b8 } },
-	{ AR5K_RF_GAIN(30), { 0x000001f8 } },
-	{ AR5K_RF_GAIN(31), { 0x00000038 } },
-	{ AR5K_RF_GAIN(32), { 0x00000078 } },
-	{ AR5K_RF_GAIN(33), { 0x00000199 } },
-	{ AR5K_RF_GAIN(34), { 0x000001d9 } },
-	{ AR5K_RF_GAIN(35), { 0x00000019 } },
-	{ AR5K_RF_GAIN(36), { 0x00000059 } },
-	{ AR5K_RF_GAIN(37), { 0x00000099 } },
-	{ AR5K_RF_GAIN(38), { 0x000000d9 } },
-	{ AR5K_RF_GAIN(39), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(40), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(41), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(42), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(43), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(44), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(45), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(46), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(47), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(48), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(49), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(50), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(51), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(52), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(53), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(54), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(55), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(56), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(57), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(58), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(59), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(60), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(61), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(62), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(63), { 0x000000f9 } },
-};
-
-/* Initial RF Gain settings for RF2425 */
-static const struct ath5k_ini_rfgain rfgain_2425[] = {
-	{ AR5K_RF_GAIN(0), { 0x00000000 } },
-	{ AR5K_RF_GAIN(1), { 0x00000040 } },
-	{ AR5K_RF_GAIN(2), { 0x00000080 } },
-	{ AR5K_RF_GAIN(3), { 0x00000181 } },
-	{ AR5K_RF_GAIN(4), { 0x000001c1 } },
-	{ AR5K_RF_GAIN(5), { 0x00000001 } },
-	{ AR5K_RF_GAIN(6), { 0x00000041 } },
-	{ AR5K_RF_GAIN(7), { 0x00000081 } },
-	{ AR5K_RF_GAIN(8), { 0x00000188 } },
-	{ AR5K_RF_GAIN(9), { 0x000001c8 } },
-	{ AR5K_RF_GAIN(10), { 0x00000008 } },
-	{ AR5K_RF_GAIN(11), { 0x00000048 } },
-	{ AR5K_RF_GAIN(12), { 0x00000088 } },
-	{ AR5K_RF_GAIN(13), { 0x00000189 } },
-	{ AR5K_RF_GAIN(14), { 0x000001c9 } },
-	{ AR5K_RF_GAIN(15), { 0x00000009 } },
-	{ AR5K_RF_GAIN(16), { 0x00000049 } },
-	{ AR5K_RF_GAIN(17), { 0x00000089 } },
-	{ AR5K_RF_GAIN(18), { 0x000001b0 } },
-	{ AR5K_RF_GAIN(19), { 0x000001f0 } },
-	{ AR5K_RF_GAIN(20), { 0x00000030 } },
-	{ AR5K_RF_GAIN(21), { 0x00000070 } },
-	{ AR5K_RF_GAIN(22), { 0x00000171 } },
-	{ AR5K_RF_GAIN(23), { 0x000001b1 } },
-	{ AR5K_RF_GAIN(24), { 0x000001f1 } },
-	{ AR5K_RF_GAIN(25), { 0x00000031 } },
-	{ AR5K_RF_GAIN(26), { 0x00000071 } },
-	{ AR5K_RF_GAIN(27), { 0x000001b8 } },
-	{ AR5K_RF_GAIN(28), { 0x000001f8 } },
-	{ AR5K_RF_GAIN(29), { 0x00000038 } },
-	{ AR5K_RF_GAIN(30), { 0x00000078 } },
-	{ AR5K_RF_GAIN(31), { 0x000000b8 } },
-	{ AR5K_RF_GAIN(32), { 0x000001b9 } },
-	{ AR5K_RF_GAIN(33), { 0x000001f9 } },
-	{ AR5K_RF_GAIN(34), { 0x00000039 } },
-	{ AR5K_RF_GAIN(35), { 0x00000079 } },
-	{ AR5K_RF_GAIN(36), { 0x000000b9 } },
-	{ AR5K_RF_GAIN(37), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(38), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(39), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(40), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(41), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(42), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(43), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(44), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(45), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(46), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(47), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(48), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(49), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(50), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(51), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(52), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(53), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(54), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(55), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(56), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(57), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(58), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(59), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(60), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(61), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(62), { 0x000000f9 } },
-	{ AR5K_RF_GAIN(63), { 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 },
-	}
-};
+#include "rfbuffer.h"
+#include "rfgain.h"
 
 /*
  * 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)
+static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
+					const struct ath5k_rf_reg *rf_regs,
+					u32 val, u8 reg_id, bool set)
 {
-	u32 mask, entry, last, data, shift, position;
-	s32 left;
+	const struct ath5k_rf_reg *rfreg = NULL;
+	u8 offset, bank, num_bits, col, position;
+	u16 entry;
+	u32 mask, data, last_bit, bits_shifted, first_bit;
+	u32 *rfb;
+	s32 bits_left;
 	int i;
 
 	data = 0;
+	rfb = ah->ah_rf_banks;
 
-	if (rf == NULL)
+	for (i = 0; i < ah->ah_rf_regs_count; i++) {
+		if (rf_regs[i].index == reg_id) {
+			rfreg = &rf_regs[i];
+			break;
+		}
+	}
+
+	if (rfb == NULL || rfreg == NULL) {
+		ATH5K_PRINTF("Rf register not found!\n");
 		/* should not happen */
 		return 0;
+	}
 
-	if (!(col <= 3 && bits <= 32 && first + bits <= 319)) {
+	bank = rfreg->bank;
+	num_bits = rfreg->field.len;
+	first_bit = rfreg->field.pos;
+	col = rfreg->field.col;
+
+	/* first_bit is an offset from bank's
+	 * start. Since we have all banks on
+	 * the same array, we use this offset
+	 * to mark each bank's start */
+	offset = ah->ah_offset[bank];
+
+	/* Boundary check */
+	if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) {
 		ATH5K_PRINTF("invalid values at offset %u\n", offset);
 		return 0;
 	}
 
-	entry = ((first - 1) / 8) + offset;
-	position = (first - 1) % 8;
+	entry = ((first_bit - 1) / 8) + offset;
+	position = (first_bit - 1) % 8;
 
 	if (set)
-		data = ath5k_hw_bitswap(reg, bits);
+		data = ath5k_hw_bitswap(val, num_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);
+	for (bits_shifted = 0, bits_left = num_bits; bits_left > 0;
+	position = 0, entry++) {
+
+		last_bit = (position + bits_left > 8) ? 8 :
+					position + bits_left;
+
+		mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) <<
+								(col * 8);
 
 		if (set) {
-			rf[entry] &= ~mask;
-			rf[entry] |= ((data << position) << (col * 8)) & mask;
+			rfb[entry] &= ~mask;
+			rfb[entry] |= ((data << position) << (col * 8)) & mask;
 			data >>= (8 - position);
 		} else {
-			data = (((rf[entry] & mask) >> (col * 8)) >> position)
-				<< shift;
-			shift += last - position;
+			data |= (((rfb[entry] & mask) >> (col * 8)) >> position)
+				<< bits_shifted;
+			bits_shifted += last_bit - position;
 		}
 
-		left -= 8 - position;
+		bits_left -= 8 - position;
 	}
 
-	data = set ? 1 : ath5k_hw_bitswap(data, bits);
+	data = set ? 1 : ath5k_hw_bitswap(data, num_bits);
 
 	return data;
 }
 
-static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
+/**********************\
+* RF Gain optimization *
+\**********************/
+
+/*
+ * This code is used to optimize rf gain on different environments
+ * (temprature mostly) based on feedback from a power detector.
+ *
+ * It's only used on RF5111 and RF5112, later RF chips seem to have
+ * auto adjustment on hw -notice they have a much smaller BANK 7 and
+ * no gain optimization ladder-.
+ *
+ * For more infos check out this patent doc
+ * http://www.freepatentsonline.com/7400691.html
+ *
+ * This paper describes power drops as seen on the receiver due to
+ * probe packets
+ * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
+ * %20of%20Power%20Control.pdf
+ *
+ * And this is the MadWiFi bug entry related to the above
+ * http://madwifi-project.org/ticket/1659
+ * with various measurements and diagrams
+ *
+ * TODO: Deal with power drops due to probes by setting an apropriate
+ * tx power on the probe packets ! Make this part of the calibration process.
+ */
+
+/* Initialize ah_gain durring attach */
+int ath5k_hw_rfgain_opt_init(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_low = 20;
+		ah->ah_gain.g_high = 35;
+		ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		break;
+	case AR5K_RF5112:
+		ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
+		ah->ah_gain.g_low = 20;
+		ah->ah_gain.g_high = 85;
+		ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Schedule a gain probe check on the next transmited packet.
+ * That means our next packet is going to be sent with lower
+ * tx power and a Peak to Average Power Detector (PAPD) will try
+ * to measure the gain.
+ *
+ * TODO: Use propper tx power setting for the probe packet so
+ * that we don't observe a serious power drop on the receiver
+ *
+ * XXX:  How about forcing a tx packet (bypassing PCU arbitrator etc)
+ * just after we enable the probe so that we don't mess with
+ * standard traffic ? Maybe it's time to use sw interrupts and
+ * a probe tasklet !!!
+ */
+static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
+{
+
+	/* Skip if gain calibration is inactive or
+	 * we already handle a probe request */
+	if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
+		return;
+
+	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_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
+
+}
+
+/* Calculate gain_F measurement correction
+ * based on the current step for RF5112 rev. 2 */
+static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
 {
 	u32 mix, step;
 	u32 *rf;
+	const struct ath5k_gain_opt *go;
+	const struct ath5k_gain_opt_step *g_step;
+	const struct ath5k_rf_reg *rf_regs;
+
+	/* Only RF5112 Rev. 2 supports it */
+	if ((ah->ah_radio != AR5K_RF5112) ||
+	(ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
+		return 0;
+
+	go = &rfgain_opt_5112;
+	rf_regs = rf_regs_5112a;
+	ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
+
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
 
 	if (ah->ah_rf_banks == NULL)
 		return 0;
@@ -1165,11 +218,15 @@
 	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)
+	/* No VGA (Variable Gain Amplifier) override, skip */
+	if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, 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];
+	/* Mix gain stepping */
+	step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, false);
+
+	/* Mix gain override */
+	mix = g_step->gos_param[0];
 
 	switch (mix) {
 	case 3:
@@ -1189,9 +246,14 @@
 	return ah->ah_gain.g_f_corr;
 }
 
-static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
+/* Check if current gain_F measurement is in the range of our
+ * power detector windows. If we get a measurement outside range
+ * we know it's not accurate (detectors can't measure anything outside
+ * their detection window) so we must ignore it */
+static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
 {
-	u32 step, mix, level[4];
+	const struct ath5k_rf_reg *rf_regs;
+	u32 step, mix_ovr, level[4];
 	u32 *rf;
 
 	if (ah->ah_rf_banks == NULL)
@@ -1200,23 +262,33 @@
 	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);
+
+		rf_regs = rf_regs_5111;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
+
+		step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP,
+			false);
+
 		level[0] = 0;
-		level[1] = (step == 0x3f) ? 0x32 : step + 4;
-		level[2] = (step != 0x3f) ? 0x40 : level[0];
-		level[3] = level[2] + 0x32;
+		level[1] = (step == 63) ? 50 : step + 4;
+		level[2] = (step != 63) ? 64 : level[0];
+		level[3] = level[2] + 50 ;
 
 		ah->ah_gain.g_high = level[3] -
-			(step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
+			(step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
 		ah->ah_gain.g_low = level[0] +
-			(step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
+			(step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
 	} else {
-		mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0,
-				false);
+
+		rf_regs = rf_regs_5112;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
+
+		mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR,
+			false);
+
 		level[0] = level[2] = 0;
 
-		if (mix == 1) {
+		if (mix_ovr == 1) {
 			level[1] = level[3] = 83;
 		} else {
 			level[1] = level[3] = 107;
@@ -1230,9 +302,12 @@
 			ah->ah_gain.g_current <= level[3]);
 }
 
-static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah)
+/* Perform gain_F adjustment by choosing the right set
+ * of parameters from rf gain optimization ladder */
+static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
 {
 	const struct ath5k_gain_opt *go;
+	const struct ath5k_gain_opt_step *g_step;
 	int ret = 0;
 
 	switch (ah->ah_radio) {
@@ -1246,35 +321,39 @@
 		return 0;
 	}
 
-	ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx];
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
 
 	if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
+
+		/* Reached maximum */
 		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])
+				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);
+			    g_step->gos_gain);
 
 		ret = 1;
 		goto done;
 	}
 
 	if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
+
+		/* Reached minimum */
 		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])
+				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);
+			    g_step->gos_gain);
 
 		ret = 2;
 		goto done;
@@ -1289,353 +368,78 @@
 	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)
+/* Main callback for thermal rf gain calibration engine
+ * Check for a new gain reading and schedule an adjustment
+ * if needed.
+ *
+ * TODO: Use sw interrupt to schedule reset if gain_F needs
+ * adjustment */
+enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
 {
+	u32 data, type;
 	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_MODE_MAX);
+	ATH5K_TRACE(ah->ah_sc);
 
-	rf = ah->ah_rf_banks;
+	if (ah->ah_rf_banks == NULL ||
+	ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
+		return AR5K_RFGAIN_INACTIVE;
 
-	/* 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;
+	/* No check requested, either engine is inactive
+	 * or an adjustment is already requested */
+	if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
+		goto done;
+
+	/* Read the PAPD (Peak to Average Power Detector)
+	 * register */
+	data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
+
+	/* No probe is scheduled, read gain_F measurement */
+	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 tx packet is CCK correct the gain_F measurement
+		 * by cck ofdm gain delta */
+		if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
+			if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
+				ah->ah_gain.g_current +=
+					ee->ee_cck_ofdm_gain_delta;
+			else
+				ah->ah_gain.g_current +=
+					AR5K_GAIN_CCK_PROBE_CORR;
 		}
 
-		if (bank != rfregs_5111[i].rf_bank) {
-			bank = rfregs_5111[i].rf_bank;
-			ah->ah_offset[bank] = i;
+		/* Further correct gain_F measurement for
+		 * RF5112A radios */
+		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+			ath5k_hw_rf_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;
 		}
 
-		rf[i] = rfregs_5111[i].rf_value[mode];
+		/* Check if measurement is ok and if we need
+		 * to adjust gain, schedule a gain adjustment,
+		 * else switch back to the acive state */
+		if (ath5k_hw_rf_check_gainf_readback(ah) &&
+		AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
+		ath5k_hw_rf_gainf_adjust(ah)) {
+			ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
+		} else {
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		}
 	}
 
-	/* Modify bank 0 */
-	if (channel->hw_value & CHANNEL_2GHZ) {
-		if (channel->hw_value & 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->center_freq >= 5725 ? 3 :
-			(channel->center_freq >= 5500 ? 2 :
-			(channel->center_freq >= 5260 ? 1 :
-			 (channel->center_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;
+done:
+	return ah->ah_gain.g_state;
 }
 
-/*
- * 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_MODE_MAX);
-
-	rf = ah->ah_rf_banks;
-
-	if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_2112A
-		&& !test_bit(AR5K_MODE_11A, 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->hw_value & CHANNEL_2GHZ) {
-		if (channel->hw_value & 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->center_freq >= 5725 ? 3 :
-		    (channel->center_freq >= 5500 ? 2 :
-			(channel->center_freq >= 5260 ? 1 :
-			    (channel->center_freq > 4000 ? 0 : -1)));
-
-		if (obdb == -1)
-			return -EINVAL;
-
-		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 and future chips
- * (until we come up with a better solution)
- */
-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_MODE_MAX);
-
-	rf = ah->ah_rf_banks;
-
-	switch (ah->ah_radio) {
-	case AR5K_RF5413:
-		rf_ini = rfregs_5413;
-		rf_size = ARRAY_SIZE(rfregs_5413);
-		break;
-	case AR5K_RF2413:
-		rf_ini = rfregs_2413;
-		rf_size = ARRAY_SIZE(rfregs_2413);
-
-		if (mode < 2) {
-			ATH5K_ERR(ah->ah_sc,
-				"invalid channel mode: %i\n", mode);
-			return -EINVAL;
-		}
-
-		mode = mode - 2;
-		break;
-	case AR5K_RF2425:
-		rf_ini = rfregs_2425;
-		rf_size = ARRAY_SIZE(rfregs_2425);
-
-		if (mode < 2) {
-			ATH5K_ERR(ah->ah_sc,
-				"invalid channel mode: %i\n", mode);
-			return -EINVAL;
-		}
-
-		/* Map b to g */
-		if (mode == 2)
-			mode = 0;
-		else
-			mode = mode - 3;
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* 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;
-	case AR5K_RF2413:
-		ah->ah_rf_banks_size = sizeof(rfregs_2413);
-		func = ath5k_hw_rf5413_rfregs;
-		break;
-	case AR5K_RF2425:
-		ah->ah_rf_banks_size = sizeof(rfregs_2425);
-		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)
+/* Write initial rf gain table to set the RF sensitivity
+ * this one works on all RF chips and has nothing to do
+ * with gain_F calibration */
+int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
 {
 	const struct ath5k_ini_rfgain *ath5k_rfg;
 	unsigned int i, size;
@@ -1649,19 +453,22 @@
 		ath5k_rfg = rfgain_5112;
 		size = ARRAY_SIZE(rfgain_5112);
 		break;
+	case AR5K_RF2413:
+		ath5k_rfg = rfgain_2413;
+		size = ARRAY_SIZE(rfgain_2413);
+		break;
+	case AR5K_RF2316:
+		ath5k_rfg = rfgain_2316;
+		size = ARRAY_SIZE(rfgain_2316);
+		break;
 	case AR5K_RF5413:
 		ath5k_rfg = rfgain_5413;
 		size = ARRAY_SIZE(rfgain_5413);
 		break;
-	case AR5K_RF2413:
-		ath5k_rfg = rfgain_2413;
-		size = ARRAY_SIZE(rfgain_2413);
-		freq = 0; /* only 2Ghz */
-		break;
+	case AR5K_RF2317:
 	case AR5K_RF2425:
 		ath5k_rfg = rfgain_2425;
 		size = ARRAY_SIZE(rfgain_2425);
-		freq = 0; /* only 2Ghz */
 		break;
 	default:
 		return -EINVAL;
@@ -1684,73 +491,326 @@
 	return 0;
 }
 
-enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah)
+
+
+/********************\
+* RF Registers setup *
+\********************/
+
+
+/*
+ * Setup RF registers by writing rf buffer on hw
+ */
+int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+		unsigned int mode)
 {
-	u32 data, type;
+	const struct ath5k_rf_reg *rf_regs;
+	const struct ath5k_ini_rfbuffer *ini_rfb;
+	const struct ath5k_gain_opt *go = NULL;
+	const struct ath5k_gain_opt_step *g_step;
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u8 ee_mode = 0;
+	u32 *rfb;
+	int i, obdb = -1, bank = -1;
 
-	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;
+		rf_regs = rf_regs_5111;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
+		ini_rfb = rfb_5111;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111);
+		go = &rfgain_opt_5111;
 		break;
 	case AR5K_RF5112:
-		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;
+		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+			rf_regs = rf_regs_5112a;
+			ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
+			ini_rfb = rfb_5112a;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a);
+		} else {
+			rf_regs = rf_regs_5112;
+			ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
+			ini_rfb = rfb_5112;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112);
+		}
+		go = &rfgain_opt_5112;
+		break;
+	case AR5K_RF2413:
+		rf_regs = rf_regs_2413;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413);
+		ini_rfb = rfb_2413;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413);
+		break;
+	case AR5K_RF2316:
+		rf_regs = rf_regs_2316;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316);
+		ini_rfb = rfb_2316;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316);
+		break;
+	case AR5K_RF5413:
+		rf_regs = rf_regs_5413;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413);
+		ini_rfb = rfb_5413;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413);
+		break;
+	case AR5K_RF2317:
+		rf_regs = rf_regs_2425;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
+		ini_rfb = rfb_2317;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317);
+		break;
+	case AR5K_RF2425:
+		rf_regs = rf_regs_2425;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
+		if (ah->ah_mac_srev < AR5K_SREV_AR2417) {
+			ini_rfb = rfb_2425;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425);
+		} else {
+			ini_rfb = rfb_2417;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417);
+		}
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	/* If it's the first time we set rf buffer, allocate
+	 * ah->ah_rf_banks based on ah->ah_rf_banks_size
+	 * we set above */
+	if (ah->ah_rf_banks == NULL) {
+		ah->ah_rf_banks = kmalloc(sizeof(u32) * ah->ah_rf_banks_size,
+								GFP_KERNEL);
+		if (ah->ah_rf_banks == NULL) {
+			ATH5K_ERR(ah->ah_sc, "out of memory\n");
+			return -ENOMEM;
+		}
+	}
+
+	/* Copy values to modify them */
+	rfb = ah->ah_rf_banks;
+
+	for (i = 0; i < ah->ah_rf_banks_size; i++) {
+		if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) {
+			ATH5K_ERR(ah->ah_sc, "invalid bank\n");
+			return -EINVAL;
+		}
+
+		/* Bank changed, write down the offset */
+		if (bank != ini_rfb[i].rfb_bank) {
+			bank = ini_rfb[i].rfb_bank;
+			ah->ah_offset[bank] = i;
+		}
+
+		rfb[i] = ini_rfb[i].rfb_mode_data[mode];
+	}
+
+	/* Set Output and Driver bias current (OB/DB) */
+	if (channel->hw_value & CHANNEL_2GHZ) {
+
+		if (channel->hw_value & CHANNEL_CCK)
+			ee_mode = AR5K_EEPROM_MODE_11B;
+		else
+			ee_mode = AR5K_EEPROM_MODE_11G;
+
+		/* For RF511X/RF211X combination we
+		 * use b_OB and b_DB parameters stored
+		 * in eeprom on ee->ee_ob[ee_mode][0]
+		 *
+		 * For all other chips we use OB/DB for 2Ghz
+		 * stored in the b/g modal section just like
+		 * 802.11a on ee->ee_ob[ee_mode][1] */
+		if ((ah->ah_radio == AR5K_RF5111) ||
+		(ah->ah_radio == AR5K_RF5112))
+			obdb = 0;
+		else
+			obdb = 1;
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
+						AR5K_RF_OB_2GHZ, true);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
+						AR5K_RF_DB_2GHZ, true);
+
+	/* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
+	} else if ((channel->hw_value & CHANNEL_5GHZ) ||
+			(ah->ah_radio == AR5K_RF5111)) {
+
+		/* For 11a, Turbo and XR we need to choose
+		 * OB/DB based on frequency range */
+		ee_mode = AR5K_EEPROM_MODE_11A;
+		obdb =	 channel->center_freq >= 5725 ? 3 :
+			(channel->center_freq >= 5500 ? 2 :
+			(channel->center_freq >= 5260 ? 1 :
+			 (channel->center_freq > 4000 ? 0 : -1)));
+
+		if (obdb < 0)
+			return -EINVAL;
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
+						AR5K_RF_OB_5GHZ, true);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
+						AR5K_RF_DB_5GHZ, true);
+	}
+
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+	/* Bank Modifications (chip-specific) */
+	if (ah->ah_radio == AR5K_RF5111) {
+
+		/* Set gain_F settings according to current step */
+		if (channel->hw_value & CHANNEL_OFDM) {
+
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
+					AR5K_PHY_FRAME_CTL_TX_CLIP,
+					g_step->gos_param[0]);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
+							AR5K_RF_PWD_90, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
+							AR5K_RF_PWD_84, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
+						AR5K_RF_RFGAIN_SEL, true);
+
+			/* We programmed gain_F parameters, switch back
+			 * to active state */
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+
+		}
+
+		/* Bank 6/7 setup */
+
+		ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode],
+						AR5K_RF_PWD_XPD, true);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode],
+						AR5K_RF_XPD_GAIN, true);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
+						AR5K_RF_GAIN_I, true);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
+						AR5K_RF_PLO_SEL, true);
+
+		/* TODO: Half/quarter channel support */
+	}
+
+	if (ah->ah_radio == AR5K_RF5112) {
+
+		/* Set gain_F settings according to current step */
+		if (channel->hw_value & CHANNEL_OFDM) {
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
+						AR5K_RF_MIXGAIN_OVR, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
+						AR5K_RF_PWD_138, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
+						AR5K_RF_PWD_137, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
+						AR5K_RF_PWD_136, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4],
+						AR5K_RF_PWD_132, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5],
+						AR5K_RF_PWD_131, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6],
+						AR5K_RF_PWD_130, true);
+
+			/* We programmed gain_F parameters, switch back
+			 * to active state */
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		}
+
+		/* Bank 6/7 setup */
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
+						AR5K_RF_XPD_SEL, true);
+
+		if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
+			/* Rev. 1 supports only one xpd */
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_XPD_GAIN, true);
+
+		} else {
+			/* TODO: Set high and low gain bits */
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_PD_GAIN_LO, true);
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_PD_GAIN_HI, true);
+
+			/* Lower synth voltage on Rev 2 */
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_HIGH_VC_CP, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_MID_VC_CP, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_LOW_VC_CP, true);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_PUSH_UP, true);
+
+			/* Decrease power consumption on 5213+ BaseBand */
+			if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PAD2GND, true);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_XB2_LVL, true);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_XB5_LVL, true);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PWD_167, true);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PWD_166, true);
+			}
+		}
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
+						AR5K_RF_GAIN_I, true);
+
+		/* TODO: Half/quarter channel support */
+
+	}
+
+	if (ah->ah_radio == AR5K_RF5413 &&
+	channel->hw_value & CHANNEL_2GHZ) {
+
+		ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
+									true);
+
+		/* Set optimum value for early revisions (on pci-e chips) */
+		if (ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
+		ah->ah_mac_srev < AR5K_SREV_AR5413)
+			ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3),
+						AR5K_RF_PWD_ICLOBUF_2G, true);
+
+	}
+
+	/* Write RF banks on hw */
+	for (i = 0; i < ah->ah_rf_banks_size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register);
+	}
+
 	return 0;
 }
 
+
 /**************************\
   PHY/RF channel functions
 \**************************/
@@ -2271,13 +1331,8 @@
 	 * as often as I/Q calibration.*/
 	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 
-	/* Request RF gain */
-	if (channel->hw_value & 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;
-	}
+	/* Initiate a gain_F calibration */
+	ath5k_hw_request_rfgain_probe(ah);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
index 9189ab1..2dc008e 100644
--- a/drivers/net/wireless/ath5k/reg.h
+++ b/drivers/net/wireless/ath5k/reg.h
@@ -187,6 +187,7 @@
 #define AR5K_TXCFG_FRMPAD_DIS		0x00002000	/* [5211+] */
 #define AR5K_TXCFG_RDY_CBR_DIS		0x00004000	/* Ready time CBR disable [5211+] */
 #define AR5K_TXCFG_JUMBO_FRM_MODE	0x00008000	/* Jumbo frame mode [5211+] */
+#define	AR5K_TXCFG_DCU_DBL_BUF_DIS	0x00008000	/* Disable double buffering on DCU */
 #define AR5K_TXCFG_DCU_CACHING_DIS	0x00010000	/* Disable DCU caching */
 
 /*
@@ -753,7 +754,7 @@
  */
 #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)
+#define	AR5K_QUEUE_DCU_SEQNUM(_q)	AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
 
 /*
  * DCU global IFS SIFS register
@@ -811,6 +812,8 @@
 
 /*
  * DCU transmit filter table 0 (32 entries)
+ * each entry contains a 32bit slice of the
+ * 128bit tx filter for each DCU (4 slices per DCU)
  */
 #define AR5K_DCU_TX_FILTER_0_BASE	0x1038
 #define	AR5K_DCU_TX_FILTER_0(_n)	(AR5K_DCU_TX_FILTER_0_BASE + (_n * 64))
@@ -819,7 +822,7 @@
  * DCU transmit filter table 1 (16 entries)
  */
 #define AR5K_DCU_TX_FILTER_1_BASE	0x103c
-#define	AR5K_DCU_TX_FILTER_1(_n)	(AR5K_DCU_TX_FILTER_1_BASE + ((_n - 32) * 64))
+#define	AR5K_DCU_TX_FILTER_1(_n)	(AR5K_DCU_TX_FILTER_1_BASE + (_n * 64))
 
 /*
  * DCU clear transmit filter register
@@ -1447,7 +1450,7 @@
 				AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
 
 /*
- * Last beacon timestamp register
+ * Last beacon timestamp register (Read Only)
  */
 #define AR5K_LAST_TSTP	0x8080
 
@@ -1465,7 +1468,7 @@
 #define AR5K_ADDAC_TEST_TRIG_PTY	0x00020000	/* Trigger polarity */
 #define AR5K_ADDAC_TEST_RXCONT		0x00040000	/* Continuous capture */
 #define AR5K_ADDAC_TEST_CAPTURE		0x00080000	/* Begin capture */
-#define AR5K_ADDAC_TEST_TST_ARM		0x00100000	/* Test ARM (Adaptive Radio Mode ?) */
+#define AR5K_ADDAC_TEST_TST_ARM		0x00100000	/* ARM rx buffer for capture */
 
 /*
  * Default antenna register [5211+]
@@ -1677,7 +1680,7 @@
  * TSF parameter register
  */
 #define AR5K_TSF_PARM			0x8104			/* Register Address */
-#define AR5K_TSF_PARM_INC_M		0x000000ff	/* Mask for TSF increment */
+#define AR5K_TSF_PARM_INC		0x000000ff	/* Mask for TSF increment */
 #define AR5K_TSF_PARM_INC_S		0
 
 /*
@@ -1689,7 +1692,7 @@
 #define AR5K_QOS_NOACK_BIT_OFFSET	0x00000070	/* ??? */
 #define AR5K_QOS_NOACK_BIT_OFFSET_S	4
 #define AR5K_QOS_NOACK_BYTE_OFFSET	0x00000180	/* ??? */
-#define AR5K_QOS_NOACK_BYTE_OFFSET_S	8
+#define AR5K_QOS_NOACK_BYTE_OFFSET_S	7
 
 /*
  * PHY error filter register
@@ -1848,15 +1851,14 @@
  * TST_2 (Misc config parameters)
  */
 #define	AR5K_PHY_TST2			0x9800			/* Register Address */
-#define AR5K_PHY_TST2_TRIG_SEL		0x00000001	/* Trigger select (?) (field ?) */
-#define AR5K_PHY_TST2_TRIG		0x00000010	/* Trigger (?) (field ?) */
-#define AR5K_PHY_TST2_CBUS_MODE		0x00000100	/* Cardbus mode (?) */
-/* bit reserved */
+#define AR5K_PHY_TST2_TRIG_SEL		0x00000007	/* Trigger select (?)*/
+#define AR5K_PHY_TST2_TRIG		0x00000010	/* Trigger (?) */
+#define AR5K_PHY_TST2_CBUS_MODE		0x00000060	/* Cardbus mode (?) */
 #define AR5K_PHY_TST2_CLK32		0x00000400	/* CLK_OUT is CLK32 (32Khz external) */
 #define AR5K_PHY_TST2_CHANCOR_DUMP_EN	0x00000800	/* Enable Chancor dump (?) */
 #define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP	0x00001000	/* Even Chancor dump (?) */
 #define AR5K_PHY_TST2_RFSILENT_EN	0x00002000	/* Enable RFSILENT */
-#define AR5K_PHY_TST2_ALT_RFDATA	0x00004000	/* Alternate RFDATA (5-2GHz switch) */
+#define AR5K_PHY_TST2_ALT_RFDATA	0x00004000	/* Alternate RFDATA (5-2GHz switch ?) */
 #define AR5K_PHY_TST2_MINI_OBS_EN	0x00008000	/* Enable mini OBS (?) */
 #define AR5K_PHY_TST2_RX2_IS_RX5_INV	0x00010000	/* 2GHz rx path is the 5GHz path inverted (?) */
 #define AR5K_PHY_TST2_SLOW_CLK160	0x00020000	/* Slow CLK160 (?) */
@@ -1926,8 +1928,8 @@
 #define	AR5K_PHY_RF_CTL2_TXF2TXD_START_S	0
 
 #define AR5K_PHY_RF_CTL3		0x9828			/* Register Address */
-#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON	0x0000000f	/* TX end to XLNA on */
-#define	AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S	0
+#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON	0x0000ff00	/* TX end to XLNA on */
+#define	AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S	8
 
 #define	AR5K_PHY_ADC_CTL			0x982c
 #define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF		0x00000003
@@ -1961,7 +1963,7 @@
 #define	AR5K_PHY_SETTLING_AGC		0x0000007f	/* AGC settling time */
 #define	AR5K_PHY_SETTLING_AGC_S		0
 #define	AR5K_PHY_SETTLING_SWITCH	0x00003f80	/* Switch settlig time */
-#define	AR5K_PHY_SETTLINK_SWITCH_S	7
+#define	AR5K_PHY_SETTLING_SWITCH_S	7
 
 /*
  * PHY Gain registers
@@ -2067,14 +2069,14 @@
  * 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
-
+#define	AR5K_PHY_SCAL_32MHZ_2417	0x0000000a
+#define	AR5K_PHY_SCAL_32MHZ_HB63	0x00000032
 
 /*
  * PHY PLL (Phase Locked Loop) control register
@@ -2101,34 +2103,10 @@
 /*
  * 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
@@ -2178,7 +2156,8 @@
 #define	AR5K_PHY_ANT_CTL_TXRX_EN	0x00000001	/* Enable TX/RX (?) */
 #define	AR5K_PHY_ANT_CTL_SECTORED_ANT	0x00000004	/* Sectored Antenna */
 #define	AR5K_PHY_ANT_CTL_HITUNE5	0x00000008	/* Hitune5 (?) */
-#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE	0x00000010	/* Switch table idle (?) */
+#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE	0x000003f0	/* Switch table idle (?) */
+#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S	4
 
 /*
  * PHY receiver delay register [5111+]
@@ -2218,7 +2197,7 @@
 #define	AR5K_PHY_OFDM_SELFCORR			0x9924			/* Register Address */
 #define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN	0x00000001	/* Enable cyclic RSSI thr 1 */
 #define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1	0x000000fe	/* Mask for Cyclic RSSI threshold 1 */
-#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S	0
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S	1
 #define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3	0x00000100	/* Cyclic RSSI threshold 3 (field) (?) */
 #define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN	0x00008000	/* Enable 1A RSSI threshold (?) */
 #define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR	0x00010000	/* 1A RSSI threshold (field) (?) */
@@ -2243,9 +2222,7 @@
 #define	AR5K_PHY_CTL_LOW_FREQ_SLE_EN	0x00000080	/* Enable low freq sleep */
 
 /*
- * PHY PAPD probe register [5111+ (?)]
- * Is this only present in 5212 ?
- * Because it's always 0 in 5211 initialization code
+ * PHY PAPD probe register [5111+]
  */
 #define	AR5K_PHY_PAPD_PROBE		0x9930
 #define	AR5K_PHY_PAPD_PROBE_SH_HI_PAR	0x00000001
@@ -2303,6 +2280,15 @@
 			AR5K_PHY_FRAME_CTL_TIMING_ERR
 
 /*
+ * PHY Tx Power adjustment register [5212A+]
+ */
+#define	AR5K_PHY_TX_PWR_ADJ			0x994c
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA	0x00000fc0
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S	6
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX	0x00fc0000
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S	18
+
+/*
  * PHY radar detection register [5111+]
  */
 #define	AR5K_PHY_RADAR			0x9954
@@ -2355,7 +2341,7 @@
 #define AR5K_PHY_SIGMA_DELTA_FILT2_S	3
 #define AR5K_PHY_SIGMA_DELTA_FILT1	0x00001f00
 #define AR5K_PHY_SIGMA_DELTA_FILT1_S	8
-#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP	0x01ff3000
+#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP	0x01ffe000
 #define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S	13
 
 /*
@@ -2387,21 +2373,21 @@
 #define AR5K_PHY_BIN_MASK2_4_MASK_4	0x00003fff
 #define AR5K_PHY_BIN_MASK2_4_MASK_4_S	0
 
-#define AR_PHY_TIMING_9			0x9998
-#define AR_PHY_TIMING_10		0x999c
-#define AR_PHY_TIMING_10_PILOT_MASK_2	0x000fffff
-#define AR_PHY_TIMING_10_PILOT_MASK_2_S	0
+#define AR5K_PHY_TIMING_9			0x9998
+#define AR5K_PHY_TIMING_10			0x999c
+#define AR5K_PHY_TIMING_10_PILOT_MASK_2		0x000fffff
+#define AR5K_PHY_TIMING_10_PILOT_MASK_2_S	0
 
 /*
  * Spur mitigation control
  */
-#define AR_PHY_TIMING_11			0x99a0		/* Register address */
-#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE	0x000fffff	/* Spur delta phase */
-#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE_S	0
-#define AR_PHY_TIMING_11_SPUR_FREQ_SD		0x3ff00000	/* Freq sigma delta */
-#define AR_PHY_TIMING_11_SPUR_FREQ_SD_S	20
-#define AR_PHY_TIMING_11_USE_SPUR_IN_AGC	0x40000000	/* Spur filter in AGC detector */
-#define AR_PHY_TIMING_11_USE_SPUR_IN_SELFCOR	0x80000000	/* Spur filter in OFDM self correlator */
+#define AR5K_PHY_TIMING_11			0x99a0		/* Register address */
+#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE	0x000fffff	/* Spur delta phase */
+#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S	0
+#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD		0x3ff00000	/* Freq sigma delta */
+#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S	20
+#define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC	0x40000000	/* Spur filter in AGC detector */
+#define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR	0x80000000	/* Spur filter in OFDM self correlator */
 
 /*
  * Gain tables
@@ -2483,17 +2469,7 @@
 #define AR5K_PHY_SDELAY			0x99f4
 #define AR5K_PHY_SDELAY_32MHZ		0x000000ff
 #define AR5K_PHY_SPENDING		0x99f8
-#define AR5K_PHY_SPENDING_14		0x00000014
-#define AR5K_PHY_SPENDING_18		0x00000018
-#define AR5K_PHY_SPENDING_RF5111	0x00000018
-#define AR5K_PHY_SPENDING_RF5112	0x00000014
-/* #define AR5K_PHY_SPENDING_RF5112A	0x0000000e */
-/* #define AR5K_PHY_SPENDING_RF5424	0x00000012 */
-#define AR5K_PHY_SPENDING_RF5413	0x00000018
-#define AR5K_PHY_SPENDING_RF2413	0x00000018
-#define AR5K_PHY_SPENDING_RF2316	0x00000018
-#define AR5K_PHY_SPENDING_RF2317	0x00000018
-#define AR5K_PHY_SPENDING_RF2425	0x00000014
+
 
 /*
  * PHY PAPD I (power?) table (?)
@@ -2505,11 +2481,7 @@
 /*
  * PHY PCDAC TX power table
  */
-#define	AR5K_PHY_PCDAC_TXPOWER_BASE_5211	0xa180
-#define AR5K_PHY_PCDAC_TXPOWER_BASE_2413	0xa280
-#define AR5K_PHY_PCDAC_TXPOWER_BASE	(ah->ah_radio >= AR5K_RF2413 ? \
-					AR5K_PHY_PCDAC_TXPOWER_BASE_2413 :\
-					AR5K_PHY_PCDAC_TXPOWER_BASE_5211)
+#define	AR5K_PHY_PCDAC_TXPOWER_BASE	0xa180
 #define	AR5K_PHY_PCDAC_TXPOWER(_n)	(AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
 
 /*
@@ -2590,3 +2562,9 @@
 #define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S	16
 #define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4	0x0FC00000
 #define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S	22
+
+/*
+ * PHY PDADC Tx power table
+ */
+#define AR5K_PHY_PDADC_TXPOWER_BASE	0xa280
+#define	AR5K_PHY_PDADC_TXPOWER(_n)	(AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2))
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c
index dc2d7d8..1531ccd 100644
--- a/drivers/net/wireless/ath5k/reset.c
+++ b/drivers/net/wireless/ath5k/reset.c
@@ -25,7 +25,8 @@
   Reset functions and helpers
 \*****************************/
 
-#include <linux/pci.h>
+#include <linux/pci.h> 		/* To determine if a card is pci-e */
+#include <linux/bitops.h>	/* For get_bitmask_order */
 #include "ath5k.h"
 #include "reg.h"
 #include "base.h"
@@ -37,10 +38,14 @@
  * @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.
+ * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
+ * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset().
  *
+ * Since delta slope is floating point we split it on its exponent and
+ * mantissa and provide these values on hw.
+ *
+ * For more infos i think this patent is related
+ * http://www.freepatentsonline.com/7184495.html
  */
 static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
 	struct ieee80211_channel *channel)
@@ -53,23 +58,34 @@
 		!(channel->hw_value & 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->hw_value & CHANNEL_TURBO ? 80 : 40;
-	coef_scaled = ((5 * (clock << 24)) / 2) /
-	channel->center_freq;
+	/* Get coefficient
+	 * ALGO: coef = (5 * clock * carrier_freq) / 2)
+	 * we scale coef by shifting clock value by 24 for
+	 * better precision since we use integers */
+	/* TODO: Half/quarter rate */
+	clock =  ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO);
 
-	for (coef_exp = 31; coef_exp > 0; coef_exp--)
-		if ((coef_scaled >> coef_exp) & 0x1)
-			break;
+	coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
 
+	/* Get exponent
+	 * ALGO: coef_exp = 14 - highest set bit position */
+	coef_exp = get_bitmask_order(coef_scaled);
+
+	/* Doesn't make sense if it's zero*/
 	if (!coef_exp)
 		return -EINVAL;
 
+	/* Note: we've shifted coef_scaled by 24 */
 	coef_exp = 14 - (coef_exp - 24);
+
+
+	/* Get mantissa (significant digits)
+	 * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
 	coef_man = coef_scaled +
 		(1 << (24 - coef_exp - 1));
+
+	/* Calculate delta slope coefficient exponent
+	 * and mantissa (remove scaling) and set them on hw */
 	ds_coef_man = coef_man >> (24 - coef_exp);
 	ds_coef_exp = coef_exp - 16;
 
@@ -90,16 +106,23 @@
 	{ 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
 
 /**
- * ath5k_hw_write_rate_duration - set rate duration during hw resets
+ * ath5k_hw_write_rate_duration - fill rate code to duration table
  *
  * @ah: the &struct ath5k_hw
  * @mode: one of enum ath5k_driver_mode
  *
- * Write the rate duration table 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.
+ * Write the rate code to duration table upon hw reset. This is a helper for
+ * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on
+ * the hardware, based on current mode, for each rate. The rates which are
+ * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
+ * different rate code so we write their value twice (one for long preample
+ * and one for short).
+ *
+ * Note: Band doesn't matter here, if we set the values for OFDM it works
+ * on both a and g modes. So all we have to do is set values for all g rates
+ * that include all OFDM and CCK rates. If we operate in turbo or xr/half/
+ * quarter rate mode, we need to use another set of bitrates (that's why we
+ * need the mode parameter) but we don't handle these proprietary modes yet.
  */
 static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
        unsigned int mode)
@@ -275,7 +298,8 @@
 }
 
 /*
- * Bring up MAC + PHY Chips
+ * Bring up MAC + PHY Chips and program PLL
+ * TODO: Half/Quarter rate support
  */
 int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 {
@@ -333,7 +357,11 @@
 			}
 		} else if (flags & CHANNEL_5GHZ) {
 			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
-			clock |= AR5K_PHY_PLL_40MHZ;
+
+			if (ah->ah_radio == AR5K_RF5413)
+				clock |= AR5K_PHY_PLL_40MHZ_5413;
+			else
+				clock |= AR5K_PHY_PLL_40MHZ;
 
 			if (flags & CHANNEL_OFDM)
 				mode |= AR5K_PHY_MODE_MOD_OFDM;
@@ -391,10 +419,14 @@
 	}
 
 	if (ah->ah_version != AR5K_AR5210) {
-		/* ...set the PHY operating mode */
-		ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
-		udelay(300);
 
+		/* ...update PLL if needed */
+		if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
+			ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
+			udelay(300);
+		}
+
+		/* ...set the PHY operating mode */
 		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
 		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
 	}
@@ -403,22 +435,393 @@
 }
 
 /*
+ * If there is an external 32KHz crystal available, use it
+ * as ref. clock instead of 32/40MHz clock and baseband clocks
+ * to save power during sleep or restore normal 32/40MHz
+ * operation.
+ *
+ * XXX: When operating on 32KHz certain PHY registers (27 - 31,
+ * 	123 - 127) require delay on access.
+ */
+static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 scal, spending, usec32;
+
+	/* Only set 32KHz settings if we have an external
+	 * 32KHz crystal present */
+	if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) ||
+	AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) &&
+	enable) {
+
+		/* 1 usec/cycle */
+		AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1);
+		/* Set up tsf increment on each cycle */
+		AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61);
+
+		/* Set baseband sleep control registers
+		 * and sleep control rate */
+		ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
+
+		if ((ah->ah_radio == AR5K_RF5112) ||
+		(ah->ah_radio == AR5K_RF5413) ||
+		(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+			spending = 0x14;
+		else
+			spending = 0x18;
+		ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
+
+		if ((ah->ah_radio == AR5K_RF5112) ||
+		(ah->ah_radio == AR5K_RF5413) ||
+		(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+			ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
+			ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
+			ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
+			ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
+			AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+				AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
+		} else {
+			ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT);
+			ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL);
+			ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK);
+			ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY);
+			AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+				AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03);
+		}
+
+		/* Enable sleep clock operation */
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
+				AR5K_PCICFG_SLEEP_CLOCK_EN);
+
+	} else {
+
+		/* Disable sleep clock operation and
+		 * restore default parameters */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
+				AR5K_PCICFG_SLEEP_CLOCK_EN);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+				AR5K_PCICFG_SLEEP_CLOCK_RATE, 0);
+
+		ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
+
+		if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
+			scal = AR5K_PHY_SCAL_32MHZ_2417;
+		else if (ath5k_eeprom_is_hb63(ah))
+			scal = AR5K_PHY_SCAL_32MHZ_HB63;
+		else
+			scal = AR5K_PHY_SCAL_32MHZ;
+		ath5k_hw_reg_write(ah, scal, 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);
+
+		if ((ah->ah_radio == AR5K_RF5112) ||
+		(ah->ah_radio == AR5K_RF5413) ||
+		(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+			spending = 0x14;
+		else
+			spending = 0x18;
+		ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
+
+		if ((ah->ah_radio == AR5K_RF5112) ||
+		(ah->ah_radio == AR5K_RF5413))
+			usec32 = 39;
+		else
+			usec32 = 31;
+		AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, usec32);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
+	}
+	return;
+}
+
+static bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
+				struct ieee80211_channel *channel)
+{
+	u8 refclk_freq;
+
+	if ((ah->ah_radio == AR5K_RF5112) ||
+	(ah->ah_radio == AR5K_RF5413) ||
+	(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+		refclk_freq = 40;
+	else
+		refclk_freq = 32;
+
+	if ((channel->center_freq % refclk_freq != 0) &&
+	((channel->center_freq % refclk_freq < 10) ||
+	(channel->center_freq % refclk_freq > 22)))
+		return true;
+	else
+		return false;
+}
+
+/* TODO: Half/Quarter rate */
+static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
+				struct ieee80211_channel *channel)
+{
+	if (ah->ah_version == AR5K_AR5212 &&
+	    ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+
+		/* Setup ADC control */
+		ath5k_hw_reg_write(ah,
+				(AR5K_REG_SM(2,
+				AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) |
+				AR5K_REG_SM(2,
+				AR5K_PHY_ADC_CTL_INBUFGAIN_ON) |
+				AR5K_PHY_ADC_CTL_PWD_DAC_OFF |
+				AR5K_PHY_ADC_CTL_PWD_ADC_OFF),
+				AR5K_PHY_ADC_CTL);
+
+
+
+		/* Disable barker RSSI threshold */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
+				AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
+			AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2);
+
+		/* Set the mute mask */
+		ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
+	}
+
+	/* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */
+	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B)
+		ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH);
+
+	/* Enable DCU double buffering */
+	if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B)
+		AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+				AR5K_TXCFG_DCU_DBL_BUF_DIS);
+
+	/* Set DAC/ADC delays */
+	if (ah->ah_version == AR5K_AR5212) {
+		u32 scal;
+		if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
+			scal = AR5K_PHY_SCAL_32MHZ_2417;
+		else if (ath5k_eeprom_is_hb63(ah))
+			scal = AR5K_PHY_SCAL_32MHZ_HB63;
+		else
+			scal = AR5K_PHY_SCAL_32MHZ;
+		ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
+	}
+
+	/* Set fast ADC */
+	if ((ah->ah_radio == AR5K_RF5413) ||
+	(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+		u32 fast_adc = true;
+
+		if (channel->center_freq == 2462 ||
+		channel->center_freq == 2467)
+			fast_adc = 0;
+
+		/* Only update if needed */
+		if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc)
+				ath5k_hw_reg_write(ah, fast_adc,
+						AR5K_PHY_FAST_ADC);
+	}
+
+	/* Fix for first revision of the RF5112 RF chipset */
+	if (ah->ah_radio == AR5K_RF5112 &&
+			ah->ah_radio_5ghz_revision <
+			AR5K_SREV_RAD_5112A) {
+		u32 data;
+		ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
+				AR5K_PHY_CCKTXCTL);
+		if (channel->hw_value & CHANNEL_5GHZ)
+			data = 0xffb81020;
+		else
+			data = 0xffb80d20;
+		ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+	}
+
+	if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+		u32 usec_reg;
+		/* 5311 has different tx/rx latency masks
+		 * from 5211, since we deal 5311 the same
+		 * as 5211 when setting initvals, shift
+		 * values here to their proper locations */
+		usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
+		ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 |
+				AR5K_USEC_32 |
+				AR5K_USEC_TX_LATENCY_5211 |
+				AR5K_REG_SM(29,
+				AR5K_USEC_RX_LATENCY_5210)),
+				AR5K_USEC_5211);
+		/* Clear QCU/DCU clock gating register */
+		ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
+		/* Set DAC/ADC delays */
+		ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL);
+		/* Enable PCU FIFO corruption ECO */
+		AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_ECO_ENABLE);
+	}
+}
+
+static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel, u8 *ant, u8 ee_mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+
+	/* Set CCK to OFDM power delta */
+	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+		int16_t cck_ofdm_pwr_delta;
+
+		/* Adjust power delta for channel 14 */
+		if (channel->center_freq == 2484)
+			cck_ofdm_pwr_delta =
+				((ee->ee_cck_ofdm_power_delta -
+				ee->ee_scaled_cck_delta) * 2) / 10;
+		else
+			cck_ofdm_pwr_delta =
+				(ee->ee_cck_ofdm_power_delta * 2) / 10;
+
+		if (channel->hw_value == CHANNEL_G)
+			ath5k_hw_reg_write(ah,
+			AR5K_REG_SM((ee->ee_cck_ofdm_power_delta * -1),
+				AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
+			AR5K_REG_SM((cck_ofdm_pwr_delta * -1),
+				AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX),
+				AR5K_PHY_TX_PWR_ADJ);
+		else
+			ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ);
+	}
+
+	/* Set antenna idle switch table */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
+			AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
+			(ah->ah_antenna[ee_mode][0] |
+			AR5K_PHY_ANT_CTL_TXRX_EN));
+
+	/* Set antenna switch table */
+	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);
+
+	/* Noise floor threshold */
+	ath5k_hw_reg_write(ah,
+		AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
+		AR5K_PHY_NFTHRES);
+
+	if ((channel->hw_value & CHANNEL_TURBO) &&
+	(ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
+		/* Switch settling time (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+				AR5K_PHY_SETTLING_SWITCH,
+				ee->ee_switch_settling_turbo[ee_mode]);
+
+		/* Tx/Rx attenuation (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
+				AR5K_PHY_GAIN_TXRX_ATTEN,
+				ee->ee_atn_tx_rx_turbo[ee_mode]);
+
+		/* ADC/PGA desired size (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_ADC,
+				ee->ee_adc_desired_size_turbo[ee_mode]);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_PGA,
+				ee->ee_pga_desired_size_turbo[ee_mode]);
+
+		/* Tx/Rx margin (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+				ee->ee_margin_tx_rx_turbo[ee_mode]);
+
+	} else {
+		/* Switch settling time */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+				AR5K_PHY_SETTLING_SWITCH,
+				ee->ee_switch_settling[ee_mode]);
+
+		/* Tx/Rx attenuation */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
+				AR5K_PHY_GAIN_TXRX_ATTEN,
+				ee->ee_atn_tx_rx[ee_mode]);
+
+		/* ADC/PGA desired size */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_ADC,
+				ee->ee_adc_desired_size[ee_mode]);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_PGA,
+				ee->ee_pga_desired_size[ee_mode]);
+
+		/* Tx/Rx margin */
+		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]);
+	}
+
+	/* XPA delays */
+	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_RF_CTL4);
+
+	/* XLNA delay */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3,
+			AR5K_PHY_RF_CTL3_TXE2XLNA_ON,
+			ee->ee_tx_end2xlna_enable[ee_mode]);
+
+	/* Thresh64 (ANI) */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF,
+			AR5K_PHY_NF_THRESH62,
+			ee->ee_thr_62[ee_mode]);
+
+
+	/* False detect backoff for channels
+	 * that have spur noise. Write the new
+	 * cyclic power RSSI threshold. */
+	if (ath5k_hw_chan_has_spur_noise(ah, channel))
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
+				AR5K_INIT_CYCRSSI_THR1 +
+				ee->ee_false_detect[ee_mode]);
+	else
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
+				AR5K_INIT_CYCRSSI_THR1);
+
+	/* I/Q correction
+	 * TODO: Per channel i/q infos ? */
+	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]);
+
+	/* Heavy clipping -disable for now */
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
+		ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
+
+	return;
+}
+
+/*
  * Main reset function
  */
 int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
 	struct ieee80211_channel *channel, bool change_channel)
 {
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct pci_dev *pdev = ah->ah_sc->pdev;
-	u32 data, s_seq, s_ant, s_led[3], dma_size;
-	unsigned int i, mode, freq, ee_mode, ant[2];
-	int ret;
+	u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo;
+	u32 phy_tst1;
+	u8 mode, freq, ee_mode, ant[2];
+	int i, ret;
 
 	ATH5K_TRACE(ah->ah_sc);
 
-	s_seq = 0;
 	s_ant = 0;
 	ee_mode = 0;
+	staid1_flags = 0;
+	tsf_up = 0;
+	tsf_lo = 0;
 	freq = 0;
 	mode = 0;
 
@@ -427,48 +830,6 @@
 	 */
 	/*DCU/Antenna selection not available on 5210*/
 	if (ah->ah_version != AR5K_AR5210) {
-		if (change_channel) {
-			/* 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 && ah->ah_rf_banks != NULL)
-		ath5k_hw_get_rf_gain(ah);
-
-
-	/*Wakeup the device*/
-	ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, 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 &&
-			ah->ah_radio != AR5K_RF2413 &&
-			ah->ah_radio != AR5K_RF2425) {
-			ATH5K_ERR(ah->ah_sc,
-				"invalid phy radio: %u\n", ah->ah_radio);
-			return -EINVAL;
-		}
 
 		switch (channel->hw_value & CHANNEL_MODES) {
 		case CHANNEL_A:
@@ -491,8 +852,12 @@
 			freq = AR5K_INI_RFGAIN_5GHZ;
 			ee_mode = AR5K_EEPROM_MODE_11A;
 			break;
-		/*Is this ok on 5211 too ?*/
 		case CHANNEL_TG:
+			if (ah->ah_version == AR5K_AR5211) {
+				ATH5K_ERR(ah->ah_sc,
+					"TurboG mode not available on 5211");
+				return -EINVAL;
+			}
 			mode = AR5K_MODE_11G_TURBO;
 			freq = AR5K_INI_RFGAIN_2GHZ;
 			ee_mode = AR5K_EEPROM_MODE_11G;
@@ -513,11 +878,93 @@
 			return -EINVAL;
 		}
 
-		/* PHY access enable */
-		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+		if (change_channel) {
+			/*
+			 * Save frame sequence count
+			 * For revs. after Oahu, only save
+			 * seq num for DCU 0 (Global seq num)
+			 */
+			if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
 
+				for (i = 0; i < 10; i++)
+					s_seq[i] = ath5k_hw_reg_read(ah,
+						AR5K_QUEUE_DCU_SEQNUM(i));
+
+			} else {
+				s_seq[0] = ath5k_hw_reg_read(ah,
+						AR5K_QUEUE_DCU_SEQNUM(0));
+			}
+
+			/* TSF accelerates on AR5211 durring reset
+			 * As a workaround save it here and restore
+			 * it later so that it's back in time after
+			 * reset. This way it'll get re-synced on the
+			 * next beacon without breaking ad-hoc.
+			 *
+			 * On AR5212 TSF is almost preserved across a
+			 * reset so it stays back in time anyway and
+			 * we don't have to save/restore it.
+			 *
+			 * XXX: Since this breaks power saving we have
+			 * to disable power saving until we receive the
+			 * next beacon, so we can resync beacon timers */
+			if (ah->ah_version == AR5K_AR5211) {
+				tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+				tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
+			}
+		}
+
+		/* Save default antenna */
+		s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+
+		if (ah->ah_version == AR5K_AR5212) {
+			/* Restore normal 32/40MHz clock operation
+			 * to avoid register access delay on certain
+			 * PHY registers */
+			ath5k_hw_set_sleep_clock(ah, false);
+
+			/* Since we are going to write rf buffer
+			 * check if we have any pending gain_F
+			 * optimization settings */
+			if (change_channel && ah->ah_rf_banks != NULL)
+				ath5k_hw_gainf_calibrate(ah);
+		}
 	}
 
+	/*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);
+
+	/* AR5K_STA_ID1 flags, only preserve antenna
+	 * settings and ack/cts rate mode */
+	staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) &
+			(AR5K_STA_ID1_DEFAULT_ANTENNA |
+			AR5K_STA_ID1_DESC_ANTENNA |
+			AR5K_STA_ID1_RTS_DEF_ANTENNA |
+			AR5K_STA_ID1_ACKCTS_6MB |
+			AR5K_STA_ID1_BASE_RATE_11B |
+			AR5K_STA_ID1_SELFGEN_DEF_ANT);
+
+	/* Wakeup the device */
+	ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
+	if (ret)
+		return ret;
+
+	/*
+	 * Initialize operating mode
+	 */
+	ah->ah_op_mode = op_mode;
+
+	/* PHY access enable */
+	if (ah->ah_mac_srev >= AR5K_SREV_AR5211)
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+	else
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40,
+							AR5K_PHY(0));
+
+	/* Write initial settings */
 	ret = ath5k_hw_write_initvals(ah, mode, change_channel);
 	if (ret)
 		return ret;
@@ -526,64 +973,23 @@
 	 * 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);
+		ret = ath5k_hw_rfgain_init(ah, freq);
 		if (ret)
 			return ret;
 
 		mdelay(1);
 
 		/*
-		 * Write some more initial register settings for revised chips
+		 * Tweak initval settings for revised
+		 * chipsets and add some more config
+		 * bits
 		 */
-		if (ah->ah_version == AR5K_AR5212 &&
-		    ah->ah_phy_revision > 0x41) {
-			ath5k_hw_reg_write(ah, 0x0002a002, 0x982c);
-
-			if (channel->hw_value == CHANNEL_G)
-				if (ah->ah_mac_srev < AR5K_SREV_AR2413)
-					ath5k_hw_reg_write(ah, 0x00f80d80,
-								0x994c);
-				else if (ah->ah_mac_srev < AR5K_SREV_AR5424)
-					ath5k_hw_reg_write(ah, 0x00380140,
-								0x994c);
-				else if (ah->ah_mac_srev < AR5K_SREV_AR2425)
-					ath5k_hw_reg_write(ah, 0x00fc0ec0,
-								0x994c);
-				else /* 2425 */
-					ath5k_hw_reg_write(ah, 0x00fc0fc0,
-								0x994c);
-			else
-				ath5k_hw_reg_write(ah, 0x00000000, 0x994c);
-
-			/* Got this from legacy-hal */
-			AR5K_REG_DISABLE_BITS(ah, 0xa228, 0x200);
-
-			AR5K_REG_MASKED_BITS(ah, 0xa228, 0x800, 0xfffe03ff);
-
-			/* Just write 0x9b5 ? */
-			/* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */
-			ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
-			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->hw_value & CHANNEL_5GHZ)
-				data = 0xffb81020;
-			else
-				data = 0xffb80d20;
-			ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
-			data = 0;
-		}
+		ath5k_hw_tweak_initval_settings(ah, channel);
 
 		/*
 		 * Set TX power (FIXME)
@@ -601,15 +1007,12 @@
 			ath5k_hw_write_rate_duration(ah, mode);
 
 		/*
-		 * Write RF registers
+		 * Write RF buffer
 		 */
-		ret = ath5k_hw_rfregs(ah, channel, mode);
+		ret = ath5k_hw_rfregs_init(ah, channel, mode);
 		if (ret)
 			return ret;
 
-		/*
-		 * Configure additional registers
-		 */
 
 		/* Write OFDM timings on 5212*/
 		if (ah->ah_version == AR5K_AR5212 &&
@@ -631,17 +1034,6 @@
 		}
 
 		/*
-		 * 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_ANT_CTL,
-			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.
@@ -656,54 +1048,16 @@
 			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_NFTHRES);
-
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING,
-			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
-			0xffffc07f);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
-			(ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000,
-			0xfffc0fff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
-			(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_RF_CTL4);
-
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3,
-			ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF,
-			(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 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]);
+		ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode);
 
 	} else {
+		/*
+		 * For 5210 we do all initialization using
+		 * initvals, so we don't have to modify
+		 * any settings (5210 also only supports
+		 * a/aturbo modes)
+		 */
 		mdelay(1);
 		/* Disable phy and wait */
 		ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
@@ -713,100 +1067,154 @@
 	/*
 	 * 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));
+
+		if (change_channel) {
+			if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+				for (i = 0; i < 10; i++)
+					ath5k_hw_reg_write(ah, s_seq[i],
+						AR5K_QUEUE_DCU_SEQNUM(i));
+			} else {
+				ath5k_hw_reg_write(ah, s_seq[0],
+					AR5K_QUEUE_DCU_SEQNUM(0));
+			}
+
+
+			if (ah->ah_version == AR5K_AR5211) {
+				ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32);
+				ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
+			}
+		}
+
 		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
 	}
+
+	/* Ledstate */
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
+
+	/* Gpio settings */
 	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
 	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
 
+	/* Restore sta_id flags and preserve our mac address*/
+	ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id),
+						AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id),
+						AR5K_STA_ID1);
+
+
 	/*
-	 * Misc
+	 * Configure PCU
 	 */
+
+	/* Restore bssid and bssid mask */
 	/* XXX: add ah->aid once mac80211 gives this to us */
 	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
 
+	/* Set PCU config */
 	ath5k_hw_set_opmode(ah);
-	/*PISR/SISR Not available on 5210*/
-	if (ah->ah_version != AR5K_AR5210) {
+
+	/* Clear any pending interrupts
+	 * 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 RSSI/BRSSI thresholds
+	 *
+	 * Note: If we decide to set this value
+	 * dynamicaly, have in mind that when AR5K_RSSI_THR
+	 * register is read it might return 0x40 if we haven't
+	 * wrote anything to it plus BMISS RSSI threshold is zeroed.
+	 * So doing a save/restore procedure here isn't the right
+	 * choice. Instead store it on ath5k_hw */
+	ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
+				AR5K_TUNE_BMISS_THRES <<
+				AR5K_RSSI_THR_BMISS_S),
+				AR5K_RSSI_THR);
+
+	/* MIC QoS support */
+	if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
+		ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
+		ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
 	}
 
-	/*
-	 * Set Rx/Tx DMA Configuration
-	 *
-	 * Set maximum DMA size (512) except for PCI-E cards since
-	 * it causes rx overruns and tx errors (tested on 5424 but since
-	 * rx overruns also occur on 5416/5418 with madwifi we set 128
-	 * for all PCI-E cards to be safe).
-	 *
-	 * In dumps this is 128 for allchips.
-	 *
-	 * XXX: need to check 5210 for this
-	 * TODO: Check out tx triger level, it's always 64 on dumps but I
-	 * guess we can tweak it and see how it goes ;-)
-	 */
-	dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B;
-	if (ah->ah_version != AR5K_AR5210) {
-		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
-			AR5K_TXCFG_SDMAMR, dma_size);
-		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
-			AR5K_RXCFG_SDMAMW, dma_size);
+	/* QoS NOACK Policy */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
+			AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
+			AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
+			AR5K_QOS_NOACK);
 	}
 
+
+	/*
+	 * Configure PHY
+	 */
+
+	/* Set channel on PHY */
+	ret = ath5k_hw_channel(ah, channel);
+	if (ret)
+		return ret;
+
 	/*
 	 * Enable the PHY and wait until completion
+	 * This includes BaseBand and Synthesizer
+	 * activation.
 	 */
 	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
 
 	/*
 	 * On 5211+ read activation -> rx delay
 	 * and use it.
+	 *
+	 * TODO: Half/quarter rate support
 	 */
 	if (ah->ah_version != AR5K_AR5210) {
-		data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+		u32 delay;
+		delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
 			AR5K_PHY_RX_DELAY_M;
-		data = (channel->hw_value & CHANNEL_CCK) ?
-			((data << 2) / 22) : (data / 10);
+		delay = (channel->hw_value & CHANNEL_CCK) ?
+			((delay << 2) / 22) : (delay / 10);
 
-		udelay(100 + (2 * data));
-		data = 0;
+		udelay(100 + (2 * delay));
 	} else {
 		mdelay(1);
 	}
 
 	/*
-	 * Perform ADC test (?)
+	 * Perform ADC test to see if baseband is ready
+	 * Set tx hold and check adc test register
 	 */
-	data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+	phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
 	ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
 	for (i = 0; i <= 20; i++) {
 		if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
 			break;
 		udelay(200);
 	}
-	ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1);
-	data = 0;
+	ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
 
 	/*
-	 * Start automatic gain calibration
+	 * Start automatic gain control calibration
 	 *
 	 * During AGC calibration RX path is re-routed to
-	 * a signal detector so we don't receive anything.
+	 * a power detector so we don't receive anything.
 	 *
 	 * This method is used to calibrate some static offsets
 	 * used together with on-the fly I/Q calibration (the
 	 * one performed via ath5k_hw_phy_calibrate), that doesn't
 	 * interrupt rx path.
 	 *
+	 * While rx path is re-routed to the power detector we also
+	 * start a noise floor calibration, to measure the
+	 * card's noise floor (the noise we measure when we are not
+	 * transmiting or receiving anything).
+	 *
 	 * If we are in a noisy environment AGC calibration may time
-	 * out.
+	 * out and/or noise floor calibration might timeout.
 	 */
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
 				AR5K_PHY_AGCCTL_CAL);
@@ -828,30 +1236,37 @@
 			AR5K_PHY_AGCCTL_CAL, 0, false)) {
 		ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
 			channel->center_freq);
-		return -EAGAIN;
 	}
 
 	/*
-	 * Start noise floor calibration
-	 *
 	 * If we run NF calibration before AGC, it always times out.
 	 * Binary HAL starts NF and AGC calibration at the same time
-	 * and only waits for AGC to finish. I believe that's wrong because
-	 * during NF calibration, rx path is also routed to a detector, so if
-	 * it doesn't finish we won't have RX.
-	 *
-	 * XXX: Find an interval that's OK for all cards...
+	 * and only waits for AGC to finish. Also if AGC or NF cal.
+	 * times out, reset doesn't fail on binary HAL. I believe
+	 * that's wrong because since rx path is routed to a detector,
+	 * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
+	 * enables noise floor calibration after offset calibration and if noise
+	 * floor calibration fails, reset fails. I believe that's
+	 * a better approach, we just need to find a polling interval
+	 * that suits best, even if reset continues we need to make
+	 * sure that rx path is ready.
 	 */
 	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 
+
+	/*
+	 * Configure QCUs/DCUs
+	 */
+
+	/* TODO: HW Compression support for data queues */
+	/* TODO: Burst prefetch for data queues */
+
 	/*
 	 * Reset queues and start beacon timers at the end of the reset routine
+	 * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
+	 * Note: If we want we can assign multiple qcus on one dcu.
 	 */
 	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,
@@ -860,14 +1275,40 @@
 		}
 	}
 
+
+	/*
+	 * Configure DMA/Interrupts
+	 */
+
+	/*
+	 * Set Rx/Tx DMA Configuration
+	 *
+	 * Set standard DMA size (128). Note that
+	 * a DMA size of 512 causes rx overruns and tx errors
+	 * on pci-e cards (tested on 5424 but since rx overruns
+	 * also occur on 5416/5418 with madwifi we set 128
+	 * for all PCI-E cards to be safe).
+	 *
+	 * XXX: need to check 5210 for this
+	 * TODO: Check out tx triger level, it's always 64 on dumps but I
+	 * guess we can tweak it and see how it goes ;-)
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
+	}
+
 	/* Pre-enable interrupts on 5211/5212*/
 	if (ah->ah_version != AR5K_AR5210)
 		ath5k_hw_set_imr(ah, ah->ah_imr);
 
 	/*
-	 * 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
+	 * Setup RFKill interrupt if rfkill flag is set on eeprom.
+	 * TODO: Use gpio pin and polarity infos from eeprom
+	 * TODO: Handle this in ath5k_intr because it'll result
+	 * 	 a nasty interrupt storm.
 	 */
 #if 0
 	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
@@ -880,33 +1321,12 @@
 	}
 #endif
 
-	/*
-	 * Set the 32MHz reference clock on 5212 phy clock sleep register
-	 *
-	 * TODO: Find out how to switch to external 32Khz clock to save power
-	 */
-	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_phy_spending, AR5K_PHY_SPENDING);
-
-		data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ;
-		data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ?
-						0x00000f80 : 0x00001380 ;
-		ath5k_hw_reg_write(ah, data, AR5K_USEC_5211);
-		data = 0;
-	}
-
-	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah, 0x000100aa, 0x8118);
-		ath5k_hw_reg_write(ah, 0x00003210, 0x811c);
-		ath5k_hw_reg_write(ah, 0x00000052, 0x8108);
-		if (ah->ah_mac_srev >= AR5K_SREV_AR2413)
-			ath5k_hw_reg_write(ah, 0x00000004, 0x8120);
-	}
+	/* Enable 32KHz clock function for AR5212+ chips
+	 * Set clocks to 32KHz operation and use an
+	 * external 32KHz crystal when sleeping if one
+	 * exists */
+	if (ah->ah_version == AR5K_AR5212)
+			ath5k_hw_set_sleep_clock(ah, true);
 
 	/*
 	 * Disable beacons and reset the register
diff --git a/drivers/net/wireless/ath5k/rfbuffer.h b/drivers/net/wireless/ath5k/rfbuffer.h
new file mode 100644
index 0000000..e50baff
--- /dev/null
+++ b/drivers/net/wireless/ath5k/rfbuffer.h
@@ -0,0 +1,1181 @@
+/*
+ * RF Buffer handling functions
+ *
+ * Copyright (c) 2009 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.
+ *
+ */
+
+
+/*
+ * There are some special registers on the RF chip
+ * that control 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 chip, using a special register,
+ * that holds all the settings we need. After we 've sent the
+ * data packet, we 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 call each data packet an "RF Bank" and all the data we write
+ * (all RF Banks) "RF Buffer". This file holds initial RF Buffer
+ * data for the different RF chips, and various info to match RF
+ * Buffer offsets with specific RF registers so that we can access
+ * them. We tweak these settings on rfregs_init function.
+ *
+ * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer
+ * registers and control registers):
+ *
+ * http://www.google.com/patents?id=qNURAAAAEBAJ
+ */
+
+
+/*
+ * Struct to hold default mode specific RF
+ * register values (RF Banks)
+ */
+struct ath5k_ini_rfbuffer {
+	u8	rfb_bank;		/* RF Bank number */
+	u16	rfb_ctrl_register;	/* RF Buffer control register */
+	u32	rfb_mode_data[5];	/* RF Buffer data for each mode */
+};
+
+/*
+ * Struct to hold RF Buffer field
+ * infos used to access certain RF
+ * analog registers
+ */
+struct ath5k_rfb_field {
+	u8	len;	/* Field length */
+	u16	pos;	/* Offset on the raw packet */
+	u8	col;	/* Column -used for shifting */
+};
+
+/*
+ * RF analog register definition
+ */
+struct ath5k_rf_reg {
+	u8			bank;	/* RF Buffer Bank number */
+	u8			index;	/* Register's index on rf_regs_idx */
+	struct ath5k_rfb_field	field;	/* RF Buffer field for this register */
+};
+
+/* Map RF registers to indexes
+ * We do this to handle common bits and make our
+ * life easier by using an index for each register
+ * instead of a full rfb_field */
+enum ath5k_rf_regs_idx {
+	/* BANK 6 */
+	AR5K_RF_OB_2GHZ = 0,
+	AR5K_RF_OB_5GHZ,
+	AR5K_RF_DB_2GHZ,
+	AR5K_RF_DB_5GHZ,
+	AR5K_RF_FIXED_BIAS_A,
+	AR5K_RF_FIXED_BIAS_B,
+	AR5K_RF_PWD_XPD,
+	AR5K_RF_XPD_SEL,
+	AR5K_RF_XPD_GAIN,
+	AR5K_RF_PD_GAIN_LO,
+	AR5K_RF_PD_GAIN_HI,
+	AR5K_RF_HIGH_VC_CP,
+	AR5K_RF_MID_VC_CP,
+	AR5K_RF_LOW_VC_CP,
+	AR5K_RF_PUSH_UP,
+	AR5K_RF_PAD2GND,
+	AR5K_RF_XB2_LVL,
+	AR5K_RF_XB5_LVL,
+	AR5K_RF_PWD_ICLOBUF_2G,
+	AR5K_RF_PWD_84,
+	AR5K_RF_PWD_90,
+	AR5K_RF_PWD_130,
+	AR5K_RF_PWD_131,
+	AR5K_RF_PWD_132,
+	AR5K_RF_PWD_136,
+	AR5K_RF_PWD_137,
+	AR5K_RF_PWD_138,
+	AR5K_RF_PWD_166,
+	AR5K_RF_PWD_167,
+	AR5K_RF_DERBY_CHAN_SEL_MODE,
+	/* BANK 7 */
+	AR5K_RF_GAIN_I,
+	AR5K_RF_PLO_SEL,
+	AR5K_RF_RFGAIN_SEL,
+	AR5K_RF_RFGAIN_STEP,
+	AR5K_RF_WAIT_S,
+	AR5K_RF_WAIT_I,
+	AR5K_RF_MAX_TIME,
+	AR5K_RF_MIXVGA_OVR,
+	AR5K_RF_MIXGAIN_OVR,
+	AR5K_RF_MIXGAIN_STEP,
+	AR5K_RF_PD_DELAY_A,
+	AR5K_RF_PD_DELAY_B,
+	AR5K_RF_PD_DELAY_XR,
+	AR5K_RF_PD_PERIOD_A,
+	AR5K_RF_PD_PERIOD_B,
+	AR5K_RF_PD_PERIOD_XR,
+};
+
+
+/*******************\
+* RF5111 (Sombrero) *
+\*******************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5111_OB_2GHZ		{ 3, 119, 0 }
+#define	AR5K_RF5111_DB_2GHZ		{ 3, 122, 0 }
+
+#define	AR5K_RF5111_OB_5GHZ		{ 3, 104, 0 }
+#define	AR5K_RF5111_DB_5GHZ		{ 3, 107, 0 }
+
+#define	AR5K_RF5111_PWD_XPD		{ 1, 95,  0 }
+#define	AR5K_RF5111_XPD_GAIN		{ 4, 96,  0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5111_PWD(_n)		{ 1, (135 - _n), 3 }
+
+/* BANK 7				len  pos col */
+#define	AR5K_RF5111_GAIN_I		{ 6, 29,  0 }
+#define	AR5K_RF5111_PLO_SEL		{ 1, 4,   0 }
+#define	AR5K_RF5111_RFGAIN_SEL		{ 1, 36,  0 }
+#define AR5K_RF5111_RFGAIN_STEP		{ 6, 37,  0 }
+/* Only on AR5212 BaseBand and up */
+#define	AR5K_RF5111_WAIT_S		{ 5, 19,  0 }
+#define	AR5K_RF5111_WAIT_I		{ 5, 24,  0 }
+#define	AR5K_RF5111_MAX_TIME		{ 2, 49,  0 }
+
+static const struct ath5k_rf_reg rf_regs_5111[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5111_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5111_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5111_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5111_DB_5GHZ},
+	{6, AR5K_RF_PWD_XPD,		AR5K_RF5111_PWD_XPD},
+	{6, AR5K_RF_XPD_GAIN,		AR5K_RF5111_XPD_GAIN},
+	{6, AR5K_RF_PWD_84,		AR5K_RF5111_PWD(84)},
+	{6, AR5K_RF_PWD_90,		AR5K_RF5111_PWD(90)},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5111_GAIN_I},
+	{7, AR5K_RF_PLO_SEL,		AR5K_RF5111_PLO_SEL},
+	{7, AR5K_RF_RFGAIN_SEL,		AR5K_RF5111_RFGAIN_SEL},
+	{7, AR5K_RF_RFGAIN_STEP,	AR5K_RF5111_RFGAIN_STEP},
+	{7, AR5K_RF_WAIT_S,		AR5K_RF5111_WAIT_S},
+	{7, AR5K_RF_WAIT_I,		AR5K_RF5111_WAIT_I},
+	{7, AR5K_RF_MAX_TIME,		AR5K_RF5111_MAX_TIME}
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_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 } },
+};
+
+
+
+/***********************\
+* RF5112/RF2112 (Derby) *
+\***********************/
+
+/* BANK 7 (Common)			len  pos col */
+#define	AR5K_RF5112X_GAIN_I		{ 6, 14,  0 }
+#define	AR5K_RF5112X_MIXVGA_OVR		{ 1, 36,  0 }
+#define	AR5K_RF5112X_MIXGAIN_OVR	{ 2, 37,  0 }
+#define AR5K_RF5112X_MIXGAIN_STEP	{ 4, 32,  0 }
+#define	AR5K_RF5112X_PD_DELAY_A		{ 4, 58,  0 }
+#define	AR5K_RF5112X_PD_DELAY_B		{ 4, 62,  0 }
+#define	AR5K_RF5112X_PD_DELAY_XR	{ 4, 66,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_A	{ 4, 70,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_B	{ 4, 74,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_XR	{ 4, 78,  0 }
+
+/* RFX112 (Derby 1) */
+
+/* BANK 6 				len  pos col */
+#define	AR5K_RF5112_OB_2GHZ		{ 3, 269, 0 }
+#define	AR5K_RF5112_DB_2GHZ		{ 3, 272, 0 }
+
+#define	AR5K_RF5112_OB_5GHZ		{ 3, 261, 0 }
+#define	AR5K_RF5112_DB_5GHZ		{ 3, 264, 0 }
+
+#define	AR5K_RF5112_FIXED_BIAS_A	{ 1, 260, 0 }
+#define	AR5K_RF5112_FIXED_BIAS_B	{ 1, 259, 0 }
+
+#define	AR5K_RF5112_XPD_SEL		{ 1, 284, 0 }
+#define	AR5K_RF5112_XPD_GAIN		{ 2, 252, 0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5112_PWD(_n)		{ 1, (302 - _n), 3 }
+
+static const struct ath5k_rf_reg rf_regs_5112[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5112_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5112_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5112_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5112_DB_5GHZ},
+	{6, AR5K_RF_FIXED_BIAS_A,	AR5K_RF5112_FIXED_BIAS_A},
+	{6, AR5K_RF_FIXED_BIAS_B,	AR5K_RF5112_FIXED_BIAS_B},
+	{6, AR5K_RF_XPD_SEL,		AR5K_RF5112_XPD_SEL},
+	{6, AR5K_RF_XPD_GAIN,		AR5K_RF5112_XPD_GAIN},
+	{6, AR5K_RF_PWD_130,		AR5K_RF5112_PWD(130)},
+	{6, AR5K_RF_PWD_131,		AR5K_RF5112_PWD(131)},
+	{6, AR5K_RF_PWD_132,		AR5K_RF5112_PWD(132)},
+	{6, AR5K_RF_PWD_136,		AR5K_RF5112_PWD(136)},
+	{6, AR5K_RF_PWD_137,		AR5K_RF5112_PWD(137)},
+	{6, AR5K_RF_PWD_138,		AR5K_RF5112_PWD(138)},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5112X_GAIN_I},
+	{7, AR5K_RF_MIXVGA_OVR,		AR5K_RF5112X_MIXVGA_OVR},
+	{7, AR5K_RF_MIXGAIN_OVR,	AR5K_RF5112X_MIXGAIN_OVR},
+	{7, AR5K_RF_MIXGAIN_STEP,	AR5K_RF5112X_MIXGAIN_STEP},
+	{7, AR5K_RF_PD_DELAY_A,		AR5K_RF5112X_PD_DELAY_A},
+	{7, AR5K_RF_PD_DELAY_B,		AR5K_RF5112X_PD_DELAY_B},
+	{7, AR5K_RF_PD_DELAY_XR,	AR5K_RF5112X_PD_DELAY_XR},
+	{7, AR5K_RF_PD_PERIOD_A,	AR5K_RF5112X_PD_PERIOD_A},
+	{7, AR5K_RF_PD_PERIOD_B,	AR5K_RF5112X_PD_PERIOD_B},
+	{7, AR5K_RF_PD_PERIOD_XR,	AR5K_RF5112X_PD_PERIOD_XR},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_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 } },
+};
+
+/* RFX112A (Derby 2) */
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5112A_OB_2GHZ		{ 3, 287, 0 }
+#define	AR5K_RF5112A_DB_2GHZ		{ 3, 290, 0 }
+
+#define	AR5K_RF5112A_OB_5GHZ		{ 3, 279, 0 }
+#define	AR5K_RF5112A_DB_5GHZ		{ 3, 282, 0 }
+
+#define	AR5K_RF5112A_FIXED_BIAS_A	{ 1, 278, 0 }
+#define	AR5K_RF5112A_FIXED_BIAS_B	{ 1, 277, 0 }
+
+#define	AR5K_RF5112A_XPD_SEL		{ 1, 302, 0 }
+#define	AR5K_RF5112A_PDGAINLO		{ 2, 270, 0 }
+#define	AR5K_RF5112A_PDGAINHI		{ 2, 257, 0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5112A_PWD(_n)		{ 1, (306 - _n), 3 }
+
+/* Voltage regulators */
+#define	AR5K_RF5112A_HIGH_VC_CP		{ 2, 90,  2 }
+#define	AR5K_RF5112A_MID_VC_CP		{ 2, 92,  2 }
+#define	AR5K_RF5112A_LOW_VC_CP		{ 2, 94,  2 }
+#define	AR5K_RF5112A_PUSH_UP		{ 1, 254,  2 }
+
+/* Power consumption */
+#define	AR5K_RF5112A_PAD2GND		{ 1, 281, 1 }
+#define	AR5K_RF5112A_XB2_LVL		{ 2, 1,	  3 }
+#define	AR5K_RF5112A_XB5_LVL		{ 2, 3,	  3 }
+
+static const struct ath5k_rf_reg rf_regs_5112a[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5112A_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5112A_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5112A_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5112A_DB_5GHZ},
+	{6, AR5K_RF_FIXED_BIAS_A,	AR5K_RF5112A_FIXED_BIAS_A},
+	{6, AR5K_RF_FIXED_BIAS_B,	AR5K_RF5112A_FIXED_BIAS_B},
+	{6, AR5K_RF_XPD_SEL,		AR5K_RF5112A_XPD_SEL},
+	{6, AR5K_RF_PD_GAIN_LO,		AR5K_RF5112A_PDGAINLO},
+	{6, AR5K_RF_PD_GAIN_HI,		AR5K_RF5112A_PDGAINHI},
+	{6, AR5K_RF_PWD_130,		AR5K_RF5112A_PWD(130)},
+	{6, AR5K_RF_PWD_131,		AR5K_RF5112A_PWD(131)},
+	{6, AR5K_RF_PWD_132,		AR5K_RF5112A_PWD(132)},
+	{6, AR5K_RF_PWD_136,		AR5K_RF5112A_PWD(136)},
+	{6, AR5K_RF_PWD_137,		AR5K_RF5112A_PWD(137)},
+	{6, AR5K_RF_PWD_138,		AR5K_RF5112A_PWD(138)},
+	{6, AR5K_RF_PWD_166,		AR5K_RF5112A_PWD(166)},
+	{6, AR5K_RF_PWD_167,		AR5K_RF5112A_PWD(167)},
+	{6, AR5K_RF_HIGH_VC_CP,		AR5K_RF5112A_HIGH_VC_CP},
+	{6, AR5K_RF_MID_VC_CP,		AR5K_RF5112A_MID_VC_CP},
+	{6, AR5K_RF_LOW_VC_CP,		AR5K_RF5112A_LOW_VC_CP},
+	{6, AR5K_RF_PUSH_UP,		AR5K_RF5112A_PUSH_UP},
+	{6, AR5K_RF_PAD2GND,		AR5K_RF5112A_PAD2GND},
+	{6, AR5K_RF_XB2_LVL,		AR5K_RF5112A_XB2_LVL},
+	{6, AR5K_RF_XB5_LVL,		AR5K_RF5112A_XB5_LVL},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5112X_GAIN_I},
+	{7, AR5K_RF_MIXVGA_OVR,		AR5K_RF5112X_MIXVGA_OVR},
+	{7, AR5K_RF_MIXGAIN_OVR,	AR5K_RF5112X_MIXGAIN_OVR},
+	{7, AR5K_RF_MIXGAIN_STEP,	AR5K_RF5112X_MIXGAIN_STEP},
+	{7, AR5K_RF_PD_DELAY_A,		AR5K_RF5112X_PD_DELAY_A},
+	{7, AR5K_RF_PD_DELAY_B,		AR5K_RF5112X_PD_DELAY_B},
+	{7, AR5K_RF_PD_DELAY_XR,	AR5K_RF5112X_PD_DELAY_XR},
+	{7, AR5K_RF_PD_PERIOD_A,	AR5K_RF5112X_PD_PERIOD_A},
+	{7, AR5K_RF_PD_PERIOD_B,	AR5K_RF5112X_PD_PERIOD_B},
+	{7, AR5K_RF_PD_PERIOD_XR,	AR5K_RF5112X_PD_PERIOD_XR},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_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,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 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,
+	    { 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 } },
+	{ 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,
+	    { 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 } },
+	{ 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,
+	    { 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 } },
+	{ 6, 0x989c,
+	    { 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 } },
+	{ 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 } },
+};
+
+
+
+/******************\
+* RF2413 (Griffin) *
+\******************/
+
+/* BANK 6 				len  pos col */
+#define	AR5K_RF2413_OB_2GHZ		{ 3, 168, 0 }
+#define	AR5K_RF2413_DB_2GHZ		{ 3, 165, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2413[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2413_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2413_DB_2GHZ},
+};
+
+/* Default mode specific settings
+ * XXX: a/aTurbo ???
+ */
+static const struct ath5k_ini_rfbuffer rfb_2413[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 } },
+	{ 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,
+	    { 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 } },
+	{ 6, 0x989c,
+	    { 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 } },
+	{ 6, 0x989c,
+	    { 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 } },
+	{ 6, 0x989c,
+	    { 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 } },
+	{ 6, 0x989c,
+	    { 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 } },
+	{ 6, 0x989c,
+	    { 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 } },
+	{ 6, 0x989c,
+	    { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
+	{ 6, 0x989c,
+	    { 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 } },
+	{ 6, 0x989c,
+	    { 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 } },
+	{ 6, 0x989c,
+	    { 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 } },
+	{ 6, 0x989c,
+	    { 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 } },
+	{ 6, 0x989c,
+	    { 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f } },
+	{ 6, 0x989c,
+	    { 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 } },
+	{ 6, 0x98d8,
+	    { 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/***************************\
+* RF2315/RF2316 (Cobra SoC) *
+\***************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF2316_OB_2GHZ		{ 3, 178, 0 }
+#define	AR5K_RF2316_DB_2GHZ		{ 3, 175, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2316[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2316_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2316_DB_2GHZ},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_2316[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 } },
+	{ 6, 0x989c,
+	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
+	{ 6, 0x989c,
+	    { 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 } },
+	{ 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,
+	    { 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 } },
+	{ 6, 0x989c,
+	    { 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 } },
+	{ 6, 0x989c,
+	    { 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 } },
+	{ 6, 0x989c,
+	    { 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 } },
+	{ 6, 0x989c,
+	    { 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 } },
+	{ 6, 0x989c,
+	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
+	{ 6, 0x989c,
+	    { 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 } },
+	{ 6, 0x989c,
+	    { 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 } },
+	{ 6, 0x989c,
+	    { 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 } },
+	{ 6, 0x989c,
+	    { 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 } },
+	{ 6, 0x989c,
+	    { 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d } },
+	{ 6, 0x989c,
+	    { 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 } },
+	{ 6, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 6, 0x989c,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 6, 0x989c,
+	    { 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 } },
+	{ 6, 0x989c,
+	    { 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 } },
+	{ 6, 0x98c0,
+	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/******************************\
+* RF5413/RF5424 (Eagle/Condor) *
+\******************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5413_OB_2GHZ		{ 3, 241, 0 }
+#define	AR5K_RF5413_DB_2GHZ		{ 3, 238, 0 }
+
+#define	AR5K_RF5413_OB_5GHZ		{ 3, 247, 0 }
+#define	AR5K_RF5413_DB_5GHZ		{ 3, 244, 0 }
+
+#define	AR5K_RF5413_PWD_ICLOBUF2G	{ 3, 131, 3 }
+#define	AR5K_RF5413_DERBY_CHAN_SEL_MODE	{ 1, 291, 2 }
+
+static const struct ath5k_rf_reg rf_regs_5413[] = {
+	{6, AR5K_RF_OB_2GHZ,		 AR5K_RF5413_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		 AR5K_RF5413_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		 AR5K_RF5413_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		 AR5K_RF5413_DB_5GHZ},
+	{6, AR5K_RF_PWD_ICLOBUF_2G,	 AR5K_RF5413_PWD_ICLOBUF2G},
+	{6, AR5K_RF_DERBY_CHAN_SEL_MODE, AR5K_RF5413_DERBY_CHAN_SEL_MODE},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_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, 0x00510040, 0x00510040, 0x00510040 } },
+	{ 6, 0x989c,
+	    { 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 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, 0x00002c00 } },
+	{ 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 } },
+};
+
+
+
+/***************************\
+* RF2425/RF2417 (Swan/Nala) *
+* AR2317 (Spider SoC)       *
+\***************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF2425_OB_2GHZ		{ 3, 193, 0 }
+#define	AR5K_RF2425_DB_2GHZ		{ 3, 190, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2425[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2425_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2425_DB_2GHZ},
+};
+
+/* Default mode specific settings
+ * XXX: a/aTurbo ?
+ */
+static const struct ath5k_ini_rfbuffer rfb_2425[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 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,
+	    { 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,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+/*
+ * TODO: Handle the few differences with swan during
+ * bank modification and get rid of this
+ */
+static const struct ath5k_ini_rfbuffer rfb_2317[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 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,
+	    { 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,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00009688, 0x00009688, 0x00009688, 0x00009688, 0x00009688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+/*
+ * TODO: Handle the few differences with swan during
+ * bank modification and get rid of this
+ * XXX: a/aTurbo ?
+ */
+static const struct ath5k_ini_rfbuffer rfb_2417[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 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,
+	    { 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,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
diff --git a/drivers/net/wireless/ath5k/rfgain.h b/drivers/net/wireless/ath5k/rfgain.h
new file mode 100644
index 0000000..1354d8c
--- /dev/null
+++ b/drivers/net/wireless/ath5k/rfgain.h
@@ -0,0 +1,516 @@
+/*
+ * RF Gain optimization
+ *
+ * Copyright (c) 2004-2009 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2009 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.
+ *
+ */
+
+/*
+ * 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)] */
+};
+
+/* 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 } },
+};
+
+/* 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 RF2413 */
+static const struct ath5k_ini_rfgain rfgain_2413[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x00000181 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000001c1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x00000001 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000041 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000081 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000168 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x000001a8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x000001e8 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x00000028 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000068 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000189 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000001c9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x00000009 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x00000049 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000089 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x00000190 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x000001d0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x00000010 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x00000050 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000090 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x00000191 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000001d1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x00000011 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x00000051 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x00000091 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x00000178 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x000001b8 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x000001f8 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x00000038 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x00000078 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x00000199 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x000001d9 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x00000019 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x00000059 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x00000099 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000d9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f9 } },
+};
+
+/* Initial RF Gain settings for AR2316 */
+static const struct ath5k_ini_rfgain rfgain_2316[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x000000c0 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000000e0 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x000000e0 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x00000168 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x000001a8 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x000001e8 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000028 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000068 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000000a8 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x000000e8 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x000000e8 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000130 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x00000130 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x00000170 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x000001b0 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x000001f0 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000030 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x00000070 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000000b0 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f0 } },
+};
+
+
+/* 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 } },
+};
+
+
+/* Initial RF Gain settings for RF2425 */
+static const struct ath5k_ini_rfgain rfgain_2425[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x00000181 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000001c1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x00000001 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000041 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000081 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000188 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x000001c8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x00000008 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x00000048 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000088 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000189 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000001c9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x00000009 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x00000049 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000089 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x000001b0 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x000001f0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x00000030 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x00000070 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000171 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x000001b1 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000001f1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x00000031 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x00000071 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x000001b8 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x000001f8 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x00000038 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x00000078 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x000000b8 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x000001b9 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x000001f9 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x00000039 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x00000079 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x000000b9 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f9 } },
+};
+
+#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
+
+/* Check if our current measurement is inside our
+ * current variable attenuation window */
+#define AR5K_GAIN_CHECK_ADJUST(_g) 		\
+	((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
+
+struct ath5k_gain_opt_step {
+	s8				gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
+	s8				gos_gain;
+};
+
+struct ath5k_gain_opt {
+	u8				go_default;
+	u8				go_steps_count;
+	const struct ath5k_gain_opt_step	go_step[AR5K_GAIN_STEP_COUNT];
+};
+
+/*
+ * Parameters on gos_param:
+ * 1) Tx clip PHY register
+ * 2) PWD 90 RF register
+ * 3) PWD 84 RF register
+ * 4) RFGainSel RF register
+ */
+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 }
+	}
+};
+
+/*
+ * Parameters on gos_param:
+ * 1) Mixgain ovr RF register
+ * 2) PWD 138 RF register
+ * 3) PWD 137 RF register
+ * 4) PWD 136 RF register
+ * 5) PWD 132 RF register
+ * 6) PWD 131 RF register
+ * 7) PWD 130 RF register
+ */
+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 },
+	}
+};
+
diff --git a/drivers/net/wireless/ath9k/ahb.c b/drivers/net/wireless/ath9k/ahb.c
index 7f2c3a0..391c9fd 100644
--- a/drivers/net/wireless/ath9k/ahb.c
+++ b/drivers/net/wireless/ath9k/ahb.c
@@ -19,9 +19,7 @@
 #include <linux/nl80211.h>
 #include <linux/platform_device.h>
 #include <linux/ath9k_platform.h>
-#include "core.h"
-#include "reg.h"
-#include "hw.h"
+#include "ath9k.h"
 
 /* return bus cachesize in 4B word units */
 static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz)
@@ -34,7 +32,7 @@
 	iounmap(sc->mem);
 }
 
-static bool ath_ahb_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
+static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
 {
 	struct ath_softc *sc = ah->ah_sc;
 	struct platform_device *pdev = to_platform_device(sc->dev);
@@ -67,7 +65,7 @@
 	struct resource *res;
 	int irq;
 	int ret = 0;
-	struct ath_hal *ah;
+	struct ath_hw *ah;
 
 	if (!pdev->dev.platform_data) {
 		dev_err(&pdev->dev, "no platform data specified\n");
@@ -134,10 +132,10 @@
 	       "%s: Atheros AR%s MAC/BB Rev:%x, "
 	       "AR%s RF Rev:%x, mem=0x%lx, irq=%d\n",
 	       wiphy_name(hw->wiphy),
-	       ath_mac_bb_name(ah->ah_macVersion),
-	       ah->ah_macRev,
-	       ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
-	       ah->ah_phyRev,
+	       ath_mac_bb_name(ah->hw_version.macVersion),
+	       ah->hw_version.macRev,
+	       ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)),
+	       ah->hw_version.phyRev,
 	       (unsigned long)mem, irq);
 
 	return 0;
diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c
index 42197ff..d4df7e6 100644
--- a/drivers/net/wireless/ath9k/ani.c
+++ b/drivers/net/wireless/ath9k/ani.c
@@ -14,23 +14,19 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
-#include "hw.h"
-#include "reg.h"
-#include "phy.h"
+#include "ath9k.h"
 
-static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
+static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
 					struct ath9k_channel *chan)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
-		if (ahp->ah_ani[i].c.channel == chan->channel)
+	for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
+		if (ah->ani[i].c &&
+		    ah->ani[i].c->channel == chan->channel)
 			return i;
-		if (ahp->ah_ani[i].c.channel == 0) {
-			ahp->ah_ani[i].c.channel = chan->channel;
-			ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
+		if (ah->ani[i].c == NULL) {
+			ah->ani[i].c = chan;
 			return i;
 		}
 	}
@@ -41,41 +37,40 @@
 	return 0;
 }
 
-static bool ath9k_hw_ani_control(struct ath_hal *ah,
+static bool ath9k_hw_ani_control(struct ath_hw *ah,
 				 enum ath9k_ani_cmd cmd, int param)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416AniState *aniState = ahp->ah_curani;
+	struct ar5416AniState *aniState = ah->curani;
 
-	switch (cmd & ahp->ah_ani_function) {
+	switch (cmd & ah->ani_function) {
 	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
 		u32 level = param;
 
-		if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
+		if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
 			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
 				"level out of range (%u > %u)\n",
 				level,
-				(unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired));
+				(unsigned)ARRAY_SIZE(ah->totalSizeDesired));
 			return false;
 		}
 
 		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
 			      AR_PHY_DESIRED_SZ_TOT_DES,
-			      ahp->ah_totalSizeDesired[level]);
+			      ah->totalSizeDesired[level]);
 		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
 			      AR_PHY_AGC_CTL1_COARSE_LOW,
-			      ahp->ah_coarseLow[level]);
+			      ah->coarse_low[level]);
 		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
 			      AR_PHY_AGC_CTL1_COARSE_HIGH,
-			      ahp->ah_coarseHigh[level]);
+			      ah->coarse_high[level]);
 		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
 			      AR_PHY_FIND_SIG_FIRPWR,
-			      ahp->ah_firpwr[level]);
+			      ah->firpwr[level]);
 
 		if (level > aniState->noiseImmunityLevel)
-			ahp->ah_stats.ast_ani_niup++;
+			ah->stats.ast_ani_niup++;
 		else if (level < aniState->noiseImmunityLevel)
-			ahp->ah_stats.ast_ani_nidown++;
+			ah->stats.ast_ani_nidown++;
 		aniState->noiseImmunityLevel = level;
 		break;
 	}
@@ -129,9 +124,9 @@
 
 		if (!on != aniState->ofdmWeakSigDetectOff) {
 			if (on)
-				ahp->ah_stats.ast_ani_ofdmon++;
+				ah->stats.ast_ani_ofdmon++;
 			else
-				ahp->ah_stats.ast_ani_ofdmoff++;
+				ah->stats.ast_ani_ofdmoff++;
 			aniState->ofdmWeakSigDetectOff = !on;
 		}
 		break;
@@ -145,9 +140,9 @@
 			      weakSigThrCck[high]);
 		if (high != aniState->cckWeakSigThreshold) {
 			if (high)
-				ahp->ah_stats.ast_ani_cckhigh++;
+				ah->stats.ast_ani_cckhigh++;
 			else
-				ahp->ah_stats.ast_ani_ccklow++;
+				ah->stats.ast_ani_ccklow++;
 			aniState->cckWeakSigThreshold = high;
 		}
 		break;
@@ -167,9 +162,9 @@
 			      AR_PHY_FIND_SIG_FIRSTEP,
 			      firstep[level]);
 		if (level > aniState->firstepLevel)
-			ahp->ah_stats.ast_ani_stepup++;
+			ah->stats.ast_ani_stepup++;
 		else if (level < aniState->firstepLevel)
-			ahp->ah_stats.ast_ani_stepdown++;
+			ah->stats.ast_ani_stepdown++;
 		aniState->firstepLevel = level;
 		break;
 	}
@@ -190,9 +185,9 @@
 			      AR_PHY_TIMING5_CYCPWR_THR1,
 			      cycpwrThr1[level]);
 		if (level > aniState->spurImmunityLevel)
-			ahp->ah_stats.ast_ani_spurup++;
+			ah->stats.ast_ani_spurup++;
 		else if (level < aniState->spurImmunityLevel)
-			ahp->ah_stats.ast_ani_spurdown++;
+			ah->stats.ast_ani_spurdown++;
 		aniState->spurImmunityLevel = level;
 		break;
 	}
@@ -223,7 +218,7 @@
 	return true;
 }
 
-static void ath9k_hw_update_mibstats(struct ath_hal *ah,
+static void ath9k_hw_update_mibstats(struct ath_hw *ah,
 				     struct ath9k_mib_stats *stats)
 {
 	stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
@@ -233,18 +228,17 @@
 	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
 }
 
-static void ath9k_ani_restart(struct ath_hal *ah)
+static void ath9k_ani_restart(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ar5416AniState *aniState;
 
 	if (!DO_ANI(ah))
 		return;
 
-	aniState = ahp->ah_curani;
+	aniState = ah->curani;
 
 	aniState->listenTime = 0;
-	if (ahp->ah_hasHwPhyCounters) {
+	if (ah->has_hw_phycounters) {
 		if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
 			aniState->ofdmPhyErrBase = 0;
 			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
@@ -270,15 +264,14 @@
 		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
-		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+		ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 	}
 	aniState->ofdmPhyErrCount = 0;
 	aniState->cckPhyErrCount = 0;
 }
 
-static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
 	struct ar5416AniState *aniState;
 	int32_t rssi;
@@ -286,7 +279,7 @@
 	if (!DO_ANI(ah))
 		return;
 
-	aniState = ahp->ah_curani;
+	aniState = ah->curani;
 
 	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
@@ -302,14 +295,14 @@
 		}
 	}
 
-	if (ah->ah_opmode == NL80211_IFTYPE_AP) {
+	if (ah->opmode == NL80211_IFTYPE_AP) {
 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
 			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 					     aniState->firstepLevel + 1);
 		}
 		return;
 	}
-	rssi = BEACON_RSSI(ahp);
+	rssi = BEACON_RSSI(ah);
 	if (rssi > aniState->rssiThrHigh) {
 		if (!aniState->ofdmWeakSigDetectOff) {
 			if (ath9k_hw_ani_control(ah,
@@ -348,9 +341,8 @@
 	}
 }
 
-static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
+static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
 	struct ar5416AniState *aniState;
 	int32_t rssi;
@@ -358,21 +350,21 @@
 	if (!DO_ANI(ah))
 		return;
 
-	aniState = ahp->ah_curani;
+	aniState = ah->curani;
 	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
 		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 					 aniState->noiseImmunityLevel + 1)) {
 			return;
 		}
 	}
-	if (ah->ah_opmode == NL80211_IFTYPE_AP) {
+	if (ah->opmode == NL80211_IFTYPE_AP) {
 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
 			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 					     aniState->firstepLevel + 1);
 		}
 		return;
 	}
-	rssi = BEACON_RSSI(ahp);
+	rssi = BEACON_RSSI(ah);
 	if (rssi > aniState->rssiThrLow) {
 		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
 			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
@@ -386,22 +378,21 @@
 	}
 }
 
-static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
+static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ar5416AniState *aniState;
 	int32_t rssi;
 
-	aniState = ahp->ah_curani;
+	aniState = ah->curani;
 
-	if (ah->ah_opmode == NL80211_IFTYPE_AP) {
+	if (ah->opmode == NL80211_IFTYPE_AP) {
 		if (aniState->firstepLevel > 0) {
 			if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 						 aniState->firstepLevel - 1))
 				return;
 		}
 	} else {
-		rssi = BEACON_RSSI(ahp);
+		rssi = BEACON_RSSI(ah);
 		if (rssi > aniState->rssiThrHigh) {
 			/* XXX: Handle me */
 		} else if (rssi > aniState->rssiThrLow) {
@@ -440,9 +431,8 @@
 	}
 }
 
-static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
+static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ar5416AniState *aniState;
 	u32 txFrameCount, rxFrameCount, cycleCount;
 	int32_t listenTime;
@@ -451,11 +441,11 @@
 	rxFrameCount = REG_READ(ah, AR_RFCNT);
 	cycleCount = REG_READ(ah, AR_CCCNT);
 
-	aniState = ahp->ah_curani;
+	aniState = ah->curani;
 	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
 
 		listenTime = 0;
-		ahp->ah_stats.ast_ani_lzero++;
+		ah->stats.ast_ani_lzero++;
 	} else {
 		int32_t ccdelta = cycleCount - aniState->cycleCount;
 		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
@@ -469,25 +459,24 @@
 	return listenTime;
 }
 
-void ath9k_ani_reset(struct ath_hal *ah)
+void ath9k_ani_reset(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ar5416AniState *aniState;
-	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ath9k_channel *chan = ah->curchan;
 	int index;
 
 	if (!DO_ANI(ah))
 		return;
 
 	index = ath9k_hw_get_ani_channel_idx(ah, chan);
-	aniState = &ahp->ah_ani[index];
-	ahp->ah_curani = aniState;
+	aniState = &ah->ani[index];
+	ah->curani = aniState;
 
-	if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION
-	    && ah->ah_opmode != NL80211_IFTYPE_ADHOC) {
+	if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
+	    && ah->opmode != NL80211_IFTYPE_ADHOC) {
 		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-			"Reset ANI state opmode %u\n", ah->ah_opmode);
-		ahp->ah_stats.ast_ani_reset++;
+			"Reset ANI state opmode %u\n", ah->opmode);
+		ah->stats.ast_ani_reset++;
 
 		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
 		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
@@ -500,15 +489,15 @@
 		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
 				     ATH9K_RX_FILTER_PHYERR);
 
-		if (ah->ah_opmode == NL80211_IFTYPE_AP) {
-			ahp->ah_curani->ofdmTrigHigh =
-				ah->ah_config.ofdm_trig_high;
-			ahp->ah_curani->ofdmTrigLow =
-				ah->ah_config.ofdm_trig_low;
-			ahp->ah_curani->cckTrigHigh =
-				ah->ah_config.cck_trig_high;
-			ahp->ah_curani->cckTrigLow =
-				ah->ah_config.cck_trig_low;
+		if (ah->opmode == NL80211_IFTYPE_AP) {
+			ah->curani->ofdmTrigHigh =
+				ah->config.ofdm_trig_high;
+			ah->curani->ofdmTrigLow =
+				ah->config.ofdm_trig_low;
+			ah->curani->cckTrigHigh =
+				ah->config.cck_trig_high;
+			ah->curani->cckTrigLow =
+				ah->config.cck_trig_low;
 		}
 		ath9k_ani_restart(ah);
 		return;
@@ -529,7 +518,7 @@
 	if (aniState->firstepLevel != 0)
 		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 				     aniState->firstepLevel);
-	if (ahp->ah_hasHwPhyCounters) {
+	if (ah->has_hw_phycounters) {
 		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
 				     ~ATH9K_RX_FILTER_PHYERR);
 		ath9k_ani_restart(ah);
@@ -543,34 +532,33 @@
 	}
 }
 
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
+void ath9k_hw_ani_monitor(struct ath_hw *ah,
 			  const struct ath9k_node_stats *stats,
 			  struct ath9k_channel *chan)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ar5416AniState *aniState;
 	int32_t listenTime;
 
 	if (!DO_ANI(ah))
 		return;
 
-	aniState = ahp->ah_curani;
-	ahp->ah_stats.ast_nodestats = *stats;
+	aniState = ah->curani;
+	ah->stats.ast_nodestats = *stats;
 
 	listenTime = ath9k_hw_ani_get_listen_time(ah);
 	if (listenTime < 0) {
-		ahp->ah_stats.ast_ani_lneg++;
+		ah->stats.ast_ani_lneg++;
 		ath9k_ani_restart(ah);
 		return;
 	}
 
 	aniState->listenTime += listenTime;
 
-	if (ahp->ah_hasHwPhyCounters) {
+	if (ah->has_hw_phycounters) {
 		u32 phyCnt1, phyCnt2;
 		u32 ofdmPhyErrCnt, cckPhyErrCnt;
 
-		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+		ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
 		phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
 		phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
@@ -603,24 +591,24 @@
 		}
 
 		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
-		ahp->ah_stats.ast_ani_ofdmerrs +=
+		ah->stats.ast_ani_ofdmerrs +=
 			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
 		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
 
 		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
-		ahp->ah_stats.ast_ani_cckerrs +=
+		ah->stats.ast_ani_cckerrs +=
 			cckPhyErrCnt - aniState->cckPhyErrCount;
 		aniState->cckPhyErrCount = cckPhyErrCnt;
 	}
 
-	if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
+	if (aniState->listenTime > 5 * ah->aniperiod) {
 		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
 		    aniState->ofdmTrigLow / 1000 &&
 		    aniState->cckPhyErrCount <= aniState->listenTime *
 		    aniState->cckTrigLow / 1000)
 			ath9k_hw_ani_lower_immunity(ah);
 		ath9k_ani_restart(ah);
-	} else if (aniState->listenTime > ahp->ah_aniPeriod) {
+	} else if (aniState->listenTime > ah->aniperiod) {
 		if (aniState->ofdmPhyErrCount > aniState->listenTime *
 		    aniState->ofdmTrigHigh / 1000) {
 			ath9k_hw_ani_ofdm_err_trigger(ah);
@@ -634,20 +622,16 @@
 	}
 }
 
-bool ath9k_hw_phycounters(struct ath_hal *ah)
+bool ath9k_hw_phycounters(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	return ahp->ah_hasHwPhyCounters ? true : false;
+	return ah->has_hw_phycounters ? true : false;
 }
 
-void ath9k_enable_mib_counters(struct ath_hal *ah)
+void ath9k_enable_mib_counters(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
 
-	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
 	REG_WRITE(ah, AR_FILT_OFDM, 0);
 	REG_WRITE(ah, AR_FILT_CCK, 0);
@@ -658,21 +642,19 @@
 	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 }
 
-void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
+void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
 
 	REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
 
-	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
 	REG_WRITE(ah, AR_FILT_OFDM, 0);
 	REG_WRITE(ah, AR_FILT_CCK, 0);
 }
 
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
 				  u32 *rxc_pcnt,
 				  u32 *rxf_pcnt,
 				  u32 *txf_pcnt)
@@ -717,10 +699,9 @@
  * any of the MIB counters overflow/trigger so don't assume we're
  * here because a PHY error counter triggered.
  */
-void ath9k_hw_procmibevent(struct ath_hal *ah,
+void ath9k_hw_procmibevent(struct ath_hw *ah,
 			   const struct ath9k_node_stats *stats)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	u32 phyCnt1, phyCnt2;
 
 	/* Reset these counters regardless */
@@ -730,8 +711,8 @@
 		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
 
 	/* Clear the mib counters and save them in the stats */
-	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-	ahp->ah_stats.ast_nodestats = *stats;
+	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+	ah->stats.ast_nodestats = *stats;
 
 	if (!DO_ANI(ah))
 		return;
@@ -741,17 +722,17 @@
 	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
 	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
-		struct ar5416AniState *aniState = ahp->ah_curani;
+		struct ar5416AniState *aniState = ah->curani;
 		u32 ofdmPhyErrCnt, cckPhyErrCnt;
 
 		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
 		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
-		ahp->ah_stats.ast_ani_ofdmerrs +=
+		ah->stats.ast_ani_ofdmerrs +=
 			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
 		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
 
 		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
-		ahp->ah_stats.ast_ani_cckerrs +=
+		ah->stats.ast_ani_cckerrs +=
 			cckPhyErrCnt - aniState->cckPhyErrCount;
 		aniState->cckPhyErrCount = cckPhyErrCnt;
 
@@ -770,9 +751,8 @@
 	}
 }
 
-void ath9k_hw_ani_setup(struct ath_hal *ah)
+void ath9k_hw_ani_setup(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
 
 	const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
@@ -781,66 +761,63 @@
 	const int firpwr[] = { -78, -78, -78, -78, -80 };
 
 	for (i = 0; i < 5; i++) {
-		ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
-		ahp->ah_coarseHigh[i] = coarseHigh[i];
-		ahp->ah_coarseLow[i] = coarseLow[i];
-		ahp->ah_firpwr[i] = firpwr[i];
+		ah->totalSizeDesired[i] = totalSizeDesired[i];
+		ah->coarse_high[i] = coarseHigh[i];
+		ah->coarse_low[i] = coarseLow[i];
+		ah->firpwr[i] = firpwr[i];
 	}
 }
 
-void ath9k_hw_ani_attach(struct ath_hal *ah)
+void ath9k_hw_ani_attach(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
 
 	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
 
-	ahp->ah_hasHwPhyCounters = 1;
+	ah->has_hw_phycounters = 1;
 
-	memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
-	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
-		ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
-		ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
-		ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
-		ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
-		ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
-		ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
-		ahp->ah_ani[i].ofdmWeakSigDetectOff =
+	memset(ah->ani, 0, sizeof(ah->ani));
+	for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
+		ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
+		ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
+		ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
+		ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
+		ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+		ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+		ah->ani[i].ofdmWeakSigDetectOff =
 			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
-		ahp->ah_ani[i].cckWeakSigThreshold =
+		ah->ani[i].cckWeakSigThreshold =
 			ATH9K_ANI_CCK_WEAK_SIG_THR;
-		ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
-		ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
-		if (ahp->ah_hasHwPhyCounters) {
-			ahp->ah_ani[i].ofdmPhyErrBase =
+		ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+		ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+		if (ah->has_hw_phycounters) {
+			ah->ani[i].ofdmPhyErrBase =
 				AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
-			ahp->ah_ani[i].cckPhyErrBase =
+			ah->ani[i].cckPhyErrBase =
 				AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
 		}
 	}
-	if (ahp->ah_hasHwPhyCounters) {
+	if (ah->has_hw_phycounters) {
 		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
 			"Setting OfdmErrBase = 0x%08x\n",
-			ahp->ah_ani[0].ofdmPhyErrBase);
+			ah->ani[0].ofdmPhyErrBase);
 		DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
-			ahp->ah_ani[0].cckPhyErrBase);
+			ah->ani[0].cckPhyErrBase);
 
-		REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
-		REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
 		ath9k_enable_mib_counters(ah);
 	}
-	ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
-	if (ah->ah_config.enable_ani)
-		ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
+	ah->aniperiod = ATH9K_ANI_PERIOD;
+	if (ah->config.enable_ani)
+		ah->proc_phyerr |= HAL_PROCESS_ANI;
 }
 
-void ath9k_hw_ani_detach(struct ath_hal *ah)
+void ath9k_hw_ani_detach(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
 
-	if (ahp->ah_hasHwPhyCounters) {
+	if (ah->has_hw_phycounters) {
 		ath9k_hw_disable_mib_counters(ah);
 		REG_WRITE(ah, AR_PHY_ERR_1, 0);
 		REG_WRITE(ah, AR_PHY_ERR_2, 0);
diff --git a/drivers/net/wireless/ath9k/ani.h b/drivers/net/wireless/ath9k/ani.h
new file mode 100644
index 0000000..7315761
--- /dev/null
+++ b/drivers/net/wireless/ath9k/ani.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ANI_H
+#define ANI_H
+
+#define HAL_PROCESS_ANI           0x00000001
+#define ATH9K_RSSI_EP_MULTIPLIER  (1<<7)
+
+#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI))
+
+#define HAL_EP_RND(x, mul)						\
+	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+#define BEACON_RSSI(ahp)					\
+	HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi,	\
+		   ATH9K_RSSI_EP_MULTIPLIER)
+
+#define ATH9K_ANI_OFDM_TRIG_HIGH          500
+#define ATH9K_ANI_OFDM_TRIG_LOW           200
+#define ATH9K_ANI_CCK_TRIG_HIGH           200
+#define ATH9K_ANI_CCK_TRIG_LOW            100
+#define ATH9K_ANI_NOISE_IMMUNE_LVL        4
+#define ATH9K_ANI_USE_OFDM_WEAK_SIG       true
+#define ATH9K_ANI_CCK_WEAK_SIG_THR        false
+#define ATH9K_ANI_SPUR_IMMUNE_LVL         7
+#define ATH9K_ANI_FIRSTEP_LVL             0
+#define ATH9K_ANI_RSSI_THR_HIGH           40
+#define ATH9K_ANI_RSSI_THR_LOW            7
+#define ATH9K_ANI_PERIOD                  100
+
+#define HAL_NOISE_IMMUNE_MAX              4
+#define HAL_SPUR_IMMUNE_MAX               7
+#define HAL_FIRST_STEP_MAX                2
+
+enum ath9k_ani_cmd {
+	ATH9K_ANI_PRESENT = 0x1,
+	ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
+	ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4,
+	ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8,
+	ATH9K_ANI_FIRSTEP_LEVEL = 0x10,
+	ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
+	ATH9K_ANI_MODE = 0x40,
+	ATH9K_ANI_PHYERR_RESET = 0x80,
+	ATH9K_ANI_ALL = 0xff
+};
+
+struct ath9k_mib_stats {
+	u32 ackrcv_bad;
+	u32 rts_bad;
+	u32 rts_good;
+	u32 fcs_bad;
+	u32 beacons;
+};
+
+struct ath9k_node_stats {
+	u32 ns_avgbrssi;
+	u32 ns_avgrssi;
+	u32 ns_avgtxrssi;
+	u32 ns_avgtxrate;
+};
+
+struct ar5416AniState {
+	struct ath9k_channel *c;
+	u8 noiseImmunityLevel;
+	u8 spurImmunityLevel;
+	u8 firstepLevel;
+	u8 ofdmWeakSigDetectOff;
+	u8 cckWeakSigThreshold;
+	u32 listenTime;
+	u32 ofdmTrigHigh;
+	u32 ofdmTrigLow;
+	int32_t cckTrigHigh;
+	int32_t cckTrigLow;
+	int32_t rssiThrLow;
+	int32_t rssiThrHigh;
+	u32 noiseFloor;
+	u32 txFrameCount;
+	u32 rxFrameCount;
+	u32 cycleCount;
+	u32 ofdmPhyErrCount;
+	u32 cckPhyErrCount;
+	u32 ofdmPhyErrBase;
+	u32 cckPhyErrBase;
+	int16_t pktRssi[2];
+	int16_t ofdmErrRssi[2];
+	int16_t cckErrRssi[2];
+};
+
+struct ar5416Stats {
+	u32 ast_ani_niup;
+	u32 ast_ani_nidown;
+	u32 ast_ani_spurup;
+	u32 ast_ani_spurdown;
+	u32 ast_ani_ofdmon;
+	u32 ast_ani_ofdmoff;
+	u32 ast_ani_cckhigh;
+	u32 ast_ani_ccklow;
+	u32 ast_ani_stepup;
+	u32 ast_ani_stepdown;
+	u32 ast_ani_ofdmerrs;
+	u32 ast_ani_cckerrs;
+	u32 ast_ani_reset;
+	u32 ast_ani_lzero;
+	u32 ast_ani_lneg;
+	struct ath9k_mib_stats ast_mibstats;
+	struct ath9k_node_stats ast_nodestats;
+};
+#define ah_mibStats stats.ast_mibstats
+
+void ath9k_ani_reset(struct ath_hw *ah);
+void ath9k_hw_ani_monitor(struct ath_hw *ah,
+			  const struct ath9k_node_stats *stats,
+			  struct ath9k_channel *chan);
+bool ath9k_hw_phycounters(struct ath_hw *ah);
+void ath9k_enable_mib_counters(struct ath_hw *ah);
+void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
+				  u32 *rxf_pcnt, u32 *txf_pcnt);
+void ath9k_hw_procmibevent(struct ath_hw *ah,
+			   const struct ath9k_node_stats *stats);
+void ath9k_hw_ani_setup(struct ath_hw *ah);
+void ath9k_hw_ani_attach(struct ath_hw *ah);
+void ath9k_hw_ani_detach(struct ath_hw *ah);
+
+#endif /* ANI_H */
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 5289d28..0b0f82c 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -17,1028 +17,670 @@
 #ifndef ATH9K_H
 #define ATH9K_H
 
-#include <linux/io.h>
+#include <linux/etherdevice.h>
+#include <linux/device.h>
+#include <net/mac80211.h>
+#include <linux/leds.h>
+#include <linux/rfkill.h>
 
-#define ATHEROS_VENDOR_ID	0x168c
+#include "hw.h"
+#include "rc.h"
+#include "debug.h"
 
-#define AR5416_DEVID_PCI	0x0023
-#define AR5416_DEVID_PCIE	0x0024
-#define AR9160_DEVID_PCI	0x0027
-#define AR9280_DEVID_PCI	0x0029
-#define AR9280_DEVID_PCIE	0x002a
-#define AR9285_DEVID_PCIE	0x002b
+struct ath_node;
 
-#define AR5416_AR9100_DEVID	0x000b
+/* Macro to expand scalars to 64-bit objects */
 
-#define	AR_SUBVENDOR_ID_NOG	0x0e11
-#define AR_SUBVENDOR_ID_NEW_A	0x7065
+#define	ito64(x) (sizeof(x) == 8) ?			\
+	(((unsigned long long int)(x)) & (0xff)) :	\
+	(sizeof(x) == 16) ?				\
+	(((unsigned long long int)(x)) & 0xffff) :	\
+	((sizeof(x) == 32) ?				\
+	 (((unsigned long long int)(x)) & 0xffffffff) : \
+	 (unsigned long long int)(x))
 
-#define ATH9K_TXERR_XRETRY         0x01
-#define ATH9K_TXERR_FILT           0x02
-#define ATH9K_TXERR_FIFO           0x04
-#define ATH9K_TXERR_XTXOP          0x08
-#define ATH9K_TXERR_TIMER_EXPIRED  0x10
+/* increment with wrap-around */
+#define INCR(_l, _sz)   do {			\
+		(_l)++;				\
+		(_l) &= ((_sz) - 1);		\
+	} while (0)
 
-#define ATH9K_TX_BA                0x01
-#define ATH9K_TX_PWRMGMT           0x02
-#define ATH9K_TX_DESC_CFG_ERR      0x04
-#define ATH9K_TX_DATA_UNDERRUN     0x08
-#define ATH9K_TX_DELIM_UNDERRUN    0x10
-#define ATH9K_TX_SW_ABORTED        0x40
-#define ATH9K_TX_SW_FILTERED       0x80
+/* decrement with wrap-around */
+#define DECR(_l,  _sz)  do {			\
+		(_l)--;				\
+		(_l) &= ((_sz) - 1);		\
+	} while (0)
 
-#define NBBY    8
+#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
 
-struct ath_tx_status {
-	u32 ts_tstamp;
-	u16 ts_seqnum;
-	u8 ts_status;
-	u8 ts_ratecode;
-	u8 ts_rateindex;
-	int8_t ts_rssi;
-	u8 ts_shortretry;
-	u8 ts_longretry;
-	u8 ts_virtcol;
-	u8 ts_antenna;
-	u8 ts_flags;
-	int8_t ts_rssi_ctl0;
-	int8_t ts_rssi_ctl1;
-	int8_t ts_rssi_ctl2;
-	int8_t ts_rssi_ext0;
-	int8_t ts_rssi_ext1;
-	int8_t ts_rssi_ext2;
-	u8 pad[3];
-	u32 ba_low;
-	u32 ba_high;
-	u32 evm0;
-	u32 evm1;
-	u32 evm2;
+#define ASSERT(exp) do {			\
+		if (unlikely(!(exp))) {		\
+			BUG();			\
+		}				\
+	} while (0)
+
+#define TSF_TO_TU(_h,_l) \
+	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
+
+#define	ATH_TXQ_SETUP(sc, i)        ((sc)->tx.txqsetup & (1<<i))
+
+static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+struct ath_config {
+	u32 ath_aggr_prot;
+	u16 txpowlimit;
+	u8 cabqReadytime;
+	u8 swBeaconProcess;
 };
 
-struct ath_rx_status {
-	u32 rs_tstamp;
-	u16 rs_datalen;
-	u8 rs_status;
-	u8 rs_phyerr;
-	int8_t rs_rssi;
-	u8 rs_keyix;
-	u8 rs_rate;
-	u8 rs_antenna;
-	u8 rs_more;
-	int8_t rs_rssi_ctl0;
-	int8_t rs_rssi_ctl1;
-	int8_t rs_rssi_ctl2;
-	int8_t rs_rssi_ext0;
-	int8_t rs_rssi_ext1;
-	int8_t rs_rssi_ext2;
-	u8 rs_isaggr;
-	u8 rs_moreaggr;
-	u8 rs_num_delims;
-	u8 rs_flags;
-	u32 evm0;
-	u32 evm1;
-	u32 evm2;
+/*************************/
+/* Descriptor Management */
+/*************************/
+
+#define ATH_TXBUF_RESET(_bf) do {				\
+		(_bf)->bf_status = 0;				\
+		(_bf)->bf_lastbf = NULL;			\
+		(_bf)->bf_next = NULL;				\
+		memset(&((_bf)->bf_state), 0,			\
+		       sizeof(struct ath_buf_state));		\
+	} while (0)
+
+/**
+ * enum buffer_type - Buffer type flags
+ *
+ * @BUF_HT: Send this buffer using HT capabilities
+ * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
+ * @BUF_AGGR: Indicates whether the buffer can be aggregated
+ *	(used in aggregation scheduling)
+ * @BUF_RETRY: Indicates whether the buffer is retried
+ * @BUF_XRETRY: To denote excessive retries of the buffer
+ */
+enum buffer_type {
+	BUF_HT			= BIT(1),
+	BUF_AMPDU		= BIT(2),
+	BUF_AGGR		= BIT(3),
+	BUF_RETRY		= BIT(4),
+	BUF_XRETRY		= BIT(5),
 };
 
-#define ATH9K_RXERR_CRC           0x01
-#define ATH9K_RXERR_PHY           0x02
-#define ATH9K_RXERR_FIFO          0x04
-#define ATH9K_RXERR_DECRYPT       0x08
-#define ATH9K_RXERR_MIC           0x10
+struct ath_buf_state {
+	int bfs_nframes;
+	u16 bfs_al;
+	u16 bfs_frmlen;
+	int bfs_seqno;
+	int bfs_tidno;
+	int bfs_retries;
+	u32 bf_type;
+	u32 bfs_keyix;
+	enum ath9k_key_type bfs_keytype;
+};
 
-#define ATH9K_RX_MORE             0x01
-#define ATH9K_RX_MORE_AGGR        0x02
-#define ATH9K_RX_GI               0x04
-#define ATH9K_RX_2040             0x08
-#define ATH9K_RX_DELIM_CRC_PRE    0x10
-#define ATH9K_RX_DELIM_CRC_POST   0x20
-#define ATH9K_RX_DECRYPT_BUSY     0x40
+#define bf_nframes      	bf_state.bfs_nframes
+#define bf_al           	bf_state.bfs_al
+#define bf_frmlen       	bf_state.bfs_frmlen
+#define bf_retries      	bf_state.bfs_retries
+#define bf_seqno        	bf_state.bfs_seqno
+#define bf_tidno        	bf_state.bfs_tidno
+#define bf_keyix                bf_state.bfs_keyix
+#define bf_keytype      	bf_state.bfs_keytype
+#define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
+#define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
+#define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
+#define bf_isretried(bf)	(bf->bf_state.bf_type & BUF_RETRY)
+#define bf_isxretried(bf)	(bf->bf_state.bf_type & BUF_XRETRY)
 
-#define ATH9K_RXKEYIX_INVALID	((u8)-1)
-#define ATH9K_TXKEYIX_INVALID	((u32)-1)
+struct ath_buf {
+	struct list_head list;
+	struct ath_buf *bf_lastbf;	/* last buf of this unit (a frame or
+					   an aggregate) */
+	struct ath_buf *bf_next;	/* next subframe in the aggregate */
+	void *bf_mpdu;			/* enclosing frame structure */
+	struct ath_desc *bf_desc;	/* virtual addr of desc */
+	dma_addr_t bf_daddr;		/* physical addr of desc */
+	dma_addr_t bf_buf_addr;		/* physical addr of data buffer */
+	u32 bf_status;
+	u16 bf_flags;
+	struct ath_buf_state bf_state;
+	dma_addr_t bf_dmacontext;
+};
 
-struct ath_desc {
-	u32 ds_link;
-	u32 ds_data;
-	u32 ds_ctl0;
-	u32 ds_ctl1;
-	u32 ds_hw[20];
+#define ATH_RXBUF_RESET(_bf)    ((_bf)->bf_status = 0)
+#define ATH_BUFSTATUS_STALE     0x00000002
+
+struct ath_descdma {
+	const char *dd_name;
+	struct ath_desc *dd_desc;
+	dma_addr_t dd_desc_paddr;
+	u32 dd_desc_len;
+	struct ath_buf *dd_bufptr;
+	dma_addr_t dd_dmacontext;
+};
+
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+		      struct list_head *head, const char *name,
+		      int nbuf, int ndesc);
+void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
+			 struct list_head *head);
+
+/***********/
+/* RX / TX */
+/***********/
+
+#define ATH_MAX_ANTENNA         3
+#define ATH_RXBUF               512
+#define WME_NUM_TID             16
+#define ATH_TXBUF               512
+#define ATH_TXMAXTRY            13
+#define ATH_11N_TXMAXTRY        10
+#define ATH_MGT_TXMAXTRY        4
+#define WME_BA_BMP_SIZE         64
+#define WME_MAX_BA              WME_BA_BMP_SIZE
+#define ATH_TID_MAX_BUFS        (2 * WME_MAX_BA)
+
+#define TID_TO_WME_AC(_tid)				\
+	((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE :	\
+	 (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK :	\
+	 (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI :	\
+	 WME_AC_VO)
+
+#define WME_AC_BE   0
+#define WME_AC_BK   1
+#define WME_AC_VI   2
+#define WME_AC_VO   3
+#define WME_NUM_AC  4
+
+#define ADDBA_EXCHANGE_ATTEMPTS    10
+#define ATH_AGGR_DELIM_SZ          4
+#define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
+/* number of delimiters for encryption padding */
+#define ATH_AGGR_ENCRYPTDELIM      10
+/* minimum h/w qdepth to be sustained to maximize aggregation */
+#define ATH_AGGR_MIN_QDEPTH        2
+#define ATH_AMPDU_SUBFRAME_DEFAULT 32
+#define ATH_AMPDU_LIMIT_MAX        (64 * 1024 - 1)
+#define ATH_AMPDU_LIMIT_DEFAULT    ATH_AMPDU_LIMIT_MAX
+
+#define IEEE80211_SEQ_SEQ_SHIFT    4
+#define IEEE80211_SEQ_MAX          4096
+#define IEEE80211_MIN_AMPDU_BUF    0x8
+#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
+#define IEEE80211_WEP_IVLEN        3
+#define IEEE80211_WEP_KIDLEN       1
+#define IEEE80211_WEP_CRCLEN       4
+#define IEEE80211_MAX_MPDU_LEN     (3840 + FCS_LEN +		\
+				    (IEEE80211_WEP_IVLEN +	\
+				     IEEE80211_WEP_KIDLEN +	\
+				     IEEE80211_WEP_CRCLEN))
+
+/* return whether a bit at index _n in bitmap _bm is set
+ * _sz is the size of the bitmap  */
+#define ATH_BA_ISSET(_bm, _n)  (((_n) < (WME_BA_BMP_SIZE)) &&		\
+				((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
+
+/* return block-ack bitmap index given sequence and starting sequence */
+#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1))
+
+/* returns delimiter padding required given the packet length */
+#define ATH_AGGR_GET_NDELIM(_len)					\
+	(((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ?           \
+	  (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+	((((_seqno) - (_start)) & 4095) < (_bawsz))
+
+#define ATH_DS_BA_SEQ(_ds)         ((_ds)->ds_us.tx.ts_seqnum)
+#define ATH_DS_BA_BITMAP(_ds)      (&(_ds)->ds_us.tx.ba_low)
+#define ATH_DS_TX_BA(_ds)          ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
+#define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
+
+enum ATH_AGGR_STATUS {
+	ATH_AGGR_DONE,
+	ATH_AGGR_BAW_CLOSED,
+	ATH_AGGR_LIMITED,
+};
+
+struct ath_txq {
+	u32 axq_qnum;
+	u32 *axq_link;
+	struct list_head axq_q;
+	spinlock_t axq_lock;
+	u32 axq_depth;
+	u8 axq_aggr_depth;
+	u32 axq_totalqueued;
+	bool stopped;
+	struct ath_buf *axq_linkbuf;
+
+	/* first desc of the last descriptor that contains CTS */
+	struct ath_desc *axq_lastdsWithCTS;
+
+	/* final desc of the gating desc that determines whether
+	   lastdsWithCTS has been DMA'ed or not */
+	struct ath_desc *axq_gatingds;
+
+	struct list_head axq_acq;
+};
+
+#define AGGR_CLEANUP         BIT(1)
+#define AGGR_ADDBA_COMPLETE  BIT(2)
+#define AGGR_ADDBA_PROGRESS  BIT(3)
+
+struct ath_atx_tid {
+	struct list_head list;
+	struct list_head buf_q;
+	struct ath_node *an;
+	struct ath_atx_ac *ac;
+	struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
+	u16 seq_start;
+	u16 seq_next;
+	u16 baw_size;
+	int tidno;
+	int baw_head;	/* first un-acked tx buffer */
+	int baw_tail;	/* next unused tx buffer slot */
+	int sched;
+	int paused;
+	u8 state;
+	int addba_exchangeattempts;
+};
+
+struct ath_atx_ac {
+	int sched;
+	int qnum;
+	struct list_head list;
+	struct list_head tid_q;
+};
+
+struct ath_tx_control {
+	struct ath_txq *txq;
+	int if_id;
+};
+
+struct ath_xmit_status {
+	int retries;
+	int flags;
+#define ATH_TX_ERROR        0x01
+#define ATH_TX_XRETRY       0x02
+#define ATH_TX_BAR          0x04
+};
+
+/* All RSSI values are noise floor adjusted */
+struct ath_tx_stat {
+	int rssi;
+	int rssictl[ATH_MAX_ANTENNA];
+	int rssiextn[ATH_MAX_ANTENNA];
+	int rateieee;
+	int rateKbps;
+	int ratecode;
+	int flags;
+	u32 airtime;	/* time on air per final tx rate */
+};
+
+struct aggr_rifs_param {
+	int param_max_frames;
+	int param_max_len;
+	int param_rl;
+	int param_al;
+	struct ath_rc_series *param_rcs;
+};
+
+struct ath_node {
+	struct ath_softc *an_sc;
+	struct ath_atx_tid tid[WME_NUM_TID];
+	struct ath_atx_ac ac[WME_NUM_AC];
+	u16 maxampdu;
+	u8 mpdudensity;
+};
+
+struct ath_tx {
+	u16 seq_no;
+	u32 txqsetup;
+	int hwq_map[ATH9K_WME_AC_VO+1];
+	spinlock_t txbuflock;
+	struct list_head txbuf;
+	struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
+	struct ath_descdma txdma;
+};
+
+struct ath_rx {
+	u8 defant;
+	u8 rxotherant;
+	u32 *rxlink;
+	int bufsize;
+	unsigned int rxfilter;
+	spinlock_t rxflushlock;
+	spinlock_t rxbuflock;
+	struct list_head rxbuf;
+	struct ath_descdma rxdma;
+};
+
+int ath_startrecv(struct ath_softc *sc);
+bool ath_stoprecv(struct ath_softc *sc);
+void ath_flushrecv(struct ath_softc *sc);
+u32 ath_calcrxfilter(struct ath_softc *sc);
+int ath_rx_init(struct ath_softc *sc, int nbufs);
+void ath_rx_cleanup(struct ath_softc *sc);
+int ath_rx_tasklet(struct ath_softc *sc, int flush);
+struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
+void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
+int ath_tx_setup(struct ath_softc *sc, int haltype);
+void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
+void ath_draintxq(struct ath_softc *sc,
+		     struct ath_txq *txq, bool retry_tx);
+void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
+void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
+void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
+int ath_tx_init(struct ath_softc *sc, int nbufs);
+int ath_tx_cleanup(struct ath_softc *sc);
+struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
+int ath_txq_update(struct ath_softc *sc, int qnum,
+		   struct ath9k_tx_queue_info *q);
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+		 struct ath_tx_control *txctl);
+void ath_tx_tasklet(struct ath_softc *sc);
+void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
+bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+		      u16 tid, u16 *ssn);
+int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+
+/********/
+/* VIFs */
+/********/
+
+/*
+ * Define the scheme that we select MAC address for multiple
+ * BSS on the same radio. The very first VIF will just use the MAC
+ * address from the EEPROM. For the next 3 VIFs, we set the
+ * U/L bit (bit 1) in MAC address, and use the next two bits as the
+ * index of the VIF.
+ */
+
+#define ATH_SET_VIF_BSSID_MASK(bssid_mask) \
+	((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
+
+struct ath_vif {
+	int av_bslot;
+	enum nl80211_iftype av_opmode;
+	struct ath_buf *av_bcbuf;
+	struct ath_tx_control av_btxctl;
+};
+
+/*******************/
+/* Beacon Handling */
+/*******************/
+
+/*
+ * Regardless of the number of beacons we stagger, (i.e. regardless of the
+ * number of BSSIDs) if a given beacon does not go out even after waiting this
+ * number of beacon intervals, the game's up.
+ */
+#define BSTUCK_THRESH           	(9 * ATH_BCBUF)
+#define	ATH_BCBUF               	1
+#define ATH_DEFAULT_BINTVAL     	100 /* TU */
+#define ATH_DEFAULT_BMISS_LIMIT 	10
+#define IEEE80211_MS_TO_TU(x)           (((x) * 1000) / 1024)
+
+struct ath_beacon_config {
+	u16 beacon_interval;
+	u16 listen_interval;
+	u16 dtim_period;
+	u16 bmiss_timeout;
+	u8 dtim_count;
+	u8 tim_offset;
 	union {
-		struct ath_tx_status tx;
-		struct ath_rx_status rx;
-		void *stats;
-	} ds_us;
-	void *ds_vdata;
-} __packed;
-
-#define	ds_txstat	ds_us.tx
-#define	ds_rxstat	ds_us.rx
-#define ds_stat		ds_us.stats
-
-#define ATH9K_TXDESC_CLRDMASK		0x0001
-#define ATH9K_TXDESC_NOACK		0x0002
-#define ATH9K_TXDESC_RTSENA		0x0004
-#define ATH9K_TXDESC_CTSENA		0x0008
-/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for
- * the descriptor its marked on.  We take a tx interrupt to reap
- * descriptors when the h/w hits an EOL condition or
- * when the descriptor is specifically marked to generate
- * an interrupt with this flag. Descriptors should be
- * marked periodically to insure timely replenishing of the
- * supply needed for sending frames. Defering interrupts
- * reduces system load and potentially allows more concurrent
- * work to be done but if done to aggressively can cause
- * senders to backup. When the hardware queue is left too
- * large rate control information may also be too out of
- * date. An Alternative for this is TX interrupt mitigation
- * but this needs more testing. */
-#define ATH9K_TXDESC_INTREQ		0x0010
-#define ATH9K_TXDESC_VEOL		0x0020
-#define ATH9K_TXDESC_EXT_ONLY		0x0040
-#define ATH9K_TXDESC_EXT_AND_CTL	0x0080
-#define ATH9K_TXDESC_VMF		0x0100
-#define ATH9K_TXDESC_FRAG_IS_ON 	0x0200
-#define ATH9K_TXDESC_CAB		0x0400
-
-#define ATH9K_RXDESC_INTREQ		0x0020
-
-enum wireless_mode {
-	ATH9K_MODE_11A = 0,
-	ATH9K_MODE_11B = 2,
-	ATH9K_MODE_11G = 3,
-	ATH9K_MODE_11NA_HT20 = 6,
-	ATH9K_MODE_11NG_HT20 = 7,
-	ATH9K_MODE_11NA_HT40PLUS = 8,
-	ATH9K_MODE_11NA_HT40MINUS = 9,
-	ATH9K_MODE_11NG_HT40PLUS = 10,
-	ATH9K_MODE_11NG_HT40MINUS = 11,
-	ATH9K_MODE_MAX
+		u64 last_tsf;
+		u8 last_tstamp[8];
+	} u; /* last received beacon/probe response timestamp of this BSS. */
 };
 
-enum ath9k_hw_caps {
-	ATH9K_HW_CAP_CHAN_SPREAD		= BIT(0),
-	ATH9K_HW_CAP_MIC_AESCCM                 = BIT(1),
-	ATH9K_HW_CAP_MIC_CKIP                   = BIT(2),
-	ATH9K_HW_CAP_MIC_TKIP                   = BIT(3),
-	ATH9K_HW_CAP_CIPHER_AESCCM              = BIT(4),
-	ATH9K_HW_CAP_CIPHER_CKIP                = BIT(5),
-	ATH9K_HW_CAP_CIPHER_TKIP                = BIT(6),
-	ATH9K_HW_CAP_VEOL                       = BIT(7),
-	ATH9K_HW_CAP_BSSIDMASK                  = BIT(8),
-	ATH9K_HW_CAP_MCAST_KEYSEARCH            = BIT(9),
-	ATH9K_HW_CAP_CHAN_HALFRATE              = BIT(10),
-	ATH9K_HW_CAP_CHAN_QUARTERRATE           = BIT(11),
-	ATH9K_HW_CAP_HT                         = BIT(12),
-	ATH9K_HW_CAP_GTT                        = BIT(13),
-	ATH9K_HW_CAP_FASTCC                     = BIT(14),
-	ATH9K_HW_CAP_RFSILENT                   = BIT(15),
-	ATH9K_HW_CAP_WOW                        = BIT(16),
-	ATH9K_HW_CAP_CST                        = BIT(17),
-	ATH9K_HW_CAP_ENHANCEDPM                 = BIT(18),
-	ATH9K_HW_CAP_AUTOSLEEP                  = BIT(19),
-	ATH9K_HW_CAP_4KB_SPLITTRANS             = BIT(20),
-	ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT     = BIT(21),
-	ATH9K_HW_CAP_BT_COEX			= BIT(22)
+struct ath_beacon {
+	enum {
+		OK,		/* no change needed */
+		UPDATE,		/* update pending */
+		COMMIT		/* beacon sent, commit change */
+	} updateslot;		/* slot time update fsm */
+
+	u32 beaconq;
+	u32 bmisscnt;
+	u32 ast_be_xmit;
+	u64 bc_tstamp;
+	int bslot[ATH_BCBUF];
+	int slottime;
+	int slotupdate;
+	struct ath9k_tx_queue_info beacon_qi;
+	struct ath_descdma bdma;
+	struct ath_txq *cabq;
+	struct list_head bbuf;
 };
 
-enum ath9k_capability_type {
-	ATH9K_CAP_CIPHER = 0,
-	ATH9K_CAP_TKIP_MIC,
-	ATH9K_CAP_TKIP_SPLIT,
-	ATH9K_CAP_PHYCOUNTERS,
-	ATH9K_CAP_DIVERSITY,
-	ATH9K_CAP_TXPOW,
-	ATH9K_CAP_PHYDIAG,
-	ATH9K_CAP_MCAST_KEYSRCH,
-	ATH9K_CAP_TSF_ADJUST,
-	ATH9K_CAP_WME_TKIPMIC,
-	ATH9K_CAP_RFSILENT,
-	ATH9K_CAP_ANT_CFG_2GHZ,
-	ATH9K_CAP_ANT_CFG_5GHZ
+void ath9k_beacon_tasklet(unsigned long data);
+void ath_beacon_config(struct ath_softc *sc, int if_id);
+int ath_beaconq_setup(struct ath_hw *ah);
+int ath_beacon_alloc(struct ath_softc *sc, int if_id);
+void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
+void ath_beacon_sync(struct ath_softc *sc, int if_id);
+
+/*******/
+/* ANI */
+/*******/
+
+/* ANI values for STA only.
+   FIXME: Add appropriate values for AP later */
+
+#define ATH_ANI_POLLINTERVAL    100     /* 100 milliseconds between ANI poll */
+#define ATH_SHORT_CALINTERVAL   1000    /* 1 second between calibrations */
+#define ATH_LONG_CALINTERVAL    30000   /* 30 seconds between calibrations */
+#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */
+
+struct ath_ani {
+	bool caldone;
+	int16_t noise_floor;
+	unsigned int longcal_timer;
+	unsigned int shortcal_timer;
+	unsigned int resetcal_timer;
+	unsigned int checkani_timer;
+	struct timer_list timer;
 };
 
-struct ath9k_hw_capabilities {
-	u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
-	DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */
-	u16 total_queues;
-	u16 keycache_size;
-	u16 low_5ghz_chan, high_5ghz_chan;
-	u16 low_2ghz_chan, high_2ghz_chan;
-	u16 num_mr_retries;
-	u16 rts_aggr_limit;
+/********************/
+/*   LED Control    */
+/********************/
+
+#define ATH_LED_PIN	1
+#define ATH_LED_ON_DURATION_IDLE	350	/* in msecs */
+#define ATH_LED_OFF_DURATION_IDLE	250	/* in msecs */
+
+enum ath_led_type {
+	ATH_LED_RADIO,
+	ATH_LED_ASSOC,
+	ATH_LED_TX,
+	ATH_LED_RX
+};
+
+struct ath_led {
+	struct ath_softc *sc;
+	struct led_classdev led_cdev;
+	enum ath_led_type led_type;
+	char name[32];
+	bool registered;
+};
+
+/* Rfkill */
+#define ATH_RFKILL_POLL_INTERVAL	2000 /* msecs */
+
+struct ath_rfkill {
+	struct rfkill *rfkill;
+	struct delayed_work rfkill_poll;
+	char rfkill_name[32];
+};
+
+/********************/
+/* Main driver core */
+/********************/
+
+/*
+ * Default cache line size, in bytes.
+ * Used when PCI device not fully initialized by bootrom/BIOS
+*/
+#define DEFAULT_CACHELINE       32
+#define	ATH_DEFAULT_NOISE_FLOOR -95
+#define ATH_REGCLASSIDS_MAX     10
+#define ATH_CABQ_READY_TIME     80      /* % of beacon interval */
+#define ATH_MAX_SW_RETRIES      10
+#define ATH_CHAN_MAX            255
+#define IEEE80211_WEP_NKID      4       /* number of key ids */
+
+/*
+ * The key cache is used for h/w cipher state and also for
+ * tracking station state such as the current tx antenna.
+ * We also setup a mapping table between key cache slot indices
+ * and station state to short-circuit node lookups on rx.
+ * Different parts have different size key caches.  We handle
+ * up to ATH_KEYMAX entries (could dynamically allocate state).
+ */
+#define	ATH_KEYMAX	        128     /* max key cache size we handle */
+
+#define ATH_IF_ID_ANY   	0xff
+#define ATH_TXPOWER_MAX         100     /* .5 dBm units */
+#define ATH_RSSI_DUMMY_MARKER   0x127
+#define ATH_RATE_DUMMY_MARKER   0
+
+#define SC_OP_INVALID		BIT(0)
+#define SC_OP_BEACONS		BIT(1)
+#define SC_OP_RXAGGR		BIT(2)
+#define SC_OP_TXAGGR		BIT(3)
+#define SC_OP_CHAINMASK_UPDATE	BIT(4)
+#define SC_OP_FULL_RESET	BIT(5)
+#define SC_OP_NO_RESET		BIT(6)
+#define SC_OP_PREAMBLE_SHORT	BIT(7)
+#define SC_OP_PROTECT_ENABLE	BIT(8)
+#define SC_OP_RXFLUSH		BIT(9)
+#define SC_OP_LED_ASSOCIATED	BIT(10)
+#define SC_OP_RFKILL_REGISTERED	BIT(11)
+#define SC_OP_RFKILL_SW_BLOCKED	BIT(12)
+#define SC_OP_RFKILL_HW_BLOCKED	BIT(13)
+#define SC_OP_WAIT_FOR_BEACON	BIT(14)
+#define SC_OP_LED_ON		BIT(15)
+
+struct ath_bus_ops {
+	void		(*read_cachesize)(struct ath_softc *sc, int *csz);
+	void		(*cleanup)(struct ath_softc *sc);
+	bool		(*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data);
+};
+
+struct ath_softc {
+	struct ieee80211_hw *hw;
+	struct device *dev;
+	struct tasklet_struct intr_tq;
+	struct tasklet_struct bcon_tasklet;
+	struct ath_hw *sc_ah;
+	void __iomem *mem;
+	int irq;
+	spinlock_t sc_resetlock;
+	struct mutex mutex;
+
+	u8 curbssid[ETH_ALEN];
+	u8 bssidmask[ETH_ALEN];
+	u32 intrstatus;
+	u32 sc_flags; /* SC_OP_* */
+	u16 curtxpow;
+	u16 curaid;
+	u16 cachelsz;
+	u8 nbcnvifs;
+	u16 nvifs;
 	u8 tx_chainmask;
 	u8 rx_chainmask;
-	u16 tx_triglevel_max;
-	u16 reg_cap;
-	u8 num_gpio_pins;
-	u8 num_antcfg_2ghz;
-	u8 num_antcfg_5ghz;
-};
-
-struct ath9k_ops_config {
-	int dma_beacon_response_time;
-	int sw_beacon_response_time;
-	int additional_swba_backoff;
-	int ack_6mb;
-	int cwm_ignore_extcca;
-	u8 pcie_powersave_enable;
-	u8 pcie_l1skp_enable;
-	u8 pcie_clock_req;
-	u32 pcie_waen;
-	int pcie_power_reset;
-	u8 pcie_restore;
-	u8 analog_shiftreg;
-	u8 ht_enable;
-	u32 ofdm_trig_low;
-	u32 ofdm_trig_high;
-	u32 cck_trig_high;
-	u32 cck_trig_low;
-	u32 enable_ani;
-	u8 noise_immunity_level;
-	u32 ofdm_weaksignal_det;
-	u32 cck_weaksignal_thr;
-	u8 spur_immunity_level;
-	u8 firstep_level;
-	int8_t rssi_thr_high;
-	int8_t rssi_thr_low;
-	u16 diversity_control;
-	u16 antenna_switch_swap;
-	int serialize_regmode;
-	int intr_mitigation;
-#define SPUR_DISABLE        	0
-#define SPUR_ENABLE_IOCTL   	1
-#define SPUR_ENABLE_EEPROM  	2
-#define AR_EEPROM_MODAL_SPURS   5
-#define AR_SPUR_5413_1      	1640
-#define AR_SPUR_5413_2      	1200
-#define AR_NO_SPUR      	0x8000
-#define AR_BASE_FREQ_2GHZ   	2300
-#define AR_BASE_FREQ_5GHZ   	4900
-#define AR_SPUR_FEEQ_BOUND_HT40 19
-#define AR_SPUR_FEEQ_BOUND_HT20 10
-	int spurmode;
-	u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
-};
-
-enum ath9k_tx_queue {
-	ATH9K_TX_QUEUE_INACTIVE = 0,
-	ATH9K_TX_QUEUE_DATA,
-	ATH9K_TX_QUEUE_BEACON,
-	ATH9K_TX_QUEUE_CAB,
-	ATH9K_TX_QUEUE_UAPSD,
-	ATH9K_TX_QUEUE_PSPOLL
-};
-
-#define	ATH9K_NUM_TX_QUEUES 10
-
-enum ath9k_tx_queue_subtype {
-	ATH9K_WME_AC_BK = 0,
-	ATH9K_WME_AC_BE,
-	ATH9K_WME_AC_VI,
-	ATH9K_WME_AC_VO,
-	ATH9K_WME_UPSD
-};
-
-enum ath9k_tx_queue_flags {
-	TXQ_FLAG_TXOKINT_ENABLE = 0x0001,
-	TXQ_FLAG_TXERRINT_ENABLE = 0x0001,
-	TXQ_FLAG_TXDESCINT_ENABLE = 0x0002,
-	TXQ_FLAG_TXEOLINT_ENABLE = 0x0004,
-	TXQ_FLAG_TXURNINT_ENABLE = 0x0008,
-	TXQ_FLAG_BACKOFF_DISABLE = 0x0010,
-	TXQ_FLAG_COMPRESSION_ENABLE = 0x0020,
-	TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040,
-	TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080,
-};
-
-#define ATH9K_TXQ_USEDEFAULT ((u32) -1)
-
-#define ATH9K_DECOMP_MASK_SIZE     128
-#define ATH9K_READY_TIME_LO_BOUND  50
-#define ATH9K_READY_TIME_HI_BOUND  96
-
-enum ath9k_pkt_type {
-	ATH9K_PKT_TYPE_NORMAL = 0,
-	ATH9K_PKT_TYPE_ATIM,
-	ATH9K_PKT_TYPE_PSPOLL,
-	ATH9K_PKT_TYPE_BEACON,
-	ATH9K_PKT_TYPE_PROBE_RESP,
-	ATH9K_PKT_TYPE_CHIRP,
-	ATH9K_PKT_TYPE_GRP_POLL,
-};
-
-struct ath9k_tx_queue_info {
-	u32 tqi_ver;
-	enum ath9k_tx_queue tqi_type;
-	enum ath9k_tx_queue_subtype tqi_subtype;
-	enum ath9k_tx_queue_flags tqi_qflags;
-	u32 tqi_priority;
-	u32 tqi_aifs;
-	u32 tqi_cwmin;
-	u32 tqi_cwmax;
-	u16 tqi_shretry;
-	u16 tqi_lgretry;
-	u32 tqi_cbrPeriod;
-	u32 tqi_cbrOverflowLimit;
-	u32 tqi_burstTime;
-	u32 tqi_readyTime;
-	u32 tqi_physCompBuf;
-	u32 tqi_intFlags;
-};
-
-enum ath9k_rx_filter {
-	ATH9K_RX_FILTER_UCAST = 0x00000001,
-	ATH9K_RX_FILTER_MCAST = 0x00000002,
-	ATH9K_RX_FILTER_BCAST = 0x00000004,
-	ATH9K_RX_FILTER_CONTROL = 0x00000008,
-	ATH9K_RX_FILTER_BEACON = 0x00000010,
-	ATH9K_RX_FILTER_PROM = 0x00000020,
-	ATH9K_RX_FILTER_PROBEREQ = 0x00000080,
-	ATH9K_RX_FILTER_PSPOLL = 0x00004000,
-	ATH9K_RX_FILTER_PHYERR = 0x00000100,
-	ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
-};
-
-enum ath9k_int {
-	ATH9K_INT_RX = 0x00000001,
-	ATH9K_INT_RXDESC = 0x00000002,
-	ATH9K_INT_RXNOFRM = 0x00000008,
-	ATH9K_INT_RXEOL = 0x00000010,
-	ATH9K_INT_RXORN = 0x00000020,
-	ATH9K_INT_TX = 0x00000040,
-	ATH9K_INT_TXDESC = 0x00000080,
-	ATH9K_INT_TIM_TIMER = 0x00000100,
-	ATH9K_INT_TXURN = 0x00000800,
-	ATH9K_INT_MIB = 0x00001000,
-	ATH9K_INT_RXPHY = 0x00004000,
-	ATH9K_INT_RXKCM = 0x00008000,
-	ATH9K_INT_SWBA = 0x00010000,
-	ATH9K_INT_BMISS = 0x00040000,
-	ATH9K_INT_BNR = 0x00100000,
-	ATH9K_INT_TIM = 0x00200000,
-	ATH9K_INT_DTIM = 0x00400000,
-	ATH9K_INT_DTIMSYNC = 0x00800000,
-	ATH9K_INT_GPIO = 0x01000000,
-	ATH9K_INT_CABEND = 0x02000000,
-	ATH9K_INT_CST = 0x10000000,
-	ATH9K_INT_GTT = 0x20000000,
-	ATH9K_INT_FATAL = 0x40000000,
-	ATH9K_INT_GLOBAL = 0x80000000,
-	ATH9K_INT_BMISC = ATH9K_INT_TIM |
-		ATH9K_INT_DTIM |
-		ATH9K_INT_DTIMSYNC |
-		ATH9K_INT_CABEND,
-	ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM |
-		ATH9K_INT_RXDESC |
-		ATH9K_INT_RXEOL |
-		ATH9K_INT_RXORN |
-		ATH9K_INT_TXURN |
-		ATH9K_INT_TXDESC |
-		ATH9K_INT_MIB |
-		ATH9K_INT_RXPHY |
-		ATH9K_INT_RXKCM |
-		ATH9K_INT_SWBA |
-		ATH9K_INT_BMISS |
-		ATH9K_INT_GPIO,
-	ATH9K_INT_NOCARD = 0xffffffff
-};
-
-#define ATH9K_RATESERIES_RTS_CTS  0x0001
-#define ATH9K_RATESERIES_2040     0x0002
-#define ATH9K_RATESERIES_HALFGI   0x0004
-
-struct ath9k_11n_rate_series {
-	u32 Tries;
-	u32 Rate;
-	u32 PktDuration;
-	u32 ChSel;
-	u32 RateFlags;
-};
-
-#define CHANNEL_CW_INT    0x00002
-#define CHANNEL_CCK       0x00020
-#define CHANNEL_OFDM      0x00040
-#define CHANNEL_2GHZ      0x00080
-#define CHANNEL_5GHZ      0x00100
-#define CHANNEL_PASSIVE   0x00200
-#define CHANNEL_DYN       0x00400
-#define CHANNEL_HALF      0x04000
-#define CHANNEL_QUARTER   0x08000
-#define CHANNEL_HT20      0x10000
-#define CHANNEL_HT40PLUS  0x20000
-#define CHANNEL_HT40MINUS 0x40000
-
-#define CHANNEL_INTERFERENCE    0x01
-#define CHANNEL_DFS             0x02
-#define CHANNEL_4MS_LIMIT       0x04
-#define CHANNEL_DFS_CLEAR       0x08
-#define CHANNEL_DISALLOW_ADHOC  0x10
-#define CHANNEL_PER_11D_ADHOC   0x20
-
-#define CHANNEL_A           (CHANNEL_5GHZ|CHANNEL_OFDM)
-#define CHANNEL_B           (CHANNEL_2GHZ|CHANNEL_CCK)
-#define CHANNEL_G           (CHANNEL_2GHZ|CHANNEL_OFDM)
-#define CHANNEL_G_HT20      (CHANNEL_2GHZ|CHANNEL_HT20)
-#define CHANNEL_A_HT20      (CHANNEL_5GHZ|CHANNEL_HT20)
-#define CHANNEL_G_HT40PLUS  (CHANNEL_2GHZ|CHANNEL_HT40PLUS)
-#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS)
-#define CHANNEL_A_HT40PLUS  (CHANNEL_5GHZ|CHANNEL_HT40PLUS)
-#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS)
-#define CHANNEL_ALL				\
-	(CHANNEL_OFDM|				\
-	 CHANNEL_CCK|				\
-	 CHANNEL_2GHZ |				\
-	 CHANNEL_5GHZ |				\
-	 CHANNEL_HT20 |				\
-	 CHANNEL_HT40PLUS |			\
-	 CHANNEL_HT40MINUS)
-
-struct ath9k_channel {
-	struct ieee80211_channel *chan;
-	u16 channel;
-	u32 channelFlags;
-	u32 chanmode;
-	int32_t CalValid;
-	bool oneTimeCalsDone;
-	int8_t iCoff;
-	int8_t qCoff;
-	int16_t rawNoiseFloor;
-};
-
-#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \
-       (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
-       (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
-       (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
-#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
-       (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
-       (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
-       (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
-#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
-#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
-#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
-#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0)
-#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
-#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
-
-/* These macros check chanmode and not channelFlags */
-#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
-#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||	\
-			  ((_c)->chanmode == CHANNEL_G_HT20))
-#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||	\
-			  ((_c)->chanmode == CHANNEL_A_HT40MINUS) ||	\
-			  ((_c)->chanmode == CHANNEL_G_HT40PLUS) ||	\
-			  ((_c)->chanmode == CHANNEL_G_HT40MINUS))
-#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c)))
-
-#define IS_CHAN_A_5MHZ_SPACED(_c)			\
-	((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&	\
-	 (((_c)->channel % 20) != 0) &&			\
-	 (((_c)->channel % 10) != 0))
-
-struct ath9k_keyval {
-	u8 kv_type;
-	u8 kv_pad;
-	u16 kv_len;
-	u8 kv_val[16];
-	u8 kv_mic[8];
-	u8 kv_txmic[8];
-};
-
-enum ath9k_key_type {
-	ATH9K_KEY_TYPE_CLEAR,
-	ATH9K_KEY_TYPE_WEP,
-	ATH9K_KEY_TYPE_AES,
-	ATH9K_KEY_TYPE_TKIP,
-};
-
-enum ath9k_cipher {
-	ATH9K_CIPHER_WEP = 0,
-	ATH9K_CIPHER_AES_OCB = 1,
-	ATH9K_CIPHER_AES_CCM = 2,
-	ATH9K_CIPHER_CKIP = 3,
-	ATH9K_CIPHER_TKIP = 4,
-	ATH9K_CIPHER_CLR = 5,
-	ATH9K_CIPHER_MIC = 127
-};
-
-#define AR_EEPROM_EEPCAP_COMPRESS_DIS   0x0001
-#define AR_EEPROM_EEPCAP_AES_DIS        0x0002
-#define AR_EEPROM_EEPCAP_FASTFRAME_DIS  0x0004
-#define AR_EEPROM_EEPCAP_BURST_DIS      0x0008
-#define AR_EEPROM_EEPCAP_MAXQCU         0x01F0
-#define AR_EEPROM_EEPCAP_MAXQCU_S       4
-#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN  0x0200
-#define AR_EEPROM_EEPCAP_KC_ENTRIES     0xF000
-#define AR_EEPROM_EEPCAP_KC_ENTRIES_S   12
-
-#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND   0x0040
-#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN    0x0080
-#define AR_EEPROM_EEREGCAP_EN_KK_U2         0x0100
-#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND    0x0200
-#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD     0x0400
-#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A    0x0800
-
-#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0  0x4000
-#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000
-
-#define SD_NO_CTL               0xE0
-#define NO_CTL                  0xff
-#define CTL_MODE_M              7
-#define CTL_11A                 0
-#define CTL_11B                 1
-#define CTL_11G                 2
-#define CTL_2GHT20              5
-#define CTL_5GHT20              6
-#define CTL_2GHT40              7
-#define CTL_5GHT40              8
-
-#define AR_EEPROM_MAC(i)        (0x1d+(i))
-
-#define AR_EEPROM_RFSILENT_GPIO_SEL     0x001c
-#define AR_EEPROM_RFSILENT_GPIO_SEL_S   2
-#define AR_EEPROM_RFSILENT_POLARITY     0x0002
-#define AR_EEPROM_RFSILENT_POLARITY_S   1
-
-#define CTRY_DEBUG 0x1ff
-#define	CTRY_DEFAULT 0
-
-enum reg_ext_bitmap {
-	REG_EXT_JAPAN_MIDBAND = 1,
-	REG_EXT_FCC_DFS_HT40 = 2,
-	REG_EXT_JAPAN_NONDFS_HT40 = 3,
-	REG_EXT_JAPAN_DFS_HT40 = 4
-};
-
-struct ath9k_country_entry {
-	u16 countryCode;
-	u16 regDmnEnum;
-	u16 regDmn5G;
-	u16 regDmn2G;
-	u8 isMultidomain;
-	u8 iso[3];
-};
-
-#define REG_WRITE(_ah, _reg, _val) iowrite32(_val, _ah->ah_sh + _reg)
-#define REG_READ(_ah, _reg) ioread32(_ah->ah_sh + _reg)
-
-#define SM(_v, _f)  (((_v) << _f##_S) & _f)
-#define MS(_v, _f)  (((_v) & _f) >> _f##_S)
-#define REG_RMW(_a, _r, _set, _clr)    \
-	REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set))
-#define REG_RMW_FIELD(_a, _r, _f, _v) \
-	REG_WRITE(_a, _r, \
-	(REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f))
-#define REG_SET_BIT(_a, _r, _f) \
-	REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
-#define REG_CLR_BIT(_a, _r, _f) \
-	REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
-
-#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS   0x00000001
-
-#define INIT_AIFS       2
-#define INIT_CWMIN      15
-#define INIT_CWMIN_11B  31
-#define INIT_CWMAX      1023
-#define INIT_SH_RETRY   10
-#define INIT_LG_RETRY   10
-#define INIT_SSH_RETRY  32
-#define INIT_SLG_RETRY  32
-
-#define WLAN_CTRL_FRAME_SIZE (2+2+6+4)
-
-#define ATH_AMPDU_LIMIT_MAX      (64 * 1024 - 1)
-#define ATH_AMPDU_LIMIT_DEFAULT  ATH_AMPDU_LIMIT_MAX
-
-#define IEEE80211_WEP_IVLEN      3
-#define IEEE80211_WEP_KIDLEN     1
-#define IEEE80211_WEP_CRCLEN     4
-#define IEEE80211_MAX_MPDU_LEN  (3840 + FCS_LEN +		\
-				 (IEEE80211_WEP_IVLEN +		\
-				  IEEE80211_WEP_KIDLEN +	\
-				  IEEE80211_WEP_CRCLEN))
-#define MAX_RATE_POWER 63
-
-enum ath9k_power_mode {
-	ATH9K_PM_AWAKE = 0,
-	ATH9K_PM_FULL_SLEEP,
-	ATH9K_PM_NETWORK_SLEEP,
-	ATH9K_PM_UNDEFINED
-};
-
-struct ath9k_mib_stats {
-	u32 ackrcv_bad;
-	u32 rts_bad;
-	u32 rts_good;
-	u32 fcs_bad;
-	u32 beacons;
-};
-
-enum ath9k_ant_setting {
-	ATH9K_ANT_VARIABLE = 0,
-	ATH9K_ANT_FIXED_A,
-	ATH9K_ANT_FIXED_B
-};
-
-#define ATH9K_SLOT_TIME_6 6
-#define ATH9K_SLOT_TIME_9 9
-#define ATH9K_SLOT_TIME_20 20
-
-enum ath9k_ht_macmode {
-	ATH9K_HT_MACMODE_20 = 0,
-	ATH9K_HT_MACMODE_2040 = 1,
-};
-
-enum ath9k_ht_extprotspacing {
-	ATH9K_HT_EXTPROTSPACING_20 = 0,
-	ATH9K_HT_EXTPROTSPACING_25 = 1,
-};
-
-struct ath9k_ht_cwm {
-	enum ath9k_ht_macmode ht_macmode;
+	u32 keymax;
+	DECLARE_BITMAP(keymap, ATH_KEYMAX);
+	u8 splitmic;
+	atomic_t ps_usecount;
+	enum ath9k_int imask;
 	enum ath9k_ht_extprotspacing ht_extprotspacing;
-};
+	enum ath9k_ht_macmode tx_chan_width;
 
-enum ath9k_ani_cmd {
-	ATH9K_ANI_PRESENT = 0x1,
-	ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
-	ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4,
-	ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8,
-	ATH9K_ANI_FIRSTEP_LEVEL = 0x10,
-	ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
-	ATH9K_ANI_MODE = 0x40,
-	ATH9K_ANI_PHYERR_RESET = 0x80,
-	ATH9K_ANI_ALL = 0xff
-};
+	struct ath_config config;
+	struct ath_rx rx;
+	struct ath_tx tx;
+	struct ath_beacon beacon;
+	struct ieee80211_vif *vifs[ATH_BCBUF];
+	struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
+	struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
+	struct ath_rate_table *cur_rate_table;
+	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
 
-enum {
-	WLAN_RC_PHY_OFDM,
-	WLAN_RC_PHY_CCK,
-	WLAN_RC_PHY_HT_20_SS,
-	WLAN_RC_PHY_HT_20_DS,
-	WLAN_RC_PHY_HT_40_SS,
-	WLAN_RC_PHY_HT_40_DS,
-	WLAN_RC_PHY_HT_20_SS_HGI,
-	WLAN_RC_PHY_HT_20_DS_HGI,
-	WLAN_RC_PHY_HT_40_SS_HGI,
-	WLAN_RC_PHY_HT_40_DS_HGI,
-	WLAN_RC_PHY_MAX
-};
+	struct ath_led radio_led;
+	struct ath_led assoc_led;
+	struct ath_led tx_led;
+	struct ath_led rx_led;
+	struct delayed_work ath_led_blink_work;
+	int led_on_duration;
+	int led_off_duration;
+	int led_on_cnt;
+	int led_off_cnt;
 
-enum ath9k_tp_scale {
-	ATH9K_TP_SCALE_MAX = 0,
-	ATH9K_TP_SCALE_50,
-	ATH9K_TP_SCALE_25,
-	ATH9K_TP_SCALE_12,
-	ATH9K_TP_SCALE_MIN
-};
-
-enum ser_reg_mode {
-	SER_REG_MODE_OFF = 0,
-	SER_REG_MODE_ON = 1,
-	SER_REG_MODE_AUTO = 2,
-};
-
-#define AR_PHY_CCA_MAX_GOOD_VALUE      		-85
-#define AR_PHY_CCA_MAX_HIGH_VALUE      		-62
-#define AR_PHY_CCA_MIN_BAD_VALUE       		-121
-#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
-#define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
-
-#define ATH9K_NF_CAL_HIST_MAX           5
-#define NUM_NF_READINGS                 6
-
-struct ath9k_nfcal_hist {
-	int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX];
-	u8 currIndex;
-	int16_t privNF;
-	u8 invalidNFcount;
-};
-
-struct ath9k_beacon_state {
-	u32 bs_nexttbtt;
-	u32 bs_nextdtim;
-	u32 bs_intval;
-#define ATH9K_BEACON_PERIOD       0x0000ffff
-#define ATH9K_BEACON_ENA          0x00800000
-#define ATH9K_BEACON_RESET_TSF    0x01000000
-	u32 bs_dtimperiod;
-	u16 bs_cfpperiod;
-	u16 bs_cfpmaxduration;
-	u32 bs_cfpnext;
-	u16 bs_timoffset;
-	u16 bs_bmissthreshold;
-	u32 bs_sleepduration;
-};
-
-struct ath9k_node_stats {
-	u32 ns_avgbrssi;
-	u32 ns_avgrssi;
-	u32 ns_avgtxrssi;
-	u32 ns_avgtxrate;
-};
-
-#define ATH9K_RSSI_EP_MULTIPLIER  (1<<7)
-
-#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT             0
-#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
-#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED     2
-#define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME           3
-#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
-#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
-
-enum {
-	ATH9K_RESET_POWER_ON,
-	ATH9K_RESET_WARM,
-	ATH9K_RESET_COLD,
-};
-
-#define AH_USE_EEPROM   0x1
-
-struct ath_hal {
-	u32 ah_magic;
-	u16 ah_devid;
-	u16 ah_subvendorid;
-	u32 ah_macVersion;
-	u16 ah_macRev;
-	u16 ah_phyRev;
-	u16 ah_analog5GhzRev;
-	u16 ah_analog2GhzRev;
-
-	void __iomem *ah_sh;
-	struct ath_softc *ah_sc;
-
-	enum nl80211_iftype ah_opmode;
-	struct ath9k_ops_config ah_config;
-	struct ath9k_hw_capabilities ah_caps;
-
-	u16 ah_countryCode;
-	u32 ah_flags;
-	int16_t ah_powerLimit;
-	u16 ah_maxPowerLevel;
-	u32 ah_tpScale;
-	u16 ah_currentRD;
-	u16 ah_currentRDExt;
-	u16 ah_currentRDInUse;
-	char alpha2[2];
-	struct reg_dmn_pair_mapping *regpair;
-	enum ath9k_power_mode ah_power_mode;
-	enum ath9k_power_mode ah_restore_mode;
-
-	struct ath9k_channel ah_channels[38];
-	struct ath9k_channel *ah_curchan;
-
-	bool ah_isPciExpress;
-	u16 ah_txTrigLevel;
-	u16 ah_rfsilent;
-	u32 ah_rfkill_gpio;
-	u32 ah_rfkill_polarity;
-	u32 ah_btactive_gpio;
-	u32 ah_wlanactive_gpio;
-	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
-
-	bool sw_mgmt_crypto;
-};
-
-struct chan_centers {
-	u16 synth_center;
-	u16 ctl_center;
-	u16 ext_center;
-};
-
-struct ath_rate_table;
-
-/* Helpers */
-
-bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val);
-u32 ath9k_hw_reverse_bits(u32 val, u32 n);
-bool ath9k_get_channel_edges(struct ath_hal *ah,
-			     u16 flags, u16 *low,
-			     u16 *high);
-u16 ath9k_hw_computetxtime(struct ath_hal *ah,
-			   struct ath_rate_table *rates,
-			   u32 frameLen, u16 rateix,
-			   bool shortPreamble);
-void ath9k_hw_get_channel_centers(struct ath_hal *ah,
-				  struct ath9k_channel *chan,
-				  struct chan_centers *centers);
-
-/* Attach, Detach */
-
-const char *ath9k_hw_probe(u16 vendorid, u16 devid);
-void ath9k_hw_detach(struct ath_hal *ah);
-struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
-				void __iomem *mem, int *error);
-void ath9k_hw_rfdetach(struct ath_hal *ah);
-
-
-/* HW Reset */
-
-int ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
-		    bool bChannelChange);
-
-/* Key Cache Management */
-
-bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac);
-bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
-				 const struct ath9k_keyval *k,
-				 const u8 *mac, int xorKey);
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
-
-/* Power Management */
-
-bool ath9k_hw_setpower(struct ath_hal *ah,
-		       enum ath9k_power_mode mode);
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
-
-/* Beacon timers */
-
-void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period);
-void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
-				    const struct ath9k_beacon_state *bs);
-/* HW Capabilities */
-
-bool ath9k_hw_fill_cap_info(struct ath_hal *ah);
-bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
-			    u32 capability, u32 *result);
-bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
-			    u32 capability, u32 setting, int *status);
-
-/* GPIO / RFKILL / Antennae */
-
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
-			 u32 ah_signal_type);
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val);
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-void ath9k_enable_rfkill(struct ath_hal *ah);
+	struct ath_rfkill rf_kill;
+	struct ath_ani ani;
+	struct ath9k_node_stats nodestats;
+#ifdef CONFIG_ATH9K_DEBUG
+	struct ath9k_debug debug;
 #endif
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
-bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
-			       enum ath9k_ant_setting settings,
-			       struct ath9k_channel *chan,
-			       u8 *tx_chainmask,
-			       u8 *rx_chainmask,
-			       u8 *antenna_cfgd);
+	struct ath_bus_ops *bus_ops;
+};
 
-/* General Operation */
+int ath_reset(struct ath_softc *sc, bool retry_tx);
+int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
+int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
+int ath_cabq_update(struct ath_softc *);
 
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
-bool ath9k_hw_phy_disable(struct ath_hal *ah);
-bool ath9k_hw_disable(struct ath_hal *ah);
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
-void ath9k_hw_setopmode(struct ath_hal *ah);
-void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1);
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
-bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId);
-u64 ath9k_hw_gettsf64(struct ath_hal *ah);
-void ath9k_hw_settsf64(struct ath_hal *ah, u64 tsf64);
-void ath9k_hw_reset_tsf(struct ath_hal *ah);
-bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting);
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
+static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
+{
+	sc->bus_ops->read_cachesize(sc, csz);
+}
 
-/* Regulatory */
-u16 ath9k_regd_get_rd(struct ath_hal *ah);
-bool ath9k_is_world_regd(struct ath_hal *ah);
-const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hal *ah);
-const struct ieee80211_regdomain *ath9k_default_world_regdomain(void);
+static inline void ath_bus_cleanup(struct ath_softc *sc)
+{
+	sc->bus_ops->cleanup(sc);
+}
 
-void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby);
-void ath9k_reg_apply_radar_flags(struct wiphy *wiphy);
+extern struct ieee80211_ops ath9k_ops;
 
-int ath9k_regd_init(struct ath_hal *ah);
-bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah);
-u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
-int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+irqreturn_t ath_isr(int irq, void *dev);
+void ath_cleanup(struct ath_softc *sc);
+int ath_attach(u16 devid, struct ath_softc *sc);
+void ath_detach(struct ath_softc *sc);
+const char *ath_mac_bb_name(u32 mac_bb_version);
+const char *ath_rf_name(u16 rf_version);
 
-/* ANI */
-
-void ath9k_ani_reset(struct ath_hal *ah);
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
-			  const struct ath9k_node_stats *stats,
-			  struct ath9k_channel *chan);
-bool ath9k_hw_phycounters(struct ath_hal *ah);
-void ath9k_enable_mib_counters(struct ath_hal *ah);
-void ath9k_hw_disable_mib_counters(struct ath_hal *ah);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
-				  u32 *rxc_pcnt,
-				  u32 *rxf_pcnt,
-				  u32 *txf_pcnt);
-void ath9k_hw_procmibevent(struct ath_hal *ah,
-			   const struct ath9k_node_stats *stats);
-void ath9k_hw_ani_setup(struct ath_hal *ah);
-void ath9k_hw_ani_attach(struct ath_hal *ah);
-void ath9k_hw_ani_detach(struct ath_hal *ah);
-
-/* Calibration */
-
-bool ath9k_hw_reset_calvalid(struct ath_hal *ah);
-void ath9k_hw_start_nfcal(struct ath_hal *ah);
-void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan);
-int16_t ath9k_hw_getnf(struct ath_hal *ah,
-		       struct ath9k_channel *chan);
-void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah);
-s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan);
-bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
-			u8 rxchainmask, bool longcal,
-			bool *isCalDone);
-bool ath9k_hw_init_cal(struct ath_hal *ah,
-		       struct ath9k_channel *chan);
-
-
-/* EEPROM */
-
-int ath9k_hw_set_txpower(struct ath_hal *ah,
-			 struct ath9k_channel *chan,
-			 u16 cfgCtl,
-			 u8 twiceAntennaReduction,
-			 u8 twiceMaxRegulatoryPower,
-			 u8 powerLimit);
-void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan);
-bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
-				       struct ath9k_channel *chan,
-				       int16_t *ratesArray,
-				       u16 cfgCtl,
-				       u8 AntennaReduction,
-				       u8 twiceMaxRegulatoryPower,
-				       u8 powerLimit);
-bool ath9k_hw_set_power_cal_table(struct ath_hal *ah,
-				  struct ath9k_channel *chan,
-				  int16_t *pTxPowerIndexOffset);
-bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
-				      struct ath9k_channel *chan);
-u16 ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
-				    struct ath9k_channel *chan);
-u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
-			       enum ieee80211_band freq_band);
-u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz);
-int ath9k_hw_eeprom_attach(struct ath_hal *ah);
-
-/* Interrupt Handling */
-
-bool ath9k_hw_intrpend(struct ath_hal *ah);
-bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
-enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints);
-
-/* MAC (PCU/QCU) */
-
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp);
-bool ath9k_hw_txstart(struct ath_hal *ah, u32 q);
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
-bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel);
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
-bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
-			 u32 segLen, bool firstSeg,
-			 bool lastSeg, const struct ath_desc *ds0);
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
-int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds);
-void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
-			    u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
-			    u32 keyIx, enum ath9k_key_type keyType, u32 flags);
-void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
-				  struct ath_desc *lastds,
-				  u32 durUpdateEn, u32 rtsctsRate,
-				  u32 rtsctsDuration,
-				  struct ath9k_11n_rate_series series[],
-				  u32 nseries, u32 flags);
-void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
-				u32 aggrLen);
-void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
-				 u32 numDelims);
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
-void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
-				   u32 burstDuration);
-void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
-				     u32 vmf);
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
-bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
-			    const struct ath9k_tx_queue_info *qinfo);
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
-			    struct ath9k_tx_queue_info *qinfo);
-int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
-			  const struct ath9k_tx_queue_info *qinfo);
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
-int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
-			u32 pa, struct ath_desc *nds, u64 tsf);
-bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
-			  u32 size, u32 flags);
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
-void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp);
-void ath9k_hw_rxena(struct ath_hal *ah);
-void ath9k_hw_startpcureceive(struct ath_hal *ah);
-void ath9k_hw_stoppcurecv(struct ath_hal *ah);
-bool ath9k_hw_stopdmarecv(struct ath_hal *ah);
-void ath9k_hw_btcoex_enable(struct ath_hal *ah);
-
+#ifdef CONFIG_PCI
+int ath_pci_init(void);
+void ath_pci_exit(void);
+#else
+static inline int ath_pci_init(void) { return 0; };
+static inline void ath_pci_exit(void) {};
 #endif
+
+#ifdef CONFIG_ATHEROS_AR71XX
+int ath_ahb_init(void);
+void ath_ahb_exit(void);
+#else
+static inline int ath_ahb_init(void) { return 0; };
+static inline void ath_ahb_exit(void) {};
+#endif
+
+static inline void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+	if (atomic_inc_return(&sc->ps_usecount) == 1)
+		if (sc->sc_ah->power_mode !=  ATH9K_PM_AWAKE) {
+			sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
+			ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+		}
+}
+
+static inline void ath9k_ps_restore(struct ath_softc *sc)
+{
+	if (atomic_dec_and_test(&sc->ps_usecount))
+		if (sc->hw->conf.flags & IEEE80211_CONF_PS)
+			ath9k_hw_setpower(sc->sc_ah,
+					  sc->sc_ah->restore_mode);
+}
+#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index 61d37be..2e2ef35 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
+#include "ath9k.h"
 
 /*
  *  This function will modify certain transmit queue properties depending on
@@ -23,11 +23,11 @@
 */
 static int ath_beaconq_config(struct ath_softc *sc)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath9k_tx_queue_info qi;
 
 	ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
-	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
+	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
 		/* Always burst out beacon and CAB traffic. */
 		qi.tqi_aifs = 1;
 		qi.tqi_cwmin = 0;
@@ -63,10 +63,10 @@
  *  Beacons are always sent out at the lowest rate, and are not retried.
 */
 static void ath_beacon_setup(struct ath_softc *sc,
-			     struct ath_vap *avp, struct ath_buf *bf)
+			     struct ath_vif *avp, struct ath_buf *bf)
 {
 	struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_desc *ds;
 	struct ath9k_11n_rate_series series[4];
 	struct ath_rate_table *rt;
@@ -82,8 +82,8 @@
 
 	flags = ATH9K_TXDESC_NOACK;
 
-	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC &&
-	    (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
+	if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
+	    (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
 		ds->ds_link = bf->bf_daddr; /* self-linked */
 		flags |= ATH9K_TXDESC_VEOL;
 		/* Let hardware handle antenna switching. */
@@ -96,7 +96,7 @@
 		 * SWBA's
 		 * XXX assumes two antenna
 		 */
-		antenna = ((sc->beacon.ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1);
+		antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
 	}
 
 	ds->ds_data = bf->bf_buf_addr;
@@ -132,24 +132,24 @@
 	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
 	series[0].Tries = 1;
 	series[0].Rate = rate;
-	series[0].ChSel = sc->sc_tx_chainmask;
+	series[0].ChSel = sc->tx_chainmask;
 	series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
 	ath9k_hw_set11n_ratescenario(ah, ds, ds, 0,
 		ctsrate, ctsduration, series, 4, 0);
 }
 
-/* Generate beacon frame and queue cab data for a vap */
+/* Generate beacon frame and queue cab data for a VIF */
 static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 {
 	struct ath_buf *bf;
-	struct ath_vap *avp;
+	struct ath_vif *avp;
 	struct sk_buff *skb;
 	struct ath_txq *cabq;
 	struct ieee80211_vif *vif;
 	struct ieee80211_tx_info *info;
 	int cabq_depth;
 
-	vif = sc->sc_vaps[if_id];
+	vif = sc->vifs[if_id];
 	ASSERT(vif);
 
 	avp = (void *)vif->drv_priv;
@@ -204,10 +204,10 @@
 	/*
 	 * if the CABQ traffic from previous DTIM is pending and the current
 	 *  beacon is also a DTIM.
-	 *  1) if there is only one vap let the cab traffic continue.
-	 *  2) if there are more than one vap and we are using staggered
+	 *  1) if there is only one vif let the cab traffic continue.
+	 *  2) if there are more than one vif and we are using staggered
 	 *     beacons, then drain the cabq by dropping all the frames in
-	 *     the cabq so that the current vaps cab traffic can be scheduled.
+	 *     the cabq so that the current vifs cab traffic can be scheduled.
 	 */
 	spin_lock_bh(&cabq->axq_lock);
 	cabq_depth = cabq->axq_depth;
@@ -219,7 +219,7 @@
 		 * the lock again which is a common function and that
 		 * acquires txq lock inside.
 		 */
-		if (sc->sc_nvaps > 1) {
+		if (sc->nvifs > 1) {
 			ath_draintxq(sc, cabq, false);
 			DPRINTF(sc, ATH_DBG_BEACON,
 				"flush previous cabq traffic\n");
@@ -248,12 +248,12 @@
 static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
 {
 	struct ieee80211_vif *vif;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_buf *bf;
-	struct ath_vap *avp;
+	struct ath_vif *avp;
 	struct sk_buff *skb;
 
-	vif = sc->sc_vaps[if_id];
+	vif = sc->vifs[if_id];
 	ASSERT(vif);
 
 	avp = (void *)vif->drv_priv;
@@ -276,7 +276,7 @@
 		sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
 }
 
-int ath_beaconq_setup(struct ath_hal *ah)
+int ath_beaconq_setup(struct ath_hw *ah)
 {
 	struct ath9k_tx_queue_info qi;
 
@@ -291,13 +291,13 @@
 int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 {
 	struct ieee80211_vif *vif;
-	struct ath_vap *avp;
+	struct ath_vif *avp;
 	struct ieee80211_hdr *hdr;
 	struct ath_buf *bf;
 	struct sk_buff *skb;
 	__le64 tstamp;
 
-	vif = sc->sc_vaps[if_id];
+	vif = sc->vifs[if_id];
 	ASSERT(vif);
 
 	avp = (void *)vif->drv_priv;
@@ -310,11 +310,11 @@
 						 struct ath_buf, list);
 		list_del(&avp->av_bcbuf->list);
 
-		if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP ||
-		    !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
+		if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
+		    !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
 			int slot;
 			/*
-			 * Assign the vap to a beacon xmit slot. As
+			 * Assign the vif to a beacon xmit slot. As
 			 * above, this cannot fail to find one.
 			 */
 			avp->av_bslot = 0;
@@ -335,7 +335,7 @@
 				}
 			BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY);
 			sc->beacon.bslot[avp->av_bslot] = if_id;
-			sc->sc_nbcnvaps++;
+			sc->nbcnvifs++;
 		}
 	}
 
@@ -384,8 +384,8 @@
 		 * timestamp then convert to TSF units and handle
 		 * byte swapping before writing it in the frame.
 		 * The hardware will then add this each time a beacon
-		 * frame is sent.  Note that we align vap's 1..N
-		 * and leave vap 0 untouched.  This means vap 0
+		 * frame is sent.  Note that we align vif's 1..N
+		 * and leave vif 0 untouched.  This means vap 0
 		 * has a timestamp in one beacon interval while the
 		 * others get a timestamp aligned to the next interval.
 		 */
@@ -416,14 +416,14 @@
 	return 0;
 }
 
-void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
+void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
 {
 	if (avp->av_bcbuf != NULL) {
 		struct ath_buf *bf;
 
 		if (avp->av_bslot != -1) {
 			sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY;
-			sc->sc_nbcnvaps--;
+			sc->nbcnvifs--;
 		}
 
 		bf = avp->av_bcbuf;
@@ -444,7 +444,7 @@
 void ath9k_beacon_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_buf *bf = NULL;
 	int slot, if_id;
 	u32 bfaddr;
@@ -597,7 +597,7 @@
 		ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
 		ath9k_hw_txstart(ah, sc->beacon.beaconq);
 
-		sc->beacon.ast_be_xmit += bc;     /* XXX per-vap? */
+		sc->beacon.ast_be_xmit += bc;     /* XXX per-vif? */
 	}
 }
 
@@ -619,19 +619,19 @@
 void ath_beacon_config(struct ath_softc *sc, int if_id)
 {
 	struct ieee80211_vif *vif;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_beacon_config conf;
-	struct ath_vap *avp;
+	struct ath_vif *avp;
 	enum nl80211_iftype opmode;
 	u32 nexttbtt, intval;
 
 	if (if_id != ATH_IF_ID_ANY) {
-		vif = sc->sc_vaps[if_id];
+		vif = sc->vifs[if_id];
 		ASSERT(vif);
 		avp = (void *)vif->drv_priv;
 		opmode = avp->av_opmode;
 	} else {
-		opmode = sc->sc_ah->ah_opmode;
+		opmode = sc->sc_ah->opmode;
 	}
 
 	memset(&conf, 0, sizeof(struct ath_beacon_config));
@@ -647,7 +647,7 @@
 	nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
 
 	/* XXX conditionalize multi-bss support? */
-	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
+	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
 		/*
 		 * For multi-bss ap support beacons are either staggered
 		 * evenly over N slots or burst together.  For the former
@@ -670,7 +670,7 @@
 		nexttbtt, intval, conf.beacon_interval);
 
 	/* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */
-	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) {
+	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
 		struct ath9k_beacon_state bs;
 		u64 tsf;
 		u32 tsftu;
@@ -781,15 +781,15 @@
 
 		ath9k_hw_set_interrupts(ah, 0);
 		ath9k_hw_set_sta_beacon_timers(ah, &bs);
-		sc->sc_imask |= ATH9K_INT_BMISS;
-		ath9k_hw_set_interrupts(ah, sc->sc_imask);
+		sc->imask |= ATH9K_INT_BMISS;
+		ath9k_hw_set_interrupts(ah, sc->imask);
 	} else {
 		u64 tsf;
 		u32 tsftu;
 		ath9k_hw_set_interrupts(ah, 0);
 		if (nexttbtt == intval)
 			intval |= ATH9K_BEACON_RESET_TSF;
-		if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) {
+		if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) {
 			/*
 			 * Pull nexttbtt forward to reflect the current
 			 * TSF
@@ -818,27 +818,27 @@
 			 * deal with things.
 			 */
 			intval |= ATH9K_BEACON_ENA;
-			if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
-				sc->sc_imask |= ATH9K_INT_SWBA;
+			if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
+				sc->imask |= ATH9K_INT_SWBA;
 			ath_beaconq_config(sc);
-		} else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
+		} else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
 			/*
 			 * In AP mode we enable the beacon timers and
 			 * SWBA interrupts to prepare beacon frames.
 			 */
 			intval |= ATH9K_BEACON_ENA;
-			sc->sc_imask |= ATH9K_INT_SWBA;   /* beacon prepare */
+			sc->imask |= ATH9K_INT_SWBA;   /* beacon prepare */
 			ath_beaconq_config(sc);
 		}
 		ath9k_hw_beaconinit(ah, nexttbtt, intval);
 		sc->beacon.bmisscnt = 0;
-		ath9k_hw_set_interrupts(ah, sc->sc_imask);
+		ath9k_hw_set_interrupts(ah, sc->imask);
 		/*
 		 * When using a self-linked beacon descriptor in
 		 * ibss mode load it once here.
 		 */
-		if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC &&
-		    (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
+		if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
+		    (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
 			ath_beacon_start_adhoc(sc, 0);
 	}
 }
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c
index 69ff01c..1fc3a08 100644
--- a/drivers/net/wireless/ath9k/calib.c
+++ b/drivers/net/wireless/ath9k/calib.c
@@ -14,10 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
-#include "hw.h"
-#include "reg.h"
-#include "phy.h"
+#include "ath9k.h"
 
 /* We can tune this as we go by monitoring really low values */
 #define ATH9K_NF_TOO_LOW	-60
@@ -26,7 +23,7 @@
  * is incorrect and we should use the static NF value. Later we can try to
  * find out why they are reporting these values */
 
-static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
+static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
 {
 	if (nf > ATH9K_NF_TOO_LOW) {
 		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
@@ -89,7 +86,7 @@
 	return;
 }
 
-static void ath9k_hw_do_getnf(struct ath_hal *ah,
+static void ath9k_hw_do_getnf(struct ath_hw *ah,
 			      int16_t nfarray[NUM_NF_READINGS])
 {
 	int16_t nf;
@@ -169,16 +166,16 @@
 	}
 }
 
-static bool getNoiseFloorThresh(struct ath_hal *ah,
+static bool getNoiseFloorThresh(struct ath_hw *ah,
 				enum ieee80211_band band,
 				int16_t *nft)
 {
 	switch (band) {
 	case IEEE80211_BAND_5GHZ:
-		*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
+		*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
 		break;
 	case IEEE80211_BAND_2GHZ:
-		*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
+		*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
 		break;
 	default:
 		BUG_ON(1);
@@ -188,7 +185,7 @@
 	return true;
 }
 
-static void ath9k_hw_setup_calibration(struct ath_hal *ah,
+static void ath9k_hw_setup_calibration(struct ath_hw *ah,
 				       struct hal_cal_list *currCal)
 {
 	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
@@ -222,10 +219,9 @@
 		    AR_PHY_TIMING_CTRL4_DO_CAL);
 }
 
-static void ath9k_hw_reset_calibration(struct ath_hal *ah,
+static void ath9k_hw_reset_calibration(struct ath_hw *ah,
 				       struct hal_cal_list *currCal)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
 
 	ath9k_hw_setup_calibration(ah, currCal);
@@ -233,23 +229,21 @@
 	currCal->calState = CAL_RUNNING;
 
 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ahp->ah_Meas0.sign[i] = 0;
-		ahp->ah_Meas1.sign[i] = 0;
-		ahp->ah_Meas2.sign[i] = 0;
-		ahp->ah_Meas3.sign[i] = 0;
+		ah->meas0.sign[i] = 0;
+		ah->meas1.sign[i] = 0;
+		ah->meas2.sign[i] = 0;
+		ah->meas3.sign[i] = 0;
 	}
 
-	ahp->ah_CalSamples = 0;
+	ah->cal_samples = 0;
 }
 
-static void ath9k_hw_per_calibration(struct ath_hal *ah,
+static void ath9k_hw_per_calibration(struct ath_hw *ah,
 				     struct ath9k_channel *ichan,
 				     u8 rxchainmask,
 				     struct hal_cal_list *currCal,
 				     bool *isCalDone)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	*isCalDone = false;
 
 	if (currCal->calState == CAL_RUNNING) {
@@ -257,9 +251,9 @@
 		      AR_PHY_TIMING_CTRL4_DO_CAL)) {
 
 			currCal->calData->calCollect(ah);
-			ahp->ah_CalSamples++;
+			ah->cal_samples++;
 
-			if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) {
+			if (ah->cal_samples >= currCal->calData->calNumSamples) {
 				int i, numChains = 0;
 				for (i = 0; i < AR5416_MAX_CHAINS; i++) {
 					if (rxchainmask & (1 << i))
@@ -280,13 +274,12 @@
 }
 
 /* Assumes you are talking about the currently configured channel */
-static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
+static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
 				     enum hal_cal_types calType)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
 
-	switch (calType & ahp->ah_suppCals) {
+	switch (calType & ah->supp_cals) {
 	case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
 		return true;
 	case ADC_GAIN_CAL:
@@ -299,90 +292,86 @@
 	return false;
 }
 
-static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
+static void ath9k_hw_iqcal_collect(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
 
 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ahp->ah_totalPowerMeasI[i] +=
+		ah->totalPowerMeasI[i] +=
 			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-		ahp->ah_totalPowerMeasQ[i] +=
+		ah->totalPowerMeasQ[i] +=
 			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-		ahp->ah_totalIqCorrMeas[i] +=
+		ah->totalIqCorrMeas[i] +=
 			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
 		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 			"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
-			ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
-			ahp->ah_totalPowerMeasQ[i],
-			ahp->ah_totalIqCorrMeas[i]);
+			ah->cal_samples, i, ah->totalPowerMeasI[i],
+			ah->totalPowerMeasQ[i],
+			ah->totalIqCorrMeas[i]);
 	}
 }
 
-static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
+static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
 
 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ahp->ah_totalAdcIOddPhase[i] +=
+		ah->totalAdcIOddPhase[i] +=
 			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-		ahp->ah_totalAdcIEvenPhase[i] +=
+		ah->totalAdcIEvenPhase[i] +=
 			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-		ahp->ah_totalAdcQOddPhase[i] +=
+		ah->totalAdcQOddPhase[i] +=
 			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-		ahp->ah_totalAdcQEvenPhase[i] +=
+		ah->totalAdcQEvenPhase[i] +=
 			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
 
 		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
 			"oddq=0x%08x; evenq=0x%08x;\n",
-			ahp->ah_CalSamples, i,
-			ahp->ah_totalAdcIOddPhase[i],
-			ahp->ah_totalAdcIEvenPhase[i],
-			ahp->ah_totalAdcQOddPhase[i],
-			ahp->ah_totalAdcQEvenPhase[i]);
+			ah->cal_samples, i,
+			ah->totalAdcIOddPhase[i],
+			ah->totalAdcIEvenPhase[i],
+			ah->totalAdcQOddPhase[i],
+			ah->totalAdcQEvenPhase[i]);
 	}
 }
 
-static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
+static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int i;
 
 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
+		ah->totalAdcDcOffsetIOddPhase[i] +=
 			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-		ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
+		ah->totalAdcDcOffsetIEvenPhase[i] +=
 			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-		ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
+		ah->totalAdcDcOffsetQOddPhase[i] +=
 			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-		ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
+		ah->totalAdcDcOffsetQEvenPhase[i] +=
 			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
 
 		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
 			"oddq=0x%08x; evenq=0x%08x;\n",
-			ahp->ah_CalSamples, i,
-			ahp->ah_totalAdcDcOffsetIOddPhase[i],
-			ahp->ah_totalAdcDcOffsetIEvenPhase[i],
-			ahp->ah_totalAdcDcOffsetQOddPhase[i],
-			ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
+			ah->cal_samples, i,
+			ah->totalAdcDcOffsetIOddPhase[i],
+			ah->totalAdcDcOffsetIEvenPhase[i],
+			ah->totalAdcDcOffsetQOddPhase[i],
+			ah->totalAdcDcOffsetQEvenPhase[i]);
 	}
 }
 
-static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
+static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	u32 powerMeasQ, powerMeasI, iqCorrMeas;
 	u32 qCoffDenom, iCoffDenom;
 	int32_t qCoff, iCoff;
 	int iqCorrNeg, i;
 
 	for (i = 0; i < numChains; i++) {
-		powerMeasI = ahp->ah_totalPowerMeasI[i];
-		powerMeasQ = ahp->ah_totalPowerMeasQ[i];
-		iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
+		powerMeasI = ah->totalPowerMeasI[i];
+		powerMeasQ = ah->totalPowerMeasQ[i];
+		iqCorrMeas = ah->totalIqCorrMeas[i];
 
 		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 			"Starting IQ Cal and Correction for Chain %d\n",
@@ -390,7 +379,7 @@
 
 		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 			"Orignal: Chn %diq_corr_meas = 0x%08x\n",
-			i, ahp->ah_totalIqCorrMeas[i]);
+			i, ah->totalIqCorrMeas[i]);
 
 		iqCorrNeg = 0;
 
@@ -448,17 +437,16 @@
 		    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
 }
 
-static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
+static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
 	u32 qGainMismatch, iGainMismatch, val, i;
 
 	for (i = 0; i < numChains; i++) {
-		iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
-		iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
-		qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
-		qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
+		iOddMeasOffset = ah->totalAdcIOddPhase[i];
+		iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
+		qOddMeasOffset = ah->totalAdcQOddPhase[i];
+		qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
 
 		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 			"Starting ADC Gain Cal for Chain %d\n", i);
@@ -506,21 +494,20 @@
 		  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
 }
 
-static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
+static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	u32 iOddMeasOffset, iEvenMeasOffset, val, i;
 	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
 	const struct hal_percal_data *calData =
-		ahp->ah_cal_list_curr->calData;
+		ah->cal_list_curr->calData;
 	u32 numSamples =
 		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
 
 	for (i = 0; i < numChains; i++) {
-		iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
-		iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
-		qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
-		qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
+		iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
+		iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
+		qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
+		qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
 
 		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 			"Starting ADC DC Offset Cal for Chain %d\n", i);
@@ -565,13 +552,12 @@
 }
 
 /* This is done for the currently configured channel */
-bool ath9k_hw_reset_calvalid(struct ath_hal *ah)
+bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
-	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+	struct hal_cal_list *currCal = ah->cal_list_curr;
 
-	if (!ah->ah_curchan)
+	if (!ah->curchan)
 		return true;
 
 	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
@@ -594,13 +580,13 @@
 		"Resetting Cal %d state for channel %u\n",
 		currCal->calData->calType, conf->channel->center_freq);
 
-	ah->ah_curchan->CalValid &= ~currCal->calData->calType;
+	ah->curchan->CalValid &= ~currCal->calData->calType;
 	currCal->calState = CAL_WAITING;
 
 	return false;
 }
 
-void ath9k_hw_start_nfcal(struct ath_hal *ah)
+void ath9k_hw_start_nfcal(struct ath_hw *ah)
 {
 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 		    AR_PHY_AGC_CONTROL_ENABLE_NF);
@@ -609,7 +595,7 @@
 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 }
 
-void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	struct ath9k_nfcal_hist *h;
 	int i, j;
@@ -665,7 +651,7 @@
 	}
 }
 
-int16_t ath9k_hw_getnf(struct ath_hal *ah,
+int16_t ath9k_hw_getnf(struct ath_hw *ah,
 		       struct ath9k_channel *chan)
 {
 	int16_t nf, nfThresh;
@@ -701,7 +687,7 @@
 	return chan->rawNoiseFloor;
 }
 
-void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
 {
 	int i, j;
 
@@ -715,10 +701,9 @@
 				AR_PHY_CCA_MAX_GOOD_VALUE;
 		}
 	}
-	return;
 }
 
-s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	s16 nf;
 
@@ -733,12 +718,11 @@
 	return nf;
 }
 
-bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
 			u8 rxchainmask, bool longcal,
 			bool *isCalDone)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+	struct hal_cal_list *currCal = ah->cal_list_curr;
 
 	*isCalDone = true;
 
@@ -748,7 +732,7 @@
 		ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal,
 					 isCalDone);
 		if (*isCalDone) {
-			ahp->ah_cal_list_curr = currCal = currCal->calNext;
+			ah->cal_list_curr = currCal = currCal->calNext;
 
 			if (currCal->calState == CAL_WAITING) {
 				*isCalDone = false;
@@ -759,7 +743,7 @@
 
 	if (longcal) {
 		ath9k_hw_getnf(ah, chan);
-		ath9k_hw_loadnf(ah, ah->ah_curchan);
+		ath9k_hw_loadnf(ah, ah->curchan);
 		ath9k_hw_start_nfcal(ah);
 
 		if (chan->channelFlags & CHANNEL_CW_INT)
@@ -769,7 +753,7 @@
 	return true;
 }
 
-static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah)
+static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
 {
 
 	u32 regVal;
@@ -864,11 +848,9 @@
 
 }
 
-bool ath9k_hw_init_cal(struct ath_hal *ah,
+bool ath9k_hw_init_cal(struct ath_hw *ah,
 		       struct ath9k_channel *chan)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
 		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
 		  AR_PHY_AGC_CONTROL_CAL);
@@ -887,32 +869,32 @@
 		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
 		  AR_PHY_AGC_CONTROL_NF);
 
-	ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
+	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 
 	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
 		if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
-			INIT_CAL(&ahp->ah_adcGainCalData);
-			INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
+			INIT_CAL(&ah->adcgain_caldata);
+			INSERT_CAL(ah, &ah->adcgain_caldata);
 			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 				"enabling ADC Gain Calibration.\n");
 		}
 		if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
-			INIT_CAL(&ahp->ah_adcDcCalData);
-			INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
+			INIT_CAL(&ah->adcdc_caldata);
+			INSERT_CAL(ah, &ah->adcdc_caldata);
 			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 				"enabling ADC DC Calibration.\n");
 		}
 		if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
-			INIT_CAL(&ahp->ah_iqCalData);
-			INSERT_CAL(ahp, &ahp->ah_iqCalData);
+			INIT_CAL(&ah->iq_caldata);
+			INSERT_CAL(ah, &ah->iq_caldata);
 			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
 				"enabling IQ Calibration.\n");
 		}
 
-		ahp->ah_cal_list_curr = ahp->ah_cal_list;
+		ah->cal_list_curr = ah->cal_list;
 
-		if (ahp->ah_cal_list_curr)
-			ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
+		if (ah->cal_list_curr)
+			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
 	}
 
 	chan->CalValid = 0;
diff --git a/drivers/net/wireless/ath9k/calib.h b/drivers/net/wireless/ath9k/calib.h
new file mode 100644
index 0000000..d2448f0
--- /dev/null
+++ b/drivers/net/wireless/ath9k/calib.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef CALIB_H
+#define CALIB_H
+
+extern const struct hal_percal_data iq_cal_multi_sample;
+extern const struct hal_percal_data iq_cal_single_sample;
+extern const struct hal_percal_data adc_gain_cal_multi_sample;
+extern const struct hal_percal_data adc_gain_cal_single_sample;
+extern const struct hal_percal_data adc_dc_cal_multi_sample;
+extern const struct hal_percal_data adc_dc_cal_single_sample;
+extern const struct hal_percal_data adc_init_dc_cal;
+
+#define AR_PHY_CCA_MAX_GOOD_VALUE      		-85
+#define AR_PHY_CCA_MAX_HIGH_VALUE      		-62
+#define AR_PHY_CCA_MIN_BAD_VALUE       		-121
+#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
+#define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
+
+#define NUM_NF_READINGS       6
+#define ATH9K_NF_CAL_HIST_MAX 5
+
+struct ar5416IniArray {
+	u32 *ia_array;
+	u32 ia_rows;
+	u32 ia_columns;
+};
+
+#define INIT_INI_ARRAY(iniarray, array, rows, columns) do {	\
+		(iniarray)->ia_array = (u32 *)(array);		\
+		(iniarray)->ia_rows = (rows);			\
+		(iniarray)->ia_columns = (columns);		\
+	} while (0)
+
+#define INI_RA(iniarray, row, column) \
+	(((iniarray)->ia_array)[(row) *	((iniarray)->ia_columns) + (column)])
+
+#define INIT_CAL(_perCal) do {				\
+		(_perCal)->calState = CAL_WAITING;	\
+		(_perCal)->calNext = NULL;		\
+	} while (0)
+
+#define INSERT_CAL(_ahp, _perCal)					\
+	do {								\
+		if ((_ahp)->cal_list_last == NULL) {			\
+			(_ahp)->cal_list =				\
+				(_ahp)->cal_list_last = (_perCal);	\
+			((_ahp)->cal_list_last)->calNext = (_perCal); \
+		} else {						\
+			((_ahp)->cal_list_last)->calNext = (_perCal); \
+			(_ahp)->cal_list_last = (_perCal);		\
+			(_perCal)->calNext = (_ahp)->cal_list;	\
+		}							\
+	} while (0)
+
+enum hal_cal_types {
+	ADC_DC_INIT_CAL = 0x1,
+	ADC_GAIN_CAL = 0x2,
+	ADC_DC_CAL = 0x4,
+	IQ_MISMATCH_CAL = 0x8
+};
+
+enum hal_cal_state {
+	CAL_INACTIVE,
+	CAL_WAITING,
+	CAL_RUNNING,
+	CAL_DONE
+};
+
+#define MIN_CAL_SAMPLES     1
+#define MAX_CAL_SAMPLES    64
+#define INIT_LOG_COUNT      5
+#define PER_MIN_LOG_COUNT   2
+#define PER_MAX_LOG_COUNT  10
+
+struct hal_percal_data {
+	enum hal_cal_types calType;
+	u32 calNumSamples;
+	u32 calCountMax;
+	void (*calCollect) (struct ath_hw *);
+	void (*calPostProc) (struct ath_hw *, u8);
+};
+
+struct hal_cal_list {
+	const struct hal_percal_data *calData;
+	enum hal_cal_state calState;
+	struct hal_cal_list *calNext;
+};
+
+struct ath9k_nfcal_hist {
+	int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX];
+	u8 currIndex;
+	int16_t privNF;
+	u8 invalidNFcount;
+};
+
+bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
+void ath9k_hw_start_nfcal(struct ath_hw *ah);
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
+int16_t ath9k_hw_getnf(struct ath_hw *ah,
+		       struct ath9k_channel *chan);
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
+bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
+			u8 rxchainmask, bool longcal,
+			bool *isCalDone);
+bool ath9k_hw_init_cal(struct ath_hw *ah,
+		       struct ath9k_channel *chan);
+
+#endif /* CALIB_H */
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
deleted file mode 100644
index 791f1ac..0000000
--- a/drivers/net/wireless/ath9k/core.h
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
- * Copyright (c) 2008 Atheros Communications Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef CORE_H
-#define CORE_H
-
-#include <linux/etherdevice.h>
-#include <linux/device.h>
-#include <net/mac80211.h>
-#include <linux/leds.h>
-#include <linux/rfkill.h>
-
-#include "ath9k.h"
-#include "rc.h"
-
-struct ath_node;
-
-/* Macro to expand scalars to 64-bit objects */
-
-#define	ito64(x) (sizeof(x) == 8) ?			\
-	(((unsigned long long int)(x)) & (0xff)) :	\
-	(sizeof(x) == 16) ?				\
-	(((unsigned long long int)(x)) & 0xffff) :	\
-	((sizeof(x) == 32) ?				\
-	 (((unsigned long long int)(x)) & 0xffffffff) : \
-	 (unsigned long long int)(x))
-
-/* increment with wrap-around */
-#define INCR(_l, _sz)   do {			\
-		(_l)++;				\
-		(_l) &= ((_sz) - 1);		\
-	} while (0)
-
-/* decrement with wrap-around */
-#define DECR(_l,  _sz)  do {			\
-		(_l)--;				\
-		(_l) &= ((_sz) - 1);		\
-	} while (0)
-
-#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define ASSERT(exp) do {			\
-		if (unlikely(!(exp))) {		\
-			BUG();			\
-		}				\
-	} while (0)
-
-#define TSF_TO_TU(_h,_l) \
-	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
-
-#define	ATH_TXQ_SETUP(sc, i)        ((sc)->tx.txqsetup & (1<<i))
-
-static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-enum ATH_DEBUG {
-	ATH_DBG_RESET		= 0x00000001,
-	ATH_DBG_REG_IO		= 0x00000002,
-	ATH_DBG_QUEUE		= 0x00000004,
-	ATH_DBG_EEPROM		= 0x00000008,
-	ATH_DBG_CALIBRATE	= 0x00000010,
-	ATH_DBG_CHANNEL		= 0x00000020,
-	ATH_DBG_INTERRUPT	= 0x00000040,
-	ATH_DBG_REGULATORY	= 0x00000080,
-	ATH_DBG_ANI		= 0x00000100,
-	ATH_DBG_POWER_MGMT	= 0x00000200,
-	ATH_DBG_XMIT		= 0x00000400,
-	ATH_DBG_BEACON		= 0x00001000,
-	ATH_DBG_CONFIG		= 0x00002000,
-	ATH_DBG_KEYCACHE	= 0x00004000,
-	ATH_DBG_FATAL		= 0x00008000,
-	ATH_DBG_ANY		= 0xffffffff
-};
-
-#define DBG_DEFAULT (ATH_DBG_FATAL)
-
-#ifdef CONFIG_ATH9K_DEBUG
-
-/**
- * struct ath_interrupt_stats - Contains statistics about interrupts
- * @total: Total no. of interrupts generated so far
- * @rxok: RX with no errors
- * @rxeol: RX with no more RXDESC available
- * @rxorn: RX FIFO overrun
- * @txok: TX completed at the requested rate
- * @txurn: TX FIFO underrun
- * @mib: MIB regs reaching its threshold
- * @rxphyerr: RX with phy errors
- * @rx_keycache_miss: RX with key cache misses
- * @swba: Software Beacon Alert
- * @bmiss: Beacon Miss
- * @bnr: Beacon Not Ready
- * @cst: Carrier Sense TImeout
- * @gtt: Global TX Timeout
- * @tim: RX beacon TIM occurrence
- * @cabend: RX End of CAB traffic
- * @dtimsync: DTIM sync lossage
- * @dtim: RX Beacon with DTIM
- */
-struct ath_interrupt_stats {
-	u32 total;
-	u32 rxok;
-	u32 rxeol;
-	u32 rxorn;
-	u32 txok;
-	u32 txeol;
-	u32 txurn;
-	u32 mib;
-	u32 rxphyerr;
-	u32 rx_keycache_miss;
-	u32 swba;
-	u32 bmiss;
-	u32 bnr;
-	u32 cst;
-	u32 gtt;
-	u32 tim;
-	u32 cabend;
-	u32 dtimsync;
-	u32 dtim;
-};
-
-struct ath_legacy_rc_stats {
-	u32 success;
-};
-
-struct ath_11n_rc_stats {
-	u32 success;
-};
-
-struct ath_stats {
-	struct ath_interrupt_stats istats;
-	struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */
-	struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */
-};
-
-struct ath9k_debug {
-	int debug_mask;
-	struct dentry *debugfs_root;
-	struct dentry *debugfs_phy;
-	struct dentry *debugfs_dma;
-	struct dentry *debugfs_interrupt;
-	struct dentry *debugfs_rcstat;
-	struct ath_stats stats;
-};
-
-void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
-int ath9k_init_debug(struct ath_softc *sc);
-void ath9k_exit_debug(struct ath_softc *sc);
-void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
-void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
-
-#else
-
-static inline void DPRINTF(struct ath_softc *sc, int dbg_mask,
-			   const char *fmt, ...)
-{
-}
-
-static inline int ath9k_init_debug(struct ath_softc *sc)
-{
-	return 0;
-}
-
-static inline void ath9k_exit_debug(struct ath_softc *sc)
-{
-}
-
-static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
-					    enum ath9k_int status)
-{
-}
-
-static inline void ath_debug_stat_rc(struct ath_softc *sc,
-				     struct sk_buff *skb)
-{
-}
-
-#endif /* CONFIG_ATH9K_DEBUG */
-
-struct ath_config {
-	u32 ath_aggr_prot;
-	u16 txpowlimit;
-	u16 txpowlimit_override;
-	u8 cabqReadytime;
-	u8 swBeaconProcess;
-};
-
-/*************************/
-/* Descriptor Management */
-/*************************/
-
-#define ATH_TXBUF_RESET(_bf) do {				\
-		(_bf)->bf_status = 0;				\
-		(_bf)->bf_lastbf = NULL;			\
-		(_bf)->bf_next = NULL;				\
-		memset(&((_bf)->bf_state), 0,			\
-			    sizeof(struct ath_buf_state));	\
-	} while (0)
-
-enum buffer_type {
-	BUF_DATA		= BIT(0),
-	BUF_AGGR		= BIT(1),
-	BUF_AMPDU		= BIT(2),
-	BUF_HT			= BIT(3),
-	BUF_RETRY		= BIT(4),
-	BUF_XRETRY		= BIT(5),
-	BUF_SHORT_PREAMBLE	= BIT(6),
-	BUF_BAR			= BIT(7),
-	BUF_PSPOLL		= BIT(8),
-	BUF_AGGR_BURST		= BIT(9),
-	BUF_CALC_AIRTIME	= BIT(10),
-};
-
-struct ath_buf_state {
-	int bfs_nframes;		/* # frames in aggregate */
-	u16 bfs_al;			/* length of aggregate */
-	u16 bfs_frmlen;			/* length of frame */
-	int bfs_seqno;			/* sequence number */
-	int bfs_tidno;			/* tid of this frame */
-	int bfs_retries;		/* current retries */
-	u32 bf_type;			/* BUF_* (enum buffer_type) */
-	u32 bfs_keyix;
-	enum ath9k_key_type bfs_keytype;
-};
-
-#define bf_nframes      	bf_state.bfs_nframes
-#define bf_al           	bf_state.bfs_al
-#define bf_frmlen       	bf_state.bfs_frmlen
-#define bf_retries      	bf_state.bfs_retries
-#define bf_seqno        	bf_state.bfs_seqno
-#define bf_tidno        	bf_state.bfs_tidno
-#define bf_rcs          	bf_state.bfs_rcs
-#define bf_keyix                bf_state.bfs_keyix
-#define bf_keytype      	bf_state.bfs_keytype
-#define bf_isdata(bf)		(bf->bf_state.bf_type & BUF_DATA)
-#define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
-#define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
-#define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
-#define bf_isretried(bf)	(bf->bf_state.bf_type & BUF_RETRY)
-#define bf_isxretried(bf)	(bf->bf_state.bf_type & BUF_XRETRY)
-#define bf_isbar(bf)		(bf->bf_state.bf_type & BUF_BAR)
-#define bf_ispspoll(bf) 	(bf->bf_state.bf_type & BUF_PSPOLL)
-#define bf_isaggrburst(bf)	(bf->bf_state.bf_type & BUF_AGGR_BURST)
-
-/*
- * Abstraction of a contiguous buffer to transmit/receive.  There is only
- * a single hw descriptor encapsulated here.
- */
-struct ath_buf {
-	struct list_head list;
-	struct ath_buf *bf_lastbf;	/* last buf of this unit (a frame or
-					   an aggregate) */
-	struct ath_buf *bf_next;	/* next subframe in the aggregate */
-	void *bf_mpdu;			/* enclosing frame structure */
-	struct ath_desc *bf_desc;	/* virtual addr of desc */
-	dma_addr_t bf_daddr;		/* physical addr of desc */
-	dma_addr_t bf_buf_addr;		/* physical addr of data buffer */
-	u32 bf_status;
-	u16 bf_flags;			/* tx descriptor flags */
-	struct ath_buf_state bf_state;	/* buffer state */
-	dma_addr_t bf_dmacontext;
-};
-
-#define ATH_RXBUF_RESET(_bf)    ((_bf)->bf_status = 0)
-#define ATH_BUFSTATUS_STALE     0x00000002
-
-/* DMA state for tx/rx descriptors */
-
-struct ath_descdma {
-	const char *dd_name;
-	struct ath_desc *dd_desc;	/* descriptors  */
-	dma_addr_t dd_desc_paddr;	/* physical addr of dd_desc  */
-	u32 dd_desc_len;		/* size of dd_desc  */
-	struct ath_buf *dd_bufptr;	/* associated buffers */
-	dma_addr_t dd_dmacontext;
-};
-
-int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
-		      struct list_head *head, const char *name,
-		      int nbuf, int ndesc);
-void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
-			 struct list_head *head);
-
-/***********/
-/* RX / TX */
-/***********/
-
-#define ATH_MAX_ANTENNA         3
-#define ATH_RXBUF               512
-#define WME_NUM_TID             16
-#define ATH_TXBUF               512
-#define ATH_TXMAXTRY            13
-#define ATH_11N_TXMAXTRY        10
-#define ATH_MGT_TXMAXTRY        4
-#define WME_BA_BMP_SIZE         64
-#define WME_MAX_BA              WME_BA_BMP_SIZE
-#define ATH_TID_MAX_BUFS        (2 * WME_MAX_BA)
-
-#define TID_TO_WME_AC(_tid)				\
-	((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE :	\
-	 (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK :	\
-	 (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI :	\
-	 WME_AC_VO)
-
-#define WME_AC_BE   0
-#define WME_AC_BK   1
-#define WME_AC_VI   2
-#define WME_AC_VO   3
-#define WME_NUM_AC  4
-
-#define ADDBA_EXCHANGE_ATTEMPTS    10
-#define ATH_AGGR_DELIM_SZ          4
-#define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
-/* number of delimiters for encryption padding */
-#define ATH_AGGR_ENCRYPTDELIM      10
-/* minimum h/w qdepth to be sustained to maximize aggregation */
-#define ATH_AGGR_MIN_QDEPTH        2
-#define ATH_AMPDU_SUBFRAME_DEFAULT 32
-#define IEEE80211_SEQ_SEQ_SHIFT    4
-#define IEEE80211_SEQ_MAX          4096
-#define IEEE80211_MIN_AMPDU_BUF    0x8
-#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
-
-/* return whether a bit at index _n in bitmap _bm is set
- * _sz is the size of the bitmap  */
-#define ATH_BA_ISSET(_bm, _n)  (((_n) < (WME_BA_BMP_SIZE)) &&		\
-				((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
-
-/* return block-ack bitmap index given sequence and starting sequence */
-#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1))
-
-/* returns delimiter padding required given the packet length */
-#define ATH_AGGR_GET_NDELIM(_len)					\
-	(((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ?           \
-	  (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
-
-#define BAW_WITHIN(_start, _bawsz, _seqno) \
-	((((_seqno) - (_start)) & 4095) < (_bawsz))
-
-#define ATH_DS_BA_SEQ(_ds)         ((_ds)->ds_us.tx.ts_seqnum)
-#define ATH_DS_BA_BITMAP(_ds)      (&(_ds)->ds_us.tx.ba_low)
-#define ATH_DS_TX_BA(_ds)          ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
-#define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
-
-enum ATH_AGGR_STATUS {
-	ATH_AGGR_DONE,
-	ATH_AGGR_BAW_CLOSED,
-	ATH_AGGR_LIMITED,
-	ATH_AGGR_SHORTPKT,
-	ATH_AGGR_8K_LIMITED,
-};
-
-struct ath_txq {
-	u32 axq_qnum;			/* hardware q number */
-	u32 *axq_link;			/* link ptr in last TX desc */
-	struct list_head axq_q;		/* transmit queue */
-	spinlock_t axq_lock;
-	u32 axq_depth;			/* queue depth */
-	u8 axq_aggr_depth;		/* aggregates queued */
-	u32 axq_totalqueued;		/* total ever queued */
-	bool stopped;			/* Is mac80211 queue stopped ? */
-	struct ath_buf *axq_linkbuf;	/* virtual addr of last buffer*/
-
-	/* first desc of the last descriptor that contains CTS */
-	struct ath_desc *axq_lastdsWithCTS;
-
-	/* final desc of the gating desc that determines whether
-	   lastdsWithCTS has been DMA'ed or not */
-	struct ath_desc *axq_gatingds;
-
-	struct list_head axq_acq;
-};
-
-#define AGGR_CLEANUP         BIT(1)
-#define AGGR_ADDBA_COMPLETE  BIT(2)
-#define AGGR_ADDBA_PROGRESS  BIT(3)
-
-/* per TID aggregate tx state for a destination */
-struct ath_atx_tid {
-	struct list_head list;		/* round-robin tid entry */
-	struct list_head buf_q;		/* pending buffers */
-	struct ath_node *an;
-	struct ath_atx_ac *ac;
-	struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; /* active tx frames */
-	u16 seq_start;
-	u16 seq_next;
-	u16 baw_size;
-	int tidno;
-	int baw_head;			/* first un-acked tx buffer */
-	int baw_tail;			/* next unused tx buffer slot */
-	int sched;
-	int paused;
-	u8 state;
-	int addba_exchangeattempts;
-};
-
-/* per access-category aggregate tx state for a destination */
-struct ath_atx_ac {
-	int sched;			/* dest-ac is scheduled */
-	int qnum;			/* H/W queue number associated
-					   with this AC */
-	struct list_head list;		/* round-robin txq entry */
-	struct list_head tid_q;		/* queue of TIDs with buffers */
-};
-
-/* per-frame tx control block */
-struct ath_tx_control {
-	struct ath_txq *txq;
-	int if_id;
-};
-
-/* per frame tx status block */
-struct ath_xmit_status {
-	int retries;	/* number of retries to successufully
-			   transmit this frame */
-	int flags;	/* status of transmit */
-#define ATH_TX_ERROR        0x01
-#define ATH_TX_XRETRY       0x02
-#define ATH_TX_BAR          0x04
-};
-
-/* All RSSI values are noise floor adjusted */
-struct ath_tx_stat {
-	int rssi;
-	int rssictl[ATH_MAX_ANTENNA];
-	int rssiextn[ATH_MAX_ANTENNA];
-	int rateieee;
-	int rateKbps;
-	int ratecode;
-	int flags;
-	u32 airtime;	/* time on air per final tx rate */
-};
-
-struct aggr_rifs_param {
-	int param_max_frames;
-	int param_max_len;
-	int param_rl;
-	int param_al;
-	struct ath_rc_series *param_rcs;
-};
-
-struct ath_node {
-	struct ath_softc *an_sc;
-	struct ath_atx_tid tid[WME_NUM_TID];
-	struct ath_atx_ac ac[WME_NUM_AC];
-	u16 maxampdu;
-	u8 mpdudensity;
-};
-
-struct ath_tx {
-	u16 seq_no;
-	u32 txqsetup;
-	int hwq_map[ATH9K_WME_AC_VO+1];
-	spinlock_t txbuflock;
-	struct list_head txbuf;
-	struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
-	struct ath_descdma txdma;
-};
-
-struct ath_rx {
-	u8 defant;
-	u8 rxotherant;
-	u32 *rxlink;
-	int bufsize;
-	unsigned int rxfilter;
-	spinlock_t rxflushlock;
-	spinlock_t rxbuflock;
-	struct list_head rxbuf;
-	struct ath_descdma rxdma;
-};
-
-int ath_startrecv(struct ath_softc *sc);
-bool ath_stoprecv(struct ath_softc *sc);
-void ath_flushrecv(struct ath_softc *sc);
-u32 ath_calcrxfilter(struct ath_softc *sc);
-int ath_rx_init(struct ath_softc *sc, int nbufs);
-void ath_rx_cleanup(struct ath_softc *sc);
-int ath_rx_tasklet(struct ath_softc *sc, int flush);
-struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
-void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
-int ath_tx_setup(struct ath_softc *sc, int haltype);
-void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
-void ath_draintxq(struct ath_softc *sc,
-		     struct ath_txq *txq, bool retry_tx);
-void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
-void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
-int ath_tx_init(struct ath_softc *sc, int nbufs);
-int ath_tx_cleanup(struct ath_softc *sc);
-struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
-int ath_txq_update(struct ath_softc *sc, int qnum,
-		   struct ath9k_tx_queue_info *q);
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
-		 struct ath_tx_control *txctl);
-void ath_tx_tasklet(struct ath_softc *sc);
-void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
-bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
-int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
-		      u16 tid, u16 *ssn);
-int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
-
-/********/
-/* VAPs */
-/********/
-
-/*
- * Define the scheme that we select MAC address for multiple
- * BSS on the same radio. The very first VAP will just use the MAC
- * address from the EEPROM. For the next 3 VAPs, we set the
- * U/L bit (bit 1) in MAC address, and use the next two bits as the
- * index of the VAP.
- */
-
-#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \
-	((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
-
-struct ath_vap {
-	int av_bslot;
-	enum nl80211_iftype av_opmode;
-	struct ath_buf *av_bcbuf;
-	struct ath_tx_control av_btxctl;
-};
-
-/*******************/
-/* Beacon Handling */
-/*******************/
-
-/*
- * Regardless of the number of beacons we stagger, (i.e. regardless of the
- * number of BSSIDs) if a given beacon does not go out even after waiting this
- * number of beacon intervals, the game's up.
- */
-#define BSTUCK_THRESH           	(9 * ATH_BCBUF)
-#define	ATH_BCBUF               	1
-#define ATH_DEFAULT_BINTVAL     	100 /* TU */
-#define ATH_DEFAULT_BMISS_LIMIT 	10
-#define IEEE80211_MS_TO_TU(x)           (((x) * 1000) / 1024)
-
-struct ath_beacon_config {
-	u16 beacon_interval;
-	u16 listen_interval;
-	u16 dtim_period;
-	u16 bmiss_timeout;
-	u8 dtim_count;
-	u8 tim_offset;
-	union {
-		u64 last_tsf;
-		u8 last_tstamp[8];
-	} u; /* last received beacon/probe response timestamp of this BSS. */
-};
-
-struct ath_beacon {
-	enum {
-		OK,		/* no change needed */
-		UPDATE,		/* update pending */
-		COMMIT		/* beacon sent, commit change */
-	} updateslot;		/* slot time update fsm */
-
-	u32 beaconq;
-	u32 bmisscnt;
-	u32 ast_be_xmit;
-	u64 bc_tstamp;
-	int bslot[ATH_BCBUF];
-	int slottime;
-	int slotupdate;
-	struct ath9k_tx_queue_info beacon_qi;
-	struct ath_descdma bdma;
-	struct ath_txq *cabq;
-	struct list_head bbuf;
-};
-
-void ath9k_beacon_tasklet(unsigned long data);
-void ath_beacon_config(struct ath_softc *sc, int if_id);
-int ath_beaconq_setup(struct ath_hal *ah);
-int ath_beacon_alloc(struct ath_softc *sc, int if_id);
-void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
-void ath_beacon_sync(struct ath_softc *sc, int if_id);
-
-/*******/
-/* ANI */
-/*******/
-
-/* ANI values for STA only.
-   FIXME: Add appropriate values for AP later */
-
-#define ATH_ANI_POLLINTERVAL    100     /* 100 milliseconds between ANI poll */
-#define ATH_SHORT_CALINTERVAL   1000    /* 1 second between calibrations */
-#define ATH_LONG_CALINTERVAL    30000   /* 30 seconds between calibrations */
-#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */
-
-struct ath_ani {
-	bool sc_caldone;
-	int16_t sc_noise_floor;
-	unsigned int sc_longcal_timer;
-	unsigned int sc_shortcal_timer;
-	unsigned int sc_resetcal_timer;
-	unsigned int sc_checkani_timer;
-	struct timer_list timer;
-};
-
-/********************/
-/*   LED Control    */
-/********************/
-
-#define ATH_LED_PIN	1
-#define ATH_LED_ON_DURATION_IDLE	350	/* in msecs */
-#define ATH_LED_OFF_DURATION_IDLE	250	/* in msecs */
-
-enum ath_led_type {
-	ATH_LED_RADIO,
-	ATH_LED_ASSOC,
-	ATH_LED_TX,
-	ATH_LED_RX
-};
-
-struct ath_led {
-	struct ath_softc *sc;
-	struct led_classdev led_cdev;
-	enum ath_led_type led_type;
-	char name[32];
-	bool registered;
-};
-
-/* Rfkill */
-#define ATH_RFKILL_POLL_INTERVAL	2000 /* msecs */
-
-struct ath_rfkill {
-	struct rfkill *rfkill;
-	struct delayed_work rfkill_poll;
-	char rfkill_name[32];
-};
-
-/********************/
-/* Main driver core */
-/********************/
-
-/*
- * Default cache line size, in bytes.
- * Used when PCI device not fully initialized by bootrom/BIOS
-*/
-#define DEFAULT_CACHELINE       32
-#define	ATH_DEFAULT_NOISE_FLOOR -95
-#define ATH_REGCLASSIDS_MAX     10
-#define ATH_CABQ_READY_TIME     80      /* % of beacon interval */
-#define ATH_MAX_SW_RETRIES      10
-#define ATH_CHAN_MAX            255
-#define IEEE80211_WEP_NKID      4       /* number of key ids */
-#define IEEE80211_RATE_VAL      0x7f
-/*
- * The key cache is used for h/w cipher state and also for
- * tracking station state such as the current tx antenna.
- * We also setup a mapping table between key cache slot indices
- * and station state to short-circuit node lookups on rx.
- * Different parts have different size key caches.  We handle
- * up to ATH_KEYMAX entries (could dynamically allocate state).
- */
-#define	ATH_KEYMAX	        128     /* max key cache size we handle */
-
-#define ATH_IF_ID_ANY   	0xff
-#define ATH_TXPOWER_MAX         100     /* .5 dBm units */
-#define ATH_RSSI_DUMMY_MARKER   0x127
-#define ATH_RATE_DUMMY_MARKER   0
-
-#define SC_OP_INVALID		BIT(0)
-#define SC_OP_BEACONS		BIT(1)
-#define SC_OP_RXAGGR		BIT(2)
-#define SC_OP_TXAGGR		BIT(3)
-#define SC_OP_CHAINMASK_UPDATE	BIT(4)
-#define SC_OP_FULL_RESET	BIT(5)
-#define SC_OP_NO_RESET		BIT(6)
-#define SC_OP_PREAMBLE_SHORT	BIT(7)
-#define SC_OP_PROTECT_ENABLE	BIT(8)
-#define SC_OP_RXFLUSH		BIT(9)
-#define SC_OP_LED_ASSOCIATED	BIT(10)
-#define SC_OP_RFKILL_REGISTERED	BIT(11)
-#define SC_OP_RFKILL_SW_BLOCKED	BIT(12)
-#define SC_OP_RFKILL_HW_BLOCKED	BIT(13)
-#define SC_OP_WAIT_FOR_BEACON	BIT(14)
-#define SC_OP_LED_ON		BIT(15)
-
-struct ath_bus_ops {
-	void		(*read_cachesize)(struct ath_softc *sc, int *csz);
-	void		(*cleanup)(struct ath_softc *sc);
-	bool		(*eeprom_read)(struct ath_hal *ah, u32 off, u16 *data);
-};
-
-struct ath_softc {
-	struct ieee80211_hw *hw;
-	struct device *dev;
-	struct tasklet_struct intr_tq;
-	struct tasklet_struct bcon_tasklet;
-	struct ath_hal *sc_ah;
-	void __iomem *mem;
-	int irq;
-	spinlock_t sc_resetlock;
-	struct mutex mutex;
-
-	u8 sc_curbssid[ETH_ALEN];
-	u8 sc_myaddr[ETH_ALEN];
-	u8 sc_bssidmask[ETH_ALEN];
-	u32 sc_intrstatus;
-	u32 sc_flags; /* SC_OP_* */
-	u16 sc_curtxpow;
-	u16 sc_curaid;
-	u16 sc_cachelsz;
-	u8 sc_nbcnvaps;
-	u16 sc_nvaps;
-	u8 sc_tx_chainmask;
-	u8 sc_rx_chainmask;
-	u32 sc_keymax;
-	DECLARE_BITMAP(sc_keymap, ATH_KEYMAX);
-	u8 sc_splitmic;
-	atomic_t ps_usecount;
-	enum ath9k_int sc_imask;
-	enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
-	enum ath9k_ht_macmode tx_chan_width;
-
-	struct ath_config sc_config;
-	struct ath_rx rx;
-	struct ath_tx tx;
-	struct ath_beacon beacon;
-	struct ieee80211_vif *sc_vaps[ATH_BCBUF];
-	struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
-	struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
-	struct ath_rate_table *cur_rate_table;
-	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
-
-	struct ath_led radio_led;
-	struct ath_led assoc_led;
-	struct ath_led tx_led;
-	struct ath_led rx_led;
-	struct delayed_work ath_led_blink_work;
-	int led_on_duration;
-	int led_off_duration;
-	int led_on_cnt;
-	int led_off_cnt;
-
-	struct ath_rfkill rf_kill;
-	struct ath_ani sc_ani;
-	struct ath9k_node_stats sc_halstats;
-#ifdef CONFIG_ATH9K_DEBUG
-	struct ath9k_debug sc_debug;
-#endif
-	struct ath_bus_ops *bus_ops;
-};
-
-int ath_reset(struct ath_softc *sc, bool retry_tx);
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
-int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
-int ath_cabq_update(struct ath_softc *);
-
-static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
-{
-	sc->bus_ops->read_cachesize(sc, csz);
-}
-
-static inline void ath_bus_cleanup(struct ath_softc *sc)
-{
-	sc->bus_ops->cleanup(sc);
-}
-
-extern struct ieee80211_ops ath9k_ops;
-
-irqreturn_t ath_isr(int irq, void *dev);
-void ath_cleanup(struct ath_softc *sc);
-int ath_attach(u16 devid, struct ath_softc *sc);
-void ath_detach(struct ath_softc *sc);
-const char *ath_mac_bb_name(u32 mac_bb_version);
-const char *ath_rf_name(u16 rf_version);
-
-#ifdef CONFIG_PCI
-int ath_pci_init(void);
-void ath_pci_exit(void);
-#else
-static inline int ath_pci_init(void) { return 0; };
-static inline void ath_pci_exit(void) {};
-#endif
-
-#ifdef CONFIG_ATHEROS_AR71XX
-int ath_ahb_init(void);
-void ath_ahb_exit(void);
-#else
-static inline int ath_ahb_init(void) { return 0; };
-static inline void ath_ahb_exit(void) {};
-#endif
-
-static inline void ath9k_ps_wakeup(struct ath_softc *sc)
-{
-	if (atomic_inc_return(&sc->ps_usecount) == 1)
-		if (sc->sc_ah->ah_power_mode !=  ATH9K_PM_AWAKE) {
-			sc->sc_ah->ah_restore_mode = sc->sc_ah->ah_power_mode;
-			ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
-		}
-}
-
-static inline void ath9k_ps_restore(struct ath_softc *sc)
-{
-	if (atomic_dec_and_test(&sc->ps_usecount))
-		if (sc->hw->conf.flags & IEEE80211_CONF_PS)
-			ath9k_hw_setpower(sc->sc_ah,
-					  sc->sc_ah->ah_restore_mode);
-}
-#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c
index 6181e49..800ad59 100644
--- a/drivers/net/wireless/ath9k/debug.c
+++ b/drivers/net/wireless/ath9k/debug.c
@@ -14,9 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
-#include "reg.h"
-#include "hw.h"
+#include "ath9k.h"
 
 static unsigned int ath9k_debug = DBG_DEFAULT;
 module_param_named(debug, ath9k_debug, uint, 0);
@@ -26,7 +24,7 @@
 	if (!sc)
 		return;
 
-	if (sc->sc_debug.debug_mask & dbg_mask) {
+	if (sc->debug.debug_mask & dbg_mask) {
 		va_list args;
 
 		va_start(args, fmt);
@@ -46,7 +44,7 @@
 			     size_t count, loff_t *ppos)
 {
 	struct ath_softc *sc = file->private_data;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	char buf[1024];
 	unsigned int len = 0;
 	u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
@@ -132,41 +130,41 @@
 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
 {
 	if (status)
-		sc->sc_debug.stats.istats.total++;
+		sc->debug.stats.istats.total++;
 	if (status & ATH9K_INT_RX)
-		sc->sc_debug.stats.istats.rxok++;
+		sc->debug.stats.istats.rxok++;
 	if (status & ATH9K_INT_RXEOL)
-		sc->sc_debug.stats.istats.rxeol++;
+		sc->debug.stats.istats.rxeol++;
 	if (status & ATH9K_INT_RXORN)
-		sc->sc_debug.stats.istats.rxorn++;
+		sc->debug.stats.istats.rxorn++;
 	if (status & ATH9K_INT_TX)
-		sc->sc_debug.stats.istats.txok++;
+		sc->debug.stats.istats.txok++;
 	if (status & ATH9K_INT_TXURN)
-		sc->sc_debug.stats.istats.txurn++;
+		sc->debug.stats.istats.txurn++;
 	if (status & ATH9K_INT_MIB)
-		sc->sc_debug.stats.istats.mib++;
+		sc->debug.stats.istats.mib++;
 	if (status & ATH9K_INT_RXPHY)
-		sc->sc_debug.stats.istats.rxphyerr++;
+		sc->debug.stats.istats.rxphyerr++;
 	if (status & ATH9K_INT_RXKCM)
-		sc->sc_debug.stats.istats.rx_keycache_miss++;
+		sc->debug.stats.istats.rx_keycache_miss++;
 	if (status & ATH9K_INT_SWBA)
-		sc->sc_debug.stats.istats.swba++;
+		sc->debug.stats.istats.swba++;
 	if (status & ATH9K_INT_BMISS)
-		sc->sc_debug.stats.istats.bmiss++;
+		sc->debug.stats.istats.bmiss++;
 	if (status & ATH9K_INT_BNR)
-		sc->sc_debug.stats.istats.bnr++;
+		sc->debug.stats.istats.bnr++;
 	if (status & ATH9K_INT_CST)
-		sc->sc_debug.stats.istats.cst++;
+		sc->debug.stats.istats.cst++;
 	if (status & ATH9K_INT_GTT)
-		sc->sc_debug.stats.istats.gtt++;
+		sc->debug.stats.istats.gtt++;
 	if (status & ATH9K_INT_TIM)
-		sc->sc_debug.stats.istats.tim++;
+		sc->debug.stats.istats.tim++;
 	if (status & ATH9K_INT_CABEND)
-		sc->sc_debug.stats.istats.cabend++;
+		sc->debug.stats.istats.cabend++;
 	if (status & ATH9K_INT_DTIMSYNC)
-		sc->sc_debug.stats.istats.dtimsync++;
+		sc->debug.stats.istats.dtimsync++;
 	if (status & ATH9K_INT_DTIM)
-		sc->sc_debug.stats.istats.dtim++;
+		sc->debug.stats.istats.dtim++;
 }
 
 static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
@@ -177,41 +175,41 @@
 	unsigned int len = 0;
 
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "RX", sc->sc_debug.stats.istats.rxok);
+		"%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "RXEOL", sc->sc_debug.stats.istats.rxeol);
+		"%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "RXORN", sc->sc_debug.stats.istats.rxorn);
+		"%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "TX", sc->sc_debug.stats.istats.txok);
+		"%8s: %10u\n", "TX", sc->debug.stats.istats.txok);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "TXURN", sc->sc_debug.stats.istats.txurn);
+		"%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "MIB", sc->sc_debug.stats.istats.mib);
+		"%8s: %10u\n", "MIB", sc->debug.stats.istats.mib);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "RXPHY", sc->sc_debug.stats.istats.rxphyerr);
+		"%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "RXKCM", sc->sc_debug.stats.istats.rx_keycache_miss);
+		"%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "SWBA", sc->sc_debug.stats.istats.swba);
+		"%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "BMISS", sc->sc_debug.stats.istats.bmiss);
+		"%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "BNR", sc->sc_debug.stats.istats.bnr);
+		"%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "CST", sc->sc_debug.stats.istats.cst);
+		"%8s: %10u\n", "CST", sc->debug.stats.istats.cst);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "GTT", sc->sc_debug.stats.istats.gtt);
+		"%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "TIM", sc->sc_debug.stats.istats.tim);
+		"%8s: %10u\n", "TIM", sc->debug.stats.istats.tim);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "CABEND", sc->sc_debug.stats.istats.cabend);
+		"%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "DTIMSYNC", sc->sc_debug.stats.istats.dtimsync);
+		"%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "DTIM", sc->sc_debug.stats.istats.dtim);
+		"%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim);
 	len += snprintf(buf + len, sizeof(buf) - len,
-		"%8s: %10u\n", "TOTAL", sc->sc_debug.stats.istats.total);
+		"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
 
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
@@ -233,7 +231,7 @@
 	final_ts_idx = tx_info_priv->tx.ts_rateindex;
 	idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate;
 
-	sc->sc_debug.stats.n_rcstats[idx].success++;
+	sc->debug.stats.n_rcstats[idx].success++;
 }
 
 static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb)
@@ -247,7 +245,7 @@
 	final_ts_idx = tx_info_priv->tx.ts_rateindex;
 	idx = rates[final_ts_idx].idx;
 
-	sc->sc_debug.stats.legacy_rcstats[idx].success++;
+	sc->debug.stats.legacy_rcstats[idx].success++;
 }
 
 void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
@@ -258,21 +256,36 @@
 		ath_debug_stat_legacy_rc(sc, skb);
 }
 
+/* FIXME: legacy rates, later on .. */
+void ath_debug_stat_retries(struct ath_softc *sc, int rix,
+			    int xretries, int retries)
+{
+	if (conf_is_ht(&sc->hw->conf)) {
+		int idx = sc->cur_rate_table->info[rix].dot11rate;
+
+		sc->debug.stats.n_rcstats[idx].xretries += xretries;
+		sc->debug.stats.n_rcstats[idx].retries += retries;
+	}
+}
+
 static ssize_t ath_read_file_stat_11n_rc(struct file *file,
 					 char __user *user_buf,
 					 size_t count, loff_t *ppos)
 {
 	struct ath_softc *sc = file->private_data;
-	char buf[512];
+	char buf[1024];
 	unsigned int len = 0;
 	int i = 0;
 
-	len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success");
+	len += sprintf(buf, "%7s %13s %8s %8s\n\n", "Rate", "Success",
+		       "Retries", "XRetries");
 
 	for (i = 0; i <= 15; i++) {
 		len += snprintf(buf + len, sizeof(buf) - len,
-				"%5s%3d: %8u\n", "MCS", i,
-				sc->sc_debug.stats.n_rcstats[i].success);
+				"%5s%3d: %8u %8u %8u\n", "MCS", i,
+				sc->debug.stats.n_rcstats[i].success,
+				sc->debug.stats.n_rcstats[i].retries,
+				sc->debug.stats.n_rcstats[i].xretries);
 	}
 
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
@@ -292,7 +305,7 @@
 	for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
 		len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n",
 				sc->cur_rate_table->info[i].ratekbps / 1000,
-				sc->sc_debug.stats.legacy_rcstats[i].success);
+				sc->debug.stats.legacy_rcstats[i].success);
 	}
 
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
@@ -317,34 +330,34 @@
 
 int ath9k_init_debug(struct ath_softc *sc)
 {
-	sc->sc_debug.debug_mask = ath9k_debug;
+	sc->debug.debug_mask = ath9k_debug;
 
-	sc->sc_debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
-	if (!sc->sc_debug.debugfs_root)
+	sc->debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (!sc->debug.debugfs_root)
 		goto err;
 
-	sc->sc_debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
-						      sc->sc_debug.debugfs_root);
-	if (!sc->sc_debug.debugfs_phy)
+	sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
+						      sc->debug.debugfs_root);
+	if (!sc->debug.debugfs_phy)
 		goto err;
 
-	sc->sc_debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
-				       sc->sc_debug.debugfs_phy, sc, &fops_dma);
-	if (!sc->sc_debug.debugfs_dma)
+	sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
+				       sc->debug.debugfs_phy, sc, &fops_dma);
+	if (!sc->debug.debugfs_dma)
 		goto err;
 
-	sc->sc_debug.debugfs_interrupt = debugfs_create_file("interrupt",
+	sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
 						     S_IRUGO,
-						     sc->sc_debug.debugfs_phy,
+						     sc->debug.debugfs_phy,
 						     sc, &fops_interrupt);
-	if (!sc->sc_debug.debugfs_interrupt)
+	if (!sc->debug.debugfs_interrupt)
 		goto err;
 
-	sc->sc_debug.debugfs_rcstat = debugfs_create_file("rcstat",
+	sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
 						  S_IRUGO,
-						  sc->sc_debug.debugfs_phy,
+						  sc->debug.debugfs_phy,
 						  sc, &fops_rcstat);
-	if (!sc->sc_debug.debugfs_rcstat)
+	if (!sc->debug.debugfs_rcstat)
 		goto err;
 
 	return 0;
@@ -355,9 +368,9 @@
 
 void ath9k_exit_debug(struct ath_softc *sc)
 {
-	debugfs_remove(sc->sc_debug.debugfs_rcstat);
-	debugfs_remove(sc->sc_debug.debugfs_interrupt);
-	debugfs_remove(sc->sc_debug.debugfs_dma);
-	debugfs_remove(sc->sc_debug.debugfs_phy);
-	debugfs_remove(sc->sc_debug.debugfs_root);
+	debugfs_remove(sc->debug.debugfs_rcstat);
+	debugfs_remove(sc->debug.debugfs_interrupt);
+	debugfs_remove(sc->debug.debugfs_dma);
+	debugfs_remove(sc->debug.debugfs_phy);
+	debugfs_remove(sc->debug.debugfs_root);
 }
diff --git a/drivers/net/wireless/ath9k/debug.h b/drivers/net/wireless/ath9k/debug.h
new file mode 100644
index 0000000..61e9698
--- /dev/null
+++ b/drivers/net/wireless/ath9k/debug.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+enum ATH_DEBUG {
+	ATH_DBG_RESET		= 0x00000001,
+	ATH_DBG_REG_IO		= 0x00000002,
+	ATH_DBG_QUEUE		= 0x00000004,
+	ATH_DBG_EEPROM		= 0x00000008,
+	ATH_DBG_CALIBRATE	= 0x00000010,
+	ATH_DBG_CHANNEL		= 0x00000020,
+	ATH_DBG_INTERRUPT	= 0x00000040,
+	ATH_DBG_REGULATORY	= 0x00000080,
+	ATH_DBG_ANI		= 0x00000100,
+	ATH_DBG_POWER_MGMT	= 0x00000200,
+	ATH_DBG_XMIT		= 0x00000400,
+	ATH_DBG_BEACON		= 0x00001000,
+	ATH_DBG_CONFIG		= 0x00002000,
+	ATH_DBG_KEYCACHE	= 0x00004000,
+	ATH_DBG_FATAL		= 0x00008000,
+	ATH_DBG_ANY		= 0xffffffff
+};
+
+#define DBG_DEFAULT (ATH_DBG_FATAL)
+
+#ifdef CONFIG_ATH9K_DEBUG
+
+/**
+ * struct ath_interrupt_stats - Contains statistics about interrupts
+ * @total: Total no. of interrupts generated so far
+ * @rxok: RX with no errors
+ * @rxeol: RX with no more RXDESC available
+ * @rxorn: RX FIFO overrun
+ * @txok: TX completed at the requested rate
+ * @txurn: TX FIFO underrun
+ * @mib: MIB regs reaching its threshold
+ * @rxphyerr: RX with phy errors
+ * @rx_keycache_miss: RX with key cache misses
+ * @swba: Software Beacon Alert
+ * @bmiss: Beacon Miss
+ * @bnr: Beacon Not Ready
+ * @cst: Carrier Sense TImeout
+ * @gtt: Global TX Timeout
+ * @tim: RX beacon TIM occurrence
+ * @cabend: RX End of CAB traffic
+ * @dtimsync: DTIM sync lossage
+ * @dtim: RX Beacon with DTIM
+ */
+struct ath_interrupt_stats {
+	u32 total;
+	u32 rxok;
+	u32 rxeol;
+	u32 rxorn;
+	u32 txok;
+	u32 txeol;
+	u32 txurn;
+	u32 mib;
+	u32 rxphyerr;
+	u32 rx_keycache_miss;
+	u32 swba;
+	u32 bmiss;
+	u32 bnr;
+	u32 cst;
+	u32 gtt;
+	u32 tim;
+	u32 cabend;
+	u32 dtimsync;
+	u32 dtim;
+};
+
+struct ath_legacy_rc_stats {
+	u32 success;
+};
+
+struct ath_11n_rc_stats {
+	u32 success;
+	u32 retries;
+	u32 xretries;
+};
+
+struct ath_stats {
+	struct ath_interrupt_stats istats;
+	struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */
+	struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */
+};
+
+struct ath9k_debug {
+	int debug_mask;
+	struct dentry *debugfs_root;
+	struct dentry *debugfs_phy;
+	struct dentry *debugfs_dma;
+	struct dentry *debugfs_interrupt;
+	struct dentry *debugfs_rcstat;
+	struct ath_stats stats;
+};
+
+void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
+int ath9k_init_debug(struct ath_softc *sc);
+void ath9k_exit_debug(struct ath_softc *sc);
+void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
+void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
+void ath_debug_stat_retries(struct ath_softc *sc, int rix,
+			    int xretries, int retries);
+
+#else
+
+static inline void DPRINTF(struct ath_softc *sc, int dbg_mask,
+			   const char *fmt, ...)
+{
+}
+
+static inline int ath9k_init_debug(struct ath_softc *sc)
+{
+	return 0;
+}
+
+static inline void ath9k_exit_debug(struct ath_softc *sc)
+{
+}
+
+static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
+					    enum ath9k_int status)
+{
+}
+
+static inline void ath_debug_stat_rc(struct ath_softc *sc,
+				     struct sk_buff *skb)
+{
+}
+
+static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
+					  int xretries, int retries)
+{
+}
+
+#endif /* CONFIG_ATH9K_DEBUG */
+
+#endif /* DEBUG_H */
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c
index 5038907..c0359ad 100644
--- a/drivers/net/wireless/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath9k/eeprom.c
@@ -14,12 +14,9 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
-#include "hw.h"
-#include "reg.h"
-#include "phy.h"
+#include "ath9k.h"
 
-static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
+static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah,
 				      u32 reg, u32 mask,
 				      u32 shift, u32 val)
 {
@@ -30,7 +27,7 @@
 
 	REG_WRITE(ah, reg, regVal);
 
-	if (ah->ah_config.analog_shiftreg)
+	if (ah->config.analog_shiftreg)
 		udelay(100);
 
 	return;
@@ -91,18 +88,198 @@
 	return false;
 }
 
-static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data)
+static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
 {
 	struct ath_softc *sc = ah->ah_sc;
 
 	return sc->bus_ops->eeprom_read(ah, off, data);
 }
 
-static bool ath9k_hw_fill_4k_eeprom(struct ath_hal *ah)
+static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+					   u8 *pVpdList, u16 numIntercepts,
+					   u8 *pRetVpdList)
+{
+	u16 i, k;
+	u8 currPwr = pwrMin;
+	u16 idxL = 0, idxR = 0;
+
+	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
+		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
+					       numIntercepts, &(idxL),
+					       &(idxR));
+		if (idxR < 1)
+			idxR = 1;
+		if (idxL == numIntercepts - 1)
+			idxL = (u16) (numIntercepts - 2);
+		if (pPwrList[idxL] == pPwrList[idxR])
+			k = pVpdList[idxL];
+		else
+			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
+				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
+				  (pPwrList[idxR] - pPwrList[idxL]));
+		pRetVpdList[i] = (u8) k;
+		currPwr += 2;
+	}
+
+	return true;
+}
+
+static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
+				      struct ath9k_channel *chan,
+				      struct cal_target_power_leg *powInfo,
+				      u16 numChannels,
+				      struct cal_target_power_leg *pNewPower,
+				      u16 numRates, bool isExtTarget)
+{
+	struct chan_centers centers;
+	u16 clo, chi;
+	int i;
+	int matchIndex = -1, lowIndex = -1;
+	u16 freq;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
+
+	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
+				       IS_CHAN_2GHZ(chan))) {
+		matchIndex = 0;
+	} else {
+		for (i = 0; (i < numChannels) &&
+			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) {
+				matchIndex = i;
+				break;
+			} else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						      IS_CHAN_2GHZ(chan))) &&
+				   (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+						      IS_CHAN_2GHZ(chan)))) {
+				lowIndex = i - 1;
+				break;
+			}
+		}
+		if ((matchIndex == -1) && (lowIndex == -1))
+			matchIndex = i - 1;
+	}
+
+	if (matchIndex != -1) {
+		*pNewPower = powInfo[matchIndex];
+	} else {
+		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+					 IS_CHAN_2GHZ(chan));
+		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+					 IS_CHAN_2GHZ(chan));
+
+		for (i = 0; i < numRates; i++) {
+			pNewPower->tPow2x[i] =
+				(u8)ath9k_hw_interpolate(freq, clo, chi,
+						powInfo[lowIndex].tPow2x[i],
+						powInfo[lowIndex + 1].tPow2x[i]);
+		}
+	}
+}
+
+static void ath9k_hw_get_target_powers(struct ath_hw *ah,
+				       struct ath9k_channel *chan,
+				       struct cal_target_power_ht *powInfo,
+				       u16 numChannels,
+				       struct cal_target_power_ht *pNewPower,
+				       u16 numRates, bool isHt40Target)
+{
+	struct chan_centers centers;
+	u16 clo, chi;
+	int i;
+	int matchIndex = -1, lowIndex = -1;
+	u16 freq;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
+
+	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
+		matchIndex = 0;
+	} else {
+		for (i = 0; (i < numChannels) &&
+			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) {
+				matchIndex = i;
+				break;
+			} else
+				if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) &&
+				    (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+						       IS_CHAN_2GHZ(chan)))) {
+					lowIndex = i - 1;
+					break;
+				}
+		}
+		if ((matchIndex == -1) && (lowIndex == -1))
+			matchIndex = i - 1;
+	}
+
+	if (matchIndex != -1) {
+		*pNewPower = powInfo[matchIndex];
+	} else {
+		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+					 IS_CHAN_2GHZ(chan));
+		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+					 IS_CHAN_2GHZ(chan));
+
+		for (i = 0; i < numRates; i++) {
+			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
+						clo, chi,
+						powInfo[lowIndex].tPow2x[i],
+						powInfo[lowIndex + 1].tPow2x[i]);
+		}
+	}
+}
+
+static u16 ath9k_hw_get_max_edge_power(u16 freq,
+				       struct cal_ctl_edges *pRdEdgesPower,
+				       bool is2GHz, int num_band_edges)
+{
+	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+	int i;
+
+	for (i = 0; (i < num_band_edges) &&
+		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
+			twiceMaxEdgePower = pRdEdgesPower[i].tPower;
+			break;
+		} else if ((i > 0) &&
+			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
+						      is2GHz))) {
+			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
+					       is2GHz) < freq &&
+			    pRdEdgesPower[i - 1].flag) {
+				twiceMaxEdgePower =
+					pRdEdgesPower[i - 1].tPower;
+			}
+			break;
+		}
+	}
+
+	return twiceMaxEdgePower;
+}
+
+/****************************************/
+/* EEPROM Operations for 4K sized cards */
+/****************************************/
+
+static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
+{
+	return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF);
+}
+
+static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
+{
+	return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF);
+}
+
+static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
 {
 #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
 	u16 *eep_data;
 	int addr, eep_start_loc = 0;
 
@@ -127,176 +304,11 @@
 #undef SIZE_EEPROM_4K
 }
 
-static bool ath9k_hw_fill_def_eeprom(struct ath_hal *ah)
-{
-#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
-	u16 *eep_data;
-	int addr, ar5416_eep_start_loc = 0x100;
-
-	eep_data = (u16 *)eep;
-
-	for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
-		if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
-					 eep_data)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-				"Unable to read eeprom region\n");
-			return false;
-		}
-		eep_data++;
-	}
-	return true;
-#undef SIZE_EEPROM_DEF
-}
-
-static bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = {
-	ath9k_hw_fill_def_eeprom,
-	ath9k_hw_fill_4k_eeprom
-};
-
-static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	return ath9k_fill_eeprom[ahp->ah_eep_map](ah);
-}
-
-static int ath9k_hw_check_def_eeprom(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *eep =
-		(struct ar5416_eeprom_def *) &ahp->ah_eeprom.def;
-	u16 *eepdata, temp, magic, magic2;
-	u32 sum = 0, el;
-	bool need_swap = false;
-	int i, addr, size;
-
-	if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
-				 &magic)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			"Reading Magic # failed\n");
-		return false;
-	}
-
-	if (!ath9k_hw_use_flash(ah)) {
-
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-				"Read Magic = 0x%04X\n", magic);
-
-		if (magic != AR5416_EEPROM_MAGIC) {
-			magic2 = swab16(magic);
-
-			if (magic2 == AR5416_EEPROM_MAGIC) {
-				size = sizeof(struct ar5416_eeprom_def);
-				need_swap = true;
-				eepdata = (u16 *) (&ahp->ah_eeprom);
-
-				for (addr = 0; addr < size / sizeof(u16); addr++) {
-					temp = swab16(*eepdata);
-					*eepdata = temp;
-					eepdata++;
-
-					DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-						"0x%04X  ", *eepdata);
-
-					if (((addr + 1) % 6) == 0)
-						DPRINTF(ah->ah_sc,
-							ATH_DBG_EEPROM, "\n");
-				}
-			} else {
-				DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-					"Invalid EEPROM Magic. "
-					"endianness mismatch.\n");
-				return -EINVAL;
-			}
-		}
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
-		need_swap ? "True" : "False");
-
-	if (need_swap)
-		el = swab16(ahp->ah_eeprom.def.baseEepHeader.length);
-	else
-		el = ahp->ah_eeprom.def.baseEepHeader.length;
-
-	if (el > sizeof(struct ar5416_eeprom_def))
-		el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
-	else
-		el = el / sizeof(u16);
-
-	eepdata = (u16 *)(&ahp->ah_eeprom);
-
-	for (i = 0; i < el; i++)
-		sum ^= *eepdata++;
-
-	if (need_swap) {
-		u32 integer, j;
-		u16 word;
-
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			"EEPROM Endianness is not native.. Changing \n");
-
-		word = swab16(eep->baseEepHeader.length);
-		eep->baseEepHeader.length = word;
-
-		word = swab16(eep->baseEepHeader.checksum);
-		eep->baseEepHeader.checksum = word;
-
-		word = swab16(eep->baseEepHeader.version);
-		eep->baseEepHeader.version = word;
-
-		word = swab16(eep->baseEepHeader.regDmn[0]);
-		eep->baseEepHeader.regDmn[0] = word;
-
-		word = swab16(eep->baseEepHeader.regDmn[1]);
-		eep->baseEepHeader.regDmn[1] = word;
-
-		word = swab16(eep->baseEepHeader.rfSilent);
-		eep->baseEepHeader.rfSilent = word;
-
-		word = swab16(eep->baseEepHeader.blueToothOptions);
-		eep->baseEepHeader.blueToothOptions = word;
-
-		word = swab16(eep->baseEepHeader.deviceCap);
-		eep->baseEepHeader.deviceCap = word;
-
-		for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
-			struct modal_eep_header *pModal =
-				&eep->modalHeader[j];
-			integer = swab32(pModal->antCtrlCommon);
-			pModal->antCtrlCommon = integer;
-
-			for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-				integer = swab32(pModal->antCtrlChain[i]);
-				pModal->antCtrlChain[i] = integer;
-			}
-
-			for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
-				word = swab16(pModal->spurChans[i].spurChan);
-				pModal->spurChans[i].spurChan = word;
-			}
-		}
-	}
-
-	if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
-	    ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			"Bad EEPROM checksum 0x%x or revision 0x%04x\n",
-			sum, ar5416_get_eep_ver(ahp));
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah)
+static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
 {
 #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ar5416_eeprom_4k *eep =
-		(struct ar5416_eeprom_4k *) &ahp->ah_eeprom.map4k;
+		(struct ar5416_eeprom_4k *) &ah->eeprom.map4k;
 	u16 *eepdata, temp, magic, magic2;
 	u32 sum = 0, el;
 	bool need_swap = false;
@@ -320,7 +332,7 @@
 
 			if (magic2 == AR5416_EEPROM_MAGIC) {
 				need_swap = true;
-				eepdata = (u16 *) (&ahp->ah_eeprom);
+				eepdata = (u16 *) (&ah->eeprom);
 
 				for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
 					temp = swab16(*eepdata);
@@ -347,16 +359,16 @@
 		need_swap ? "True" : "False");
 
 	if (need_swap)
-		el = swab16(ahp->ah_eeprom.map4k.baseEepHeader.length);
+		el = swab16(ah->eeprom.map4k.baseEepHeader.length);
 	else
-		el = ahp->ah_eeprom.map4k.baseEepHeader.length;
+		el = ah->eeprom.map4k.baseEepHeader.length;
 
 	if (el > sizeof(struct ar5416_eeprom_def))
 		el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
 	else
 		el = el / sizeof(u16);
 
-	eepdata = (u16 *)(&ahp->ah_eeprom);
+	eepdata = (u16 *)(&ah->eeprom);
 
 	for (i = 0; i < el; i++)
 		sum ^= *eepdata++;
@@ -406,11 +418,11 @@
 		}
 	}
 
-	if (sum != 0xffff || ar5416_get_eep4k_ver(ahp) != AR5416_EEP_VER ||
-	    ar5416_get_eep4k_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
+	if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
+	    ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
 		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
 			"Bad EEPROM checksum 0x%x or revision 0x%04x\n",
-			sum, ar5416_get_eep4k_ver(ahp));
+			sum, ah->eep_ops->get_eeprom_ver(ah));
 		return -EINVAL;
 	}
 
@@ -418,48 +430,48 @@
 #undef EEPROM_4K_SIZE
 }
 
-static int (*ath9k_check_eeprom[]) (struct ath_hal *) = {
-	ath9k_hw_check_def_eeprom,
-	ath9k_hw_check_4k_eeprom
-};
-
-static inline int ath9k_hw_check_eeprom(struct ath_hal *ah)
+static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
+				  enum eeprom_param param)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+	struct modal_eep_4k_header *pModal = &eep->modalHeader;
+	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
 
-	return ath9k_check_eeprom[ahp->ah_eep_map](ah);
-}
-
-static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
-					   u8 *pVpdList, u16 numIntercepts,
-					   u8 *pRetVpdList)
-{
-	u16 i, k;
-	u8 currPwr = pwrMin;
-	u16 idxL = 0, idxR = 0;
-
-	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
-		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
-					       numIntercepts, &(idxL),
-					       &(idxR));
-		if (idxR < 1)
-			idxR = 1;
-		if (idxL == numIntercepts - 1)
-			idxL = (u16) (numIntercepts - 2);
-		if (pPwrList[idxL] == pPwrList[idxR])
-			k = pVpdList[idxL];
-		else
-			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
-				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
-				  (pPwrList[idxR] - pPwrList[idxL]));
-		pRetVpdList[i] = (u8) k;
-		currPwr += 2;
+	switch (param) {
+	case EEP_NFTHRESH_2:
+		return pModal[1].noiseFloorThreshCh[0];
+	case AR_EEPROM_MAC(0):
+		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+	case AR_EEPROM_MAC(1):
+		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+	case AR_EEPROM_MAC(2):
+		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_REG_0:
+		return pBase->regDmn[0];
+	case EEP_REG_1:
+		return pBase->regDmn[1];
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_OB_2:
+		return pModal->ob_01;
+	case EEP_DB_2:
+		return pModal->db1_01;
+	case EEP_MINOR_REV:
+		return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+	case EEP_TX_MASK:
+		return pBase->txMask;
+	case EEP_RX_MASK:
+		return pBase->rxMask;
+	default:
+		return 0;
 	}
-
-	return true;
 }
 
-static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah,
+static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
 				struct ath9k_channel *chan,
 				struct cal_data_per_freq_4k *pRawDataSet,
 				u8 *bChans, u16 availPiers,
@@ -627,442 +639,11 @@
 #undef TMP_VAL_VPD_TABLE
 }
 
-static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hal *ah,
-				struct ath9k_channel *chan,
-				struct cal_data_per_freq *pRawDataSet,
-				u8 *bChans, u16 availPiers,
-				u16 tPdGainOverlap, int16_t *pMinCalPower,
-				u16 *pPdGainBoundaries, u8 *pPDADCValues,
-				u16 numXpdGains)
-{
-	int i, j, k;
-	int16_t ss;
-	u16 idxL = 0, idxR = 0, numPiers;
-	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
-		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
-		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
-		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
-	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
-	u8 minPwrT4[AR5416_NUM_PD_GAINS];
-	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
-	int16_t vpdStep;
-	int16_t tmpVal;
-	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
-	bool match;
-	int16_t minDelta = 0;
-	struct chan_centers centers;
-
-	ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-	for (numPiers = 0; numPiers < availPiers; numPiers++) {
-		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
-			break;
-	}
-
-	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
-							     IS_CHAN_2GHZ(chan)),
-					       bChans, numPiers, &idxL, &idxR);
-
-	if (match) {
-		for (i = 0; i < numXpdGains; i++) {
-			minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
-			maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
-			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-					pRawDataSet[idxL].pwrPdg[i],
-					pRawDataSet[idxL].vpdPdg[i],
-					AR5416_PD_GAIN_ICEPTS,
-					vpdTableI[i]);
-		}
-	} else {
-		for (i = 0; i < numXpdGains; i++) {
-			pVpdL = pRawDataSet[idxL].vpdPdg[i];
-			pPwrL = pRawDataSet[idxL].pwrPdg[i];
-			pVpdR = pRawDataSet[idxR].vpdPdg[i];
-			pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
-			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
-			maxPwrT4[i] =
-				min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
-				    pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
-
-
-			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-						pPwrL, pVpdL,
-						AR5416_PD_GAIN_ICEPTS,
-						vpdTableL[i]);
-			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-						pPwrR, pVpdR,
-						AR5416_PD_GAIN_ICEPTS,
-						vpdTableR[i]);
-
-			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
-				vpdTableI[i][j] =
-					(u8)(ath9k_hw_interpolate((u16)
-					     FREQ2FBIN(centers.
-						       synth_center,
-						       IS_CHAN_2GHZ
-						       (chan)),
-					     bChans[idxL], bChans[idxR],
-					     vpdTableL[i][j], vpdTableR[i][j]));
-			}
-		}
-	}
-
-	*pMinCalPower = (int16_t)(minPwrT4[0] / 2);
-
-	k = 0;
-
-	for (i = 0; i < numXpdGains; i++) {
-		if (i == (numXpdGains - 1))
-			pPdGainBoundaries[i] =
-				(u16)(maxPwrT4[i] / 2);
-		else
-			pPdGainBoundaries[i] =
-				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
-
-		pPdGainBoundaries[i] =
-			min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
-
-		if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
-			minDelta = pPdGainBoundaries[0] - 23;
-			pPdGainBoundaries[0] = 23;
-		} else {
-			minDelta = 0;
-		}
-
-		if (i == 0) {
-			if (AR_SREV_9280_10_OR_LATER(ah))
-				ss = (int16_t)(0 - (minPwrT4[i] / 2));
-			else
-				ss = 0;
-		} else {
-			ss = (int16_t)((pPdGainBoundaries[i - 1] -
-					(minPwrT4[i] / 2)) -
-				       tPdGainOverlap + 1 + minDelta);
-		}
-		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
-		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
-		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
-			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
-			ss++;
-		}
-
-		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
-		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
-				(minPwrT4[i] / 2));
-		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
-			tgtIndex : sizeCurrVpdTable;
-
-		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-			pPDADCValues[k++] = vpdTableI[i][ss++];
-		}
-
-		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
-				    vpdTableI[i][sizeCurrVpdTable - 2]);
-		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
-		if (tgtIndex > maxIndex) {
-			while ((ss <= tgtIndex) &&
-			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
-						    (ss - maxIndex + 1) * vpdStep));
-				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
-							 255 : tmpVal);
-				ss++;
-			}
-		}
-	}
-
-	while (i < AR5416_PD_GAINS_IN_MASK) {
-		pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
-		i++;
-	}
-
-	while (k < AR5416_NUM_PDADC_VALUES) {
-		pPDADCValues[k] = pPDADCValues[k - 1];
-		k++;
-	}
-
-	return;
-}
-
-static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
-				      struct ath9k_channel *chan,
-				      struct cal_target_power_leg *powInfo,
-				      u16 numChannels,
-				      struct cal_target_power_leg *pNewPower,
-				      u16 numRates, bool isExtTarget)
-{
-	struct chan_centers centers;
-	u16 clo, chi;
-	int i;
-	int matchIndex = -1, lowIndex = -1;
-	u16 freq;
-
-	ath9k_hw_get_channel_centers(ah, chan, &centers);
-	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
-
-	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
-				       IS_CHAN_2GHZ(chan))) {
-		matchIndex = 0;
-	} else {
-		for (i = 0; (i < numChannels) &&
-			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
-						       IS_CHAN_2GHZ(chan))) {
-				matchIndex = i;
-				break;
-			} else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
-						      IS_CHAN_2GHZ(chan))) &&
-				   (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
-						      IS_CHAN_2GHZ(chan)))) {
-				lowIndex = i - 1;
-				break;
-			}
-		}
-		if ((matchIndex == -1) && (lowIndex == -1))
-			matchIndex = i - 1;
-	}
-
-	if (matchIndex != -1) {
-		*pNewPower = powInfo[matchIndex];
-	} else {
-		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
-					 IS_CHAN_2GHZ(chan));
-		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
-					 IS_CHAN_2GHZ(chan));
-
-		for (i = 0; i < numRates; i++) {
-			pNewPower->tPow2x[i] =
-				(u8)ath9k_hw_interpolate(freq, clo, chi,
-						powInfo[lowIndex].tPow2x[i],
-						powInfo[lowIndex + 1].tPow2x[i]);
-		}
-	}
-}
-
-static void ath9k_hw_get_target_powers(struct ath_hal *ah,
-				       struct ath9k_channel *chan,
-				       struct cal_target_power_ht *powInfo,
-				       u16 numChannels,
-				       struct cal_target_power_ht *pNewPower,
-				       u16 numRates, bool isHt40Target)
-{
-	struct chan_centers centers;
-	u16 clo, chi;
-	int i;
-	int matchIndex = -1, lowIndex = -1;
-	u16 freq;
-
-	ath9k_hw_get_channel_centers(ah, chan, &centers);
-	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
-
-	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
-		matchIndex = 0;
-	} else {
-		for (i = 0; (i < numChannels) &&
-			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
-						       IS_CHAN_2GHZ(chan))) {
-				matchIndex = i;
-				break;
-			} else
-				if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
-						       IS_CHAN_2GHZ(chan))) &&
-				    (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
-						       IS_CHAN_2GHZ(chan)))) {
-					lowIndex = i - 1;
-					break;
-				}
-		}
-		if ((matchIndex == -1) && (lowIndex == -1))
-			matchIndex = i - 1;
-	}
-
-	if (matchIndex != -1) {
-		*pNewPower = powInfo[matchIndex];
-	} else {
-		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
-					 IS_CHAN_2GHZ(chan));
-		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
-					 IS_CHAN_2GHZ(chan));
-
-		for (i = 0; i < numRates; i++) {
-			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
-						clo, chi,
-						powInfo[lowIndex].tPow2x[i],
-						powInfo[lowIndex + 1].tPow2x[i]);
-		}
-	}
-}
-
-static u16 ath9k_hw_get_max_edge_power(u16 freq,
-				       struct cal_ctl_edges *pRdEdgesPower,
-				       bool is2GHz, int num_band_edges)
-{
-	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-	int i;
-
-	for (i = 0; (i < num_band_edges) &&
-		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
-			twiceMaxEdgePower = pRdEdgesPower[i].tPower;
-			break;
-		} else if ((i > 0) &&
-			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
-						      is2GHz))) {
-			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
-					       is2GHz) < freq &&
-			    pRdEdgesPower[i - 1].flag) {
-				twiceMaxEdgePower =
-					pRdEdgesPower[i - 1].tPower;
-			}
-			break;
-		}
-	}
-
-	return twiceMaxEdgePower;
-}
-
-static bool ath9k_hw_set_def_power_cal_table(struct ath_hal *ah,
+static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
 				  struct ath9k_channel *chan,
 				  int16_t *pTxPowerIndexOffset)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
-	struct cal_data_per_freq *pRawDataset;
-	u8 *pCalBChans = NULL;
-	u16 pdGainOverlap_t2;
-	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
-	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
-	u16 numPiers, i, j;
-	int16_t tMinCalPower;
-	u16 numXpdGain, xpdMask;
-	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
-	u32 reg32, regOffset, regChainOffset;
-	int16_t modalIdx;
-
-	modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
-	xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
-
-	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-	    AR5416_EEP_MINOR_VER_2) {
-		pdGainOverlap_t2 =
-			pEepData->modalHeader[modalIdx].pdGainOverlap;
-	} else {
-		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
-					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
-	}
-
-	if (IS_CHAN_2GHZ(chan)) {
-		pCalBChans = pEepData->calFreqPier2G;
-		numPiers = AR5416_NUM_2G_CAL_PIERS;
-	} else {
-		pCalBChans = pEepData->calFreqPier5G;
-		numPiers = AR5416_NUM_5G_CAL_PIERS;
-	}
-
-	numXpdGain = 0;
-
-	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
-		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
-			if (numXpdGain >= AR5416_NUM_PD_GAINS)
-				break;
-			xpdGainValues[numXpdGain] =
-				(u16)(AR5416_PD_GAINS_IN_MASK - i);
-			numXpdGain++;
-		}
-	}
-
-	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
-		      (numXpdGain - 1) & 0x3);
-	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
-		      xpdGainValues[0]);
-	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
-		      xpdGainValues[1]);
-	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
-		      xpdGainValues[2]);
-
-	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		if (AR_SREV_5416_V20_OR_LATER(ah) &&
-		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) &&
-		    (i != 0)) {
-			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
-		} else
-			regChainOffset = i * 0x1000;
-
-		if (pEepData->baseEepHeader.txMask & (1 << i)) {
-			if (IS_CHAN_2GHZ(chan))
-				pRawDataset = pEepData->calPierData2G[i];
-			else
-				pRawDataset = pEepData->calPierData5G[i];
-
-			ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan,
-					    pRawDataset, pCalBChans,
-					    numPiers, pdGainOverlap_t2,
-					    &tMinCalPower, gainBoundaries,
-					    pdadcValues, numXpdGain);
-
-			if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
-				REG_WRITE(ah,
-					  AR_PHY_TPCRG5 + regChainOffset,
-					  SM(pdGainOverlap_t2,
-					     AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
-					  | SM(gainBoundaries[0],
-					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
-					  | SM(gainBoundaries[1],
-					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
-					  | SM(gainBoundaries[2],
-					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
-					  | SM(gainBoundaries[3],
-				       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
-			}
-
-			regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
-			for (j = 0; j < 32; j++) {
-				reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
-					((pdadcValues[4 * j + 1] & 0xFF) << 8) |
-					((pdadcValues[4 * j + 2] & 0xFF) << 16)|
-					((pdadcValues[4 * j + 3] & 0xFF) << 24);
-				REG_WRITE(ah, regOffset, reg32);
-
-				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-					"PDADC (%d,%4x): %4.4x %8.8x\n",
-					i, regChainOffset, regOffset,
-					reg32);
-				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-					"PDADC: Chain %d | PDADC %3d "
-					"Value %3d | PDADC %3d Value %3d | "
-					"PDADC %3d Value %3d | PDADC %3d "
-					"Value %3d |\n",
-					i, 4 * j, pdadcValues[4 * j],
-					4 * j + 1, pdadcValues[4 * j + 1],
-					4 * j + 2, pdadcValues[4 * j + 2],
-					4 * j + 3,
-					pdadcValues[4 * j + 3]);
-
-				regOffset += 4;
-			}
-		}
-	}
-
-	*pTxPowerIndexOffset = 0;
-
-	return true;
-}
-
-static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah,
-				  struct ath9k_channel *chan,
-				  int16_t *pTxPowerIndexOffset)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
 	struct cal_data_per_freq_4k *pRawDataset;
 	u8 *pCalBChans = NULL;
 	u16 pdGainOverlap_t2;
@@ -1111,7 +692,7 @@
 
 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
 		if (AR_SREV_5416_V20_OR_LATER(ah) &&
-		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) &&
+		    (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
 		    (i != 0)) {
 			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
 		} else
@@ -1174,298 +755,7 @@
 	return true;
 }
 
-static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah,
-						  struct ath9k_channel *chan,
-						  int16_t *ratesArray,
-						  u16 cfgCtl,
-						  u16 AntennaReduction,
-						  u16 twiceMaxRegulatoryPower,
-						  u16 powerLimit)
-{
-#define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
-#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10 /* 10*log10(3)*2 */
-
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
-	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-	static const u16 tpScaleReductionTable[5] =
-		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
-
-	int i;
-	int16_t twiceLargestAntenna;
-	struct cal_ctl_data *rep;
-	struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
-		0, { 0, 0, 0, 0}
-	};
-	struct cal_target_power_leg targetPowerOfdmExt = {
-		0, { 0, 0, 0, 0} }, targetPowerCckExt = {
-		0, { 0, 0, 0, 0 }
-	};
-	struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
-		0, {0, 0, 0, 0}
-	};
-	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
-	u16 ctlModesFor11a[] =
-		{ CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
-	u16 ctlModesFor11g[] =
-		{ CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
-		  CTL_2GHT40
-		};
-	u16 numCtlModes, *pCtlMode, ctlMode, freq;
-	struct chan_centers centers;
-	int tx_chainmask;
-	u16 twiceMinEdgePower;
-
-	tx_chainmask = ahp->ah_txchainmask;
-
-	ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-	twiceLargestAntenna = max(
-		pEepData->modalHeader
-			[IS_CHAN_2GHZ(chan)].antennaGainCh[0],
-		pEepData->modalHeader
-			[IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
-
-	twiceLargestAntenna = max((u8)twiceLargestAntenna,
-				  pEepData->modalHeader
-				  [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
-
-	twiceLargestAntenna = (int16_t)min(AntennaReduction -
-					   twiceLargestAntenna, 0);
-
-	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-
-	if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
-		maxRegAllowedPower -=
-			(tpScaleReductionTable[(ah->ah_tpScale)] * 2);
-	}
-
-	scaledPower = min(powerLimit, maxRegAllowedPower);
-
-	switch (ar5416_get_ntxchains(tx_chainmask)) {
-	case 1:
-		break;
-	case 2:
-		scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
-		break;
-	case 3:
-		scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
-		break;
-	}
-
-	scaledPower = max((u16)0, scaledPower);
-
-	if (IS_CHAN_2GHZ(chan)) {
-		numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
-			SUB_NUM_CTL_MODES_AT_2G_40;
-		pCtlMode = ctlModesFor11g;
-
-		ath9k_hw_get_legacy_target_powers(ah, chan,
-			pEepData->calTargetPowerCck,
-			AR5416_NUM_2G_CCK_TARGET_POWERS,
-			&targetPowerCck, 4, false);
-		ath9k_hw_get_legacy_target_powers(ah, chan,
-			pEepData->calTargetPower2G,
-			AR5416_NUM_2G_20_TARGET_POWERS,
-			&targetPowerOfdm, 4, false);
-		ath9k_hw_get_target_powers(ah, chan,
-			pEepData->calTargetPower2GHT20,
-			AR5416_NUM_2G_20_TARGET_POWERS,
-			&targetPowerHt20, 8, false);
-
-		if (IS_CHAN_HT40(chan)) {
-			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
-			ath9k_hw_get_target_powers(ah, chan,
-				pEepData->calTargetPower2GHT40,
-				AR5416_NUM_2G_40_TARGET_POWERS,
-				&targetPowerHt40, 8, true);
-			ath9k_hw_get_legacy_target_powers(ah, chan,
-				pEepData->calTargetPowerCck,
-				AR5416_NUM_2G_CCK_TARGET_POWERS,
-				&targetPowerCckExt, 4, true);
-			ath9k_hw_get_legacy_target_powers(ah, chan,
-				pEepData->calTargetPower2G,
-				AR5416_NUM_2G_20_TARGET_POWERS,
-				&targetPowerOfdmExt, 4, true);
-		}
-	} else {
-		numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
-			SUB_NUM_CTL_MODES_AT_5G_40;
-		pCtlMode = ctlModesFor11a;
-
-		ath9k_hw_get_legacy_target_powers(ah, chan,
-			pEepData->calTargetPower5G,
-			AR5416_NUM_5G_20_TARGET_POWERS,
-			&targetPowerOfdm, 4, false);
-		ath9k_hw_get_target_powers(ah, chan,
-			pEepData->calTargetPower5GHT20,
-			AR5416_NUM_5G_20_TARGET_POWERS,
-			&targetPowerHt20, 8, false);
-
-		if (IS_CHAN_HT40(chan)) {
-			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
-			ath9k_hw_get_target_powers(ah, chan,
-				pEepData->calTargetPower5GHT40,
-				AR5416_NUM_5G_40_TARGET_POWERS,
-				&targetPowerHt40, 8, true);
-			ath9k_hw_get_legacy_target_powers(ah, chan,
-				pEepData->calTargetPower5G,
-				AR5416_NUM_5G_20_TARGET_POWERS,
-				&targetPowerOfdmExt, 4, true);
-		}
-	}
-
-	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
-		bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
-			(pCtlMode[ctlMode] == CTL_2GHT40);
-		if (isHt40CtlMode)
-			freq = centers.synth_center;
-		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
-			freq = centers.ext_center;
-		else
-			freq = centers.ctl_center;
-
-		if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2)
-			twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-
-		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-			"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
-			"EXT_ADDITIVE %d\n",
-			ctlMode, numCtlModes, isHt40CtlMode,
-			(pCtlMode[ctlMode] & EXT_ADDITIVE));
-
-		for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
-			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-				"  LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
-				"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
-				"chan %d\n",
-				i, cfgCtl, pCtlMode[ctlMode],
-				pEepData->ctlIndex[i], chan->channel);
-
-			if ((((cfgCtl & ~CTL_MODE_M) |
-			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
-			     pEepData->ctlIndex[i]) ||
-			    (((cfgCtl & ~CTL_MODE_M) |
-			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
-			     ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
-				rep = &(pEepData->ctlData[i]);
-
-				twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
-				rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
-				IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
-
-				DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-					"    MATCH-EE_IDX %d: ch %d is2 %d "
-					"2xMinEdge %d chainmask %d chains %d\n",
-					i, freq, IS_CHAN_2GHZ(chan),
-					twiceMinEdgePower, tx_chainmask,
-					ar5416_get_ntxchains
-					(tx_chainmask));
-				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
-					twiceMaxEdgePower = min(twiceMaxEdgePower,
-								twiceMinEdgePower);
-				} else {
-					twiceMaxEdgePower = twiceMinEdgePower;
-					break;
-				}
-			}
-		}
-
-		minCtlPower = min(twiceMaxEdgePower, scaledPower);
-
-		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-			"    SEL-Min ctlMode %d pCtlMode %d "
-			"2xMaxEdge %d sP %d minCtlPwr %d\n",
-			ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
-			scaledPower, minCtlPower);
-
-		switch (pCtlMode[ctlMode]) {
-		case CTL_11B:
-			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
-				targetPowerCck.tPow2x[i] =
-					min((u16)targetPowerCck.tPow2x[i],
-					    minCtlPower);
-			}
-			break;
-		case CTL_11A:
-		case CTL_11G:
-			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
-				targetPowerOfdm.tPow2x[i] =
-					min((u16)targetPowerOfdm.tPow2x[i],
-					    minCtlPower);
-			}
-			break;
-		case CTL_5GHT20:
-		case CTL_2GHT20:
-			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
-				targetPowerHt20.tPow2x[i] =
-					min((u16)targetPowerHt20.tPow2x[i],
-					    minCtlPower);
-			}
-			break;
-		case CTL_11B_EXT:
-			targetPowerCckExt.tPow2x[0] = min((u16)
-					targetPowerCckExt.tPow2x[0],
-					minCtlPower);
-			break;
-		case CTL_11A_EXT:
-		case CTL_11G_EXT:
-			targetPowerOfdmExt.tPow2x[0] = min((u16)
-					targetPowerOfdmExt.tPow2x[0],
-					minCtlPower);
-			break;
-		case CTL_5GHT40:
-		case CTL_2GHT40:
-			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
-				targetPowerHt40.tPow2x[i] =
-					min((u16)targetPowerHt40.tPow2x[i],
-					    minCtlPower);
-			}
-			break;
-		default:
-			break;
-		}
-	}
-
-	ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
-		ratesArray[rate18mb] = ratesArray[rate24mb] =
-		targetPowerOfdm.tPow2x[0];
-	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
-	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
-	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
-	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
-
-	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
-		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
-
-	if (IS_CHAN_2GHZ(chan)) {
-		ratesArray[rate1l] = targetPowerCck.tPow2x[0];
-		ratesArray[rate2s] = ratesArray[rate2l] =
-			targetPowerCck.tPow2x[1];
-		ratesArray[rate5_5s] = ratesArray[rate5_5l] =
-			targetPowerCck.tPow2x[2];
-		;
-		ratesArray[rate11s] = ratesArray[rate11l] =
-			targetPowerCck.tPow2x[3];
-		;
-	}
-	if (IS_CHAN_HT40(chan)) {
-		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
-			ratesArray[rateHt40_0 + i] =
-				targetPowerHt40.tPow2x[i];
-		}
-		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
-		ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
-		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
-		if (IS_CHAN_2GHZ(chan)) {
-			ratesArray[rateExtCck] =
-				targetPowerCckExt.tPow2x[0];
-		}
-	}
-	return true;
-}
-
-static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah,
+static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
 						 struct ath9k_channel *chan,
 						 int16_t *ratesArray,
 						 u16 cfgCtl,
@@ -1473,8 +763,7 @@
 						 u16 twiceMaxRegulatoryPower,
 						 u16 powerLimit)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
 	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
 	static const u16 tpScaleReductionTable[5] =
 		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
@@ -1502,7 +791,7 @@
 	int tx_chainmask;
 	u16 twiceMinEdgePower;
 
-	tx_chainmask = ahp->ah_txchainmask;
+	tx_chainmask = ah->txchainmask;
 
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 
@@ -1513,9 +802,9 @@
 
 	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
 
-	if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
+	if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) {
 		maxRegAllowedPower -=
-			(tpScaleReductionTable[(ah->ah_tpScale)] * 2);
+			(tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2);
 	}
 
 	scaledPower = min(powerLimit, maxRegAllowedPower);
@@ -1563,8 +852,8 @@
 		else
 			freq = centers.ctl_center;
 
-		if (ar5416_get_eep_ver(ahp) == 14 &&
-				ar5416_get_eep_rev(ahp) <= 2)
+		if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
+		    ah->eep_ops->get_eeprom_rev(ah) <= 2)
 			twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
 
 		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
@@ -1701,148 +990,14 @@
 	return true;
 }
 
-static int ath9k_hw_def_set_txpower(struct ath_hal *ah,
-			 struct ath9k_channel *chan,
-			 u16 cfgCtl,
-			 u8 twiceAntennaReduction,
-			 u8 twiceMaxRegulatoryPower,
-			 u8 powerLimit)
+static int ath9k_hw_4k_set_txpower(struct ath_hw *ah,
+				   struct ath9k_channel *chan,
+				   u16 cfgCtl,
+				   u8 twiceAntennaReduction,
+				   u8 twiceMaxRegulatoryPower,
+				   u8 powerLimit)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
-	struct modal_eep_header *pModal =
-		&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
-	int16_t ratesArray[Ar5416RateSize];
-	int16_t txPowerIndexOffset = 0;
-	u8 ht40PowerIncForPdadc = 2;
-	int i;
-
-	memset(ratesArray, 0, sizeof(ratesArray));
-
-	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-	    AR5416_EEP_MINOR_VER_2) {
-		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
-	}
-
-	if (!ath9k_hw_set_def_power_per_rate_table(ah, chan,
-					       &ratesArray[0], cfgCtl,
-					       twiceAntennaReduction,
-					       twiceMaxRegulatoryPower,
-					       powerLimit)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			"ath9k_hw_set_txpower: unable to set "
-			"tx power per rate table\n");
-		return -EIO;
-	}
-
-	if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "ath9k_hw_set_txpower: unable to set power table\n");
-		return -EIO;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
-		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
-		if (ratesArray[i] > AR5416_MAX_RATE_POWER)
-			ratesArray[i] = AR5416_MAX_RATE_POWER;
-	}
-
-	if (AR_SREV_9280_10_OR_LATER(ah)) {
-		for (i = 0; i < Ar5416RateSize; i++)
-			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
-	}
-
-	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
-		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
-		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
-		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
-		  | ATH9K_POW_SM(ratesArray[rate6mb], 0));
-	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
-		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
-		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
-		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
-		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
-
-	if (IS_CHAN_2GHZ(chan)) {
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
-			  ATH9K_POW_SM(ratesArray[rate2s], 24)
-			  | ATH9K_POW_SM(ratesArray[rate2l], 16)
-			  | ATH9K_POW_SM(ratesArray[rateXr], 8)
-			  | ATH9K_POW_SM(ratesArray[rate1l], 0));
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
-			  ATH9K_POW_SM(ratesArray[rate11s], 24)
-			  | ATH9K_POW_SM(ratesArray[rate11l], 16)
-			  | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
-			  | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
-	}
-
-	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
-		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
-	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
-		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
-
-	if (IS_CHAN_HT40(chan)) {
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
-			  ATH9K_POW_SM(ratesArray[rateHt40_3] +
-				       ht40PowerIncForPdadc, 24)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
-					 ht40PowerIncForPdadc, 16)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
-					 ht40PowerIncForPdadc, 8)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
-					 ht40PowerIncForPdadc, 0));
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
-			  ATH9K_POW_SM(ratesArray[rateHt40_7] +
-				       ht40PowerIncForPdadc, 24)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
-					 ht40PowerIncForPdadc, 16)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
-					 ht40PowerIncForPdadc, 8)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
-					 ht40PowerIncForPdadc, 0));
-
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
-			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
-			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
-			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
-			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
-	}
-
-	REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
-		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
-		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
-
-	i = rate6mb;
-
-	if (IS_CHAN_HT40(chan))
-		i = rateHt40_0;
-	else if (IS_CHAN_HT20(chan))
-		i = rateHt20_0;
-
-	if (AR_SREV_9280_10_OR_LATER(ah))
-		ah->ah_maxPowerLevel =
-			ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
-	else
-		ah->ah_maxPowerLevel = ratesArray[i];
-
-	return 0;
-}
-
-static int ath9k_hw_4k_set_txpower(struct ath_hal *ah,
-			 struct ath9k_channel *chan,
-			 u16 cfgCtl,
-			 u8 twiceAntennaReduction,
-			 u8 twiceMaxRegulatoryPower,
-			 u8 powerLimit)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
 	struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
 	int16_t ratesArray[Ar5416RateSize];
 	int16_t txPowerIndexOffset = 0;
@@ -1954,135 +1109,509 @@
 		i = rateHt20_0;
 
 	if (AR_SREV_9280_10_OR_LATER(ah))
-		ah->ah_maxPowerLevel =
+		ah->regulatory.max_power_level =
 			ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
 	else
-		ah->ah_maxPowerLevel = ratesArray[i];
+		ah->regulatory.max_power_level = ratesArray[i];
 
 	return 0;
 }
 
-static int (*ath9k_set_txpower[]) (struct ath_hal *,
-				   struct ath9k_channel *,
-				   u16, u8, u8, u8) = {
-	ath9k_hw_def_set_txpower,
-	ath9k_hw_4k_set_txpower
-};
-
-int ath9k_hw_set_txpower(struct ath_hal *ah,
-			 struct ath9k_channel *chan,
-			 u16 cfgCtl,
-			 u8 twiceAntennaReduction,
-			 u8 twiceMaxRegulatoryPower,
-			 u8 powerLimit)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	return ath9k_set_txpower[ahp->ah_eep_map](ah, chan, cfgCtl,
-			twiceAntennaReduction, twiceMaxRegulatoryPower,
-			powerLimit);
-}
-
-static void ath9k_hw_set_def_addac(struct ath_hal *ah,
-				   struct ath9k_channel *chan)
-{
-#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])
-	struct modal_eep_header *pModal;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
-	u8 biaslevel;
-
-	if (ah->ah_macVersion != AR_SREV_VERSION_9160)
-		return;
-
-	if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
-		return;
-
-	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
-	if (pModal->xpaBiasLvl != 0xff) {
-		biaslevel = pModal->xpaBiasLvl;
-	} else {
-		u16 resetFreqBin, freqBin, freqCount = 0;
-		struct chan_centers centers;
-
-		ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-		resetFreqBin = FREQ2FBIN(centers.synth_center,
-					 IS_CHAN_2GHZ(chan));
-		freqBin = XPA_LVL_FREQ(0) & 0xff;
-		biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14);
-
-		freqCount++;
-
-		while (freqCount < 3) {
-			if (XPA_LVL_FREQ(freqCount) == 0x0)
-				break;
-
-			freqBin = XPA_LVL_FREQ(freqCount) & 0xff;
-			if (resetFreqBin >= freqBin)
-				biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14);
-			else
-				break;
-			freqCount++;
-		}
-	}
-
-	if (IS_CHAN_2GHZ(chan)) {
-		INI_RA(&ahp->ah_iniAddac, 7, 1) = (INI_RA(&ahp->ah_iniAddac,
-					7, 1) & (~0x18)) | biaslevel << 3;
-	} else {
-		INI_RA(&ahp->ah_iniAddac, 6, 1) = (INI_RA(&ahp->ah_iniAddac,
-					6, 1) & (~0xc0)) | biaslevel << 6;
-	}
-#undef XPA_LVL_FREQ
-}
-
-static void ath9k_hw_set_4k_addac(struct ath_hal *ah,
+static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
 				  struct ath9k_channel *chan)
 {
 	struct modal_eep_4k_header *pModal;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
 	u8 biaslevel;
 
-	if (ah->ah_macVersion != AR_SREV_VERSION_9160)
+	if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
 		return;
 
-	if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
+	if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
 		return;
 
 	pModal = &eep->modalHeader;
 
 	if (pModal->xpaBiasLvl != 0xff) {
 		biaslevel = pModal->xpaBiasLvl;
-		INI_RA(&ahp->ah_iniAddac, 7, 1) =
-		  (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
+		INI_RA(&ah->iniAddac, 7, 1) =
+		  (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
 	}
 }
 
-static void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = {
-	ath9k_hw_set_def_addac,
-	ath9k_hw_set_4k_addac
-};
-
-void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan)
+static bool ath9k_hw_4k_set_board_values(struct ath_hw *ah,
+					 struct ath9k_channel *chan)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct modal_eep_4k_header *pModal;
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+	int regChainOffset;
+	u8 txRxAttenLocal;
+	u8 ob[5], db1[5], db2[5];
+	u8 ant_div_control1, ant_div_control2;
+	u32 regVal;
 
-	ath9k_set_addac[ahp->ah_eep_map](ah, chan);
+
+	pModal = &eep->modalHeader;
+
+	txRxAttenLocal = 23;
+
+	REG_WRITE(ah, AR_PHY_SWITCH_COM,
+		  ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
+
+	regChainOffset = 0;
+	REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+		  pModal->antCtrlChain[0]);
+
+	REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+		 (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
+		 ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+		 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+		 SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+		 SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+			AR5416_EEP_MINOR_VER_3) {
+		txRxAttenLocal = pModal->txRxAttenCh[0];
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+			pModal->xatten2Margin[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+			AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+	REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+			AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
+	if (AR_SREV_9285_11(ah))
+		REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
+
+	/* Initialize Ant Diversity settings from EEPROM */
+	if (pModal->version == 3) {
+		ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
+		ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
+		regVal = REG_READ(ah, 0x99ac);
+		regVal &= (~(0x7f000000));
+		regVal |= ((ant_div_control1 & 0x1) << 24);
+		regVal |= (((ant_div_control1 >> 1) & 0x1) << 29);
+		regVal |= (((ant_div_control1 >> 2) & 0x1) << 30);
+		regVal |= ((ant_div_control2 & 0x3) << 25);
+		regVal |= (((ant_div_control2 >> 2) & 0x3) << 27);
+		REG_WRITE(ah, 0x99ac, regVal);
+		regVal = REG_READ(ah, 0x99ac);
+		regVal = REG_READ(ah, 0xa208);
+		regVal &= (~(0x1 << 13));
+		regVal |= (((ant_div_control1 >> 3) & 0x1) << 13);
+		REG_WRITE(ah, 0xa208, regVal);
+		regVal = REG_READ(ah, 0xa208);
+	}
+
+	if (pModal->version >= 2) {
+		ob[0] = (pModal->ob_01 & 0xf);
+		ob[1] = (pModal->ob_01 >> 4) & 0xf;
+		ob[2] = (pModal->ob_234 & 0xf);
+		ob[3] = ((pModal->ob_234 >> 4) & 0xf);
+		ob[4] = ((pModal->ob_234 >> 8) & 0xf);
+
+		db1[0] = (pModal->db1_01 & 0xf);
+		db1[1] = ((pModal->db1_01 >> 4) & 0xf);
+		db1[2] = (pModal->db1_234 & 0xf);
+		db1[3] = ((pModal->db1_234 >> 4) & 0xf);
+		db1[4] = ((pModal->db1_234 >> 8) & 0xf);
+
+		db2[0] = (pModal->db2_01 & 0xf);
+		db2[1] = ((pModal->db2_01 >> 4) & 0xf);
+		db2[2] = (pModal->db2_234 & 0xf);
+		db2[3] = ((pModal->db2_234 >> 4) & 0xf);
+		db2[4] = ((pModal->db2_234 >> 8) & 0xf);
+
+	} else if (pModal->version == 1) {
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"EEPROM Model version is set to 1 \n");
+		ob[0] = (pModal->ob_01 & 0xf);
+		ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf;
+		db1[0] = (pModal->db1_01 & 0xf);
+		db1[1] = db1[2] = db1[3] =
+			db1[4] = ((pModal->db1_01 >> 4) & 0xf);
+		db2[0] = (pModal->db2_01 & 0xf);
+		db2[1] = db2[2] = db2[3] =
+			db2[4] = ((pModal->db2_01 >> 4) & 0xf);
+	} else {
+		int i;
+		for (i = 0; i < 5; i++) {
+			ob[i] = pModal->ob_01;
+			db1[i] = pModal->db1_01;
+			db2[i] = pModal->db1_01;
+		}
+	}
+
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]);
+
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]);
+
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]);
+
+
+	if (AR_SREV_9285_11(ah))
+		REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
+
+	REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+		      pModal->switchSettling);
+	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+		      pModal->adcDesiredSize);
+
+	REG_WRITE(ah, AR_PHY_RF_CTL4,
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) |
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) |
+		  SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)  |
+		  SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+		      pModal->txEndToRxOn);
+	REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+		      pModal->thresh62);
+	REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
+		      pModal->thresh62);
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+						AR5416_EEP_MINOR_VER_2) {
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START,
+			      pModal->txFrameToDataStart);
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+			      pModal->txFrameToPaOn);
+	}
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+						AR5416_EEP_MINOR_VER_3) {
+		if (IS_CHAN_HT40(chan))
+			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+				      AR_PHY_SETTLING_SWITCH,
+				      pModal->swSettleHt40);
+	}
+
+	return true;
 }
 
+static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
+					      struct ath9k_channel *chan)
+{
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+	struct modal_eep_4k_header *pModal = &eep->modalHeader;
 
+	return pModal->antCtrlCommon & 0xFFFF;
+}
+
+static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
+					 enum ieee80211_band freq_band)
+{
+	return 1;
+}
+
+u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
+{
+#define EEP_MAP4K_SPURCHAN \
+	(ah->eeprom.map4k.modalHeader.spurChans[i].spurChan)
+
+	u16 spur_val = AR_NO_SPUR;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"Getting spur idx %d is2Ghz. %d val %x\n",
+		i, is2GHz, ah->config.spurchans[i][is2GHz]);
+
+	switch (ah->config.spurmode) {
+	case SPUR_DISABLE:
+		break;
+	case SPUR_ENABLE_IOCTL:
+		spur_val = ah->config.spurchans[i][is2GHz];
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"Getting spur val from new loc. %d\n", spur_val);
+		break;
+	case SPUR_ENABLE_EEPROM:
+		spur_val = EEP_MAP4K_SPURCHAN;
+		break;
+	}
+
+	return spur_val;
+
+#undef EEP_MAP4K_SPURCHAN
+}
+
+struct eeprom_ops eep_4k_ops = {
+	.check_eeprom		= ath9k_hw_4k_check_eeprom,
+	.get_eeprom		= ath9k_hw_4k_get_eeprom,
+	.fill_eeprom		= ath9k_hw_4k_fill_eeprom,
+	.get_eeprom_ver		= ath9k_hw_4k_get_eeprom_ver,
+	.get_eeprom_rev		= ath9k_hw_4k_get_eeprom_rev,
+	.get_num_ant_config	= ath9k_hw_4k_get_num_ant_config,
+	.get_eeprom_antenna_cfg	= ath9k_hw_4k_get_eeprom_antenna_cfg,
+	.set_board_values	= ath9k_hw_4k_set_board_values,
+	.set_addac		= ath9k_hw_4k_set_addac,
+	.set_txpower		= ath9k_hw_4k_set_txpower,
+	.get_spur_channel	= ath9k_hw_4k_get_spur_channel
+};
+
+/************************************************/
+/* EEPROM Operations for non-4K (Default) cards */
+/************************************************/
+
+static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah)
+{
+	return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF);
+}
+
+static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
+{
+	return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF);
+}
+
+static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
+{
+#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+	u16 *eep_data;
+	int addr, ar5416_eep_start_loc = 0x100;
+
+	eep_data = (u16 *)eep;
+
+	for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
+		if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+					 eep_data)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+				"Unable to read eeprom region\n");
+			return false;
+		}
+		eep_data++;
+	}
+	return true;
+#undef SIZE_EEPROM_DEF
+}
+
+static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
+{
+	struct ar5416_eeprom_def *eep =
+		(struct ar5416_eeprom_def *) &ah->eeprom.def;
+	u16 *eepdata, temp, magic, magic2;
+	u32 sum = 0, el;
+	bool need_swap = false;
+	int i, addr, size;
+
+	if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+				 &magic)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"Reading Magic # failed\n");
+		return false;
+	}
+
+	if (!ath9k_hw_use_flash(ah)) {
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+				"Read Magic = 0x%04X\n", magic);
+
+		if (magic != AR5416_EEPROM_MAGIC) {
+			magic2 = swab16(magic);
+
+			if (magic2 == AR5416_EEPROM_MAGIC) {
+				size = sizeof(struct ar5416_eeprom_def);
+				need_swap = true;
+				eepdata = (u16 *) (&ah->eeprom);
+
+				for (addr = 0; addr < size / sizeof(u16); addr++) {
+					temp = swab16(*eepdata);
+					*eepdata = temp;
+					eepdata++;
+
+					DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+						"0x%04X  ", *eepdata);
+
+					if (((addr + 1) % 6) == 0)
+						DPRINTF(ah->ah_sc,
+							ATH_DBG_EEPROM, "\n");
+				}
+			} else {
+				DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+					"Invalid EEPROM Magic. "
+					"endianness mismatch.\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+		need_swap ? "True" : "False");
+
+	if (need_swap)
+		el = swab16(ah->eeprom.def.baseEepHeader.length);
+	else
+		el = ah->eeprom.def.baseEepHeader.length;
+
+	if (el > sizeof(struct ar5416_eeprom_def))
+		el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
+	else
+		el = el / sizeof(u16);
+
+	eepdata = (u16 *)(&ah->eeprom);
+
+	for (i = 0; i < el; i++)
+		sum ^= *eepdata++;
+
+	if (need_swap) {
+		u32 integer, j;
+		u16 word;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"EEPROM Endianness is not native.. Changing \n");
+
+		word = swab16(eep->baseEepHeader.length);
+		eep->baseEepHeader.length = word;
+
+		word = swab16(eep->baseEepHeader.checksum);
+		eep->baseEepHeader.checksum = word;
+
+		word = swab16(eep->baseEepHeader.version);
+		eep->baseEepHeader.version = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[0]);
+		eep->baseEepHeader.regDmn[0] = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[1]);
+		eep->baseEepHeader.regDmn[1] = word;
+
+		word = swab16(eep->baseEepHeader.rfSilent);
+		eep->baseEepHeader.rfSilent = word;
+
+		word = swab16(eep->baseEepHeader.blueToothOptions);
+		eep->baseEepHeader.blueToothOptions = word;
+
+		word = swab16(eep->baseEepHeader.deviceCap);
+		eep->baseEepHeader.deviceCap = word;
+
+		for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+			struct modal_eep_header *pModal =
+				&eep->modalHeader[j];
+			integer = swab32(pModal->antCtrlCommon);
+			pModal->antCtrlCommon = integer;
+
+			for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+				integer = swab32(pModal->antCtrlChain[i]);
+				pModal->antCtrlChain[i] = integer;
+			}
+
+			for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+				word = swab16(pModal->spurChans[i].spurChan);
+				pModal->spurChans[i].spurChan = word;
+			}
+		}
+	}
+
+	if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
+	    ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+			sum, ah->eep_ops->get_eeprom_ver(ah));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
+				   enum eeprom_param param)
+{
+#define AR5416_VER_MASK (pBase->version & AR5416_EEP_VER_MINOR_MASK)
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+	struct modal_eep_header *pModal = eep->modalHeader;
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+
+	switch (param) {
+	case EEP_NFTHRESH_5:
+		return pModal[0].noiseFloorThreshCh[0];
+	case EEP_NFTHRESH_2:
+		return pModal[1].noiseFloorThreshCh[0];
+	case AR_EEPROM_MAC(0):
+		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+	case AR_EEPROM_MAC(1):
+		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+	case AR_EEPROM_MAC(2):
+		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_REG_0:
+		return pBase->regDmn[0];
+	case EEP_REG_1:
+		return pBase->regDmn[1];
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_OB_5:
+		return pModal[0].ob;
+	case EEP_DB_5:
+		return pModal[0].db;
+	case EEP_OB_2:
+		return pModal[1].ob;
+	case EEP_DB_2:
+		return pModal[1].db;
+	case EEP_MINOR_REV:
+		return AR5416_VER_MASK;
+	case EEP_TX_MASK:
+		return pBase->txMask;
+	case EEP_RX_MASK:
+		return pBase->rxMask;
+	case EEP_RXGAIN_TYPE:
+		return pBase->rxGainType;
+	case EEP_TXGAIN_TYPE:
+		return pBase->txGainType;
+	case EEP_DAC_HPWR_5G:
+		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20)
+			return pBase->dacHiPwrMode_5G;
+		else
+			return 0;
+	default:
+		return 0;
+	}
+#undef AR5416_VER_MASK
+}
 
 /* XXX: Clean me up, make me more legible */
-static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah,
-				      struct ath9k_channel *chan)
+static bool ath9k_hw_def_set_board_values(struct ath_hw *ah,
+					  struct ath9k_channel *chan)
 {
 #define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK)
 	struct modal_eep_header *pModal;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
 	int i, regChainOffset;
 	u8 txRxAttenLocal;
 
@@ -2091,7 +1620,7 @@
 	txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
 
 	REG_WRITE(ah, AR_PHY_SWITCH_COM,
-		  ath9k_hw_get_eeprom_antenna_cfg(ah, chan));
+		  ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
 
 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
 		if (AR_SREV_9280(ah)) {
@@ -2100,7 +1629,7 @@
 		}
 
 		if (AR_SREV_5416_V20_OR_LATER(ah) &&
-		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
+		    (ah->rxchainmask == 5 || ah->txchainmask == 5)
 		    && (i != 0))
 			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
 		else
@@ -2321,253 +1850,778 @@
 #undef AR5416_VER_MASK
 }
 
-static bool ath9k_hw_eeprom_set_4k_board_values(struct ath_hal *ah,
-				      struct ath9k_channel *chan)
+static void ath9k_hw_def_set_addac(struct ath_hw *ah,
+				   struct ath9k_channel *chan)
 {
-	struct modal_eep_4k_header *pModal;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
-	int regChainOffset;
-	u8 txRxAttenLocal;
-	u8 ob[5], db1[5], db2[5];
-	u8 ant_div_control1, ant_div_control2;
-	u32 regVal;
+#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])
+	struct modal_eep_header *pModal;
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+	u8 biaslevel;
 
+	if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
+		return;
 
-	pModal = &eep->modalHeader;
+	if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
+		return;
 
-	txRxAttenLocal = 23;
+	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
 
-	REG_WRITE(ah, AR_PHY_SWITCH_COM,
-		  ath9k_hw_get_eeprom_antenna_cfg(ah, chan));
-
-	regChainOffset = 0;
-	REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
-		  pModal->antCtrlChain[0]);
-
-	REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
-		 (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
-		 ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
-		 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
-		 SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
-		 SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
-
-	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-			AR5416_EEP_MINOR_VER_3) {
-		txRxAttenLocal = pModal->txRxAttenCh[0];
-		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
-			AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]);
-		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
-			AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
-		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
-			AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
-			pModal->xatten2Margin[0]);
-		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
-			AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
-	}
-
-	REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
-			AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
-	REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
-			AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
-
-	if (AR_SREV_9285_11(ah))
-		REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
-
-	/* Initialize Ant Diversity settings from EEPROM */
-	if (pModal->version == 3) {
-		ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
-		ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
-		regVal = REG_READ(ah, 0x99ac);
-		regVal &= (~(0x7f000000));
-		regVal |= ((ant_div_control1 & 0x1) << 24);
-		regVal |= (((ant_div_control1 >> 1) & 0x1) << 29);
-		regVal |= (((ant_div_control1 >> 2) & 0x1) << 30);
-		regVal |= ((ant_div_control2 & 0x3) << 25);
-		regVal |= (((ant_div_control2 >> 2) & 0x3) << 27);
-		REG_WRITE(ah, 0x99ac, regVal);
-		regVal = REG_READ(ah, 0x99ac);
-		regVal = REG_READ(ah, 0xa208);
-		regVal &= (~(0x1 << 13));
-		regVal |= (((ant_div_control1 >> 3) & 0x1) << 13);
-		REG_WRITE(ah, 0xa208, regVal);
-		regVal = REG_READ(ah, 0xa208);
-	}
-
-	if (pModal->version >= 2) {
-		ob[0] = (pModal->ob_01 & 0xf);
-		ob[1] = (pModal->ob_01 >> 4) & 0xf;
-		ob[2] = (pModal->ob_234 & 0xf);
-		ob[3] = ((pModal->ob_234 >> 4) & 0xf);
-		ob[4] = ((pModal->ob_234 >> 8) & 0xf);
-
-		db1[0] = (pModal->db1_01 & 0xf);
-		db1[1] = ((pModal->db1_01 >> 4) & 0xf);
-		db1[2] = (pModal->db1_234 & 0xf);
-		db1[3] = ((pModal->db1_234 >> 4) & 0xf);
-		db1[4] = ((pModal->db1_234 >> 8) & 0xf);
-
-		db2[0] = (pModal->db2_01 & 0xf);
-		db2[1] = ((pModal->db2_01 >> 4) & 0xf);
-		db2[2] = (pModal->db2_234 & 0xf);
-		db2[3] = ((pModal->db2_234 >> 4) & 0xf);
-		db2[4] = ((pModal->db2_234 >> 8) & 0xf);
-
-	} else if (pModal->version == 1) {
-
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			"EEPROM Model version is set to 1 \n");
-		ob[0] = (pModal->ob_01 & 0xf);
-		ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf;
-		db1[0] = (pModal->db1_01 & 0xf);
-		db1[1] = db1[2] = db1[3] =
-			db1[4] = ((pModal->db1_01 >> 4) & 0xf);
-		db2[0] = (pModal->db2_01 & 0xf);
-		db2[1] = db2[2] = db2[3] =
-			db2[4] = ((pModal->db2_01 >> 4) & 0xf);
+	if (pModal->xpaBiasLvl != 0xff) {
+		biaslevel = pModal->xpaBiasLvl;
 	} else {
-		int i;
-		for (i = 0; i < 5; i++) {
-			ob[i] = pModal->ob_01;
-			db1[i] = pModal->db1_01;
-			db2[i] = pModal->db1_01;
+		u16 resetFreqBin, freqBin, freqCount = 0;
+		struct chan_centers centers;
+
+		ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+		resetFreqBin = FREQ2FBIN(centers.synth_center,
+					 IS_CHAN_2GHZ(chan));
+		freqBin = XPA_LVL_FREQ(0) & 0xff;
+		biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14);
+
+		freqCount++;
+
+		while (freqCount < 3) {
+			if (XPA_LVL_FREQ(freqCount) == 0x0)
+				break;
+
+			freqBin = XPA_LVL_FREQ(freqCount) & 0xff;
+			if (resetFreqBin >= freqBin)
+				biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14);
+			else
+				break;
+			freqCount++;
 		}
 	}
 
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
-			AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
-			AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
-			AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
-			AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
-			AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]);
+	if (IS_CHAN_2GHZ(chan)) {
+		INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac,
+					7, 1) & (~0x18)) | biaslevel << 3;
+	} else {
+		INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac,
+					6, 1) & (~0xc0)) | biaslevel << 6;
+	}
+#undef XPA_LVL_FREQ
+}
 
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
-			AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
-			AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
-			AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
-			AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
-			AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]);
+static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				struct cal_data_per_freq *pRawDataSet,
+				u8 *bChans, u16 availPiers,
+				u16 tPdGainOverlap, int16_t *pMinCalPower,
+				u16 *pPdGainBoundaries, u8 *pPDADCValues,
+				u16 numXpdGains)
+{
+	int i, j, k;
+	int16_t ss;
+	u16 idxL = 0, idxR = 0, numPiers;
+	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
 
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
-			AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
-			AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
-			AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
-			AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]);
-	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
-			AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]);
+	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+	u8 minPwrT4[AR5416_NUM_PD_GAINS];
+	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+	int16_t vpdStep;
+	int16_t tmpVal;
+	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+	bool match;
+	int16_t minDelta = 0;
+	struct chan_centers centers;
 
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
 
-	if (AR_SREV_9285_11(ah))
-		REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
-
-	REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
-		      pModal->switchSettling);
-	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
-		      pModal->adcDesiredSize);
-
-	REG_WRITE(ah, AR_PHY_RF_CTL4,
-		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) |
-		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) |
-		  SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)  |
-		  SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
-
-	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
-		      pModal->txEndToRxOn);
-	REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
-		      pModal->thresh62);
-	REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
-		      pModal->thresh62);
-
-	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-						AR5416_EEP_MINOR_VER_2) {
-		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START,
-			      pModal->txFrameToDataStart);
-		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
-			      pModal->txFrameToPaOn);
+	for (numPiers = 0; numPiers < availPiers; numPiers++) {
+		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+			break;
 	}
 
-	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-						AR5416_EEP_MINOR_VER_3) {
-		if (IS_CHAN_HT40(chan))
-			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
-				      AR_PHY_SETTLING_SWITCH,
-				      pModal->swSettleHt40);
+	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
+							     IS_CHAN_2GHZ(chan)),
+					       bChans, numPiers, &idxL, &idxR);
+
+	if (match) {
+		for (i = 0; i < numXpdGains; i++) {
+			minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+			maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+					pRawDataSet[idxL].pwrPdg[i],
+					pRawDataSet[idxL].vpdPdg[i],
+					AR5416_PD_GAIN_ICEPTS,
+					vpdTableI[i]);
+		}
+	} else {
+		for (i = 0; i < numXpdGains; i++) {
+			pVpdL = pRawDataSet[idxL].vpdPdg[i];
+			pPwrL = pRawDataSet[idxL].pwrPdg[i];
+			pVpdR = pRawDataSet[idxR].vpdPdg[i];
+			pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+			maxPwrT4[i] =
+				min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
+				    pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
+
+
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrL, pVpdL,
+						AR5416_PD_GAIN_ICEPTS,
+						vpdTableL[i]);
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrR, pVpdR,
+						AR5416_PD_GAIN_ICEPTS,
+						vpdTableR[i]);
+
+			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+				vpdTableI[i][j] =
+					(u8)(ath9k_hw_interpolate((u16)
+					     FREQ2FBIN(centers.
+						       synth_center,
+						       IS_CHAN_2GHZ
+						       (chan)),
+					     bChans[idxL], bChans[idxR],
+					     vpdTableL[i][j], vpdTableR[i][j]));
+			}
+		}
 	}
 
+	*pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+	k = 0;
+
+	for (i = 0; i < numXpdGains; i++) {
+		if (i == (numXpdGains - 1))
+			pPdGainBoundaries[i] =
+				(u16)(maxPwrT4[i] / 2);
+		else
+			pPdGainBoundaries[i] =
+				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+		pPdGainBoundaries[i] =
+			min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+		if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+			minDelta = pPdGainBoundaries[0] - 23;
+			pPdGainBoundaries[0] = 23;
+		} else {
+			minDelta = 0;
+		}
+
+		if (i == 0) {
+			if (AR_SREV_9280_10_OR_LATER(ah))
+				ss = (int16_t)(0 - (minPwrT4[i] / 2));
+			else
+				ss = 0;
+		} else {
+			ss = (int16_t)((pPdGainBoundaries[i - 1] -
+					(minPwrT4[i] / 2)) -
+				       tPdGainOverlap + 1 + minDelta);
+		}
+		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+			ss++;
+		}
+
+		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+				(minPwrT4[i] / 2));
+		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+			tgtIndex : sizeCurrVpdTable;
+
+		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			pPDADCValues[k++] = vpdTableI[i][ss++];
+		}
+
+		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+				    vpdTableI[i][sizeCurrVpdTable - 2]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		if (tgtIndex > maxIndex) {
+			while ((ss <= tgtIndex) &&
+			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
+						    (ss - maxIndex + 1) * vpdStep));
+				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+							 255 : tmpVal);
+				ss++;
+			}
+		}
+	}
+
+	while (i < AR5416_PD_GAINS_IN_MASK) {
+		pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
+		i++;
+	}
+
+	while (k < AR5416_NUM_PDADC_VALUES) {
+		pPDADCValues[k] = pPDADCValues[k - 1];
+		k++;
+	}
+
+	return;
+}
+
+static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
+				  struct ath9k_channel *chan,
+				  int16_t *pTxPowerIndexOffset)
+{
+	struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+	struct cal_data_per_freq *pRawDataset;
+	u8 *pCalBChans = NULL;
+	u16 pdGainOverlap_t2;
+	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+	u16 numPiers, i, j;
+	int16_t tMinCalPower;
+	u16 numXpdGain, xpdMask;
+	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+	u32 reg32, regOffset, regChainOffset;
+	int16_t modalIdx;
+
+	modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+	xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		pdGainOverlap_t2 =
+			pEepData->modalHeader[modalIdx].pdGainOverlap;
+	} else {
+		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+	}
+
+	if (IS_CHAN_2GHZ(chan)) {
+		pCalBChans = pEepData->calFreqPier2G;
+		numPiers = AR5416_NUM_2G_CAL_PIERS;
+	} else {
+		pCalBChans = pEepData->calFreqPier5G;
+		numPiers = AR5416_NUM_5G_CAL_PIERS;
+	}
+
+	numXpdGain = 0;
+
+	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+			if (numXpdGain >= AR5416_NUM_PD_GAINS)
+				break;
+			xpdGainValues[numXpdGain] =
+				(u16)(AR5416_PD_GAINS_IN_MASK - i);
+			numXpdGain++;
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+		      (numXpdGain - 1) & 0x3);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+		      xpdGainValues[0]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+		      xpdGainValues[1]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+		      xpdGainValues[2]);
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (AR_SREV_5416_V20_OR_LATER(ah) &&
+		    (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
+		    (i != 0)) {
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		} else
+			regChainOffset = i * 0x1000;
+
+		if (pEepData->baseEepHeader.txMask & (1 << i)) {
+			if (IS_CHAN_2GHZ(chan))
+				pRawDataset = pEepData->calPierData2G[i];
+			else
+				pRawDataset = pEepData->calPierData5G[i];
+
+			ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan,
+					    pRawDataset, pCalBChans,
+					    numPiers, pdGainOverlap_t2,
+					    &tMinCalPower, gainBoundaries,
+					    pdadcValues, numXpdGain);
+
+			if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+				REG_WRITE(ah,
+					  AR_PHY_TPCRG5 + regChainOffset,
+					  SM(pdGainOverlap_t2,
+					     AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+					  | SM(gainBoundaries[0],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+					  | SM(gainBoundaries[1],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+					  | SM(gainBoundaries[2],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+					  | SM(gainBoundaries[3],
+				       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+			}
+
+			regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+			for (j = 0; j < 32; j++) {
+				reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+					((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+					((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+					((pdadcValues[4 * j + 3] & 0xFF) << 24);
+				REG_WRITE(ah, regOffset, reg32);
+
+				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+					"PDADC (%d,%4x): %4.4x %8.8x\n",
+					i, regChainOffset, regOffset,
+					reg32);
+				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+					"PDADC: Chain %d | PDADC %3d "
+					"Value %3d | PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d | PDADC %3d "
+					"Value %3d |\n",
+					i, 4 * j, pdadcValues[4 * j],
+					4 * j + 1, pdadcValues[4 * j + 1],
+					4 * j + 2, pdadcValues[4 * j + 2],
+					4 * j + 3,
+					pdadcValues[4 * j + 3]);
+
+				regOffset += 4;
+			}
+		}
+	}
+
+	*pTxPowerIndexOffset = 0;
+
 	return true;
 }
 
-static bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *,
-					       struct ath9k_channel *) = {
-	ath9k_hw_eeprom_set_def_board_values,
-	ath9k_hw_eeprom_set_4k_board_values
-};
-
-bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
-				      struct ath9k_channel *chan)
+static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
+						  struct ath9k_channel *chan,
+						  int16_t *ratesArray,
+						  u16 cfgCtl,
+						  u16 AntennaReduction,
+						  u16 twiceMaxRegulatoryPower,
+						  u16 powerLimit)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10 /* 10*log10(3)*2 */
 
-	return ath9k_eeprom_set_board_values[ahp->ah_eep_map](ah, chan);
+	struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+	static const u16 tpScaleReductionTable[5] =
+		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+	int i;
+	int16_t twiceLargestAntenna;
+	struct cal_ctl_data *rep;
+	struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+		0, { 0, 0, 0, 0}
+	};
+	struct cal_target_power_leg targetPowerOfdmExt = {
+		0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+		0, { 0, 0, 0, 0 }
+	};
+	struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+		0, {0, 0, 0, 0}
+	};
+	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	u16 ctlModesFor11a[] =
+		{ CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
+	u16 ctlModesFor11g[] =
+		{ CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+		  CTL_2GHT40
+		};
+	u16 numCtlModes, *pCtlMode, ctlMode, freq;
+	struct chan_centers centers;
+	int tx_chainmask;
+	u16 twiceMinEdgePower;
+
+	tx_chainmask = ah->txchainmask;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	twiceLargestAntenna = max(
+		pEepData->modalHeader
+			[IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+		pEepData->modalHeader
+			[IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+
+	twiceLargestAntenna = max((u8)twiceLargestAntenna,
+				  pEepData->modalHeader
+				  [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+
+	twiceLargestAntenna = (int16_t)min(AntennaReduction -
+					   twiceLargestAntenna, 0);
+
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+	if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) {
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2);
+	}
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+
+	switch (ar5416_get_ntxchains(tx_chainmask)) {
+	case 1:
+		break;
+	case 2:
+		scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+		break;
+	case 3:
+		scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+		break;
+	}
+
+	scaledPower = max((u16)0, scaledPower);
+
+	if (IS_CHAN_2GHZ(chan)) {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
+			SUB_NUM_CTL_MODES_AT_2G_40;
+		pCtlMode = ctlModesFor11g;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPowerCck,
+			AR5416_NUM_2G_CCK_TARGET_POWERS,
+			&targetPowerCck, 4, false);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower2G,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, false);
+		ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower2GHT20,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, false);
+
+		if (IS_CHAN_HT40(chan)) {
+			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+			ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower2GHT40,
+				AR5416_NUM_2G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPowerCck,
+				AR5416_NUM_2G_CCK_TARGET_POWERS,
+				&targetPowerCckExt, 4, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower2G,
+				AR5416_NUM_2G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, true);
+		}
+	} else {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+			SUB_NUM_CTL_MODES_AT_5G_40;
+		pCtlMode = ctlModesFor11a;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower5G,
+			AR5416_NUM_5G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, false);
+		ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower5GHT20,
+			AR5416_NUM_5G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, false);
+
+		if (IS_CHAN_HT40(chan)) {
+			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+			ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower5GHT40,
+				AR5416_NUM_5G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower5G,
+				AR5416_NUM_5G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, true);
+		}
+	}
+
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+			(pCtlMode[ctlMode] == CTL_2GHT40);
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
+		    ah->eep_ops->get_eeprom_rev(ah) <= 2)
+			twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+			"EXT_ADDITIVE %d\n",
+			ctlMode, numCtlModes, isHt40CtlMode,
+			(pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+		for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+				"  LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+				"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+				"chan %d\n",
+				i, cfgCtl, pCtlMode[ctlMode],
+				pEepData->ctlIndex[i], chan->channel);
+
+			if ((((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     pEepData->ctlIndex[i]) ||
+			    (((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
+				rep = &(pEepData->ctlData[i]);
+
+				twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+				rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
+				IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
+
+				DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+					"    MATCH-EE_IDX %d: ch %d is2 %d "
+					"2xMinEdge %d chainmask %d chains %d\n",
+					i, freq, IS_CHAN_2GHZ(chan),
+					twiceMinEdgePower, tx_chainmask,
+					ar5416_get_ntxchains
+					(tx_chainmask));
+				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+					twiceMaxEdgePower = min(twiceMaxEdgePower,
+								twiceMinEdgePower);
+				} else {
+					twiceMaxEdgePower = twiceMinEdgePower;
+					break;
+				}
+			}
+		}
+
+		minCtlPower = min(twiceMaxEdgePower, scaledPower);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"    SEL-Min ctlMode %d pCtlMode %d "
+			"2xMaxEdge %d sP %d minCtlPwr %d\n",
+			ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+			scaledPower, minCtlPower);
+
+		switch (pCtlMode[ctlMode]) {
+		case CTL_11B:
+			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+				targetPowerCck.tPow2x[i] =
+					min((u16)targetPowerCck.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11A:
+		case CTL_11G:
+			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+				targetPowerOfdm.tPow2x[i] =
+					min((u16)targetPowerOfdm.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_5GHT20:
+		case CTL_2GHT20:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+				targetPowerHt20.tPow2x[i] =
+					min((u16)targetPowerHt20.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11B_EXT:
+			targetPowerCckExt.tPow2x[0] = min((u16)
+					targetPowerCckExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_11A_EXT:
+		case CTL_11G_EXT:
+			targetPowerOfdmExt.tPow2x[0] = min((u16)
+					targetPowerOfdmExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_5GHT40:
+		case CTL_2GHT40:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+				targetPowerHt40.tPow2x[i] =
+					min((u16)targetPowerHt40.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+		ratesArray[rate18mb] = ratesArray[rate24mb] =
+		targetPowerOfdm.tPow2x[0];
+	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+	if (IS_CHAN_2GHZ(chan)) {
+		ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+		ratesArray[rate2s] = ratesArray[rate2l] =
+			targetPowerCck.tPow2x[1];
+		ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+			targetPowerCck.tPow2x[2];
+		;
+		ratesArray[rate11s] = ratesArray[rate11l] =
+			targetPowerCck.tPow2x[3];
+		;
+	}
+	if (IS_CHAN_HT40(chan)) {
+		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+			ratesArray[rateHt40_0 + i] =
+				targetPowerHt40.tPow2x[i];
+		}
+		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+		if (IS_CHAN_2GHZ(chan)) {
+			ratesArray[rateExtCck] =
+				targetPowerCckExt.tPow2x[0];
+		}
+	}
+	return true;
 }
 
-static u16 ath9k_hw_get_def_eeprom_antenna_cfg(struct ath_hal *ah,
-					       struct ath9k_channel *chan)
+static int ath9k_hw_def_set_txpower(struct ath_hw *ah,
+				    struct ath9k_channel *chan,
+				    u16 cfgCtl,
+				    u8 twiceAntennaReduction,
+				    u8 twiceMaxRegulatoryPower,
+				    u8 powerLimit)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
 	struct modal_eep_header *pModal =
-		&(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+		&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
+	int16_t ratesArray[Ar5416RateSize];
+	int16_t txPowerIndexOffset = 0;
+	u8 ht40PowerIncForPdadc = 2;
+	int i;
 
-	return pModal->antCtrlCommon & 0xFFFF;
+	memset(ratesArray, 0, sizeof(ratesArray));
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+	}
+
+	if (!ath9k_hw_set_def_power_per_rate_table(ah, chan,
+					       &ratesArray[0], cfgCtl,
+					       twiceAntennaReduction,
+					       twiceMaxRegulatoryPower,
+					       powerLimit)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"ath9k_hw_set_txpower: unable to set "
+			"tx power per rate table\n");
+		return -EIO;
+	}
+
+	if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			 "ath9k_hw_set_txpower: unable to set power table\n");
+		return -EIO;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
+		if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+			ratesArray[i] = AR5416_MAX_RATE_POWER;
+	}
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		for (i = 0; i < Ar5416RateSize; i++)
+			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+	if (IS_CHAN_2GHZ(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+			  ATH9K_POW_SM(ratesArray[rate2s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate2l], 16)
+			  | ATH9K_POW_SM(ratesArray[rateXr], 8)
+			  | ATH9K_POW_SM(ratesArray[rate1l], 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+			  ATH9K_POW_SM(ratesArray[rate11s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate11l], 16)
+			  | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+			  | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+	if (IS_CHAN_HT40(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+			  ATH9K_POW_SM(ratesArray[rateHt40_3] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+					 ht40PowerIncForPdadc, 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+			  ATH9K_POW_SM(ratesArray[rateHt40_7] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+					 ht40PowerIncForPdadc, 0));
+
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+	i = rate6mb;
+
+	if (IS_CHAN_HT40(chan))
+		i = rateHt40_0;
+	else if (IS_CHAN_HT20(chan))
+		i = rateHt20_0;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		ah->regulatory.max_power_level =
+			ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+	else
+		ah->regulatory.max_power_level = ratesArray[i];
+
+	return 0;
 }
 
-static u16 ath9k_hw_get_4k_eeprom_antenna_cfg(struct ath_hal *ah,
-					      struct ath9k_channel *chan)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
-	struct modal_eep_4k_header *pModal = &eep->modalHeader;
-
-	return pModal->antCtrlCommon & 0xFFFF;
-}
-
-static u16 (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *,
-					     struct ath9k_channel *) = {
-	ath9k_hw_get_def_eeprom_antenna_cfg,
-	ath9k_hw_get_4k_eeprom_antenna_cfg
-};
-
-u16 ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
-				    struct ath9k_channel *chan)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	return ath9k_get_eeprom_antenna_cfg[ahp->ah_eep_map](ah, chan);
-}
-
-static u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah,
-					 enum ieee80211_band freq_band)
-{
-	return 1;
-}
-
-static u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah,
+static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
 					  enum ieee80211_band freq_band)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
 	struct modal_eep_header *pModal =
 		&(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]);
 	struct base_eep_header *pBase = &eep->baseEepHeader;
@@ -2582,183 +2636,75 @@
 	return num_ant_config;
 }
 
-static u8 (*ath9k_get_num_ant_config[])(struct ath_hal *,
-					enum ieee80211_band) = {
-	ath9k_hw_get_def_num_ant_config,
-	ath9k_hw_get_4k_num_ant_config
-};
-
-u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
-			       enum ieee80211_band freq_band)
+static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
+					       struct ath9k_channel *chan)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+	struct modal_eep_header *pModal =
+		&(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
 
-	return ath9k_get_num_ant_config[ahp->ah_eep_map](ah, freq_band);
+	return pModal->antCtrlCommon & 0xFFFF;
 }
 
-u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz)
+u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
 {
-#define EEP_MAP4K_SPURCHAN \
-	(ahp->ah_eeprom.map4k.modalHeader.spurChans[i].spurChan)
 #define EEP_DEF_SPURCHAN \
-	(ahp->ah_eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
-	struct ath_hal_5416 *ahp = AH5416(ah);
+	(ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
+
 	u16 spur_val = AR_NO_SPUR;
 
 	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
 		"Getting spur idx %d is2Ghz. %d val %x\n",
-		i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
+		i, is2GHz, ah->config.spurchans[i][is2GHz]);
 
-	switch (ah->ah_config.spurmode) {
+	switch (ah->config.spurmode) {
 	case SPUR_DISABLE:
 		break;
 	case SPUR_ENABLE_IOCTL:
-		spur_val = ah->ah_config.spurchans[i][is2GHz];
+		spur_val = ah->config.spurchans[i][is2GHz];
 		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
 			"Getting spur val from new loc. %d\n", spur_val);
 		break;
 	case SPUR_ENABLE_EEPROM:
-		if (ahp->ah_eep_map == EEP_MAP_4KBITS)
-			spur_val = EEP_MAP4K_SPURCHAN;
-		else
-			spur_val = EEP_DEF_SPURCHAN;
+		spur_val = EEP_DEF_SPURCHAN;
 		break;
-
 	}
 
 	return spur_val;
+
 #undef EEP_DEF_SPURCHAN
-#undef EEP_MAP4K_SPURCHAN
 }
 
-static u32 ath9k_hw_get_eeprom_4k(struct ath_hal *ah,
-				  enum eeprom_param param)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
-	struct modal_eep_4k_header *pModal = &eep->modalHeader;
-	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
-
-	switch (param) {
-	case EEP_NFTHRESH_2:
-		return pModal[1].noiseFloorThreshCh[0];
-	case AR_EEPROM_MAC(0):
-		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
-	case AR_EEPROM_MAC(1):
-		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
-	case AR_EEPROM_MAC(2):
-		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
-	case EEP_REG_0:
-		return pBase->regDmn[0];
-	case EEP_REG_1:
-		return pBase->regDmn[1];
-	case EEP_OP_CAP:
-		return pBase->deviceCap;
-	case EEP_OP_MODE:
-		return pBase->opCapFlags;
-	case EEP_RF_SILENT:
-		return pBase->rfSilent;
-	case EEP_OB_2:
-		return pModal->ob_01;
-	case EEP_DB_2:
-		return pModal->db1_01;
-	case EEP_MINOR_REV:
-		return pBase->version & AR5416_EEP_VER_MINOR_MASK;
-	case EEP_TX_MASK:
-		return pBase->txMask;
-	case EEP_RX_MASK:
-		return pBase->rxMask;
-	default:
-		return 0;
-	}
-}
-
-static u32 ath9k_hw_get_eeprom_def(struct ath_hal *ah,
-				   enum eeprom_param param)
-{
-#define AR5416_VER_MASK (pBase->version & AR5416_EEP_VER_MINOR_MASK)
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
-	struct modal_eep_header *pModal = eep->modalHeader;
-	struct base_eep_header *pBase = &eep->baseEepHeader;
-
-	switch (param) {
-	case EEP_NFTHRESH_5:
-		return pModal[0].noiseFloorThreshCh[0];
-	case EEP_NFTHRESH_2:
-		return pModal[1].noiseFloorThreshCh[0];
-	case AR_EEPROM_MAC(0):
-		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
-	case AR_EEPROM_MAC(1):
-		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
-	case AR_EEPROM_MAC(2):
-		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
-	case EEP_REG_0:
-		return pBase->regDmn[0];
-	case EEP_REG_1:
-		return pBase->regDmn[1];
-	case EEP_OP_CAP:
-		return pBase->deviceCap;
-	case EEP_OP_MODE:
-		return pBase->opCapFlags;
-	case EEP_RF_SILENT:
-		return pBase->rfSilent;
-	case EEP_OB_5:
-		return pModal[0].ob;
-	case EEP_DB_5:
-		return pModal[0].db;
-	case EEP_OB_2:
-		return pModal[1].ob;
-	case EEP_DB_2:
-		return pModal[1].db;
-	case EEP_MINOR_REV:
-		return AR5416_VER_MASK;
-	case EEP_TX_MASK:
-		return pBase->txMask;
-	case EEP_RX_MASK:
-		return pBase->rxMask;
-	case EEP_RXGAIN_TYPE:
-		return pBase->rxGainType;
-	case EEP_TXGAIN_TYPE:
-		return pBase->txGainType;
-	case EEP_DAC_HPWR_5G:
-		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20)
-			return pBase->dacHiPwrMode_5G;
-		else
-			return 0;
-	default:
-		return 0;
-	}
-#undef AR5416_VER_MASK
-}
-
-static u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = {
-	ath9k_hw_get_eeprom_def,
-	ath9k_hw_get_eeprom_4k
+struct eeprom_ops eep_def_ops = {
+	.check_eeprom		= ath9k_hw_def_check_eeprom,
+	.get_eeprom		= ath9k_hw_def_get_eeprom,
+	.fill_eeprom		= ath9k_hw_def_fill_eeprom,
+	.get_eeprom_ver		= ath9k_hw_def_get_eeprom_ver,
+	.get_eeprom_rev		= ath9k_hw_def_get_eeprom_rev,
+	.get_num_ant_config	= ath9k_hw_def_get_num_ant_config,
+	.get_eeprom_antenna_cfg	= ath9k_hw_def_get_eeprom_antenna_cfg,
+	.set_board_values	= ath9k_hw_def_set_board_values,
+	.set_addac		= ath9k_hw_def_set_addac,
+	.set_txpower		= ath9k_hw_def_set_txpower,
+	.get_spur_channel	= ath9k_hw_def_get_spur_channel
 };
 
-u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
-			enum eeprom_param param)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	return ath9k_get_eeprom[ahp->ah_eep_map](ah, param);
-}
-
-int ath9k_hw_eeprom_attach(struct ath_hal *ah)
+int ath9k_hw_eeprom_attach(struct ath_hw *ah)
 {
 	int status;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	if (AR_SREV_9285(ah))
-		ahp->ah_eep_map = EEP_MAP_4KBITS;
-	else
-		ahp->ah_eep_map = EEP_MAP_DEFAULT;
+	if (AR_SREV_9285(ah)) {
+		ah->eep_map = EEP_MAP_4KBITS;
+		ah->eep_ops = &eep_4k_ops;
+	} else {
+		ah->eep_map = EEP_MAP_DEFAULT;
+		ah->eep_ops = &eep_def_ops;
+	}
 
-	if (!ath9k_hw_fill_eeprom(ah))
+	if (!ah->eep_ops->fill_eeprom(ah))
 		return -EIO;
 
-	status = ath9k_hw_check_eeprom(ah);
+	status = ah->eep_ops->check_eeprom(ah);
 
 	return status;
 }
diff --git a/drivers/net/wireless/ath9k/eeprom.h b/drivers/net/wireless/ath9k/eeprom.h
new file mode 100644
index 0000000..99863b5
--- /dev/null
+++ b/drivers/net/wireless/ath9k/eeprom.h
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef EEPROM_H
+#define EEPROM_H
+
+#define AH_USE_EEPROM   0x1
+
+#ifdef __BIG_ENDIAN
+#define AR5416_EEPROM_MAGIC 0x5aa5
+#else
+#define AR5416_EEPROM_MAGIC 0xa55a
+#endif
+
+#define CTRY_DEBUG   0x1ff
+#define	CTRY_DEFAULT 0
+
+#define AR_EEPROM_EEPCAP_COMPRESS_DIS   0x0001
+#define AR_EEPROM_EEPCAP_AES_DIS        0x0002
+#define AR_EEPROM_EEPCAP_FASTFRAME_DIS  0x0004
+#define AR_EEPROM_EEPCAP_BURST_DIS      0x0008
+#define AR_EEPROM_EEPCAP_MAXQCU         0x01F0
+#define AR_EEPROM_EEPCAP_MAXQCU_S       4
+#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN  0x0200
+#define AR_EEPROM_EEPCAP_KC_ENTRIES     0xF000
+#define AR_EEPROM_EEPCAP_KC_ENTRIES_S   12
+
+#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND   0x0040
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN    0x0080
+#define AR_EEPROM_EEREGCAP_EN_KK_U2         0x0100
+#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND    0x0200
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD     0x0400
+#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A    0x0800
+
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0  0x4000
+#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000
+
+#define AR5416_EEPROM_MAGIC_OFFSET  0x0
+#define AR5416_EEPROM_S             2
+#define AR5416_EEPROM_OFFSET        0x2000
+#define AR5416_EEPROM_MAX           0xae0
+
+#define AR5416_EEPROM_START_ADDR \
+	(AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
+
+#define SD_NO_CTL               0xE0
+#define NO_CTL                  0xff
+#define CTL_MODE_M              7
+#define CTL_11A                 0
+#define CTL_11B                 1
+#define CTL_11G                 2
+#define CTL_2GHT20              5
+#define CTL_5GHT20              6
+#define CTL_2GHT40              7
+#define CTL_5GHT40              8
+
+#define EXT_ADDITIVE (0x8000)
+#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
+#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
+#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
+
+#define SUB_NUM_CTL_MODES_AT_5G_40 2
+#define SUB_NUM_CTL_MODES_AT_2G_40 3
+
+#define AR_EEPROM_MAC(i)	(0x1d+(i))
+#define ATH9K_POW_SM(_r, _s)	(((_r) & 0x3f) << (_s))
+#define FREQ2FBIN(x, y)		((y) ? ((x) - 2300) : (((x) - 4800) / 5))
+#define ath9k_hw_use_flash(_ah)	(!(_ah->ah_flags & AH_USE_EEPROM))
+
+#define AR_EEPROM_RFSILENT_GPIO_SEL     0x001c
+#define AR_EEPROM_RFSILENT_GPIO_SEL_S   2
+#define AR_EEPROM_RFSILENT_POLARITY     0x0002
+#define AR_EEPROM_RFSILENT_POLARITY_S   1
+
+#define EEP_RFSILENT_ENABLED        0x0001
+#define EEP_RFSILENT_ENABLED_S      0
+#define EEP_RFSILENT_POLARITY       0x0002
+#define EEP_RFSILENT_POLARITY_S     1
+#define EEP_RFSILENT_GPIO_SEL       0x001c
+#define EEP_RFSILENT_GPIO_SEL_S     2
+
+#define AR5416_OPFLAGS_11A           0x01
+#define AR5416_OPFLAGS_11G           0x02
+#define AR5416_OPFLAGS_N_5G_HT40     0x04
+#define AR5416_OPFLAGS_N_2G_HT40     0x08
+#define AR5416_OPFLAGS_N_5G_HT20     0x10
+#define AR5416_OPFLAGS_N_2G_HT20     0x20
+
+#define AR5416_EEP_NO_BACK_VER       0x1
+#define AR5416_EEP_VER               0xE
+#define AR5416_EEP_VER_MINOR_MASK    0x0FFF
+#define AR5416_EEP_MINOR_VER_2       0x2
+#define AR5416_EEP_MINOR_VER_3       0x3
+#define AR5416_EEP_MINOR_VER_7       0x7
+#define AR5416_EEP_MINOR_VER_9       0x9
+#define AR5416_EEP_MINOR_VER_16      0x10
+#define AR5416_EEP_MINOR_VER_17      0x11
+#define AR5416_EEP_MINOR_VER_19      0x13
+#define AR5416_EEP_MINOR_VER_20      0x14
+
+#define AR5416_NUM_5G_CAL_PIERS         8
+#define AR5416_NUM_2G_CAL_PIERS         4
+#define AR5416_NUM_5G_20_TARGET_POWERS  8
+#define AR5416_NUM_5G_40_TARGET_POWERS  8
+#define AR5416_NUM_2G_CCK_TARGET_POWERS 3
+#define AR5416_NUM_2G_20_TARGET_POWERS  4
+#define AR5416_NUM_2G_40_TARGET_POWERS  4
+#define AR5416_NUM_CTLS                 24
+#define AR5416_NUM_BAND_EDGES           8
+#define AR5416_NUM_PD_GAINS             4
+#define AR5416_PD_GAINS_IN_MASK         4
+#define AR5416_PD_GAIN_ICEPTS           5
+#define AR5416_EEPROM_MODAL_SPURS       5
+#define AR5416_MAX_RATE_POWER           63
+#define AR5416_NUM_PDADC_VALUES         128
+#define AR5416_BCHAN_UNUSED             0xFF
+#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
+#define AR5416_MAX_CHAINS               3
+#define AR5416_PWR_TABLE_OFFSET         -5
+
+/* Rx gain type values */
+#define AR5416_EEP_RXGAIN_23DB_BACKOFF     0
+#define AR5416_EEP_RXGAIN_13DB_BACKOFF     1
+#define AR5416_EEP_RXGAIN_ORIG             2
+
+/* Tx gain type values */
+#define AR5416_EEP_TXGAIN_ORIGINAL         0
+#define AR5416_EEP_TXGAIN_HIGH_POWER       1
+
+#define AR5416_EEP4K_START_LOC                64
+#define AR5416_EEP4K_NUM_2G_CAL_PIERS         3
+#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3
+#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS  3
+#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS  3
+#define AR5416_EEP4K_NUM_CTLS                 12
+#define AR5416_EEP4K_NUM_BAND_EDGES           4
+#define AR5416_EEP4K_NUM_PD_GAINS             2
+#define AR5416_EEP4K_PD_GAINS_IN_MASK         4
+#define AR5416_EEP4K_PD_GAIN_ICEPTS           5
+#define AR5416_EEP4K_MAX_CHAINS               1
+
+enum eeprom_param {
+	EEP_NFTHRESH_5,
+	EEP_NFTHRESH_2,
+	EEP_MAC_MSW,
+	EEP_MAC_MID,
+	EEP_MAC_LSW,
+	EEP_REG_0,
+	EEP_REG_1,
+	EEP_OP_CAP,
+	EEP_OP_MODE,
+	EEP_RF_SILENT,
+	EEP_OB_5,
+	EEP_DB_5,
+	EEP_OB_2,
+	EEP_DB_2,
+	EEP_MINOR_REV,
+	EEP_TX_MASK,
+	EEP_RX_MASK,
+	EEP_RXGAIN_TYPE,
+	EEP_TXGAIN_TYPE,
+	EEP_DAC_HPWR_5G,
+};
+
+enum ar5416_rates {
+	rate6mb, rate9mb, rate12mb, rate18mb,
+	rate24mb, rate36mb, rate48mb, rate54mb,
+	rate1l, rate2l, rate2s, rate5_5l,
+	rate5_5s, rate11l, rate11s, rateXr,
+	rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3,
+	rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7,
+	rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3,
+	rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7,
+	rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm,
+	Ar5416RateSize
+};
+
+enum ath9k_hal_freq_band {
+	ATH9K_HAL_FREQ_BAND_5GHZ = 0,
+	ATH9K_HAL_FREQ_BAND_2GHZ = 1
+};
+
+struct base_eep_header {
+	u16 length;
+	u16 checksum;
+	u16 version;
+	u8 opCapFlags;
+	u8 eepMisc;
+	u16 regDmn[2];
+	u8 macAddr[6];
+	u8 rxMask;
+	u8 txMask;
+	u16 rfSilent;
+	u16 blueToothOptions;
+	u16 deviceCap;
+	u32 binBuildNumber;
+	u8 deviceType;
+	u8 pwdclkind;
+	u8 futureBase_1[2];
+	u8 rxGainType;
+	u8 dacHiPwrMode_5G;
+	u8 futureBase_2;
+	u8 dacLpMode;
+	u8 txGainType;
+	u8 rcChainMask;
+	u8 desiredScaleCCK;
+	u8 futureBase_3[23];
+} __packed;
+
+struct base_eep_header_4k {
+	u16 length;
+	u16 checksum;
+	u16 version;
+	u8 opCapFlags;
+	u8 eepMisc;
+	u16 regDmn[2];
+	u8 macAddr[6];
+	u8 rxMask;
+	u8 txMask;
+	u16 rfSilent;
+	u16 blueToothOptions;
+	u16 deviceCap;
+	u32 binBuildNumber;
+	u8 deviceType;
+	u8 futureBase[1];
+} __packed;
+
+
+struct spur_chan {
+	u16 spurChan;
+	u8 spurRangeLow;
+	u8 spurRangeHigh;
+} __packed;
+
+struct modal_eep_header {
+	u32 antCtrlChain[AR5416_MAX_CHAINS];
+	u32 antCtrlCommon;
+	u8 antennaGainCh[AR5416_MAX_CHAINS];
+	u8 switchSettling;
+	u8 txRxAttenCh[AR5416_MAX_CHAINS];
+	u8 rxTxMarginCh[AR5416_MAX_CHAINS];
+	u8 adcDesiredSize;
+	u8 pgaDesiredSize;
+	u8 xlnaGainCh[AR5416_MAX_CHAINS];
+	u8 txEndToXpaOff;
+	u8 txEndToRxOn;
+	u8 txFrameToXpaOn;
+	u8 thresh62;
+	u8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
+	u8 xpdGain;
+	u8 xpd;
+	u8 iqCalICh[AR5416_MAX_CHAINS];
+	u8 iqCalQCh[AR5416_MAX_CHAINS];
+	u8 pdGainOverlap;
+	u8 ob;
+	u8 db;
+	u8 xpaBiasLvl;
+	u8 pwrDecreaseFor2Chain;
+	u8 pwrDecreaseFor3Chain;
+	u8 txFrameToDataStart;
+	u8 txFrameToPaOn;
+	u8 ht40PowerIncForPdadc;
+	u8 bswAtten[AR5416_MAX_CHAINS];
+	u8 bswMargin[AR5416_MAX_CHAINS];
+	u8 swSettleHt40;
+	u8 xatten2Db[AR5416_MAX_CHAINS];
+	u8 xatten2Margin[AR5416_MAX_CHAINS];
+	u8 ob_ch1;
+	u8 db_ch1;
+	u8 useAnt1:1,
+	    force_xpaon:1,
+	    local_bias:1,
+	    femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1;
+	u8 miscBits;
+	u16 xpaBiasLvlFreq[3];
+	u8 futureModal[6];
+
+	struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
+} __packed;
+
+struct modal_eep_4k_header {
+	u32  antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
+	u32  antCtrlCommon;
+	u8   antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
+	u8   switchSettling;
+	u8   txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
+	u8   rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
+	u8   adcDesiredSize;
+	u8   pgaDesiredSize;
+	u8   xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
+	u8   txEndToXpaOff;
+	u8   txEndToRxOn;
+	u8   txFrameToXpaOn;
+	u8   thresh62;
+	u8   noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
+	u8   xpdGain;
+	u8   xpd;
+	u8   iqCalICh[AR5416_EEP4K_MAX_CHAINS];
+	u8   iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
+	u8   pdGainOverlap;
+	u8   ob_01;
+	u8   db1_01;
+	u8   xpaBiasLvl;
+	u8   txFrameToDataStart;
+	u8   txFrameToPaOn;
+	u8   ht40PowerIncForPdadc;
+	u8   bswAtten[AR5416_EEP4K_MAX_CHAINS];
+	u8   bswMargin[AR5416_EEP4K_MAX_CHAINS];
+	u8   swSettleHt40;
+	u8   xatten2Db[AR5416_EEP4K_MAX_CHAINS];
+	u8   xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
+	u8   db2_01;
+	u8   version;
+	u16  ob_234;
+	u16  db1_234;
+	u16  db2_234;
+	u8   futureModal[4];
+
+	struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
+} __packed;
+
+
+struct cal_data_per_freq {
+	u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+	u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+} __packed;
+
+struct cal_data_per_freq_4k {
+	u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
+	u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
+} __packed;
+
+struct cal_target_power_leg {
+	u8 bChannel;
+	u8 tPow2x[4];
+} __packed;
+
+struct cal_target_power_ht {
+	u8 bChannel;
+	u8 tPow2x[8];
+} __packed;
+
+
+#ifdef __BIG_ENDIAN_BITFIELD
+struct cal_ctl_edges {
+	u8 bChannel;
+	u8 flag:2, tPower:6;
+} __packed;
+#else
+struct cal_ctl_edges {
+	u8 bChannel;
+	u8 tPower:6, flag:2;
+} __packed;
+#endif
+
+struct cal_ctl_data {
+	struct cal_ctl_edges
+	ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
+} __packed;
+
+struct cal_ctl_data_4k {
+	struct cal_ctl_edges
+	ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES];
+} __packed;
+
+struct ar5416_eeprom_def {
+	struct base_eep_header baseEepHeader;
+	u8 custData[64];
+	struct modal_eep_header modalHeader[2];
+	u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS];
+	u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS];
+	struct cal_data_per_freq
+	 calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS];
+	struct cal_data_per_freq
+	 calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
+	struct cal_target_power_leg
+	 calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	 calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	 calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS];
+	struct cal_target_power_leg
+	 calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS];
+	struct cal_target_power_leg
+	 calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	 calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	 calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS];
+	u8 ctlIndex[AR5416_NUM_CTLS];
+	struct cal_ctl_data ctlData[AR5416_NUM_CTLS];
+	u8 padding;
+} __packed;
+
+struct ar5416_eeprom_4k {
+	struct base_eep_header_4k baseEepHeader;
+	u8 custData[20];
+	struct modal_eep_4k_header modalHeader;
+	u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS];
+	struct cal_data_per_freq_4k
+	calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS];
+	struct cal_target_power_leg
+	calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS];
+	struct cal_target_power_leg
+	calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS];
+	u8 ctlIndex[AR5416_EEP4K_NUM_CTLS];
+	struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS];
+	u8 padding;
+} __packed;
+
+enum reg_ext_bitmap {
+	REG_EXT_JAPAN_MIDBAND = 1,
+	REG_EXT_FCC_DFS_HT40 = 2,
+	REG_EXT_JAPAN_NONDFS_HT40 = 3,
+	REG_EXT_JAPAN_DFS_HT40 = 4
+};
+
+struct ath9k_country_entry {
+	u16 countryCode;
+	u16 regDmnEnum;
+	u16 regDmn5G;
+	u16 regDmn2G;
+	u8 isMultidomain;
+	u8 iso[3];
+};
+
+enum ath9k_eep_map {
+	EEP_MAP_DEFAULT = 0x0,
+	EEP_MAP_4KBITS,
+	EEP_MAP_MAX
+};
+
+struct eeprom_ops {
+	int (*check_eeprom)(struct ath_hw *hw);
+	u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param);
+	bool (*fill_eeprom)(struct ath_hw *hw);
+	int (*get_eeprom_ver)(struct ath_hw *hw);
+	int (*get_eeprom_rev)(struct ath_hw *hw);
+	u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band);
+	u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
+				      struct ath9k_channel *chan);
+	bool (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
+	void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
+	int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan,
+			   u16 cfgCtl, u8 twiceAntennaReduction,
+			   u8 twiceMaxRegulatoryPower, u8 powerLimit);
+	u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
+};
+
+#define ar5416_get_ntxchains(_txchainmask)			\
+	(((_txchainmask >> 2) & 1) +                            \
+	 ((_txchainmask >> 1) & 1) + (_txchainmask & 1))
+
+int ath9k_hw_eeprom_attach(struct ath_hw *ah);
+
+#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 00ed44a..cad8e39 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -17,10 +17,7 @@
 #include <linux/io.h>
 #include <asm/unaligned.h>
 
-#include "core.h"
-#include "hw.h"
-#include "reg.h"
-#include "phy.h"
+#include "ath9k.h"
 #include "initvals.h"
 
 static int btcoex_enable;
@@ -31,58 +28,63 @@
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM	40
 #define ATH9K_CLOCK_RATE_2GHZ_OFDM	44
 
-static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type);
-static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
+static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
 			      enum ath9k_ht_macmode macmode);
-static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
 			      struct ar5416_eeprom_def *pEepData,
 			      u32 reg, u32 value);
-static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
-static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
+static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
+static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
 
 /********************/
 /* Helper Functions */
 /********************/
 
-static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
+static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
 {
 	struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
-	if (!ah->ah_curchan) /* should really check for CCK instead */
+
+	if (!ah->curchan) /* should really check for CCK instead */
 		return clks / ATH9K_CLOCK_RATE_CCK;
 	if (conf->channel->band == IEEE80211_BAND_2GHZ)
 		return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM;
+
 	return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM;
 }
 
-static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
+static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
 {
 	struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+
 	if (conf_is_ht40(conf))
 		return ath9k_hw_mac_usec(ah, clks) / 2;
 	else
 		return ath9k_hw_mac_usec(ah, clks);
 }
 
-static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
+static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
 {
 	struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
-	if (!ah->ah_curchan) /* should really check for CCK instead */
+
+	if (!ah->curchan) /* should really check for CCK instead */
 		return usecs *ATH9K_CLOCK_RATE_CCK;
 	if (conf->channel->band == IEEE80211_BAND_2GHZ)
 		return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM;
 	return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM;
 }
 
-static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
+static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
 {
 	struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+
 	if (conf_is_ht40(conf))
 		return ath9k_hw_mac_clks(ah, usecs) * 2;
 	else
 		return ath9k_hw_mac_clks(ah, usecs);
 }
 
-bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val)
+bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val)
 {
 	int i;
 
@@ -112,11 +114,11 @@
 	return retval;
 }
 
-bool ath9k_get_channel_edges(struct ath_hal *ah,
+bool ath9k_get_channel_edges(struct ath_hw *ah,
 			     u16 flags, u16 *low,
 			     u16 *high)
 {
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 
 	if (flags & CHANNEL_5GHZ) {
 		*low = pCap->low_5ghz_chan;
@@ -131,7 +133,7 @@
 	return false;
 }
 
-u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+u16 ath9k_hw_computetxtime(struct ath_hw *ah,
 			   struct ath_rate_table *rates,
 			   u32 frameLen, u16 rateix,
 			   bool shortPreamble)
@@ -153,15 +155,15 @@
 		txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
 		break;
 	case WLAN_RC_PHY_OFDM:
-		if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
+		if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) {
 			bitsPerSymbol =	(kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
 			numBits = OFDM_PLCP_BITS + (frameLen << 3);
 			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
 			txTime = OFDM_SIFS_TIME_QUARTER
 				+ OFDM_PREAMBLE_TIME_QUARTER
 				+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
-		} else if (ah->ah_curchan &&
-			   IS_CHAN_HALF_RATE(ah->ah_curchan)) {
+		} else if (ah->curchan &&
+			   IS_CHAN_HALF_RATE(ah->curchan)) {
 			bitsPerSymbol =	(kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
 			numBits = OFDM_PLCP_BITS + (frameLen << 3);
 			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
@@ -187,12 +189,11 @@
 	return txTime;
 }
 
-void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+void ath9k_hw_get_channel_centers(struct ath_hw *ah,
 				  struct ath9k_channel *chan,
 				  struct chan_centers *centers)
 {
 	int8_t extoff;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
 	if (!IS_CHAN_HT40(chan)) {
 		centers->ctl_center = centers->ext_center =
@@ -215,16 +216,15 @@
 		centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
 	centers->ext_center =
 		centers->synth_center + (extoff *
-			 ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
+			 ((ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
 			  HT40_CHANNEL_CENTER_SHIFT : 15));
-
 }
 
 /******************/
 /* Chip Revisions */
 /******************/
 
-static void ath9k_hw_read_revisions(struct ath_hal *ah)
+static void ath9k_hw_read_revisions(struct ath_hw *ah)
 {
 	u32 val;
 
@@ -232,21 +232,22 @@
 
 	if (val == 0xFF) {
 		val = REG_READ(ah, AR_SREV);
-		ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
-		ah->ah_macRev = MS(val, AR_SREV_REVISION2);
-		ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
+		ah->hw_version.macVersion =
+			(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
+		ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
+		ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
 	} else {
 		if (!AR_SREV_9100(ah))
-			ah->ah_macVersion = MS(val, AR_SREV_VERSION);
+			ah->hw_version.macVersion = MS(val, AR_SREV_VERSION);
 
-		ah->ah_macRev = val & AR_SREV_REVISION;
+		ah->hw_version.macRev = val & AR_SREV_REVISION;
 
-		if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
-			ah->ah_isPciExpress = true;
+		if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)
+			ah->is_pciexpress = true;
 	}
 }
 
-static int ath9k_hw_get_radiorev(struct ath_hal *ah)
+static int ath9k_hw_get_radiorev(struct ath_hw *ah)
 {
 	u32 val;
 	int i;
@@ -265,7 +266,7 @@
 /* HW Attach, Detach, Init Routines */
 /************************************/
 
-static void ath9k_hw_disablepcie(struct ath_hal *ah)
+static void ath9k_hw_disablepcie(struct ath_hw *ah)
 {
 	if (AR_SREV_9100(ah))
 		return;
@@ -283,7 +284,7 @@
 	REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 }
 
-static bool ath9k_hw_chip_test(struct ath_hal *ah)
+static bool ath9k_hw_chip_test(struct ath_hw *ah)
 {
 	u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
 	u32 regHold[2];
@@ -325,6 +326,7 @@
 		REG_WRITE(ah, regAddr[i], regHold[i]);
 	}
 	udelay(100);
+
 	return true;
 }
 
@@ -349,99 +351,91 @@
 	return NULL;
 }
 
-static void ath9k_hw_set_defaults(struct ath_hal *ah)
+static void ath9k_hw_set_defaults(struct ath_hw *ah)
 {
 	int i;
 
-	ah->ah_config.dma_beacon_response_time = 2;
-	ah->ah_config.sw_beacon_response_time = 10;
-	ah->ah_config.additional_swba_backoff = 0;
-	ah->ah_config.ack_6mb = 0x0;
-	ah->ah_config.cwm_ignore_extcca = 0;
-	ah->ah_config.pcie_powersave_enable = 0;
-	ah->ah_config.pcie_l1skp_enable = 0;
-	ah->ah_config.pcie_clock_req = 0;
-	ah->ah_config.pcie_power_reset = 0x100;
-	ah->ah_config.pcie_restore = 0;
-	ah->ah_config.pcie_waen = 0;
-	ah->ah_config.analog_shiftreg = 1;
-	ah->ah_config.ht_enable = 1;
-	ah->ah_config.ofdm_trig_low = 200;
-	ah->ah_config.ofdm_trig_high = 500;
-	ah->ah_config.cck_trig_high = 200;
-	ah->ah_config.cck_trig_low = 100;
-	ah->ah_config.enable_ani = 1;
-	ah->ah_config.noise_immunity_level = 4;
-	ah->ah_config.ofdm_weaksignal_det = 1;
-	ah->ah_config.cck_weaksignal_thr = 0;
-	ah->ah_config.spur_immunity_level = 2;
-	ah->ah_config.firstep_level = 0;
-	ah->ah_config.rssi_thr_high = 40;
-	ah->ah_config.rssi_thr_low = 7;
-	ah->ah_config.diversity_control = 0;
-	ah->ah_config.antenna_switch_swap = 0;
+	ah->config.dma_beacon_response_time = 2;
+	ah->config.sw_beacon_response_time = 10;
+	ah->config.additional_swba_backoff = 0;
+	ah->config.ack_6mb = 0x0;
+	ah->config.cwm_ignore_extcca = 0;
+	ah->config.pcie_powersave_enable = 0;
+	ah->config.pcie_l1skp_enable = 0;
+	ah->config.pcie_clock_req = 0;
+	ah->config.pcie_power_reset = 0x100;
+	ah->config.pcie_restore = 0;
+	ah->config.pcie_waen = 0;
+	ah->config.analog_shiftreg = 1;
+	ah->config.ht_enable = 1;
+	ah->config.ofdm_trig_low = 200;
+	ah->config.ofdm_trig_high = 500;
+	ah->config.cck_trig_high = 200;
+	ah->config.cck_trig_low = 100;
+	ah->config.enable_ani = 1;
+	ah->config.noise_immunity_level = 4;
+	ah->config.ofdm_weaksignal_det = 1;
+	ah->config.cck_weaksignal_thr = 0;
+	ah->config.spur_immunity_level = 2;
+	ah->config.firstep_level = 0;
+	ah->config.rssi_thr_high = 40;
+	ah->config.rssi_thr_low = 7;
+	ah->config.diversity_control = 0;
+	ah->config.antenna_switch_swap = 0;
 
 	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-		ah->ah_config.spurchans[i][0] = AR_NO_SPUR;
-		ah->ah_config.spurchans[i][1] = AR_NO_SPUR;
+		ah->config.spurchans[i][0] = AR_NO_SPUR;
+		ah->config.spurchans[i][1] = AR_NO_SPUR;
 	}
 
-	ah->ah_config.intr_mitigation = 1;
+	ah->config.intr_mitigation = 1;
 }
 
-static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
-					      struct ath_softc *sc,
-					      void __iomem *mem,
-					      int *status)
+static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
+					int *status)
 {
-	static const u8 defbssidmask[ETH_ALEN] =
-		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-	struct ath_hal_5416 *ahp;
-	struct ath_hal *ah;
+	struct ath_hw *ah;
 
-	ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL);
-	if (ahp == NULL) {
+	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+	if (ah == NULL) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"Cannot allocate memory for state block\n");
 		*status = -ENOMEM;
 		return NULL;
 	}
 
-	ah = &ahp->ah;
 	ah->ah_sc = sc;
-	ah->ah_sh = mem;
-	ah->ah_magic = AR5416_MAGIC;
-	ah->ah_countryCode = CTRY_DEFAULT;
-	ah->ah_devid = devid;
-	ah->ah_subvendorid = 0;
+	ah->hw_version.magic = AR5416_MAGIC;
+	ah->regulatory.country_code = CTRY_DEFAULT;
+	ah->hw_version.devid = devid;
+	ah->hw_version.subvendorid = 0;
 
 	ah->ah_flags = 0;
 	if ((devid == AR5416_AR9100_DEVID))
-		ah->ah_macVersion = AR_SREV_VERSION_9100;
+		ah->hw_version.macVersion = AR_SREV_VERSION_9100;
 	if (!AR_SREV_9100(ah))
 		ah->ah_flags = AH_USE_EEPROM;
 
-	ah->ah_powerLimit = MAX_RATE_POWER;
-	ah->ah_tpScale = ATH9K_TP_SCALE_MAX;
-	ahp->ah_atimWindow = 0;
-	ahp->ah_diversityControl = ah->ah_config.diversity_control;
-	ahp->ah_antennaSwitchSwap =
-		ah->ah_config.antenna_switch_swap;
-	ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
-	ahp->ah_beaconInterval = 100;
-	ahp->ah_enable32kHzClock = DONT_USE_32KHZ;
-	ahp->ah_slottime = (u32) -1;
-	ahp->ah_acktimeout = (u32) -1;
-	ahp->ah_ctstimeout = (u32) -1;
-	ahp->ah_globaltxtimeout = (u32) -1;
-	memcpy(&ahp->ah_bssidmask, defbssidmask, ETH_ALEN);
+	ah->regulatory.power_limit = MAX_RATE_POWER;
+	ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX;
+	ah->atim_window = 0;
+	ah->diversity_control = ah->config.diversity_control;
+	ah->antenna_switch_swap =
+		ah->config.antenna_switch_swap;
+	ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
+	ah->beacon_interval = 100;
+	ah->enable_32kHz_clock = DONT_USE_32KHZ;
+	ah->slottime = (u32) -1;
+	ah->acktimeout = (u32) -1;
+	ah->ctstimeout = (u32) -1;
+	ah->globaltxtimeout = (u32) -1;
 
-	ahp->ah_gBeaconRate = 0;
+	ah->gbeacon_rate = 0;
 
-	return ahp;
+	return ah;
 }
 
-static int ath9k_hw_rfattach(struct ath_hal *ah)
+static int ath9k_hw_rfattach(struct ath_hw *ah)
 {
 	bool rfStatus = false;
 	int ecode = 0;
@@ -456,7 +450,7 @@
 	return 0;
 }
 
-static int ath9k_hw_rf_claim(struct ath_hal *ah)
+static int ath9k_hw_rf_claim(struct ath_hw *ah)
 {
 	u32 val;
 
@@ -476,88 +470,87 @@
 		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
 			"5G Radio Chip Rev 0x%02X is not "
 			"supported by this driver\n",
-			ah->ah_analog5GhzRev);
+			ah->hw_version.analog5GhzRev);
 		return -EOPNOTSUPP;
 	}
 
-	ah->ah_analog5GhzRev = val;
+	ah->hw_version.analog5GhzRev = val;
 
 	return 0;
 }
 
-static int ath9k_hw_init_macaddr(struct ath_hal *ah)
+static int ath9k_hw_init_macaddr(struct ath_hw *ah)
 {
 	u32 sum;
 	int i;
 	u16 eeval;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
 	sum = 0;
 	for (i = 0; i < 3; i++) {
-		eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i));
+		eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i));
 		sum += eeval;
-		ahp->ah_macaddr[2 * i] = eeval >> 8;
-		ahp->ah_macaddr[2 * i + 1] = eeval & 0xff;
+		ah->macaddr[2 * i] = eeval >> 8;
+		ah->macaddr[2 * i + 1] = eeval & 0xff;
 	}
 	if (sum == 0 || sum == 0xffff * 3) {
 		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
 			"mac address read failed: %pM\n",
-			ahp->ah_macaddr);
+			ah->macaddr);
 		return -EADDRNOTAVAIL;
 	}
 
 	return 0;
 }
 
-static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah)
+static void ath9k_hw_init_rxgain_ini(struct ath_hw *ah)
 {
 	u32 rxgain_type;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) {
-		rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE);
+	if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) {
+		rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE);
 
 		if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
-			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
 			ar9280Modes_backoff_13db_rxgain_9280_2,
 			ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
 		else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
-			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
 			ar9280Modes_backoff_23db_rxgain_9280_2,
 			ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
 		else
-			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
 			ar9280Modes_original_rxgain_9280_2,
 			ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
-	} else
-		INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+	} else {
+		INIT_INI_ARRAY(&ah->iniModesRxGain,
 			ar9280Modes_original_rxgain_9280_2,
 			ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+	}
 }
 
-static void ath9k_hw_init_txgain_ini(struct ath_hal *ah)
+static void ath9k_hw_init_txgain_ini(struct ath_hw *ah)
 {
 	u32 txgain_type;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) {
-		txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE);
+	if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) {
+		txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
 
 		if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
-			INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
 			ar9280Modes_high_power_tx_gain_9280_2,
 			ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
 		else
-			INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
 			ar9280Modes_original_tx_gain_9280_2,
 			ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
-	} else
-		INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+	} else {
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
 		ar9280Modes_original_tx_gain_9280_2,
 		ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+	}
 }
 
-static int ath9k_hw_post_attach(struct ath_hal *ah)
+static int ath9k_hw_post_attach(struct ath_hw *ah)
 {
 	int ecode;
 
@@ -586,237 +579,234 @@
 	return 0;
 }
 
-static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
-					  void __iomem *mem, int *status)
+static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
+					 int *status)
 {
-	struct ath_hal_5416 *ahp;
-	struct ath_hal *ah;
+	struct ath_hw *ah;
 	int ecode;
 	u32 i, j;
 
-	ahp = ath9k_hw_newstate(devid, sc, mem, status);
-	if (ahp == NULL)
+	ah = ath9k_hw_newstate(devid, sc, status);
+	if (ah == NULL)
 		return NULL;
 
-	ah = &ahp->ah;
-
 	ath9k_hw_set_defaults(ah);
 
-	if (ah->ah_config.intr_mitigation != 0)
-		ahp->ah_intrMitigation = true;
+	if (ah->config.intr_mitigation != 0)
+		ah->intr_mitigation = true;
 
 	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't reset chip\n");
+		DPRINTF(sc, ATH_DBG_RESET, "Couldn't reset chip\n");
 		ecode = -EIO;
 		goto bad;
 	}
 
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't wakeup chip\n");
+		DPRINTF(sc, ATH_DBG_RESET, "Couldn't wakeup chip\n");
 		ecode = -EIO;
 		goto bad;
 	}
 
-	if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) {
-		if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) {
-			ah->ah_config.serialize_regmode =
+	if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
+		if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) {
+			ah->config.serialize_regmode =
 				SER_REG_MODE_ON;
 		} else {
-			ah->ah_config.serialize_regmode =
+			ah->config.serialize_regmode =
 				SER_REG_MODE_OFF;
 		}
 	}
 
-	DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-		"serialize_regmode is %d\n",
-		ah->ah_config.serialize_regmode);
+	DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
+		ah->config.serialize_regmode);
 
-	if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) &&
-	    (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) &&
-	    (ah->ah_macVersion != AR_SREV_VERSION_9160) &&
+	if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) &&
+	    (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
+	    (ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
 	    (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+		DPRINTF(sc, ATH_DBG_RESET,
 			"Mac Chip Rev 0x%02x.%x is not supported by "
-			"this driver\n", ah->ah_macVersion, ah->ah_macRev);
+			"this driver\n", ah->hw_version.macVersion,
+			ah->hw_version.macRev);
 		ecode = -EOPNOTSUPP;
 		goto bad;
 	}
 
 	if (AR_SREV_9100(ah)) {
-		ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
-		ahp->ah_suppCals = IQ_MISMATCH_CAL;
-		ah->ah_isPciExpress = false;
+		ah->iq_caldata.calData = &iq_cal_multi_sample;
+		ah->supp_cals = IQ_MISMATCH_CAL;
+		ah->is_pciexpress = false;
 	}
-	ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
+	ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
 
 	if (AR_SREV_9160_10_OR_LATER(ah)) {
 		if (AR_SREV_9280_10_OR_LATER(ah)) {
-			ahp->ah_iqCalData.calData = &iq_cal_single_sample;
-			ahp->ah_adcGainCalData.calData =
+			ah->iq_caldata.calData = &iq_cal_single_sample;
+			ah->adcgain_caldata.calData =
 				&adc_gain_cal_single_sample;
-			ahp->ah_adcDcCalData.calData =
+			ah->adcdc_caldata.calData =
 				&adc_dc_cal_single_sample;
-			ahp->ah_adcDcCalInitData.calData =
+			ah->adcdc_calinitdata.calData =
 				&adc_init_dc_cal;
 		} else {
-			ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
-			ahp->ah_adcGainCalData.calData =
+			ah->iq_caldata.calData = &iq_cal_multi_sample;
+			ah->adcgain_caldata.calData =
 				&adc_gain_cal_multi_sample;
-			ahp->ah_adcDcCalData.calData =
+			ah->adcdc_caldata.calData =
 				&adc_dc_cal_multi_sample;
-			ahp->ah_adcDcCalInitData.calData =
+			ah->adcdc_calinitdata.calData =
 				&adc_init_dc_cal;
 		}
-		ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+		ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
 	}
 
 	if (AR_SREV_9160(ah)) {
-		ah->ah_config.enable_ani = 1;
-		ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+		ah->config.enable_ani = 1;
+		ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
 					ATH9K_ANI_FIRSTEP_LEVEL);
 	} else {
-		ahp->ah_ani_function = ATH9K_ANI_ALL;
+		ah->ani_function = ATH9K_ANI_ALL;
 		if (AR_SREV_9280_10_OR_LATER(ah)) {
-			ahp->ah_ani_function &=	~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+			ah->ani_function &=	~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
 		}
 	}
 
-	DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+	DPRINTF(sc, ATH_DBG_RESET,
 		"This Mac Chip Rev 0x%02x.%x is \n",
-		ah->ah_macVersion, ah->ah_macRev);
+		ah->hw_version.macVersion, ah->hw_version.macRev);
 
 	if (AR_SREV_9285_12_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2,
+		INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
 			       ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
-		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2,
+		INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
 			       ARRAY_SIZE(ar9285Common_9285_1_2), 2);
 
-		if (ah->ah_config.pcie_clock_req) {
-			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+		if (ah->config.pcie_clock_req) {
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
 			ar9285PciePhy_clkreq_off_L1_9285_1_2,
 			ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
 		} else {
-			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
 			ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
 			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
 				  2);
 		}
 	} else if (AR_SREV_9285_10_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285,
+		INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285,
 			       ARRAY_SIZE(ar9285Modes_9285), 6);
-		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285,
+		INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285,
 			       ARRAY_SIZE(ar9285Common_9285), 2);
 
-		if (ah->ah_config.pcie_clock_req) {
-			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+		if (ah->config.pcie_clock_req) {
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
 			ar9285PciePhy_clkreq_off_L1_9285,
 			ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
 		} else {
-			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
 			ar9285PciePhy_clkreq_always_on_L1_9285,
 			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2);
 		}
 	} else if (AR_SREV_9280_20_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2,
+		INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
 			       ARRAY_SIZE(ar9280Modes_9280_2), 6);
-		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2,
+		INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
 			       ARRAY_SIZE(ar9280Common_9280_2), 2);
 
-		if (ah->ah_config.pcie_clock_req) {
-			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+		if (ah->config.pcie_clock_req) {
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
 			       ar9280PciePhy_clkreq_off_L1_9280,
 			       ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2);
 		} else {
-			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
 			       ar9280PciePhy_clkreq_always_on_L1_9280,
 			       ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
 		}
-		INIT_INI_ARRAY(&ahp->ah_iniModesAdditional,
+		INIT_INI_ARRAY(&ah->iniModesAdditional,
 			       ar9280Modes_fast_clock_9280_2,
 			       ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
 	} else if (AR_SREV_9280_10_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280,
+		INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280,
 			       ARRAY_SIZE(ar9280Modes_9280), 6);
-		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280,
+		INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280,
 			       ARRAY_SIZE(ar9280Common_9280), 2);
 	} else if (AR_SREV_9160_10_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160,
+		INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160,
 			       ARRAY_SIZE(ar5416Modes_9160), 6);
-		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160,
+		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160,
 			       ARRAY_SIZE(ar5416Common_9160), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160,
+		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160,
 			       ARRAY_SIZE(ar5416Bank0_9160), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160,
+		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160,
 			       ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160,
+		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160,
 			       ARRAY_SIZE(ar5416Bank1_9160), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160,
+		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160,
 			       ARRAY_SIZE(ar5416Bank2_9160), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160,
+		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160,
 			       ARRAY_SIZE(ar5416Bank3_9160), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160,
+		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160,
 			       ARRAY_SIZE(ar5416Bank6_9160), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160,
+		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160,
 			       ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160,
+		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160,
 			       ARRAY_SIZE(ar5416Bank7_9160), 2);
 		if (AR_SREV_9160_11(ah)) {
-			INIT_INI_ARRAY(&ahp->ah_iniAddac,
+			INIT_INI_ARRAY(&ah->iniAddac,
 				       ar5416Addac_91601_1,
 				       ARRAY_SIZE(ar5416Addac_91601_1), 2);
 		} else {
-			INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160,
+			INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160,
 				       ARRAY_SIZE(ar5416Addac_9160), 2);
 		}
 	} else if (AR_SREV_9100_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100,
+		INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100,
 			       ARRAY_SIZE(ar5416Modes_9100), 6);
-		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100,
+		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100,
 			       ARRAY_SIZE(ar5416Common_9100), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100,
+		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100,
 			       ARRAY_SIZE(ar5416Bank0_9100), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100,
+		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100,
 			       ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100,
+		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100,
 			       ARRAY_SIZE(ar5416Bank1_9100), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100,
+		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100,
 			       ARRAY_SIZE(ar5416Bank2_9100), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100,
+		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100,
 			       ARRAY_SIZE(ar5416Bank3_9100), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100,
+		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100,
 			       ARRAY_SIZE(ar5416Bank6_9100), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100,
+		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
 			       ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100,
+		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100,
 			       ARRAY_SIZE(ar5416Bank7_9100), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100,
+		INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100,
 			       ARRAY_SIZE(ar5416Addac_9100), 2);
 	} else {
-		INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes,
+		INIT_INI_ARRAY(&ah->iniModes, ar5416Modes,
 			       ARRAY_SIZE(ar5416Modes), 6);
-		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common,
+		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common,
 			       ARRAY_SIZE(ar5416Common), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0,
+		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
 			       ARRAY_SIZE(ar5416Bank0), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain,
+		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain,
 			       ARRAY_SIZE(ar5416BB_RfGain), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1,
+		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1,
 			       ARRAY_SIZE(ar5416Bank1), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2,
+		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2,
 			       ARRAY_SIZE(ar5416Bank2), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3,
+		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3,
 			       ARRAY_SIZE(ar5416Bank3), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6,
+		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
 			       ARRAY_SIZE(ar5416Bank6), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC,
+		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
 			       ARRAY_SIZE(ar5416Bank6TPC), 3);
-		INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7,
+		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7,
 			       ARRAY_SIZE(ar5416Bank7), 2);
-		INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac,
+		INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
 			       ARRAY_SIZE(ar5416Addac), 2);
 	}
 
-	if (ah->ah_isPciExpress)
+	if (ah->is_pciexpress)
 		ath9k_hw_configpcipowersave(ah, 0);
 	else
 		ath9k_hw_disablepcie(ah);
@@ -833,23 +823,23 @@
 	if (AR_SREV_9280_20(ah))
 		ath9k_hw_init_txgain_ini(ah);
 
-	if (ah->ah_devid == AR9280_DEVID_PCI) {
-		for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
-			u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
+	if (ah->hw_version.devid == AR9280_DEVID_PCI) {
+		for (i = 0; i < ah->iniModes.ia_rows; i++) {
+			u32 reg = INI_RA(&ah->iniModes, i, 0);
 
-			for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) {
-				u32 val = INI_RA(&ahp->ah_iniModes, i, j);
+			for (j = 1; j < ah->iniModes.ia_columns; j++) {
+				u32 val = INI_RA(&ah->iniModes, i, j);
 
-				INI_RA(&ahp->ah_iniModes, i, j) =
+				INI_RA(&ah->iniModes, i, j) =
 					ath9k_hw_ini_fixup(ah,
-							   &ahp->ah_eeprom.def,
+							   &ah->eeprom.def,
 							   reg, val);
 			}
 		}
 	}
 
 	if (!ath9k_hw_fill_cap_info(ah)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+		DPRINTF(sc, ATH_DBG_RESET,
 			"failed ath9k_hw_fill_cap_info\n");
 		ecode = -EINVAL;
 		goto bad;
@@ -857,29 +847,29 @@
 
 	ecode = ath9k_hw_init_macaddr(ah);
 	if (ecode != 0) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+		DPRINTF(sc, ATH_DBG_RESET,
 			"failed initializing mac address\n");
 		goto bad;
 	}
 
 	if (AR_SREV_9285(ah))
-		ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S);
+		ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
 	else
-		ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S);
+		ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
 
 	ath9k_init_nfcal_hist_buffer(ah);
 
 	return ah;
 bad:
-	if (ahp)
-		ath9k_hw_detach((struct ath_hal *) ahp);
+	if (ah)
+		ath9k_hw_detach(ah);
 	if (status)
 		*status = ecode;
 
 	return NULL;
 }
 
-static void ath9k_hw_init_bb(struct ath_hal *ah,
+static void ath9k_hw_init_bb(struct ath_hw *ah,
 			     struct ath9k_channel *chan)
 {
 	u32 synthDelay;
@@ -895,7 +885,7 @@
 	udelay(synthDelay + BASE_ACTIVATE_DELAY);
 }
 
-static void ath9k_hw_init_qos(struct ath_hal *ah)
+static void ath9k_hw_init_qos(struct ath_hw *ah)
 {
 	REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
 	REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
@@ -912,7 +902,7 @@
 	REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
 }
 
-static void ath9k_hw_init_pll(struct ath_hal *ah,
+static void ath9k_hw_init_pll(struct ath_hw *ah,
 			      struct ath9k_channel *chan)
 {
 	u32 pll;
@@ -980,20 +970,19 @@
 	REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
 }
 
-static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
+static void ath9k_hw_init_chain_masks(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int rx_chainmask, tx_chainmask;
 
-	rx_chainmask = ahp->ah_rxchainmask;
-	tx_chainmask = ahp->ah_txchainmask;
+	rx_chainmask = ah->rxchainmask;
+	tx_chainmask = ah->txchainmask;
 
 	switch (rx_chainmask) {
 	case 0x5:
 		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
 			    AR_PHY_SWAP_ALT_CHAIN);
 	case 0x3:
-		if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) {
+		if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) {
 			REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
 			REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
 			break;
@@ -1018,28 +1007,26 @@
 			  REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
 }
 
-static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
+static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
 					  enum nl80211_iftype opmode)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	ahp->ah_maskReg = AR_IMR_TXERR |
+	ah->mask_reg = AR_IMR_TXERR |
 		AR_IMR_TXURN |
 		AR_IMR_RXERR |
 		AR_IMR_RXORN |
 		AR_IMR_BCNMISC;
 
-	if (ahp->ah_intrMitigation)
-		ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+	if (ah->intr_mitigation)
+		ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
 	else
-		ahp->ah_maskReg |= AR_IMR_RXOK;
+		ah->mask_reg |= AR_IMR_RXOK;
 
-	ahp->ah_maskReg |= AR_IMR_TXOK;
+	ah->mask_reg |= AR_IMR_TXOK;
 
 	if (opmode == NL80211_IFTYPE_AP)
-		ahp->ah_maskReg |= AR_IMR_MIB;
+		ah->mask_reg |= AR_IMR_MIB;
 
-	REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
+	REG_WRITE(ah, AR_IMR, ah->mask_reg);
 	REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
 
 	if (!AR_SREV_9100(ah)) {
@@ -1049,72 +1036,64 @@
 	}
 }
 
-static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us)
+static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
 		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us);
-		ahp->ah_acktimeout = (u32) -1;
+		ah->acktimeout = (u32) -1;
 		return false;
 	} else {
 		REG_RMW_FIELD(ah, AR_TIME_OUT,
 			      AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
-		ahp->ah_acktimeout = us;
+		ah->acktimeout = us;
 		return true;
 	}
 }
 
-static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us)
+static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
 		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us);
-		ahp->ah_ctstimeout = (u32) -1;
+		ah->ctstimeout = (u32) -1;
 		return false;
 	} else {
 		REG_RMW_FIELD(ah, AR_TIME_OUT,
 			      AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
-		ahp->ah_ctstimeout = us;
+		ah->ctstimeout = us;
 		return true;
 	}
 }
 
-static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu)
+static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	if (tu > 0xFFFF) {
 		DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
 			"bad global tx timeout %u\n", tu);
-		ahp->ah_globaltxtimeout = (u32) -1;
+		ah->globaltxtimeout = (u32) -1;
 		return false;
 	} else {
 		REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
-		ahp->ah_globaltxtimeout = tu;
+		ah->globaltxtimeout = tu;
 		return true;
 	}
 }
 
-static void ath9k_hw_init_user_settings(struct ath_hal *ah)
+static void ath9k_hw_init_user_settings(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
+	DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
+		ah->misc_mode);
 
-	DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ahp->ah_miscMode 0x%x\n",
-		ahp->ah_miscMode);
-
-	if (ahp->ah_miscMode != 0)
+	if (ah->misc_mode != 0)
 		REG_WRITE(ah, AR_PCU_MISC,
-			  REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
-	if (ahp->ah_slottime != (u32) -1)
-		ath9k_hw_setslottime(ah, ahp->ah_slottime);
-	if (ahp->ah_acktimeout != (u32) -1)
-		ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
-	if (ahp->ah_ctstimeout != (u32) -1)
-		ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
-	if (ahp->ah_globaltxtimeout != (u32) -1)
-		ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
+			  REG_READ(ah, AR_PCU_MISC) | ah->misc_mode);
+	if (ah->slottime != (u32) -1)
+		ath9k_hw_setslottime(ah, ah->slottime);
+	if (ah->acktimeout != (u32) -1)
+		ath9k_hw_set_ack_timeout(ah, ah->acktimeout);
+	if (ah->ctstimeout != (u32) -1)
+		ath9k_hw_set_cts_timeout(ah, ah->ctstimeout);
+	if (ah->globaltxtimeout != (u32) -1)
+		ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
 }
 
 const char *ath9k_hw_probe(u16 vendorid, u16 devid)
@@ -1123,7 +1102,7 @@
 		ath9k_hw_devname(devid) : NULL;
 }
 
-void ath9k_hw_detach(struct ath_hal *ah)
+void ath9k_hw_detach(struct ath_hw *ah)
 {
 	if (!AR_SREV_9100(ah))
 		ath9k_hw_ani_detach(ah);
@@ -1133,10 +1112,9 @@
 	kfree(ah);
 }
 
-struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
-				void __iomem *mem, int *error)
+struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
 {
-	struct ath_hal *ah = NULL;
+	struct ath_hw *ah = NULL;
 
 	switch (devid) {
 	case AR5416_DEVID_PCI:
@@ -1146,7 +1124,7 @@
 	case AR9280_DEVID_PCI:
 	case AR9280_DEVID_PCIE:
 	case AR9285_DEVID_PCIE:
-		ah = ath9k_hw_do_attach(devid, sc, mem, error);
+		ah = ath9k_hw_do_attach(devid, sc, error);
 		break;
 	default:
 		*error = -ENXIO;
@@ -1160,7 +1138,7 @@
 /* INI */
 /*******/
 
-static void ath9k_hw_override_ini(struct ath_hal *ah,
+static void ath9k_hw_override_ini(struct ath_hw *ah,
 				  struct ath9k_channel *chan)
 {
 	/*
@@ -1178,13 +1156,13 @@
 	REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
 }
 
-static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah,
+static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
 			      struct ar5416_eeprom_def *pEepData,
 			      u32 reg, u32 value)
 {
 	struct base_eep_header *pBase = &(pEepData->baseEepHeader);
 
-	switch (ah->ah_devid) {
+	switch (ah->hw_version.devid) {
 	case AR9280_DEVID_PCI:
 		if (reg == 0x7894) {
 			DPRINTF(ah->ah_sc, ATH_DBG_ANY,
@@ -1212,24 +1190,21 @@
 	return value;
 }
 
-static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
 			      struct ar5416_eeprom_def *pEepData,
 			      u32 reg, u32 value)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (ahp->ah_eep_map == EEP_MAP_4KBITS)
+	if (ah->eep_map == EEP_MAP_4KBITS)
 		return value;
 	else
 		return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value);
 }
 
-static int ath9k_hw_process_ini(struct ath_hal *ah,
+static int ath9k_hw_process_ini(struct ath_hw *ah,
 				struct ath9k_channel *chan,
 				enum ath9k_ht_macmode macmode)
 {
 	int i, regWrites = 0;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ieee80211_channel *channel = chan->chan;
 	u32 modesIndex, freqIndex;
 	int status;
@@ -1262,40 +1237,38 @@
 	}
 
 	REG_WRITE(ah, AR_PHY(0), 0x00000007);
-
 	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
-
-	ath9k_hw_set_addac(ah, chan);
+	ah->eep_ops->set_addac(ah, chan);
 
 	if (AR_SREV_5416_V22_OR_LATER(ah)) {
-		REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites);
+		REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
 	} else {
 		struct ar5416IniArray temp;
 		u32 addacSize =
-			sizeof(u32) * ahp->ah_iniAddac.ia_rows *
-			ahp->ah_iniAddac.ia_columns;
+			sizeof(u32) * ah->iniAddac.ia_rows *
+			ah->iniAddac.ia_columns;
 
-		memcpy(ahp->ah_addac5416_21,
-		       ahp->ah_iniAddac.ia_array, addacSize);
+		memcpy(ah->addac5416_21,
+		       ah->iniAddac.ia_array, addacSize);
 
-		(ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0;
+		(ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0;
 
-		temp.ia_array = ahp->ah_addac5416_21;
-		temp.ia_columns = ahp->ah_iniAddac.ia_columns;
-		temp.ia_rows = ahp->ah_iniAddac.ia_rows;
+		temp.ia_array = ah->addac5416_21;
+		temp.ia_columns = ah->iniAddac.ia_columns;
+		temp.ia_rows = ah->iniAddac.ia_rows;
 		REG_WRITE_ARRAY(&temp, 1, regWrites);
 	}
 
 	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
 
-	for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
-		u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
-		u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex);
+	for (i = 0; i < ah->iniModes.ia_rows; i++) {
+		u32 reg = INI_RA(&ah->iniModes, i, 0);
+		u32 val = INI_RA(&ah->iniModes, i, modesIndex);
 
 		REG_WRITE(ah, reg, val);
 
 		if (reg >= 0x7800 && reg < 0x78a0
-		    && ah->ah_config.analog_shiftreg) {
+		    && ah->config.analog_shiftreg) {
 			udelay(100);
 		}
 
@@ -1303,19 +1276,19 @@
 	}
 
 	if (AR_SREV_9280(ah))
-		REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites);
+		REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
 
 	if (AR_SREV_9280(ah))
-		REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites);
+		REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
 
-	for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
-		u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
-		u32 val = INI_RA(&ahp->ah_iniCommon, i, 1);
+	for (i = 0; i < ah->iniCommon.ia_rows; i++) {
+		u32 reg = INI_RA(&ah->iniCommon, i, 0);
+		u32 val = INI_RA(&ah->iniCommon, i, 1);
 
 		REG_WRITE(ah, reg, val);
 
 		if (reg >= 0x7800 && reg < 0x78a0
-		    && ah->ah_config.analog_shiftreg) {
+		    && ah->config.analog_shiftreg) {
 			udelay(100);
 		}
 
@@ -1325,7 +1298,7 @@
 	ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites);
 
 	if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
-		REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex,
+		REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex,
 				regWrites);
 	}
 
@@ -1333,12 +1306,12 @@
 	ath9k_hw_set_regs(ah, chan, macmode);
 	ath9k_hw_init_chain_masks(ah);
 
-	status = ath9k_hw_set_txpower(ah, chan,
-				      ath9k_regd_get_ctl(ah, chan),
-				      channel->max_antenna_gain * 2,
-				      channel->max_power * 2,
-				      min((u32) MAX_RATE_POWER,
-					  (u32) ah->ah_powerLimit));
+	status = ah->eep_ops->set_txpower(ah, chan,
+				  ath9k_regd_get_ctl(ah, chan),
+				  channel->max_antenna_gain * 2,
+				  channel->max_power * 2,
+				  min((u32) MAX_RATE_POWER,
+				      (u32) ah->regulatory.power_limit));
 	if (status != 0) {
 		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
 			"error init'ing transmit power\n");
@@ -1358,7 +1331,7 @@
 /* Reset and Channel Switching Routines */
 /****************************************/
 
-static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
+static void ath9k_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	u32 rfMode = 0;
 
@@ -1378,12 +1351,12 @@
 	REG_WRITE(ah, AR_PHY_MODE, rfMode);
 }
 
-static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
+static void ath9k_hw_mark_phy_inactive(struct ath_hw *ah)
 {
 	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
 }
 
-static inline void ath9k_hw_set_dma(struct ath_hal *ah)
+static inline void ath9k_hw_set_dma(struct ath_hw *ah)
 {
 	u32 regval;
 
@@ -1393,7 +1366,7 @@
 	regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
 	REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
 
-	REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
+	REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
 
 	regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
 	REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
@@ -1409,7 +1382,7 @@
 	}
 }
 
-static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
+static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
 {
 	u32 val;
 
@@ -1433,7 +1406,7 @@
 	}
 }
 
-static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah,
+static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah,
 						 u32 coef_scaled,
 						 u32 *coef_mantissa,
 						 u32 *coef_exponent)
@@ -1452,7 +1425,7 @@
 	*coef_exponent = coef_exp - 16;
 }
 
-static void ath9k_hw_set_delta_slope(struct ath_hal *ah,
+static void ath9k_hw_set_delta_slope(struct ath_hw *ah,
 				     struct ath9k_channel *chan)
 {
 	u32 coef_scaled, ds_coef_exp, ds_coef_man;
@@ -1486,7 +1459,7 @@
 		      AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
 }
 
-static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
+static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 {
 	u32 rst_flags;
 	u32 tmpReg;
@@ -1534,7 +1507,7 @@
 	return true;
 }
 
-static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
+static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 {
 	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
 		  AR_RTC_FORCE_WAKE_ON_INT);
@@ -1555,7 +1528,7 @@
 	return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
 }
 
-static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type)
+static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 {
 	REG_WRITE(ah, AR_RTC_FORCE_WAKE,
 		  AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
@@ -1573,12 +1546,11 @@
 	}
 }
 
-static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
 			      enum ath9k_ht_macmode macmode)
 {
 	u32 phymode;
 	u32 enableDacFifo = 0;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
 	if (AR_SREV_9285_10_OR_LATER(ah))
 		enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
@@ -1594,7 +1566,7 @@
 		    (chan->chanmode == CHANNEL_G_HT40PLUS))
 			phymode |= AR_PHY_FC_DYN2040_PRI_CH;
 
-		if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
+		if (ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
 			phymode |= AR_PHY_FC_DYN2040_EXT_CH;
 	}
 	REG_WRITE(ah, AR_PHY_TURBO, phymode);
@@ -1605,27 +1577,23 @@
 	REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
 }
 
-static bool ath9k_hw_chip_reset(struct ath_hal *ah,
+static bool ath9k_hw_chip_reset(struct ath_hw *ah,
 				struct ath9k_channel *chan)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
 		return false;
 
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
 		return false;
 
-	ahp->ah_chipFullSleep = false;
-
+	ah->chip_fullsleep = false;
 	ath9k_hw_init_pll(ah, chan);
-
 	ath9k_hw_set_rfmode(ah, chan);
 
 	return true;
 }
 
-static bool ath9k_hw_channel_change(struct ath_hal *ah,
+static bool ath9k_hw_channel_change(struct ath_hw *ah,
 				    struct ath9k_channel *chan,
 				    enum ath9k_ht_macmode macmode)
 {
@@ -1664,12 +1632,12 @@
 		}
 	}
 
-	if (ath9k_hw_set_txpower(ah, chan,
-				 ath9k_regd_get_ctl(ah, chan),
-				 channel->max_antenna_gain * 2,
-				 channel->max_power * 2,
-				 min((u32) MAX_RATE_POWER,
-				     (u32) ah->ah_powerLimit)) != 0) {
+	if (ah->eep_ops->set_txpower(ah, chan,
+			     ath9k_regd_get_ctl(ah, chan),
+			     channel->max_antenna_gain * 2,
+			     channel->max_power * 2,
+			     min((u32) MAX_RATE_POWER,
+				 (u32) ah->regulatory.power_limit)) != 0) {
 		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
 			"error init'ing transmit power\n");
 		return false;
@@ -1699,7 +1667,7 @@
 	return true;
 }
 
-static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
+static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	int bb_spur = AR_NO_SPUR;
 	int freq;
@@ -1733,9 +1701,9 @@
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 	freq = centers.synth_center;
 
-	ah->ah_config.spurmode = SPUR_ENABLE_EEPROM;
+	ah->config.spurmode = SPUR_ENABLE_EEPROM;
 	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-		cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
+		cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
 
 		if (is2GHz)
 			cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
@@ -1949,7 +1917,7 @@
 	REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
-static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
+static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	int bb_spur = AR_NO_SPUR;
 	int bin, cur_bin;
@@ -1978,7 +1946,7 @@
 	memset(&mask_p, 0, sizeof(int8_t) * 123);
 
 	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-		cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
+		cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
 		if (AR_NO_SPUR == cur_bb_spur)
 			break;
 		cur_bb_spur = cur_bb_spur - (chan->channel * 10);
@@ -2150,27 +2118,26 @@
 	REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
-int ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
+int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 		    bool bChannelChange)
 {
 	u32 saveLedState;
 	struct ath_softc *sc = ah->ah_sc;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_channel *curchan = ah->ah_curchan;
+	struct ath9k_channel *curchan = ah->curchan;
 	u32 saveDefAntenna;
 	u32 macStaId1;
 	int i, rx_chainmask, r;
 
-	ahp->ah_extprotspacing = sc->sc_ht_extprotspacing;
-	ahp->ah_txchainmask = sc->sc_tx_chainmask;
-	ahp->ah_rxchainmask = sc->sc_rx_chainmask;
+	ah->extprotspacing = sc->ht_extprotspacing;
+	ah->txchainmask = sc->tx_chainmask;
+	ah->rxchainmask = sc->rx_chainmask;
 
 	if (AR_SREV_9285(ah)) {
-		ahp->ah_txchainmask &= 0x1;
-		ahp->ah_rxchainmask &= 0x1;
+		ah->txchainmask &= 0x1;
+		ah->rxchainmask &= 0x1;
 	} else if (AR_SREV_9280(ah)) {
-		ahp->ah_txchainmask &= 0x3;
-		ahp->ah_rxchainmask &= 0x3;
+		ah->txchainmask &= 0x3;
+		ah->rxchainmask &= 0x3;
 	}
 
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
@@ -2180,16 +2147,16 @@
 		ath9k_hw_getnf(ah, curchan);
 
 	if (bChannelChange &&
-	    (ahp->ah_chipFullSleep != true) &&
-	    (ah->ah_curchan != NULL) &&
-	    (chan->channel != ah->ah_curchan->channel) &&
+	    (ah->chip_fullsleep != true) &&
+	    (ah->curchan != NULL) &&
+	    (chan->channel != ah->curchan->channel) &&
 	    ((chan->channelFlags & CHANNEL_ALL) ==
-	     (ah->ah_curchan->channelFlags & CHANNEL_ALL)) &&
+	     (ah->curchan->channelFlags & CHANNEL_ALL)) &&
 	    (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
-				   !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) {
+				   !IS_CHAN_A_5MHZ_SPACED(ah->curchan)))) {
 
 		if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) {
-			ath9k_hw_loadnf(ah, ah->ah_curchan);
+			ath9k_hw_loadnf(ah, ah->curchan);
 			ath9k_hw_start_nfcal(ah);
 			return 0;
 		}
@@ -2244,7 +2211,7 @@
 	else
 		ath9k_hw_spur_mitigate(ah, chan);
 
-	if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
+	if (!ah->eep_ops->set_board_values(ah, chan)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
 			"error setting board options\n");
 		return -EIO;
@@ -2252,23 +2219,23 @@
 
 	ath9k_hw_decrease_chain_power(ah, chan);
 
-	REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ahp->ah_macaddr));
-	REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ahp->ah_macaddr + 4)
+	REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ah->macaddr));
+	REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ah->macaddr + 4)
 		  | macStaId1
 		  | AR_STA_ID1_RTS_USE_DEF
-		  | (ah->ah_config.
+		  | (ah->config.
 		     ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
-		  | ahp->ah_staId1Defaults);
-	ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
+		  | ah->sta_id1_defaults);
+	ath9k_hw_set_operating_mode(ah, ah->opmode);
 
-	REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
-	REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
+	REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask));
+	REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4));
 
 	REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
 
-	REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
-	REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
-		  ((ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S));
+	REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid));
+	REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) |
+		  ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
 
 	REG_WRITE(ah, AR_ISR, ~0);
 
@@ -2285,15 +2252,15 @@
 	for (i = 0; i < AR_NUM_DCU; i++)
 		REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
 
-	ahp->ah_intrTxqs = 0;
-	for (i = 0; i < ah->ah_caps.total_queues; i++)
+	ah->intr_txqs = 0;
+	for (i = 0; i < ah->caps.total_queues; i++)
 		ath9k_hw_resettxqueue(ah, i);
 
-	ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
+	ath9k_hw_init_interrupt_masks(ah, ah->opmode);
 	ath9k_hw_init_qos(ah);
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		ath9k_enable_rfkill(ah);
 #endif
 	ath9k_hw_init_user_settings(ah);
@@ -2305,7 +2272,7 @@
 
 	REG_WRITE(ah, AR_OBS, 8);
 
-	if (ahp->ah_intrMitigation) {
+	if (ah->intr_mitigation) {
 
 		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
 		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
@@ -2316,7 +2283,7 @@
 	if (!ath9k_hw_init_cal(ah, chan))
 		return -EIO;;
 
-	rx_chainmask = ahp->ah_rxchainmask;
+	rx_chainmask = ah->rxchainmask;
 	if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
 		REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
 		REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
@@ -2350,11 +2317,11 @@
 /* Key Cache Management */
 /************************/
 
-bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
+bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
 {
 	u32 keyType;
 
-	if (entry >= ah->ah_caps.keycache_size) {
+	if (entry >= ah->caps.keycache_size) {
 		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
 			"entry %u out of range\n", entry);
 		return false;
@@ -2381,17 +2348,17 @@
 
 	}
 
-	if (ah->ah_curchan == NULL)
+	if (ah->curchan == NULL)
 		return true;
 
 	return true;
 }
 
-bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac)
+bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
 {
 	u32 macHi, macLo;
 
-	if (entry >= ah->ah_caps.keycache_size) {
+	if (entry >= ah->caps.keycache_size) {
 		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
 			"entry %u out of range\n", entry);
 		return false;
@@ -2415,17 +2382,16 @@
 	return true;
 }
 
-bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
 				 const struct ath9k_keyval *k,
 				 const u8 *mac, int xorKey)
 {
-	const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	const struct ath9k_hw_capabilities *pCap = &ah->caps;
 	u32 key0, key1, key2, key3, key4;
 	u32 keyType;
 	u32 xorMask = xorKey ?
 		(ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
 		 | ATH9K_KEY_XOR) : 0;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
 	if (entry >= pCap->keycache_size) {
 		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
@@ -2441,7 +2407,7 @@
 		if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
 			DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
 				"AES-CCM not supported by mac rev 0x%x\n",
-				ah->ah_macRev);
+				ah->hw_version.macRev);
 			return false;
 		}
 		keyType = AR_KEYTABLE_TYPE_CCM;
@@ -2496,7 +2462,7 @@
 		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
 		(void) ath9k_hw_keysetmac(ah, entry, mac);
 
-		if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
+		if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) {
 			u32 mic0, mic1, mic2, mic3, mic4;
 
 			mic0 = get_unaligned_le32(k->kv_mic + 0);
@@ -2540,15 +2506,15 @@
 		(void) ath9k_hw_keysetmac(ah, entry, mac);
 	}
 
-	if (ah->ah_curchan == NULL)
+	if (ah->curchan == NULL)
 		return true;
 
 	return true;
 }
 
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
+bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
 {
-	if (entry < ah->ah_caps.keycache_size) {
+	if (entry < ah->caps.keycache_size) {
 		u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
 		if (val & AR_KEYTABLE_VALID)
 			return true;
@@ -2560,7 +2526,7 @@
 /* Power Management (Chipset) */
 /******************************/
 
-static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
+static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
 {
 	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
 	if (setChip) {
@@ -2574,11 +2540,11 @@
 	}
 }
 
-static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
+static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
 {
 	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
 	if (setChip) {
-		struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+		struct ath9k_hw_capabilities *pCap = &ah->caps;
 
 		if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
 			REG_WRITE(ah, AR_RTC_FORCE_WAKE,
@@ -2590,8 +2556,7 @@
 	}
 }
 
-static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
-				     int setChip)
+static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
 {
 	u32 val;
 	int i;
@@ -2632,20 +2597,18 @@
 	return true;
 }
 
-bool ath9k_hw_setpower(struct ath_hal *ah,
-		       enum ath9k_power_mode mode)
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
+	int status = true, setChip = true;
 	static const char *modes[] = {
 		"AWAKE",
 		"FULL-SLEEP",
 		"NETWORK SLEEP",
 		"UNDEFINED"
 	};
-	int status = true, setChip = true;
 
 	DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n",
-		modes[ah->ah_power_mode], modes[mode],
+		modes[ah->power_mode], modes[mode],
 		setChip ? "set chip " : "");
 
 	switch (mode) {
@@ -2654,7 +2617,7 @@
 		break;
 	case ATH9K_PM_FULL_SLEEP:
 		ath9k_set_power_sleep(ah, setChip);
-		ahp->ah_chipFullSleep = true;
+		ah->chip_fullsleep = true;
 		break;
 	case ATH9K_PM_NETWORK_SLEEP:
 		ath9k_set_power_network_sleep(ah, setChip);
@@ -2664,41 +2627,57 @@
 			"Unknown power mode %u\n", mode);
 		return false;
 	}
-	ah->ah_power_mode = mode;
+	ah->power_mode = mode;
 
 	return status;
 }
 
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
+/*
+ * Helper for ASPM support.
+ *
+ * Disable PLL when in L0s as well as receiver clock when in L1.
+ * This power saving option must be enabled through the SerDes.
+ *
+ * Programming the SerDes must go through the same 288 bit serial shift
+ * register as the other analog registers.  Hence the 9 writes.
+ */
+void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	u8 i;
 
-	if (ah->ah_isPciExpress != true)
+	if (ah->is_pciexpress != true)
 		return;
 
-	if (ah->ah_config.pcie_powersave_enable == 2)
+	/* Do not touch SerDes registers */
+	if (ah->config.pcie_powersave_enable == 2)
 		return;
 
+	/* Nothing to do on restore for 11N */
 	if (restore)
 		return;
 
 	if (AR_SREV_9280_20_OR_LATER(ah)) {
-		for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
-			REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
-				  INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
+		/*
+		 * AR9280 2.0 or later chips use SerDes values from the
+		 * initvals.h initialized depending on chipset during
+		 * ath9k_hw_do_attach()
+		 */
+		for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
+			REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
+				  INI_RA(&ah->iniPcieSerdes, i, 1));
 		}
-		udelay(1000);
 	} else if (AR_SREV_9280(ah) &&
-		   (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
+		   (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) {
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
 
+		/* RX shut off when elecidle is asserted */
 		REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
 
-		if (ah->ah_config.pcie_clock_req)
+		/* Shut off CLKREQ active in L1 */
+		if (ah->config.pcie_clock_req)
 			REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
 		else
 			REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
@@ -2707,42 +2686,59 @@
 		REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
 
+		/* Load the new settings */
 		REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 
-		udelay(1000);
 	} else {
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+
+		/* RX shut off when elecidle is asserted */
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
+
+		/*
+		 * Ignore ah->ah_config.pcie_clock_req setting for
+		 * pre-AR9280 11n
+		 */
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
+
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
 		REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
+
+		/* Load the new settings */
 		REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 	}
 
+	udelay(1000);
+
+	/* set bit 19 to allow forcing of pcie core into L1 state */
 	REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 
-	if (ah->ah_config.pcie_waen) {
-		REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
+	/* Several PCIe massages to ensure proper behaviour */
+	if (ah->config.pcie_waen) {
+		REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
 	} else {
 		if (AR_SREV_9285(ah))
 			REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
+		/*
+		 * On AR9280 chips bit 22 of 0x4004 needs to be set to
+		 * otherwise card may disappear.
+		 */
 		else if (AR_SREV_9280(ah))
 			REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT);
 		else
 			REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
 	}
-
 }
 
 /**********************/
 /* Interrupt Handling */
 /**********************/
 
-bool ath9k_hw_intrpend(struct ath_hal *ah)
+bool ath9k_hw_intrpend(struct ath_hw *ah)
 {
 	u32 host_isr;
 
@@ -2761,14 +2757,13 @@
 	return false;
 }
 
-bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
+bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
 {
 	u32 isr = 0;
 	u32 mask2 = 0;
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	u32 sync_cause = 0;
 	bool fatal_int = false;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
 	if (!AR_SREV_9100(ah)) {
 		if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
@@ -2816,7 +2811,7 @@
 
 		*masked = isr & ATH9K_INT_COMMON;
 
-		if (ahp->ah_intrMitigation) {
+		if (ah->intr_mitigation) {
 			if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
 				*masked |= ATH9K_INT_RX;
 		}
@@ -2831,12 +2826,12 @@
 			*masked |= ATH9K_INT_TX;
 
 			s0_s = REG_READ(ah, AR_ISR_S0_S);
-			ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
-			ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
+			ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
+			ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
 
 			s1_s = REG_READ(ah, AR_ISR_S1_S);
-			ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
-			ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
+			ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
+			ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
 		}
 
 		if (isr & AR_ISR_RXORN) {
@@ -2893,17 +2888,16 @@
 	return true;
 }
 
-enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah)
+enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah)
 {
-	return AH5416(ah)->ah_maskReg;
+	return ah->mask_reg;
 }
 
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 omask = ahp->ah_maskReg;
+	u32 omask = ah->mask_reg;
 	u32 mask, mask2;
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 
 	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
 
@@ -2924,18 +2918,18 @@
 	mask2 = 0;
 
 	if (ints & ATH9K_INT_TX) {
-		if (ahp->ah_txOkInterruptMask)
+		if (ah->txok_interrupt_mask)
 			mask |= AR_IMR_TXOK;
-		if (ahp->ah_txDescInterruptMask)
+		if (ah->txdesc_interrupt_mask)
 			mask |= AR_IMR_TXDESC;
-		if (ahp->ah_txErrInterruptMask)
+		if (ah->txerr_interrupt_mask)
 			mask |= AR_IMR_TXERR;
-		if (ahp->ah_txEolInterruptMask)
+		if (ah->txeol_interrupt_mask)
 			mask |= AR_IMR_TXEOL;
 	}
 	if (ints & ATH9K_INT_RX) {
 		mask |= AR_IMR_RXERR;
-		if (ahp->ah_intrMitigation)
+		if (ah->intr_mitigation)
 			mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
 		else
 			mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
@@ -2973,7 +2967,7 @@
 					   AR_IMR_S2_TSFOOR |
 					   AR_IMR_S2_GTT | AR_IMR_S2_CST);
 	REG_WRITE(ah, AR_IMR_S2, mask | mask2);
-	ahp->ah_maskReg = ints;
+	ah->mask_reg = ints;
 
 	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
 		if (ints & ATH9K_INT_TIM_TIMER)
@@ -3007,14 +3001,13 @@
 /* Beacon Handling */
 /*******************/
 
-void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period)
+void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	int flags = 0;
 
-	ahp->ah_beaconInterval = beacon_period;
+	ah->beacon_interval = beacon_period;
 
-	switch (ah->ah_opmode) {
+	switch (ah->opmode) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_MONITOR:
 		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
@@ -3027,18 +3020,18 @@
 			    AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
 		REG_WRITE(ah, AR_NEXT_NDP_TIMER,
 			  TU_TO_USEC(next_beacon +
-				     (ahp->ah_atimWindow ? ahp->
-				      ah_atimWindow : 1)));
+				     (ah->atim_window ? ah->
+				      atim_window : 1)));
 		flags |= AR_NDP_TIMER_EN;
 	case NL80211_IFTYPE_AP:
 		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
 		REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
 			  TU_TO_USEC(next_beacon -
-				     ah->ah_config.
+				     ah->config.
 				     dma_beacon_response_time));
 		REG_WRITE(ah, AR_NEXT_SWBA,
 			  TU_TO_USEC(next_beacon -
-				     ah->ah_config.
+				     ah->config.
 				     sw_beacon_response_time));
 		flags |=
 			AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
@@ -3046,7 +3039,7 @@
 	default:
 		DPRINTF(ah->ah_sc, ATH_DBG_BEACON,
 			"%s: unsupported opmode: %d\n",
-			__func__, ah->ah_opmode);
+			__func__, ah->opmode);
 		return;
 		break;
 	}
@@ -3065,11 +3058,11 @@
 	REG_SET_BIT(ah, AR_TIMER_MODE, flags);
 }
 
-void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 				    const struct ath9k_beacon_state *bs)
 {
 	u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 
 	REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
 
@@ -3129,37 +3122,37 @@
 /* HW Capabilities */
 /*******************/
 
-bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
+bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	u16 capField = 0, eeval;
 
-	eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0);
+	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
 
-	ah->ah_currentRD = eeval;
+	ah->regulatory.current_rd = eeval;
 
-	eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1);
-	ah->ah_currentRDExt = eeval;
+	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1);
+	ah->regulatory.current_rd_ext = eeval;
 
-	capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP);
+	capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP);
 
-	if (ah->ah_opmode != NL80211_IFTYPE_AP &&
-	    ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
-		if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
-			ah->ah_currentRD += 5;
-		else if (ah->ah_currentRD == 0x41)
-			ah->ah_currentRD = 0x43;
+	if (ah->opmode != NL80211_IFTYPE_AP &&
+	    ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
+		if (ah->regulatory.current_rd == 0x64 ||
+		    ah->regulatory.current_rd == 0x65)
+			ah->regulatory.current_rd += 5;
+		else if (ah->regulatory.current_rd == 0x41)
+			ah->regulatory.current_rd = 0x43;
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"regdomain mapped to 0x%x\n", ah->ah_currentRD);
+			"regdomain mapped to 0x%x\n", ah->regulatory.current_rd);
 	}
 
-	eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE);
+	eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
 	bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
 
 	if (eeval & AR5416_OPFLAGS_11A) {
 		set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
-		if (ah->ah_config.ht_enable) {
+		if (ah->config.ht_enable) {
 			if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
 				set_bit(ATH9K_MODE_11NA_HT20,
 					pCap->wireless_modes);
@@ -3175,7 +3168,7 @@
 	if (eeval & AR5416_OPFLAGS_11G) {
 		set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
 		set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
-		if (ah->ah_config.ht_enable) {
+		if (ah->config.ht_enable) {
 			if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
 				set_bit(ATH9K_MODE_11NG_HT20,
 					pCap->wireless_modes);
@@ -3188,18 +3181,18 @@
 		}
 	}
 
-	pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK);
-	if ((ah->ah_isPciExpress)
+	pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK);
+	if ((ah->is_pciexpress)
 	    || (eeval & AR5416_OPFLAGS_11A)) {
 		pCap->rx_chainmask =
-			ath9k_hw_get_eeprom(ah, EEP_RX_MASK);
+			ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
 	} else {
 		pCap->rx_chainmask =
 			(ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
 	}
 
-	if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
-		ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
+	if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0)))
+		ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
 
 	pCap->low_2ghz_chan = 2312;
 	pCap->high_2ghz_chan = 2732;
@@ -3217,7 +3210,7 @@
 
 	pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
 
-	if (ah->ah_config.ht_enable)
+	if (ah->config.ht_enable)
 		pCap->hw_caps |= ATH9K_HW_CAP_HT;
 	else
 		pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
@@ -3268,22 +3261,22 @@
 	pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-	ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT);
-	if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
-		ah->ah_rfkill_gpio =
-			MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
-		ah->ah_rfkill_polarity =
-			MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
+	ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT);
+	if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
+		ah->rfkill_gpio =
+			MS(ah->rfsilent, EEP_RFSILENT_GPIO_SEL);
+		ah->rfkill_polarity =
+			MS(ah->rfsilent, EEP_RFSILENT_POLARITY);
 
 		pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
 	}
 #endif
 
-	if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
-	    (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
-	    (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
-	    (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
-	    (ah->ah_macVersion == AR_SREV_VERSION_9280))
+	if ((ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) ||
+	    (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) ||
+	    (ah->hw_version.macVersion == AR_SREV_VERSION_9160) ||
+	    (ah->hw_version.macVersion == AR_SREV_VERSION_9100) ||
+	    (ah->hw_version.macVersion == AR_SREV_VERSION_9280))
 		pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
 	else
 		pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
@@ -3293,7 +3286,7 @@
 	else
 		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
-	if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
+	if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
 		pCap->reg_cap =
 			AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
 			AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
@@ -3308,24 +3301,23 @@
 	pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
 
 	pCap->num_antcfg_5ghz =
-		ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
+		ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
 	pCap->num_antcfg_2ghz =
-		ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
+		ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
 
 	if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) {
 		pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX;
-		ah->ah_btactive_gpio = 6;
-		ah->ah_wlanactive_gpio = 5;
+		ah->btactive_gpio = 6;
+		ah->wlanactive_gpio = 5;
 	}
 
 	return true;
 }
 
-bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
 			    u32 capability, u32 *result)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	const struct ath9k_hw_capabilities *pCap = &ah->caps;
 
 	switch (type) {
 	case ATH9K_CAP_CIPHER:
@@ -3345,17 +3337,17 @@
 		case 0:
 			return true;
 		case 1:
-			return (ahp->ah_staId1Defaults &
+			return (ah->sta_id1_defaults &
 				AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
 			false;
 		}
 	case ATH9K_CAP_TKIP_SPLIT:
-		return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ?
+		return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ?
 			false : true;
 	case ATH9K_CAP_WME_TKIPMIC:
 		return 0;
 	case ATH9K_CAP_PHYCOUNTERS:
-		return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO;
+		return ah->has_hw_phycounters ? 0 : -ENXIO;
 	case ATH9K_CAP_DIVERSITY:
 		return (REG_READ(ah, AR_PHY_CCK_DETECT) &
 			AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
@@ -3370,14 +3362,14 @@
 			if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
 				return false;
 			} else {
-				return (ahp->ah_staId1Defaults &
+				return (ah->sta_id1_defaults &
 					AR_STA_ID1_MCAST_KSRCH) ? true :
 					false;
 			}
 		}
 		return false;
 	case ATH9K_CAP_TSF_ADJUST:
-		return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ?
+		return (ah->misc_mode & AR_PCU_TX_ADD_TSF) ?
 			true : false;
 	case ATH9K_CAP_RFSILENT:
 		if (capability == 3)
@@ -3393,13 +3385,13 @@
 		case 0:
 			return 0;
 		case 1:
-			*result = ah->ah_powerLimit;
+			*result = ah->regulatory.power_limit;
 			return 0;
 		case 2:
-			*result = ah->ah_maxPowerLevel;
+			*result = ah->regulatory.max_power_level;
 			return 0;
 		case 3:
-			*result = ah->ah_tpScale;
+			*result = ah->regulatory.tp_scale;
 			return 0;
 		}
 		return false;
@@ -3408,19 +3400,18 @@
 	}
 }
 
-bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
 			    u32 capability, u32 setting, int *status)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	u32 v;
 
 	switch (type) {
 	case ATH9K_CAP_TKIP_MIC:
 		if (setting)
-			ahp->ah_staId1Defaults |=
+			ah->sta_id1_defaults |=
 				AR_STA_ID1_CRPT_MIC_ENABLE;
 		else
-			ahp->ah_staId1Defaults &=
+			ah->sta_id1_defaults &=
 				~AR_STA_ID1_CRPT_MIC_ENABLE;
 		return true;
 	case ATH9K_CAP_DIVERSITY:
@@ -3433,15 +3424,15 @@
 		return true;
 	case ATH9K_CAP_MCAST_KEYSRCH:
 		if (setting)
-			ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
+			ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH;
 		else
-			ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
+			ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH;
 		return true;
 	case ATH9K_CAP_TSF_ADJUST:
 		if (setting)
-			ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+			ah->misc_mode |= AR_PCU_TX_ADD_TSF;
 		else
-			ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+			ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
 		return true;
 	default:
 		return false;
@@ -3452,7 +3443,7 @@
 /* GPIO / RFKILL / Antennae */
 /****************************/
 
-static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
+static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
 					 u32 gpio, u32 type)
 {
 	int addr;
@@ -3480,11 +3471,11 @@
 	}
 }
 
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
+void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
 {
 	u32 gpio_shift;
 
-	ASSERT(gpio < ah->ah_caps.num_gpio_pins);
+	ASSERT(gpio < ah->caps.num_gpio_pins);
 
 	gpio_shift = gpio << 1;
 
@@ -3494,12 +3485,12 @@
 		(AR_GPIO_OE_OUT_DRV << gpio_shift));
 }
 
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
+u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
 {
 #define MS_REG_READ(x, y) \
 	(MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y)))
 
-	if (gpio >= ah->ah_caps.num_gpio_pins)
+	if (gpio >= ah->caps.num_gpio_pins)
 		return 0xffffffff;
 
 	if (AR_SREV_9285_10_OR_LATER(ah))
@@ -3510,7 +3501,7 @@
 		return MS_REG_READ(AR, gpio) != 0;
 }
 
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
 			 u32 ah_signal_type)
 {
 	u32 gpio_shift;
@@ -3525,14 +3516,14 @@
 		(AR_GPIO_OE_OUT_DRV << gpio_shift));
 }
 
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
+void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
 {
 	REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
 		AR_GPIO_BIT(gpio));
 }
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-void ath9k_enable_rfkill(struct ath_hal *ah)
+void ath9k_enable_rfkill(struct ath_hw *ah)
 {
 	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
@@ -3540,29 +3531,28 @@
 	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
 		    AR_GPIO_INPUT_MUX2_RFSILENT);
 
-	ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
+	ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
 	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
 }
 #endif
 
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
+u32 ath9k_hw_getdefantenna(struct ath_hw *ah)
 {
 	return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
 }
 
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
+void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
 {
 	REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
 }
 
-bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
+bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
 			       enum ath9k_ant_setting settings,
 			       struct ath9k_channel *chan,
 			       u8 *tx_chainmask,
 			       u8 *rx_chainmask,
 			       u8 *antenna_cfgd)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	static u8 tx_chainmask_cfg, rx_chainmask_cfg;
 
 	if (AR_SREV_9280(ah)) {
@@ -3579,7 +3569,7 @@
 			*antenna_cfgd = true;
 			break;
 		case ATH9K_ANT_FIXED_B:
-			if (ah->ah_caps.tx_chainmask >
+			if (ah->caps.tx_chainmask >
 			    ATH9K_ANTENNA1_CHAINMASK) {
 				*tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
 			}
@@ -3595,7 +3585,7 @@
 			break;
 		}
 	} else {
-		ahp->ah_diversityControl = settings;
+		ah->diversity_control = settings;
 	}
 
 	return true;
@@ -3605,7 +3595,7 @@
 /* General Operation */
 /*********************/
 
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
+u32 ath9k_hw_getrxfilter(struct ath_hw *ah)
 {
 	u32 bits = REG_READ(ah, AR_RX_FILTER);
 	u32 phybits = REG_READ(ah, AR_PHY_ERR);
@@ -3618,7 +3608,7 @@
 	return bits;
 }
 
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
+void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
 {
 	u32 phybits;
 
@@ -3638,12 +3628,12 @@
 			  REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
 }
 
-bool ath9k_hw_phy_disable(struct ath_hal *ah)
+bool ath9k_hw_phy_disable(struct ath_hw *ah)
 {
 	return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
 }
 
-bool ath9k_hw_disable(struct ath_hal *ah)
+bool ath9k_hw_disable(struct ath_hw *ah)
 {
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
 		return false;
@@ -3651,83 +3641,54 @@
 	return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
 }
 
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
+bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
 {
-	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ath9k_channel *chan = ah->curchan;
 	struct ieee80211_channel *channel = chan->chan;
 
-	ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
+	ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER);
 
-	if (ath9k_hw_set_txpower(ah, chan,
-				 ath9k_regd_get_ctl(ah, chan),
-				 channel->max_antenna_gain * 2,
-				 channel->max_power * 2,
-				 min((u32) MAX_RATE_POWER,
-				     (u32) ah->ah_powerLimit)) != 0)
+	if (ah->eep_ops->set_txpower(ah, chan,
+			     ath9k_regd_get_ctl(ah, chan),
+			     channel->max_antenna_gain * 2,
+			     channel->max_power * 2,
+			     min((u32) MAX_RATE_POWER,
+				 (u32) ah->regulatory.power_limit)) != 0)
 		return false;
 
 	return true;
 }
 
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
+void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
+	memcpy(ah->macaddr, mac, ETH_ALEN);
 }
 
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
+void ath9k_hw_setopmode(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
-
-	return true;
+	ath9k_hw_set_operating_mode(ah, ah->opmode);
 }
 
-void ath9k_hw_setopmode(struct ath_hal *ah)
-{
-	ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
-}
-
-void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1)
+void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1)
 {
 	REG_WRITE(ah, AR_MCAST_FIL0, filter0);
 	REG_WRITE(ah, AR_MCAST_FIL1, filter1);
 }
 
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
+void ath9k_hw_setbssidmask(struct ath_softc *sc)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
+	REG_WRITE(sc->sc_ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask));
+	REG_WRITE(sc->sc_ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4));
 }
 
-bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
+void ath9k_hw_write_associd(struct ath_softc *sc)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
-
-	REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
-	REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
-
-	return true;
+	REG_WRITE(sc->sc_ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid));
+	REG_WRITE(sc->sc_ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) |
+		  ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
 }
 
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
-	ahp->ah_assocId = assocId;
-
-	REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
-	REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
-		  ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
-}
-
-u64 ath9k_hw_gettsf64(struct ath_hal *ah)
+u64 ath9k_hw_gettsf64(struct ath_hw *ah)
 {
 	u64 tsf;
 
@@ -3737,14 +3698,14 @@
 	return tsf;
 }
 
-void ath9k_hw_settsf64(struct ath_hal *ah, u64 tsf64)
+void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
 {
 	REG_WRITE(ah, AR_TSF_L32, 0x00000000);
 	REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
 	REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
 }
 
-void ath9k_hw_reset_tsf(struct ath_hal *ah)
+void ath9k_hw_reset_tsf(struct ath_hw *ah)
 {
 	int count;
 
@@ -3761,39 +3722,35 @@
 	REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
 }
 
-bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
+bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	if (setting)
-		ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+		ah->misc_mode |= AR_PCU_TX_ADD_TSF;
 	else
-		ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+		ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
 
 	return true;
 }
 
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
+bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us);
-		ahp->ah_slottime = (u32) -1;
+		ah->slottime = (u32) -1;
 		return false;
 	} else {
 		REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
-		ahp->ah_slottime = us;
+		ah->slottime = us;
 		return true;
 	}
 }
 
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
+void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode)
 {
 	u32 macmode;
 
 	if (mode == ATH9K_HT_MACMODE_2040 &&
-	    !ah->ah_config.cwm_ignore_extcca)
+	    !ah->config.cwm_ignore_extcca)
 		macmode = AR_2040_JOINED_RX_CLEAR;
 	else
 		macmode = 0;
@@ -3805,7 +3762,7 @@
 /*  Bluetooth Coexistence  */
 /***************************/
 
-void ath9k_hw_btcoex_enable(struct ath_hal *ah)
+void ath9k_hw_btcoex_enable(struct ath_hw *ah)
 {
 	/* connect bt_active to baseband */
 	REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
@@ -3818,12 +3775,12 @@
 	/* Set input mux for bt_active to gpio pin */
 	REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
 			AR_GPIO_INPUT_MUX1_BT_ACTIVE,
-			ah->ah_btactive_gpio);
+			ah->btactive_gpio);
 
 	/* Configure the desired gpio port for input */
-	ath9k_hw_cfg_gpio_input(ah, ah->ah_btactive_gpio);
+	ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio);
 
 	/* Configure the desired GPIO port for TX_FRAME output */
-	ath9k_hw_cfg_output(ah, ah->ah_wlanactive_gpio,
+	ath9k_hw_cfg_output(ah, ah->wlanactive_gpio,
 			    AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
 }
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
index 087c571..8211163 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -19,949 +19,43 @@
 
 #include <linux/if_ether.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
-extern const struct hal_percal_data iq_cal_multi_sample;
-extern const struct hal_percal_data iq_cal_single_sample;
-extern const struct hal_percal_data adc_gain_cal_multi_sample;
-extern const struct hal_percal_data adc_gain_cal_single_sample;
-extern const struct hal_percal_data adc_dc_cal_multi_sample;
-extern const struct hal_percal_data adc_dc_cal_single_sample;
-extern const struct hal_percal_data adc_init_dc_cal;
+#include "mac.h"
+#include "ani.h"
+#include "eeprom.h"
+#include "calib.h"
+#include "regd.h"
+#include "reg.h"
+#include "phy.h"
 
-struct ar5416_desc {
-	u32 ds_link;
-	u32 ds_data;
-	u32 ds_ctl0;
-	u32 ds_ctl1;
-	union {
-		struct {
-			u32 ctl2;
-			u32 ctl3;
-			u32 ctl4;
-			u32 ctl5;
-			u32 ctl6;
-			u32 ctl7;
-			u32 ctl8;
-			u32 ctl9;
-			u32 ctl10;
-			u32 ctl11;
-			u32 status0;
-			u32 status1;
-			u32 status2;
-			u32 status3;
-			u32 status4;
-			u32 status5;
-			u32 status6;
-			u32 status7;
-			u32 status8;
-			u32 status9;
-		} tx;
-		struct {
-			u32 status0;
-			u32 status1;
-			u32 status2;
-			u32 status3;
-			u32 status4;
-			u32 status5;
-			u32 status6;
-			u32 status7;
-			u32 status8;
-		} rx;
-	} u;
-} __packed;
+#define ATHEROS_VENDOR_ID	0x168c
+#define AR5416_DEVID_PCI	0x0023
+#define AR5416_DEVID_PCIE	0x0024
+#define AR9160_DEVID_PCI	0x0027
+#define AR9280_DEVID_PCI	0x0029
+#define AR9280_DEVID_PCIE	0x002a
+#define AR9285_DEVID_PCIE	0x002b
+#define AR5416_AR9100_DEVID	0x000b
+#define	AR_SUBVENDOR_ID_NOG	0x0e11
+#define AR_SUBVENDOR_ID_NEW_A	0x7065
+#define AR5416_MAGIC		0x19641014
 
-#define AR5416DESC(_ds)         ((struct ar5416_desc *)(_ds))
-#define AR5416DESC_CONST(_ds)   ((const struct ar5416_desc *)(_ds))
+/* Register read/write primitives */
+#define REG_WRITE(_ah, _reg, _val) iowrite32(_val, _ah->ah_sc->mem + _reg)
+#define REG_READ(_ah, _reg) ioread32(_ah->ah_sc->mem + _reg)
 
-#define ds_ctl2     u.tx.ctl2
-#define ds_ctl3     u.tx.ctl3
-#define ds_ctl4     u.tx.ctl4
-#define ds_ctl5     u.tx.ctl5
-#define ds_ctl6     u.tx.ctl6
-#define ds_ctl7     u.tx.ctl7
-#define ds_ctl8     u.tx.ctl8
-#define ds_ctl9     u.tx.ctl9
-#define ds_ctl10    u.tx.ctl10
-#define ds_ctl11    u.tx.ctl11
-
-#define ds_txstatus0    u.tx.status0
-#define ds_txstatus1    u.tx.status1
-#define ds_txstatus2    u.tx.status2
-#define ds_txstatus3    u.tx.status3
-#define ds_txstatus4    u.tx.status4
-#define ds_txstatus5    u.tx.status5
-#define ds_txstatus6    u.tx.status6
-#define ds_txstatus7    u.tx.status7
-#define ds_txstatus8    u.tx.status8
-#define ds_txstatus9    u.tx.status9
-
-#define ds_rxstatus0    u.rx.status0
-#define ds_rxstatus1    u.rx.status1
-#define ds_rxstatus2    u.rx.status2
-#define ds_rxstatus3    u.rx.status3
-#define ds_rxstatus4    u.rx.status4
-#define ds_rxstatus5    u.rx.status5
-#define ds_rxstatus6    u.rx.status6
-#define ds_rxstatus7    u.rx.status7
-#define ds_rxstatus8    u.rx.status8
-
-#define AR_FrameLen         0x00000fff
-#define AR_VirtMoreFrag     0x00001000
-#define AR_TxCtlRsvd00      0x0000e000
-#define AR_XmitPower        0x003f0000
-#define AR_XmitPower_S      16
-#define AR_RTSEnable        0x00400000
-#define AR_VEOL             0x00800000
-#define AR_ClrDestMask      0x01000000
-#define AR_TxCtlRsvd01      0x1e000000
-#define AR_TxIntrReq        0x20000000
-#define AR_DestIdxValid     0x40000000
-#define AR_CTSEnable        0x80000000
-
-#define AR_BufLen           0x00000fff
-#define AR_TxMore           0x00001000
-#define AR_DestIdx          0x000fe000
-#define AR_DestIdx_S        13
-#define AR_FrameType        0x00f00000
-#define AR_FrameType_S      20
-#define AR_NoAck            0x01000000
-#define AR_InsertTS         0x02000000
-#define AR_CorruptFCS       0x04000000
-#define AR_ExtOnly          0x08000000
-#define AR_ExtAndCtl        0x10000000
-#define AR_MoreAggr         0x20000000
-#define AR_IsAggr           0x40000000
-
-#define AR_BurstDur         0x00007fff
-#define AR_BurstDur_S       0
-#define AR_DurUpdateEna     0x00008000
-#define AR_XmitDataTries0   0x000f0000
-#define AR_XmitDataTries0_S 16
-#define AR_XmitDataTries1   0x00f00000
-#define AR_XmitDataTries1_S 20
-#define AR_XmitDataTries2   0x0f000000
-#define AR_XmitDataTries2_S 24
-#define AR_XmitDataTries3   0xf0000000
-#define AR_XmitDataTries3_S 28
-
-#define AR_XmitRate0        0x000000ff
-#define AR_XmitRate0_S      0
-#define AR_XmitRate1        0x0000ff00
-#define AR_XmitRate1_S      8
-#define AR_XmitRate2        0x00ff0000
-#define AR_XmitRate2_S      16
-#define AR_XmitRate3        0xff000000
-#define AR_XmitRate3_S      24
-
-#define AR_PacketDur0       0x00007fff
-#define AR_PacketDur0_S     0
-#define AR_RTSCTSQual0      0x00008000
-#define AR_PacketDur1       0x7fff0000
-#define AR_PacketDur1_S     16
-#define AR_RTSCTSQual1      0x80000000
-
-#define AR_PacketDur2       0x00007fff
-#define AR_PacketDur2_S     0
-#define AR_RTSCTSQual2      0x00008000
-#define AR_PacketDur3       0x7fff0000
-#define AR_PacketDur3_S     16
-#define AR_RTSCTSQual3      0x80000000
-
-#define AR_AggrLen          0x0000ffff
-#define AR_AggrLen_S        0
-#define AR_TxCtlRsvd60      0x00030000
-#define AR_PadDelim         0x03fc0000
-#define AR_PadDelim_S       18
-#define AR_EncrType         0x0c000000
-#define AR_EncrType_S       26
-#define AR_TxCtlRsvd61      0xf0000000
-
-#define AR_2040_0           0x00000001
-#define AR_GI0              0x00000002
-#define AR_ChainSel0        0x0000001c
-#define AR_ChainSel0_S      2
-#define AR_2040_1           0x00000020
-#define AR_GI1              0x00000040
-#define AR_ChainSel1        0x00000380
-#define AR_ChainSel1_S      7
-#define AR_2040_2           0x00000400
-#define AR_GI2              0x00000800
-#define AR_ChainSel2        0x00007000
-#define AR_ChainSel2_S      12
-#define AR_2040_3           0x00008000
-#define AR_GI3              0x00010000
-#define AR_ChainSel3        0x000e0000
-#define AR_ChainSel3_S      17
-#define AR_RTSCTSRate       0x0ff00000
-#define AR_RTSCTSRate_S     20
-#define AR_TxCtlRsvd70      0xf0000000
-
-#define AR_TxRSSIAnt00      0x000000ff
-#define AR_TxRSSIAnt00_S    0
-#define AR_TxRSSIAnt01      0x0000ff00
-#define AR_TxRSSIAnt01_S    8
-#define AR_TxRSSIAnt02      0x00ff0000
-#define AR_TxRSSIAnt02_S    16
-#define AR_TxStatusRsvd00   0x3f000000
-#define AR_TxBaStatus       0x40000000
-#define AR_TxStatusRsvd01   0x80000000
-
-#define AR_FrmXmitOK            0x00000001
-#define AR_ExcessiveRetries     0x00000002
-#define AR_FIFOUnderrun         0x00000004
-#define AR_Filtered             0x00000008
-#define AR_RTSFailCnt           0x000000f0
-#define AR_RTSFailCnt_S         4
-#define AR_DataFailCnt          0x00000f00
-#define AR_DataFailCnt_S        8
-#define AR_VirtRetryCnt         0x0000f000
-#define AR_VirtRetryCnt_S       12
-#define AR_TxDelimUnderrun      0x00010000
-#define AR_TxDataUnderrun       0x00020000
-#define AR_DescCfgErr           0x00040000
-#define AR_TxTimerExpired       0x00080000
-#define AR_TxStatusRsvd10       0xfff00000
-
-#define AR_SendTimestamp    ds_txstatus2
-#define AR_BaBitmapLow      ds_txstatus3
-#define AR_BaBitmapHigh     ds_txstatus4
-
-#define AR_TxRSSIAnt10      0x000000ff
-#define AR_TxRSSIAnt10_S    0
-#define AR_TxRSSIAnt11      0x0000ff00
-#define AR_TxRSSIAnt11_S    8
-#define AR_TxRSSIAnt12      0x00ff0000
-#define AR_TxRSSIAnt12_S    16
-#define AR_TxRSSICombined   0xff000000
-#define AR_TxRSSICombined_S 24
-
-#define AR_TxEVM0           ds_txstatus5
-#define AR_TxEVM1           ds_txstatus6
-#define AR_TxEVM2           ds_txstatus7
-
-#define AR_TxDone           0x00000001
-#define AR_SeqNum           0x00001ffe
-#define AR_SeqNum_S         1
-#define AR_TxStatusRsvd80   0x0001e000
-#define AR_TxOpExceeded     0x00020000
-#define AR_TxStatusRsvd81   0x001c0000
-#define AR_FinalTxIdx       0x00600000
-#define AR_FinalTxIdx_S     21
-#define AR_TxStatusRsvd82   0x01800000
-#define AR_PowerMgmt        0x02000000
-#define AR_TxStatusRsvd83   0xfc000000
-
-#define AR_RxCTLRsvd00  0xffffffff
-
-#define AR_BufLen       0x00000fff
-#define AR_RxCtlRsvd00  0x00001000
-#define AR_RxIntrReq    0x00002000
-#define AR_RxCtlRsvd01  0xffffc000
-
-#define AR_RxRSSIAnt00      0x000000ff
-#define AR_RxRSSIAnt00_S    0
-#define AR_RxRSSIAnt01      0x0000ff00
-#define AR_RxRSSIAnt01_S    8
-#define AR_RxRSSIAnt02      0x00ff0000
-#define AR_RxRSSIAnt02_S    16
-#define AR_RxRate           0xff000000
-#define AR_RxRate_S         24
-#define AR_RxStatusRsvd00   0xff000000
-
-#define AR_DataLen          0x00000fff
-#define AR_RxMore           0x00001000
-#define AR_NumDelim         0x003fc000
-#define AR_NumDelim_S       14
-#define AR_RxStatusRsvd10   0xff800000
-
-#define AR_RcvTimestamp     ds_rxstatus2
-
-#define AR_GI               0x00000001
-#define AR_2040             0x00000002
-#define AR_Parallel40       0x00000004
-#define AR_Parallel40_S     2
-#define AR_RxStatusRsvd30   0x000000f8
-#define AR_RxAntenna	    0xffffff00
-#define AR_RxAntenna_S	    8
-
-#define AR_RxRSSIAnt10            0x000000ff
-#define AR_RxRSSIAnt10_S          0
-#define AR_RxRSSIAnt11            0x0000ff00
-#define AR_RxRSSIAnt11_S          8
-#define AR_RxRSSIAnt12            0x00ff0000
-#define AR_RxRSSIAnt12_S          16
-#define AR_RxRSSICombined         0xff000000
-#define AR_RxRSSICombined_S       24
-
-#define AR_RxEVM0           ds_rxstatus4
-#define AR_RxEVM1           ds_rxstatus5
-#define AR_RxEVM2           ds_rxstatus6
-
-#define AR_RxDone           0x00000001
-#define AR_RxFrameOK        0x00000002
-#define AR_CRCErr           0x00000004
-#define AR_DecryptCRCErr    0x00000008
-#define AR_PHYErr           0x00000010
-#define AR_MichaelErr       0x00000020
-#define AR_PreDelimCRCErr   0x00000040
-#define AR_RxStatusRsvd70   0x00000080
-#define AR_RxKeyIdxValid    0x00000100
-#define AR_KeyIdx           0x0000fe00
-#define AR_KeyIdx_S         9
-#define AR_PHYErrCode       0x0000ff00
-#define AR_PHYErrCode_S     8
-#define AR_RxMoreAggr       0x00010000
-#define AR_RxAggr           0x00020000
-#define AR_PostDelimCRCErr  0x00040000
-#define AR_RxStatusRsvd71   0x3ff80000
-#define AR_DecryptBusyErr   0x40000000
-#define AR_KeyMiss          0x80000000
-
-#define AR5416_MAGIC        0x19641014
-
-#define RXSTATUS_RATE(ah, ads)  (AR_SREV_5416_V20_OR_LATER(ah) ?	\
-				 MS(ads->ds_rxstatus0, AR_RxRate) :	\
-				 (ads->ds_rxstatus3 >> 2) & 0xFF)
-
-#define set11nTries(_series, _index) \
-	(SM((_series)[_index].Tries, AR_XmitDataTries##_index))
-
-#define set11nRate(_series, _index) \
-	(SM((_series)[_index].Rate, AR_XmitRate##_index))
-
-#define set11nPktDurRTSCTS(_series, _index)				\
-	(SM((_series)[_index].PktDuration, AR_PacketDur##_index) |	\
-	((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS   ?	\
-		AR_RTSCTSQual##_index : 0))
-
-#define set11nRateFlags(_series, _index)				\
-	(((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ?		\
-	  AR_2040_##_index : 0)						\
-	 |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ?	\
-	   AR_GI##_index : 0)						\
-	 |SM((_series)[_index].ChSel, AR_ChainSel##_index))
-
-#define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100)
-
-#define INIT_CONFIG_STATUS  0x00000000
-#define INIT_RSSI_THR       0x00000700
-#define INIT_BCON_CNTRL_REG 0x00000000
-
-#define MIN_TX_FIFO_THRESHOLD   0x1
-#define MAX_TX_FIFO_THRESHOLD   ((4096 / 64) - 1)
-#define INIT_TX_FIFO_THRESHOLD  MIN_TX_FIFO_THRESHOLD
-
-struct ar5416AniState {
-	struct ath9k_channel c;
-	u8 noiseImmunityLevel;
-	u8 spurImmunityLevel;
-	u8 firstepLevel;
-	u8 ofdmWeakSigDetectOff;
-	u8 cckWeakSigThreshold;
-	u32 listenTime;
-	u32 ofdmTrigHigh;
-	u32 ofdmTrigLow;
-	int32_t cckTrigHigh;
-	int32_t cckTrigLow;
-	int32_t rssiThrLow;
-	int32_t rssiThrHigh;
-	u32 noiseFloor;
-	u32 txFrameCount;
-	u32 rxFrameCount;
-	u32 cycleCount;
-	u32 ofdmPhyErrCount;
-	u32 cckPhyErrCount;
-	u32 ofdmPhyErrBase;
-	u32 cckPhyErrBase;
-	int16_t pktRssi[2];
-	int16_t ofdmErrRssi[2];
-	int16_t cckErrRssi[2];
-};
-
-#define HAL_PROCESS_ANI     0x00000001
-#define DO_ANI(ah) \
-	((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI))
-
-struct ar5416Stats {
-	u32 ast_ani_niup;
-	u32 ast_ani_nidown;
-	u32 ast_ani_spurup;
-	u32 ast_ani_spurdown;
-	u32 ast_ani_ofdmon;
-	u32 ast_ani_ofdmoff;
-	u32 ast_ani_cckhigh;
-	u32 ast_ani_ccklow;
-	u32 ast_ani_stepup;
-	u32 ast_ani_stepdown;
-	u32 ast_ani_ofdmerrs;
-	u32 ast_ani_cckerrs;
-	u32 ast_ani_reset;
-	u32 ast_ani_lzero;
-	u32 ast_ani_lneg;
-	struct ath9k_mib_stats ast_mibstats;
-	struct ath9k_node_stats ast_nodestats;
-};
-
-#define AR5416_OPFLAGS_11A           0x01
-#define AR5416_OPFLAGS_11G           0x02
-#define AR5416_OPFLAGS_N_5G_HT40     0x04
-#define AR5416_OPFLAGS_N_2G_HT40     0x08
-#define AR5416_OPFLAGS_N_5G_HT20     0x10
-#define AR5416_OPFLAGS_N_2G_HT20     0x20
-
-#define EEP_RFSILENT_ENABLED        0x0001
-#define EEP_RFSILENT_ENABLED_S      0
-#define EEP_RFSILENT_POLARITY       0x0002
-#define EEP_RFSILENT_POLARITY_S     1
-#define EEP_RFSILENT_GPIO_SEL       0x001c
-#define EEP_RFSILENT_GPIO_SEL_S     2
-
-#define AR5416_EEP_NO_BACK_VER       0x1
-#define AR5416_EEP_VER               0xE
-#define AR5416_EEP_VER_MINOR_MASK    0x0FFF
-#define AR5416_EEP_MINOR_VER_2       0x2
-#define AR5416_EEP_MINOR_VER_3       0x3
-#define AR5416_EEP_MINOR_VER_7       0x7
-#define AR5416_EEP_MINOR_VER_9       0x9
-#define AR5416_EEP_MINOR_VER_16      0x10
-#define AR5416_EEP_MINOR_VER_17      0x11
-#define AR5416_EEP_MINOR_VER_19      0x13
-#define AR5416_EEP_MINOR_VER_20      0x14
-
-#define AR5416_NUM_5G_CAL_PIERS         8
-#define AR5416_NUM_2G_CAL_PIERS         4
-#define AR5416_NUM_5G_20_TARGET_POWERS  8
-#define AR5416_NUM_5G_40_TARGET_POWERS  8
-#define AR5416_NUM_2G_CCK_TARGET_POWERS 3
-#define AR5416_NUM_2G_20_TARGET_POWERS  4
-#define AR5416_NUM_2G_40_TARGET_POWERS  4
-#define AR5416_NUM_CTLS                 24
-#define AR5416_NUM_BAND_EDGES           8
-#define AR5416_NUM_PD_GAINS             4
-#define AR5416_PD_GAINS_IN_MASK         4
-#define AR5416_PD_GAIN_ICEPTS           5
-#define AR5416_EEPROM_MODAL_SPURS       5
-#define AR5416_MAX_RATE_POWER           63
-#define AR5416_NUM_PDADC_VALUES         128
-#define AR5416_BCHAN_UNUSED             0xFF
-#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
-#define AR5416_MAX_CHAINS               3
-#define AR5416_PWR_TABLE_OFFSET         -5
-
-/* Rx gain type values */
-#define AR5416_EEP_RXGAIN_23DB_BACKOFF     0
-#define AR5416_EEP_RXGAIN_13DB_BACKOFF     1
-#define AR5416_EEP_RXGAIN_ORIG             2
-
-/* Tx gain type values */
-#define AR5416_EEP_TXGAIN_ORIGINAL         0
-#define AR5416_EEP_TXGAIN_HIGH_POWER       1
-
-#define AR5416_EEP4K_START_LOC         64
-#define AR5416_EEP4K_NUM_2G_CAL_PIERS      3
-#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3
-#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS  3
-#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS  3
-#define AR5416_EEP4K_NUM_CTLS              12
-#define AR5416_EEP4K_NUM_BAND_EDGES        4
-#define AR5416_EEP4K_NUM_PD_GAINS          2
-#define AR5416_EEP4K_PD_GAINS_IN_MASK      4
-#define AR5416_EEP4K_PD_GAIN_ICEPTS        5
-#define AR5416_EEP4K_MAX_CHAINS            1
-
-enum eeprom_param {
-	EEP_NFTHRESH_5,
-	EEP_NFTHRESH_2,
-	EEP_MAC_MSW,
-	EEP_MAC_MID,
-	EEP_MAC_LSW,
-	EEP_REG_0,
-	EEP_REG_1,
-	EEP_OP_CAP,
-	EEP_OP_MODE,
-	EEP_RF_SILENT,
-	EEP_OB_5,
-	EEP_DB_5,
-	EEP_OB_2,
-	EEP_DB_2,
-	EEP_MINOR_REV,
-	EEP_TX_MASK,
-	EEP_RX_MASK,
-	EEP_RXGAIN_TYPE,
-	EEP_TXGAIN_TYPE,
-	EEP_DAC_HPWR_5G,
-};
-
-enum ar5416_rates {
-	rate6mb, rate9mb, rate12mb, rate18mb,
-	rate24mb, rate36mb, rate48mb, rate54mb,
-	rate1l, rate2l, rate2s, rate5_5l,
-	rate5_5s, rate11l, rate11s, rateXr,
-	rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3,
-	rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7,
-	rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3,
-	rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7,
-	rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm,
-	Ar5416RateSize
-};
-
-enum ath9k_hal_freq_band {
-	ATH9K_HAL_FREQ_BAND_5GHZ = 0,
-	ATH9K_HAL_FREQ_BAND_2GHZ = 1
-};
-
-struct base_eep_header {
-	u16 length;
-	u16 checksum;
-	u16 version;
-	u8 opCapFlags;
-	u8 eepMisc;
-	u16 regDmn[2];
-	u8 macAddr[6];
-	u8 rxMask;
-	u8 txMask;
-	u16 rfSilent;
-	u16 blueToothOptions;
-	u16 deviceCap;
-	u32 binBuildNumber;
-	u8 deviceType;
-	u8 pwdclkind;
-	u8 futureBase_1[2];
-	u8 rxGainType;
-	u8 dacHiPwrMode_5G;
-	u8 futureBase_2;
-	u8 dacLpMode;
-	u8 txGainType;
-	u8 rcChainMask;
-	u8 desiredScaleCCK;
-	u8 futureBase_3[23];
-} __packed;
-
-struct base_eep_header_4k {
-	u16 length;
-	u16 checksum;
-	u16 version;
-	u8 opCapFlags;
-	u8 eepMisc;
-	u16 regDmn[2];
-	u8 macAddr[6];
-	u8 rxMask;
-	u8 txMask;
-	u16 rfSilent;
-	u16 blueToothOptions;
-	u16 deviceCap;
-	u32 binBuildNumber;
-	u8 deviceType;
-	u8 futureBase[1];
-} __packed;
-
-
-struct spur_chan {
-	u16 spurChan;
-	u8 spurRangeLow;
-	u8 spurRangeHigh;
-} __packed;
-
-struct modal_eep_header {
-	u32 antCtrlChain[AR5416_MAX_CHAINS];
-	u32 antCtrlCommon;
-	u8 antennaGainCh[AR5416_MAX_CHAINS];
-	u8 switchSettling;
-	u8 txRxAttenCh[AR5416_MAX_CHAINS];
-	u8 rxTxMarginCh[AR5416_MAX_CHAINS];
-	u8 adcDesiredSize;
-	u8 pgaDesiredSize;
-	u8 xlnaGainCh[AR5416_MAX_CHAINS];
-	u8 txEndToXpaOff;
-	u8 txEndToRxOn;
-	u8 txFrameToXpaOn;
-	u8 thresh62;
-	u8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
-	u8 xpdGain;
-	u8 xpd;
-	u8 iqCalICh[AR5416_MAX_CHAINS];
-	u8 iqCalQCh[AR5416_MAX_CHAINS];
-	u8 pdGainOverlap;
-	u8 ob;
-	u8 db;
-	u8 xpaBiasLvl;
-	u8 pwrDecreaseFor2Chain;
-	u8 pwrDecreaseFor3Chain;
-	u8 txFrameToDataStart;
-	u8 txFrameToPaOn;
-	u8 ht40PowerIncForPdadc;
-	u8 bswAtten[AR5416_MAX_CHAINS];
-	u8 bswMargin[AR5416_MAX_CHAINS];
-	u8 swSettleHt40;
-	u8 xatten2Db[AR5416_MAX_CHAINS];
-	u8 xatten2Margin[AR5416_MAX_CHAINS];
-	u8 ob_ch1;
-	u8 db_ch1;
-	u8 useAnt1:1,
-	    force_xpaon:1,
-	    local_bias:1,
-	    femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1;
-	u8 miscBits;
-	u16 xpaBiasLvlFreq[3];
-	u8 futureModal[6];
-
-	struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
-} __packed;
-
-struct modal_eep_4k_header {
-    u32  antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
-    u32  antCtrlCommon;
-    u8   antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
-    u8   switchSettling;
-    u8   txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
-    u8   rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
-    u8   adcDesiredSize;
-    u8   pgaDesiredSize;
-    u8   xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
-    u8   txEndToXpaOff;
-    u8   txEndToRxOn;
-    u8   txFrameToXpaOn;
-    u8   thresh62;
-    u8   noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
-    u8   xpdGain;
-    u8   xpd;
-    u8   iqCalICh[AR5416_EEP4K_MAX_CHAINS];
-    u8   iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
-    u8   pdGainOverlap;
-    u8   ob_01;
-    u8   db1_01;
-    u8   xpaBiasLvl;
-    u8   txFrameToDataStart;
-    u8   txFrameToPaOn;
-    u8   ht40PowerIncForPdadc;
-    u8   bswAtten[AR5416_EEP4K_MAX_CHAINS];
-    u8   bswMargin[AR5416_EEP4K_MAX_CHAINS];
-    u8   swSettleHt40;
-    u8   xatten2Db[AR5416_EEP4K_MAX_CHAINS];
-    u8   xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
-    u8   db2_01;
-    u8   version;
-    u16  ob_234;
-    u16  db1_234;
-    u16  db2_234;
-    u8   futureModal[4];
-
-    struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
-} __packed;
-
-
-struct cal_data_per_freq {
-	u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
-	u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
-} __packed;
-
-struct cal_data_per_freq_4k {
-	u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
-	u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
-} __packed;
-
-struct cal_target_power_leg {
-	u8 bChannel;
-	u8 tPow2x[4];
-} __packed;
-
-struct cal_target_power_ht {
-	u8 bChannel;
-	u8 tPow2x[8];
-} __packed;
-
-
-#ifdef __BIG_ENDIAN_BITFIELD
-struct cal_ctl_edges {
-	u8 bChannel;
-	u8 flag:2, tPower:6;
-} __packed;
-#else
-struct cal_ctl_edges {
-	u8 bChannel;
-	u8 tPower:6, flag:2;
-} __packed;
-#endif
-
-struct cal_ctl_data {
-	struct cal_ctl_edges
-	ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
-} __packed;
-
-struct cal_ctl_data_4k {
-	struct cal_ctl_edges
-	ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES];
-} __packed;
-
-struct ar5416_eeprom_def {
-	struct base_eep_header baseEepHeader;
-	u8 custData[64];
-	struct modal_eep_header modalHeader[2];
-	u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS];
-	u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS];
-	struct cal_data_per_freq
-	 calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS];
-	struct cal_data_per_freq
-	 calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
-	struct cal_target_power_leg
-	 calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS];
-	struct cal_target_power_ht
-	 calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS];
-	struct cal_target_power_ht
-	 calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS];
-	struct cal_target_power_leg
-	 calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS];
-	struct cal_target_power_leg
-	 calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS];
-	struct cal_target_power_ht
-	 calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS];
-	struct cal_target_power_ht
-	 calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS];
-	u8 ctlIndex[AR5416_NUM_CTLS];
-	struct cal_ctl_data ctlData[AR5416_NUM_CTLS];
-	u8 padding;
-} __packed;
-
-struct ar5416_eeprom_4k {
-	struct base_eep_header_4k baseEepHeader;
-	u8 custData[20];
-	struct modal_eep_4k_header modalHeader;
-	u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS];
-	struct cal_data_per_freq_4k
-	calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS];
-	struct cal_target_power_leg
-	calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS];
-	struct cal_target_power_leg
-	calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
-	struct cal_target_power_ht
-	calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
-	struct cal_target_power_ht
-	calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS];
-	u8 ctlIndex[AR5416_EEP4K_NUM_CTLS];
-	struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS];
-	u8 padding;
-} __packed;
-
-struct ar5416IniArray {
-	u32 *ia_array;
-	u32 ia_rows;
-	u32 ia_columns;
-};
-
-#define INIT_INI_ARRAY(iniarray, array, rows, columns) do {	\
-		(iniarray)->ia_array = (u32 *)(array);		\
-		(iniarray)->ia_rows = (rows);			\
-		(iniarray)->ia_columns = (columns);		\
-	} while (0)
-
-#define INI_RA(iniarray, row, column) \
-	(((iniarray)->ia_array)[(row) *	((iniarray)->ia_columns) + (column)])
-
-#define INIT_CAL(_perCal) do {				\
-		(_perCal)->calState = CAL_WAITING;	\
-		(_perCal)->calNext = NULL;		\
-	} while (0)
-
-#define INSERT_CAL(_ahp, _perCal)					\
-	do {								\
-		if ((_ahp)->ah_cal_list_last == NULL) {			\
-			(_ahp)->ah_cal_list =				\
-				(_ahp)->ah_cal_list_last = (_perCal);	\
-			((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
-		} else {						\
-			((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
-			(_ahp)->ah_cal_list_last = (_perCal);		\
-			(_perCal)->calNext = (_ahp)->ah_cal_list;	\
-		}							\
-	} while (0)
-
-enum hal_cal_types {
-	ADC_DC_INIT_CAL = 0x1,
-	ADC_GAIN_CAL = 0x2,
-	ADC_DC_CAL = 0x4,
-	IQ_MISMATCH_CAL = 0x8
-};
-
-enum hal_cal_state {
-	CAL_INACTIVE,
-	CAL_WAITING,
-	CAL_RUNNING,
-	CAL_DONE
-};
-
-#define MIN_CAL_SAMPLES     1
-#define MAX_CAL_SAMPLES    64
-#define INIT_LOG_COUNT      5
-#define PER_MIN_LOG_COUNT   2
-#define PER_MAX_LOG_COUNT  10
-
-struct hal_percal_data {
-	enum hal_cal_types calType;
-	u32 calNumSamples;
-	u32 calCountMax;
-	void (*calCollect) (struct ath_hal *);
-	void (*calPostProc) (struct ath_hal *, u8);
-};
-
-struct hal_cal_list {
-	const struct hal_percal_data *calData;
-	enum hal_cal_state calState;
-	struct hal_cal_list *calNext;
-};
-
-/*
- * Enum to indentify the eeprom mappings
- */
-enum hal_eep_map {
-	EEP_MAP_DEFAULT = 0x0,
-	EEP_MAP_4KBITS,
-	EEP_MAP_MAX
-};
-
-
-struct ath_hal_5416 {
-	struct ath_hal ah;
-	union {
-		struct ar5416_eeprom_def def;
-		struct ar5416_eeprom_4k map4k;
-	} ah_eeprom;
-	struct ar5416Stats ah_stats;
-	struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
-	void __iomem *ah_cal_mem;
-
-	u8 ah_macaddr[ETH_ALEN];
-	u8 ah_bssid[ETH_ALEN];
-	u8 ah_bssidmask[ETH_ALEN];
-	u16 ah_assocId;
-
-	int16_t ah_curchanRadIndex;
-	u32 ah_maskReg;
-	u32 ah_txOkInterruptMask;
-	u32 ah_txErrInterruptMask;
-	u32 ah_txDescInterruptMask;
-	u32 ah_txEolInterruptMask;
-	u32 ah_txUrnInterruptMask;
-	bool ah_chipFullSleep;
-	u32 ah_atimWindow;
-	u16 ah_antennaSwitchSwap;
-	enum ath9k_ant_setting ah_diversityControl;
-
-	/* Calibration */
-	enum hal_cal_types ah_suppCals;
-	struct hal_cal_list ah_iqCalData;
-	struct hal_cal_list ah_adcGainCalData;
-	struct hal_cal_list ah_adcDcCalInitData;
-	struct hal_cal_list ah_adcDcCalData;
-	struct hal_cal_list *ah_cal_list;
-	struct hal_cal_list *ah_cal_list_last;
-	struct hal_cal_list *ah_cal_list_curr;
-#define ah_totalPowerMeasI ah_Meas0.unsign
-#define ah_totalPowerMeasQ ah_Meas1.unsign
-#define ah_totalIqCorrMeas ah_Meas2.sign
-#define ah_totalAdcIOddPhase  ah_Meas0.unsign
-#define ah_totalAdcIEvenPhase ah_Meas1.unsign
-#define ah_totalAdcQOddPhase  ah_Meas2.unsign
-#define ah_totalAdcQEvenPhase ah_Meas3.unsign
-#define ah_totalAdcDcOffsetIOddPhase  ah_Meas0.sign
-#define ah_totalAdcDcOffsetIEvenPhase ah_Meas1.sign
-#define ah_totalAdcDcOffsetQOddPhase  ah_Meas2.sign
-#define ah_totalAdcDcOffsetQEvenPhase ah_Meas3.sign
-	union {
-		u32 unsign[AR5416_MAX_CHAINS];
-		int32_t sign[AR5416_MAX_CHAINS];
-	} ah_Meas0;
-	union {
-		u32 unsign[AR5416_MAX_CHAINS];
-		int32_t sign[AR5416_MAX_CHAINS];
-	} ah_Meas1;
-	union {
-		u32 unsign[AR5416_MAX_CHAINS];
-		int32_t sign[AR5416_MAX_CHAINS];
-	} ah_Meas2;
-	union {
-		u32 unsign[AR5416_MAX_CHAINS];
-		int32_t sign[AR5416_MAX_CHAINS];
-	} ah_Meas3;
-	u16 ah_CalSamples;
-
-	u32 ah_staId1Defaults;
-	u32 ah_miscMode;
-	enum {
-		AUTO_32KHZ,
-		USE_32KHZ,
-		DONT_USE_32KHZ,
-	} ah_enable32kHzClock;
-
-	/* RF */
-	u32 *ah_analogBank0Data;
-	u32 *ah_analogBank1Data;
-	u32 *ah_analogBank2Data;
-	u32 *ah_analogBank3Data;
-	u32 *ah_analogBank6Data;
-	u32 *ah_analogBank6TPCData;
-	u32 *ah_analogBank7Data;
-	u32 *ah_addac5416_21;
-	u32 *ah_bank6Temp;
-
-	int16_t ah_txPowerIndexOffset;
-	u32 ah_beaconInterval;
-	u32 ah_slottime;
-	u32 ah_acktimeout;
-	u32 ah_ctstimeout;
-	u32 ah_globaltxtimeout;
-	u8 ah_gBeaconRate;
-	u32 ah_gpioSelect;
-	u32 ah_polarity;
-	u32 ah_gpioBit;
-
-	/* ANI */
-	u32 ah_procPhyErr;
-	bool ah_hasHwPhyCounters;
-	u32 ah_aniPeriod;
-	struct ar5416AniState *ah_curani;
-	struct ar5416AniState ah_ani[255];
-	int ah_totalSizeDesired[5];
-	int ah_coarseHigh[5];
-	int ah_coarseLow[5];
-	int ah_firpwr[5];
-	enum ath9k_ani_cmd ah_ani_function;
-
-	u32 ah_intrTxqs;
-	bool ah_intrMitigation;
-	enum ath9k_ht_extprotspacing ah_extprotspacing;
-	u8 ah_txchainmask;
-	u8 ah_rxchainmask;
-
-	struct ar5416IniArray ah_iniModes;
-	struct ar5416IniArray ah_iniCommon;
-	struct ar5416IniArray ah_iniBank0;
-	struct ar5416IniArray ah_iniBB_RfGain;
-	struct ar5416IniArray ah_iniBank1;
-	struct ar5416IniArray ah_iniBank2;
-	struct ar5416IniArray ah_iniBank3;
-	struct ar5416IniArray ah_iniBank6;
-	struct ar5416IniArray ah_iniBank6TPC;
-	struct ar5416IniArray ah_iniBank7;
-	struct ar5416IniArray ah_iniAddac;
-	struct ar5416IniArray ah_iniPcieSerdes;
-	struct ar5416IniArray ah_iniModesAdditional;
-	struct ar5416IniArray ah_iniModesRxGain;
-	struct ar5416IniArray ah_iniModesTxGain;
-	/* To indicate EEPROM mapping used */
-	enum hal_eep_map ah_eep_map;
-};
-#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
-
-#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
-
-#define ar5416RfDetach(ah) do {					\
-		if (AH5416(ah)->ah_rfHal.rfDetach != NULL)	\
-			AH5416(ah)->ah_rfHal.rfDetach(ah);	\
-	} while (0)
-
-#define ath9k_hw_use_flash(_ah)			\
-	(!(_ah->ah_flags & AH_USE_EEPROM))
-
+#define SM(_v, _f)  (((_v) << _f##_S) & _f)
+#define MS(_v, _f)  (((_v) & _f) >> _f##_S)
+#define REG_RMW(_a, _r, _set, _clr)    \
+	REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set))
+#define REG_RMW_FIELD(_a, _r, _f, _v) \
+	REG_WRITE(_a, _r, \
+	(REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f))
+#define REG_SET_BIT(_a, _r, _f) \
+	REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
+#define REG_CLR_BIT(_a, _r, _f) \
+	REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
 
 #define DO_DELAY(x) do {			\
 		if ((++(x) % 64) == 0)          \
@@ -977,117 +71,575 @@
 		}							\
 	} while (0)
 
+#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT             0
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED     2
+#define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME           3
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
+
+#define AR_GPIOD_MASK               0x00001FFF
+#define AR_GPIO_BIT(_gpio)          (1 << (_gpio))
+
 #define BASE_ACTIVATE_DELAY         100
 #define RTC_PLL_SETTLE_DELAY        1000
 #define COEF_SCALE_S                24
 #define HT40_CHANNEL_CENTER_SHIFT   10
 
-#define AR5416_EEPROM_MAGIC_OFFSET  0x0
+#define ATH9K_ANTENNA0_CHAINMASK    0x1
+#define ATH9K_ANTENNA1_CHAINMASK    0x2
 
-#define AR5416_EEPROM_S             2
-#define AR5416_EEPROM_OFFSET        0x2000
-#define AR5416_EEPROM_START_ADDR \
-	(AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
-#define AR5416_EEPROM_MAX           0xae0
-#define ar5416_get_eep_ver(_ahp) \
-	(((_ahp)->ah_eeprom.def.baseEepHeader.version >> 12) & 0xF)
-#define ar5416_get_eep_rev(_ahp) \
-	(((_ahp)->ah_eeprom.def.baseEepHeader.version) & 0xFFF)
-#define ar5416_get_ntxchains(_txchainmask) \
-	(((_txchainmask >> 2) & 1) + \
-		((_txchainmask >> 1) & 1) + (_txchainmask & 1))
+#define ATH9K_NUM_DMA_DEBUG_REGS    8
+#define ATH9K_NUM_QUEUES            10
 
-/* EEPROM 4K bit map definations */
-#define ar5416_get_eep4k_ver(_ahp)   \
-    (((_ahp)->ah_eeprom.map4k.baseEepHeader.version >> 12) & 0xF)
-#define ar5416_get_eep4k_rev(_ahp)   \
-    (((_ahp)->ah_eeprom.map4k.baseEepHeader.version) & 0xFFF)
+#define MAX_RATE_POWER              63
+#define AH_TIMEOUT                  100000
+#define AH_TIME_QUANTUM             10
+#define AR_KEYTABLE_SIZE            128
+#define POWER_UP_TIME               200000
+#define SPUR_RSSI_THRESH            40
 
+#define CAB_TIMEOUT_VAL             10
+#define BEACON_TIMEOUT_VAL          10
+#define MIN_BEACON_TIMEOUT_VAL      1
+#define SLEEP_SLOP                  3
 
-#ifdef __BIG_ENDIAN
-#define AR5416_EEPROM_MAGIC 0x5aa5
-#else
-#define AR5416_EEPROM_MAGIC 0xa55a
+#define INIT_CONFIG_STATUS          0x00000000
+#define INIT_RSSI_THR               0x00000700
+#define INIT_BCON_CNTRL_REG         0x00000000
+
+#define TU_TO_USEC(_tu)             ((_tu) << 10)
+
+enum wireless_mode {
+	ATH9K_MODE_11A = 0,
+	ATH9K_MODE_11B = 2,
+	ATH9K_MODE_11G = 3,
+	ATH9K_MODE_11NA_HT20 = 6,
+	ATH9K_MODE_11NG_HT20 = 7,
+	ATH9K_MODE_11NA_HT40PLUS = 8,
+	ATH9K_MODE_11NA_HT40MINUS = 9,
+	ATH9K_MODE_11NG_HT40PLUS = 10,
+	ATH9K_MODE_11NG_HT40MINUS = 11,
+	ATH9K_MODE_MAX
+};
+
+enum ath9k_hw_caps {
+	ATH9K_HW_CAP_CHAN_SPREAD		= BIT(0),
+	ATH9K_HW_CAP_MIC_AESCCM                 = BIT(1),
+	ATH9K_HW_CAP_MIC_CKIP                   = BIT(2),
+	ATH9K_HW_CAP_MIC_TKIP                   = BIT(3),
+	ATH9K_HW_CAP_CIPHER_AESCCM              = BIT(4),
+	ATH9K_HW_CAP_CIPHER_CKIP                = BIT(5),
+	ATH9K_HW_CAP_CIPHER_TKIP                = BIT(6),
+	ATH9K_HW_CAP_VEOL                       = BIT(7),
+	ATH9K_HW_CAP_BSSIDMASK                  = BIT(8),
+	ATH9K_HW_CAP_MCAST_KEYSEARCH            = BIT(9),
+	ATH9K_HW_CAP_CHAN_HALFRATE              = BIT(10),
+	ATH9K_HW_CAP_CHAN_QUARTERRATE           = BIT(11),
+	ATH9K_HW_CAP_HT                         = BIT(12),
+	ATH9K_HW_CAP_GTT                        = BIT(13),
+	ATH9K_HW_CAP_FASTCC                     = BIT(14),
+	ATH9K_HW_CAP_RFSILENT                   = BIT(15),
+	ATH9K_HW_CAP_WOW                        = BIT(16),
+	ATH9K_HW_CAP_CST                        = BIT(17),
+	ATH9K_HW_CAP_ENHANCEDPM                 = BIT(18),
+	ATH9K_HW_CAP_AUTOSLEEP                  = BIT(19),
+	ATH9K_HW_CAP_4KB_SPLITTRANS             = BIT(20),
+	ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT     = BIT(21),
+	ATH9K_HW_CAP_BT_COEX			= BIT(22)
+};
+
+enum ath9k_capability_type {
+	ATH9K_CAP_CIPHER = 0,
+	ATH9K_CAP_TKIP_MIC,
+	ATH9K_CAP_TKIP_SPLIT,
+	ATH9K_CAP_PHYCOUNTERS,
+	ATH9K_CAP_DIVERSITY,
+	ATH9K_CAP_TXPOW,
+	ATH9K_CAP_PHYDIAG,
+	ATH9K_CAP_MCAST_KEYSRCH,
+	ATH9K_CAP_TSF_ADJUST,
+	ATH9K_CAP_WME_TKIPMIC,
+	ATH9K_CAP_RFSILENT,
+	ATH9K_CAP_ANT_CFG_2GHZ,
+	ATH9K_CAP_ANT_CFG_5GHZ
+};
+
+struct ath9k_hw_capabilities {
+	u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
+	DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */
+	u16 total_queues;
+	u16 keycache_size;
+	u16 low_5ghz_chan, high_5ghz_chan;
+	u16 low_2ghz_chan, high_2ghz_chan;
+	u16 num_mr_retries;
+	u16 rts_aggr_limit;
+	u8 tx_chainmask;
+	u8 rx_chainmask;
+	u16 tx_triglevel_max;
+	u16 reg_cap;
+	u8 num_gpio_pins;
+	u8 num_antcfg_2ghz;
+	u8 num_antcfg_5ghz;
+};
+
+struct ath9k_ops_config {
+	int dma_beacon_response_time;
+	int sw_beacon_response_time;
+	int additional_swba_backoff;
+	int ack_6mb;
+	int cwm_ignore_extcca;
+	u8 pcie_powersave_enable;
+	u8 pcie_l1skp_enable;
+	u8 pcie_clock_req;
+	u32 pcie_waen;
+	int pcie_power_reset;
+	u8 pcie_restore;
+	u8 analog_shiftreg;
+	u8 ht_enable;
+	u32 ofdm_trig_low;
+	u32 ofdm_trig_high;
+	u32 cck_trig_high;
+	u32 cck_trig_low;
+	u32 enable_ani;
+	u8 noise_immunity_level;
+	u32 ofdm_weaksignal_det;
+	u32 cck_weaksignal_thr;
+	u8 spur_immunity_level;
+	u8 firstep_level;
+	int8_t rssi_thr_high;
+	int8_t rssi_thr_low;
+	u16 diversity_control;
+	u16 antenna_switch_swap;
+	int serialize_regmode;
+	int intr_mitigation;
+#define SPUR_DISABLE        	0
+#define SPUR_ENABLE_IOCTL   	1
+#define SPUR_ENABLE_EEPROM  	2
+#define AR_EEPROM_MODAL_SPURS   5
+#define AR_SPUR_5413_1      	1640
+#define AR_SPUR_5413_2      	1200
+#define AR_NO_SPUR      	0x8000
+#define AR_BASE_FREQ_2GHZ   	2300
+#define AR_BASE_FREQ_5GHZ   	4900
+#define AR_SPUR_FEEQ_BOUND_HT40 19
+#define AR_SPUR_FEEQ_BOUND_HT20 10
+	int spurmode;
+	u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
+};
+
+enum ath9k_int {
+	ATH9K_INT_RX = 0x00000001,
+	ATH9K_INT_RXDESC = 0x00000002,
+	ATH9K_INT_RXNOFRM = 0x00000008,
+	ATH9K_INT_RXEOL = 0x00000010,
+	ATH9K_INT_RXORN = 0x00000020,
+	ATH9K_INT_TX = 0x00000040,
+	ATH9K_INT_TXDESC = 0x00000080,
+	ATH9K_INT_TIM_TIMER = 0x00000100,
+	ATH9K_INT_TXURN = 0x00000800,
+	ATH9K_INT_MIB = 0x00001000,
+	ATH9K_INT_RXPHY = 0x00004000,
+	ATH9K_INT_RXKCM = 0x00008000,
+	ATH9K_INT_SWBA = 0x00010000,
+	ATH9K_INT_BMISS = 0x00040000,
+	ATH9K_INT_BNR = 0x00100000,
+	ATH9K_INT_TIM = 0x00200000,
+	ATH9K_INT_DTIM = 0x00400000,
+	ATH9K_INT_DTIMSYNC = 0x00800000,
+	ATH9K_INT_GPIO = 0x01000000,
+	ATH9K_INT_CABEND = 0x02000000,
+	ATH9K_INT_CST = 0x10000000,
+	ATH9K_INT_GTT = 0x20000000,
+	ATH9K_INT_FATAL = 0x40000000,
+	ATH9K_INT_GLOBAL = 0x80000000,
+	ATH9K_INT_BMISC = ATH9K_INT_TIM |
+		ATH9K_INT_DTIM |
+		ATH9K_INT_DTIMSYNC |
+		ATH9K_INT_CABEND,
+	ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM |
+		ATH9K_INT_RXDESC |
+		ATH9K_INT_RXEOL |
+		ATH9K_INT_RXORN |
+		ATH9K_INT_TXURN |
+		ATH9K_INT_TXDESC |
+		ATH9K_INT_MIB |
+		ATH9K_INT_RXPHY |
+		ATH9K_INT_RXKCM |
+		ATH9K_INT_SWBA |
+		ATH9K_INT_BMISS |
+		ATH9K_INT_GPIO,
+	ATH9K_INT_NOCARD = 0xffffffff
+};
+
+#define CHANNEL_CW_INT    0x00002
+#define CHANNEL_CCK       0x00020
+#define CHANNEL_OFDM      0x00040
+#define CHANNEL_2GHZ      0x00080
+#define CHANNEL_5GHZ      0x00100
+#define CHANNEL_PASSIVE   0x00200
+#define CHANNEL_DYN       0x00400
+#define CHANNEL_HALF      0x04000
+#define CHANNEL_QUARTER   0x08000
+#define CHANNEL_HT20      0x10000
+#define CHANNEL_HT40PLUS  0x20000
+#define CHANNEL_HT40MINUS 0x40000
+
+#define CHANNEL_INTERFERENCE    0x01
+#define CHANNEL_DFS             0x02
+#define CHANNEL_4MS_LIMIT       0x04
+#define CHANNEL_DFS_CLEAR       0x08
+#define CHANNEL_DISALLOW_ADHOC  0x10
+#define CHANNEL_PER_11D_ADHOC   0x20
+
+#define CHANNEL_A           (CHANNEL_5GHZ|CHANNEL_OFDM)
+#define CHANNEL_B           (CHANNEL_2GHZ|CHANNEL_CCK)
+#define CHANNEL_G           (CHANNEL_2GHZ|CHANNEL_OFDM)
+#define CHANNEL_G_HT20      (CHANNEL_2GHZ|CHANNEL_HT20)
+#define CHANNEL_A_HT20      (CHANNEL_5GHZ|CHANNEL_HT20)
+#define CHANNEL_G_HT40PLUS  (CHANNEL_2GHZ|CHANNEL_HT40PLUS)
+#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS)
+#define CHANNEL_A_HT40PLUS  (CHANNEL_5GHZ|CHANNEL_HT40PLUS)
+#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS)
+#define CHANNEL_ALL				\
+	(CHANNEL_OFDM|				\
+	 CHANNEL_CCK|				\
+	 CHANNEL_2GHZ |				\
+	 CHANNEL_5GHZ |				\
+	 CHANNEL_HT20 |				\
+	 CHANNEL_HT40PLUS |			\
+	 CHANNEL_HT40MINUS)
+
+struct ath9k_channel {
+	struct ieee80211_channel *chan;
+	u16 channel;
+	u32 channelFlags;
+	u32 chanmode;
+	int32_t CalValid;
+	bool oneTimeCalsDone;
+	int8_t iCoff;
+	int8_t qCoff;
+	int16_t rawNoiseFloor;
+};
+
+#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \
+       (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
+       (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
+       (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
+#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
+       (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
+       (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
+       (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
+#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
+#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
+#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
+#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0)
+#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
+#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
+#define IS_CHAN_A_5MHZ_SPACED(_c)			\
+	((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&	\
+	 (((_c)->channel % 20) != 0) &&			\
+	 (((_c)->channel % 10) != 0))
+
+/* These macros check chanmode and not channelFlags */
+#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
+#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||	\
+			  ((_c)->chanmode == CHANNEL_G_HT20))
+#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||	\
+			  ((_c)->chanmode == CHANNEL_A_HT40MINUS) ||	\
+			  ((_c)->chanmode == CHANNEL_G_HT40PLUS) ||	\
+			  ((_c)->chanmode == CHANNEL_G_HT40MINUS))
+#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c)))
+
+enum ath9k_power_mode {
+	ATH9K_PM_AWAKE = 0,
+	ATH9K_PM_FULL_SLEEP,
+	ATH9K_PM_NETWORK_SLEEP,
+	ATH9K_PM_UNDEFINED
+};
+
+enum ath9k_ant_setting {
+	ATH9K_ANT_VARIABLE = 0,
+	ATH9K_ANT_FIXED_A,
+	ATH9K_ANT_FIXED_B
+};
+
+enum ath9k_tp_scale {
+	ATH9K_TP_SCALE_MAX = 0,
+	ATH9K_TP_SCALE_50,
+	ATH9K_TP_SCALE_25,
+	ATH9K_TP_SCALE_12,
+	ATH9K_TP_SCALE_MIN
+};
+
+enum ser_reg_mode {
+	SER_REG_MODE_OFF = 0,
+	SER_REG_MODE_ON = 1,
+	SER_REG_MODE_AUTO = 2,
+};
+
+struct ath9k_beacon_state {
+	u32 bs_nexttbtt;
+	u32 bs_nextdtim;
+	u32 bs_intval;
+#define ATH9K_BEACON_PERIOD       0x0000ffff
+#define ATH9K_BEACON_ENA          0x00800000
+#define ATH9K_BEACON_RESET_TSF    0x01000000
+	u32 bs_dtimperiod;
+	u16 bs_cfpperiod;
+	u16 bs_cfpmaxduration;
+	u32 bs_cfpnext;
+	u16 bs_timoffset;
+	u16 bs_bmissthreshold;
+	u32 bs_sleepduration;
+};
+
+struct chan_centers {
+	u16 synth_center;
+	u16 ctl_center;
+	u16 ext_center;
+};
+
+enum {
+	ATH9K_RESET_POWER_ON,
+	ATH9K_RESET_WARM,
+	ATH9K_RESET_COLD,
+};
+
+struct ath9k_hw_version {
+	u32 magic;
+	u16 devid;
+	u16 subvendorid;
+	u32 macVersion;
+	u16 macRev;
+	u16 phyRev;
+	u16 analog5GhzRev;
+	u16 analog2GhzRev;
+};
+
+struct ath_hw {
+	struct ath_softc *ah_sc;
+	struct ath9k_hw_version hw_version;
+	struct ath9k_ops_config config;
+	struct ath9k_hw_capabilities caps;
+	struct ath9k_regulatory regulatory;
+	struct ath9k_channel channels[38];
+	struct ath9k_channel *curchan;
+
+	union {
+		struct ar5416_eeprom_def def;
+		struct ar5416_eeprom_4k map4k;
+	} eeprom;
+	const struct eeprom_ops *eep_ops;
+	enum ath9k_eep_map eep_map;
+
+	bool sw_mgmt_crypto;
+	bool is_pciexpress;
+	u8 macaddr[ETH_ALEN];
+	u16 tx_trig_level;
+	u16 rfsilent;
+	u32 rfkill_gpio;
+	u32 rfkill_polarity;
+	u32 btactive_gpio;
+	u32 wlanactive_gpio;
+	u32 ah_flags;
+
+	enum nl80211_iftype opmode;
+	enum ath9k_power_mode power_mode;
+	enum ath9k_power_mode restore_mode;
+
+	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+	struct ar5416Stats stats;
+	struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
+
+	int16_t curchan_rad_index;
+	u32 mask_reg;
+	u32 txok_interrupt_mask;
+	u32 txerr_interrupt_mask;
+	u32 txdesc_interrupt_mask;
+	u32 txeol_interrupt_mask;
+	u32 txurn_interrupt_mask;
+	bool chip_fullsleep;
+	u32 atim_window;
+	u16 antenna_switch_swap;
+	enum ath9k_ant_setting diversity_control;
+
+	/* Calibration */
+	enum hal_cal_types supp_cals;
+	struct hal_cal_list iq_caldata;
+	struct hal_cal_list adcgain_caldata;
+	struct hal_cal_list adcdc_calinitdata;
+	struct hal_cal_list adcdc_caldata;
+	struct hal_cal_list *cal_list;
+	struct hal_cal_list *cal_list_last;
+	struct hal_cal_list *cal_list_curr;
+#define totalPowerMeasI meas0.unsign
+#define totalPowerMeasQ meas1.unsign
+#define totalIqCorrMeas meas2.sign
+#define totalAdcIOddPhase  meas0.unsign
+#define totalAdcIEvenPhase meas1.unsign
+#define totalAdcQOddPhase  meas2.unsign
+#define totalAdcQEvenPhase meas3.unsign
+#define totalAdcDcOffsetIOddPhase  meas0.sign
+#define totalAdcDcOffsetIEvenPhase meas1.sign
+#define totalAdcDcOffsetQOddPhase  meas2.sign
+#define totalAdcDcOffsetQEvenPhase meas3.sign
+	union {
+		u32 unsign[AR5416_MAX_CHAINS];
+		int32_t sign[AR5416_MAX_CHAINS];
+	} meas0;
+	union {
+		u32 unsign[AR5416_MAX_CHAINS];
+		int32_t sign[AR5416_MAX_CHAINS];
+	} meas1;
+	union {
+		u32 unsign[AR5416_MAX_CHAINS];
+		int32_t sign[AR5416_MAX_CHAINS];
+	} meas2;
+	union {
+		u32 unsign[AR5416_MAX_CHAINS];
+		int32_t sign[AR5416_MAX_CHAINS];
+	} meas3;
+	u16 cal_samples;
+
+	u32 sta_id1_defaults;
+	u32 misc_mode;
+	enum {
+		AUTO_32KHZ,
+		USE_32KHZ,
+		DONT_USE_32KHZ,
+	} enable_32kHz_clock;
+
+	/* RF */
+	u32 *analogBank0Data;
+	u32 *analogBank1Data;
+	u32 *analogBank2Data;
+	u32 *analogBank3Data;
+	u32 *analogBank6Data;
+	u32 *analogBank6TPCData;
+	u32 *analogBank7Data;
+	u32 *addac5416_21;
+	u32 *bank6Temp;
+
+	int16_t txpower_indexoffset;
+	u32 beacon_interval;
+	u32 slottime;
+	u32 acktimeout;
+	u32 ctstimeout;
+	u32 globaltxtimeout;
+	u8 gbeacon_rate;
+
+	/* ANI */
+	u32 proc_phyerr;
+	bool has_hw_phycounters;
+	u32 aniperiod;
+	struct ar5416AniState *curani;
+	struct ar5416AniState ani[255];
+	int totalSizeDesired[5];
+	int coarse_high[5];
+	int coarse_low[5];
+	int firpwr[5];
+	enum ath9k_ani_cmd ani_function;
+
+	u32 intr_txqs;
+	bool intr_mitigation;
+	enum ath9k_ht_extprotspacing extprotspacing;
+	u8 txchainmask;
+	u8 rxchainmask;
+
+	struct ar5416IniArray iniModes;
+	struct ar5416IniArray iniCommon;
+	struct ar5416IniArray iniBank0;
+	struct ar5416IniArray iniBB_RfGain;
+	struct ar5416IniArray iniBank1;
+	struct ar5416IniArray iniBank2;
+	struct ar5416IniArray iniBank3;
+	struct ar5416IniArray iniBank6;
+	struct ar5416IniArray iniBank6TPC;
+	struct ar5416IniArray iniBank7;
+	struct ar5416IniArray iniAddac;
+	struct ar5416IniArray iniPcieSerdes;
+	struct ar5416IniArray iniModesAdditional;
+	struct ar5416IniArray iniModesRxGain;
+	struct ar5416IniArray iniModesTxGain;
+};
+
+/* Attach, Detach, Reset */
+const char *ath9k_hw_probe(u16 vendorid, u16 devid);
+void ath9k_hw_detach(struct ath_hw *ah);
+struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error);
+void ath9k_hw_rfdetach(struct ath_hw *ah);
+int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+		   bool bChannelChange);
+bool ath9k_hw_fill_cap_info(struct ath_hw *ah);
+bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
+			    u32 capability, u32 *result);
+bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
+			    u32 capability, u32 setting, int *status);
+
+/* Key Cache Management */
+bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
+bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac);
+bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
+				 const struct ath9k_keyval *k,
+				 const u8 *mac, int xorKey);
+bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry);
+
+/* GPIO / RFKILL / Antennae */
+void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
+u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio);
+void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
+			 u32 ah_signal_type);
+void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+void ath9k_enable_rfkill(struct ath_hw *ah);
 #endif
+u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
+void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
+bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
+			       enum ath9k_ant_setting settings,
+			       struct ath9k_channel *chan,
+			       u8 *tx_chainmask, u8 *rx_chainmask,
+			       u8 *antenna_cfgd);
 
-#define ATH9K_POW_SM(_r, _s)     (((_r) & 0x3f) << (_s))
+/* General Operation */
+bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val);
+u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high);
+u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates,
+			   u32 frameLen, u16 rateix, bool shortPreamble);
+void ath9k_hw_get_channel_centers(struct ath_hw *ah,
+				  struct ath9k_channel *chan,
+				  struct chan_centers *centers);
+u32 ath9k_hw_getrxfilter(struct ath_hw *ah);
+void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
+bool ath9k_hw_phy_disable(struct ath_hw *ah);
+bool ath9k_hw_disable(struct ath_hw *ah);
+bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
+void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac);
+void ath9k_hw_setopmode(struct ath_hw *ah);
+void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
+void ath9k_hw_setbssidmask(struct ath_softc *sc);
+void ath9k_hw_write_associd(struct ath_softc *sc);
+u64 ath9k_hw_gettsf64(struct ath_hw *ah);
+void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
+void ath9k_hw_reset_tsf(struct ath_hw *ah);
+bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
+bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
+void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode);
+void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
+void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
+				    const struct ath9k_beacon_state *bs);
+bool ath9k_hw_setpower(struct ath_hw *ah,
+		       enum ath9k_power_mode mode);
+void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore);
 
-#define ATH9K_ANTENNA0_CHAINMASK        0x1
-#define ATH9K_ANTENNA1_CHAINMASK        0x2
+/* Interrupt Handling */
+bool ath9k_hw_intrpend(struct ath_hw *ah);
+bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked);
+enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah);
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
 
-#define ATH9K_NUM_DMA_DEBUG_REGS        8
-#define ATH9K_NUM_QUEUES                10
-
-#define HAL_NOISE_IMMUNE_MAX            4
-#define HAL_SPUR_IMMUNE_MAX             7
-#define HAL_FIRST_STEP_MAX              2
-
-#define ATH9K_ANI_OFDM_TRIG_HIGH          500
-#define ATH9K_ANI_OFDM_TRIG_LOW           200
-#define ATH9K_ANI_CCK_TRIG_HIGH           200
-#define ATH9K_ANI_CCK_TRIG_LOW            100
-#define ATH9K_ANI_NOISE_IMMUNE_LVL        4
-#define ATH9K_ANI_USE_OFDM_WEAK_SIG       true
-#define ATH9K_ANI_CCK_WEAK_SIG_THR        false
-#define ATH9K_ANI_SPUR_IMMUNE_LVL         7
-#define ATH9K_ANI_FIRSTEP_LVL             0
-#define ATH9K_ANI_RSSI_THR_HIGH           40
-#define ATH9K_ANI_RSSI_THR_LOW            7
-#define ATH9K_ANI_PERIOD                  100
-
-#define AR_GPIOD_MASK                   0x00001FFF
-#define AR_GPIO_BIT(_gpio)              (1 << (_gpio))
-
-#define HAL_EP_RND(x, mul) \
-	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-#define BEACON_RSSI(ahp) \
-	HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
-		ATH9K_RSSI_EP_MULTIPLIER)
-
-#define ah_mibStats     ah_stats.ast_mibstats
-
-#define AH_TIMEOUT         100000
-#define AH_TIME_QUANTUM        10
-
-#define AR_KEYTABLE_SIZE 128
-#define POWER_UP_TIME    200000
-
-#define EXT_ADDITIVE (0x8000)
-#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
-#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
-#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
-
-#define SUB_NUM_CTL_MODES_AT_5G_40 2
-#define SUB_NUM_CTL_MODES_AT_2G_40 3
-#define SPUR_RSSI_THRESH 40
-
-#define TU_TO_USEC(_tu)         ((_tu) << 10)
-
-#define CAB_TIMEOUT_VAL         10
-#define BEACON_TIMEOUT_VAL      10
-#define MIN_BEACON_TIMEOUT_VAL   1
-#define SLEEP_SLOP               3
-
-#define CCK_SIFS_TIME        10
-#define CCK_PREAMBLE_BITS   144
-#define CCK_PLCP_BITS        48
-
-#define OFDM_SIFS_TIME        16
-#define OFDM_PREAMBLE_TIME    20
-#define OFDM_PLCP_BITS        22
-#define OFDM_SYMBOL_TIME      4
-
-#define OFDM_SIFS_TIME_HALF     32
-#define OFDM_PREAMBLE_TIME_HALF 40
-#define OFDM_PLCP_BITS_HALF     22
-#define OFDM_SYMBOL_TIME_HALF   8
-
-#define OFDM_SIFS_TIME_QUARTER      64
-#define OFDM_PREAMBLE_TIME_QUARTER  80
-#define OFDM_PLCP_BITS_QUARTER      22
-#define OFDM_SYMBOL_TIME_QUARTER    16
-
-u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
-			enum eeprom_param param);
+void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 
 #endif
diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c
index 2427c44..f32c622 100644
--- a/drivers/net/wireless/ath9k/mac.c
+++ b/drivers/net/wireless/ath9k/mac.c
@@ -14,45 +14,40 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
-#include "hw.h"
-#include "reg.h"
-#include "phy.h"
+#include "ath9k.h"
 
-static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
+static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
 					struct ath9k_tx_queue_info *qi)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
 		"tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
-		ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask,
-		ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask,
-		ahp->ah_txUrnInterruptMask);
+		ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
+		ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
+		ah->txurn_interrupt_mask);
 
 	REG_WRITE(ah, AR_IMR_S0,
-		  SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
-		  | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
+		  SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
+		  | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
 	REG_WRITE(ah, AR_IMR_S1,
-		  SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
-		  | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
+		  SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
+		  | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
 	REG_RMW_FIELD(ah, AR_IMR_S2,
-		      AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
+		      AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask);
 }
 
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
+u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
 {
 	return REG_READ(ah, AR_QTXDP(q));
 }
 
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp)
+bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
 {
 	REG_WRITE(ah, AR_QTXDP(q), txdp);
 
 	return true;
 }
 
-bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
+bool ath9k_hw_txstart(struct ath_hw *ah, u32 q)
 {
 	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
 
@@ -61,7 +56,7 @@
 	return true;
 }
 
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
+u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
 {
 	u32 npend;
 
@@ -75,16 +70,15 @@
 	return npend;
 }
 
-bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
+bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	u32 txcfg, curLevel, newLevel;
 	enum ath9k_int omask;
 
-	if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
+	if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD)
 		return false;
 
-	omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
+	omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL);
 
 	txcfg = REG_READ(ah, AR_TXCFG);
 	curLevel = MS(txcfg, AR_FTRIG);
@@ -100,18 +94,17 @@
 
 	ath9k_hw_set_interrupts(ah, omask);
 
-	ah->ah_txTrigLevel = newLevel;
+	ah->tx_trig_level = newLevel;
 
 	return newLevel != curLevel;
 }
 
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
 {
 #define ATH9K_TX_STOP_DMA_TIMEOUT	4000    /* usec */
 #define ATH9K_TIME_QUANTUM		100     /* usec */
 
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath9k_tx_queue_info *qi;
 	u32 tsfLow, j, wait;
 	u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
@@ -121,7 +114,7 @@
 		return false;
 	}
 
-	qi = &ahp->ah_txq[q];
+	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
 		return false;
@@ -183,7 +176,7 @@
 #undef ATH9K_TIME_QUANTUM
 }
 
-bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
 			 u32 segLen, bool firstSeg,
 			 bool lastSeg, const struct ath_desc *ds0)
 {
@@ -211,7 +204,7 @@
 	return true;
 }
 
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
+void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
 
@@ -222,7 +215,7 @@
 	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
 }
 
-int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
+int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
 
@@ -297,14 +290,13 @@
 	return 0;
 }
 
-void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
 			    u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
 			    u32 keyIx, enum ath9k_key_type keyType, u32 flags)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
-	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	txPower += ahp->ah_txPowerIndexOffset;
+	txPower += ah->txpower_indexoffset;
 	if (txPower > 63)
 		txPower = 63;
 
@@ -333,7 +325,7 @@
 	}
 }
 
-void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
+void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
 				  struct ath_desc *lastds,
 				  u32 durUpdateEn, u32 rtsctsRate,
 				  u32 rtsctsDuration,
@@ -388,7 +380,7 @@
 	last_ads->ds_ctl3 = ads->ds_ctl3;
 }
 
-void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
 				u32 aggrLen)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
@@ -398,7 +390,7 @@
 	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
 }
 
-void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
 				 u32 numDelims)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
@@ -412,7 +404,7 @@
 	ads->ds_ctl6 = ctl6;
 }
 
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
+void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
 
@@ -421,14 +413,14 @@
 	ads->ds_ctl6 &= ~AR_PadDelim;
 }
 
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
+void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
 
 	ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
 }
 
-void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
+void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
 				   u32 burstDuration)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
@@ -437,7 +429,7 @@
 	ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
 }
 
-void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
 				     u32 vmf)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
@@ -448,20 +440,17 @@
 		ads->ds_ctl0 &= ~AR_VirtMoreFrag;
 }
 
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
+void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	*txqs &= ahp->ah_intrTxqs;
-	ahp->ah_intrTxqs &= ~(*txqs);
+	*txqs &= ah->intr_txqs;
+	ah->intr_txqs &= ~(*txqs);
 }
 
-bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
+bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
 			    const struct ath9k_tx_queue_info *qinfo)
 {
 	u32 cw;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath9k_tx_queue_info *qi;
 
 	if (q >= pCap->total_queues) {
@@ -469,7 +458,7 @@
 		return false;
 	}
 
-	qi = &ahp->ah_txq[q];
+	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
 		return false;
@@ -525,11 +514,10 @@
 	return true;
 }
 
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
 			    struct ath9k_tx_queue_info *qinfo)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath9k_tx_queue_info *qi;
 
 	if (q >= pCap->total_queues) {
@@ -537,7 +525,7 @@
 		return false;
 	}
 
-	qi = &ahp->ah_txq[q];
+	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
 		return false;
@@ -561,12 +549,11 @@
 	return true;
 }
 
-int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
 			  const struct ath9k_tx_queue_info *qinfo)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	struct ath9k_tx_queue_info *qi;
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	int q;
 
 	switch (type) {
@@ -584,7 +571,7 @@
 		break;
 	case ATH9K_TX_QUEUE_DATA:
 		for (q = 0; q < pCap->total_queues; q++)
-			if (ahp->ah_txq[q].tqi_type ==
+			if (ah->txq[q].tqi_type ==
 			    ATH9K_TX_QUEUE_INACTIVE)
 				break;
 		if (q == pCap->total_queues) {
@@ -600,7 +587,7 @@
 
 	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
 
-	qi = &ahp->ah_txq[q];
+	qi = &ah->txq[q];
 	if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
 		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
 			"tx queue %u already active\n", q);
@@ -627,17 +614,16 @@
 	return q;
 }
 
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
+bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath9k_tx_queue_info *qi;
 
 	if (q >= pCap->total_queues) {
 		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
 		return false;
 	}
-	qi = &ahp->ah_txq[q];
+	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
 		return false;
@@ -646,21 +632,20 @@
 	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q);
 
 	qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
-	ahp->ah_txOkInterruptMask &= ~(1 << q);
-	ahp->ah_txErrInterruptMask &= ~(1 << q);
-	ahp->ah_txDescInterruptMask &= ~(1 << q);
-	ahp->ah_txEolInterruptMask &= ~(1 << q);
-	ahp->ah_txUrnInterruptMask &= ~(1 << q);
+	ah->txok_interrupt_mask &= ~(1 << q);
+	ah->txerr_interrupt_mask &= ~(1 << q);
+	ah->txdesc_interrupt_mask &= ~(1 << q);
+	ah->txeol_interrupt_mask &= ~(1 << q);
+	ah->txurn_interrupt_mask &= ~(1 << q);
 	ath9k_hw_set_txq_interrupts(ah, qi);
 
 	return true;
 }
 
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
+bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
+	struct ath9k_channel *chan = ah->curchan;
 	struct ath9k_tx_queue_info *qi;
 	u32 cwMin, chanCwMin, value;
 
@@ -669,7 +654,7 @@
 		return false;
 	}
 
-	qi = &ahp->ah_txq[q];
+	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
 		return true;
@@ -757,9 +742,9 @@
 			  | AR_Q_MISC_CBR_INCR_DIS1
 			  | AR_Q_MISC_CBR_INCR_DIS0);
 		value = (qi->tqi_readyTime -
-			 (ah->ah_config.sw_beacon_response_time -
-			  ah->ah_config.dma_beacon_response_time) -
-			 ah->ah_config.additional_swba_backoff) * 1024;
+			 (ah->config.sw_beacon_response_time -
+			  ah->config.dma_beacon_response_time) -
+			 ah->config.additional_swba_backoff) * 1024;
 		REG_WRITE(ah, AR_QRDYTIMECFG(q),
 			  value | AR_Q_RDYTIMECFG_EN);
 		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
@@ -787,31 +772,31 @@
 	}
 
 	if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
-		ahp->ah_txOkInterruptMask |= 1 << q;
+		ah->txok_interrupt_mask |= 1 << q;
 	else
-		ahp->ah_txOkInterruptMask &= ~(1 << q);
+		ah->txok_interrupt_mask &= ~(1 << q);
 	if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
-		ahp->ah_txErrInterruptMask |= 1 << q;
+		ah->txerr_interrupt_mask |= 1 << q;
 	else
-		ahp->ah_txErrInterruptMask &= ~(1 << q);
+		ah->txerr_interrupt_mask &= ~(1 << q);
 	if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
-		ahp->ah_txDescInterruptMask |= 1 << q;
+		ah->txdesc_interrupt_mask |= 1 << q;
 	else
-		ahp->ah_txDescInterruptMask &= ~(1 << q);
+		ah->txdesc_interrupt_mask &= ~(1 << q);
 	if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
-		ahp->ah_txEolInterruptMask |= 1 << q;
+		ah->txeol_interrupt_mask |= 1 << q;
 	else
-		ahp->ah_txEolInterruptMask &= ~(1 << q);
+		ah->txeol_interrupt_mask &= ~(1 << q);
 	if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
-		ahp->ah_txUrnInterruptMask |= 1 << q;
+		ah->txurn_interrupt_mask |= 1 << q;
 	else
-		ahp->ah_txUrnInterruptMask &= ~(1 << q);
+		ah->txurn_interrupt_mask &= ~(1 << q);
 	ath9k_hw_set_txq_interrupts(ah, qi);
 
 	return true;
 }
 
-int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
 			u32 pa, struct ath_desc *nds, u64 tsf)
 {
 	struct ar5416_desc ads;
@@ -876,11 +861,11 @@
 	return 0;
 }
 
-bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
+bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
 			  u32 size, u32 flags)
 {
 	struct ar5416_desc *ads = AR5416DESC(ds);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
 
 	ads->ds_ctl1 = size & AR_BufLen;
 	if (flags & ATH9K_RXDESC_INTREQ)
@@ -893,7 +878,7 @@
 	return true;
 }
 
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
+bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
 {
 	u32 reg;
 
@@ -920,17 +905,17 @@
 	return true;
 }
 
-void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
+void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
 {
 	REG_WRITE(ah, AR_RXDP, rxdp);
 }
 
-void ath9k_hw_rxena(struct ath_hal *ah)
+void ath9k_hw_rxena(struct ath_hw *ah)
 {
 	REG_WRITE(ah, AR_CR, AR_CR_RXE);
 }
 
-void ath9k_hw_startpcureceive(struct ath_hal *ah)
+void ath9k_hw_startpcureceive(struct ath_hw *ah)
 {
 	ath9k_enable_mib_counters(ah);
 
@@ -939,14 +924,14 @@
 	REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 }
 
-void ath9k_hw_stoppcurecv(struct ath_hal *ah)
+void ath9k_hw_stoppcurecv(struct ath_hw *ah)
 {
 	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
 
 	ath9k_hw_disable_mib_counters(ah);
 }
 
-bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
+bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
 {
 	REG_WRITE(ah, AR_CR, AR_CR_RXD);
 
diff --git a/drivers/net/wireless/ath9k/mac.h b/drivers/net/wireless/ath9k/mac.h
new file mode 100644
index 0000000..74b660a
--- /dev/null
+++ b/drivers/net/wireless/ath9k/mac.h
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MAC_H
+#define MAC_H
+
+#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ?		\
+				MS(ads->ds_rxstatus0, AR_RxRate) :	\
+				(ads->ds_rxstatus3 >> 2) & 0xFF)
+
+#define set11nTries(_series, _index) \
+	(SM((_series)[_index].Tries, AR_XmitDataTries##_index))
+
+#define set11nRate(_series, _index) \
+	(SM((_series)[_index].Rate, AR_XmitRate##_index))
+
+#define set11nPktDurRTSCTS(_series, _index)				\
+	(SM((_series)[_index].PktDuration, AR_PacketDur##_index) |	\
+	 ((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS   ?	\
+	  AR_RTSCTSQual##_index : 0))
+
+#define set11nRateFlags(_series, _index)				\
+	(((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ?		\
+	  AR_2040_##_index : 0)						\
+	 |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ?	\
+	   AR_GI##_index : 0)						\
+	 |SM((_series)[_index].ChSel, AR_ChainSel##_index))
+
+#define CCK_SIFS_TIME        10
+#define CCK_PREAMBLE_BITS   144
+#define CCK_PLCP_BITS        48
+
+#define OFDM_SIFS_TIME        16
+#define OFDM_PREAMBLE_TIME    20
+#define OFDM_PLCP_BITS        22
+#define OFDM_SYMBOL_TIME      4
+
+#define OFDM_SIFS_TIME_HALF     32
+#define OFDM_PREAMBLE_TIME_HALF 40
+#define OFDM_PLCP_BITS_HALF     22
+#define OFDM_SYMBOL_TIME_HALF   8
+
+#define OFDM_SIFS_TIME_QUARTER      64
+#define OFDM_PREAMBLE_TIME_QUARTER  80
+#define OFDM_PLCP_BITS_QUARTER      22
+#define OFDM_SYMBOL_TIME_QUARTER    16
+
+#define INIT_AIFS       2
+#define INIT_CWMIN      15
+#define INIT_CWMIN_11B  31
+#define INIT_CWMAX      1023
+#define INIT_SH_RETRY   10
+#define INIT_LG_RETRY   10
+#define INIT_SSH_RETRY  32
+#define INIT_SLG_RETRY  32
+
+#define ATH9K_SLOT_TIME_6 6
+#define ATH9K_SLOT_TIME_9 9
+#define ATH9K_SLOT_TIME_20 20
+
+#define ATH9K_TXERR_XRETRY         0x01
+#define ATH9K_TXERR_FILT           0x02
+#define ATH9K_TXERR_FIFO           0x04
+#define ATH9K_TXERR_XTXOP          0x08
+#define ATH9K_TXERR_TIMER_EXPIRED  0x10
+
+#define ATH9K_TX_BA                0x01
+#define ATH9K_TX_PWRMGMT           0x02
+#define ATH9K_TX_DESC_CFG_ERR      0x04
+#define ATH9K_TX_DATA_UNDERRUN     0x08
+#define ATH9K_TX_DELIM_UNDERRUN    0x10
+#define ATH9K_TX_SW_ABORTED        0x40
+#define ATH9K_TX_SW_FILTERED       0x80
+
+#define MIN_TX_FIFO_THRESHOLD   0x1
+#define MAX_TX_FIFO_THRESHOLD   ((4096 / 64) - 1)
+#define INIT_TX_FIFO_THRESHOLD  MIN_TX_FIFO_THRESHOLD
+
+struct ath_tx_status {
+	u32 ts_tstamp;
+	u16 ts_seqnum;
+	u8 ts_status;
+	u8 ts_ratecode;
+	u8 ts_rateindex;
+	int8_t ts_rssi;
+	u8 ts_shortretry;
+	u8 ts_longretry;
+	u8 ts_virtcol;
+	u8 ts_antenna;
+	u8 ts_flags;
+	int8_t ts_rssi_ctl0;
+	int8_t ts_rssi_ctl1;
+	int8_t ts_rssi_ctl2;
+	int8_t ts_rssi_ext0;
+	int8_t ts_rssi_ext1;
+	int8_t ts_rssi_ext2;
+	u8 pad[3];
+	u32 ba_low;
+	u32 ba_high;
+	u32 evm0;
+	u32 evm1;
+	u32 evm2;
+};
+
+struct ath_rx_status {
+	u32 rs_tstamp;
+	u16 rs_datalen;
+	u8 rs_status;
+	u8 rs_phyerr;
+	int8_t rs_rssi;
+	u8 rs_keyix;
+	u8 rs_rate;
+	u8 rs_antenna;
+	u8 rs_more;
+	int8_t rs_rssi_ctl0;
+	int8_t rs_rssi_ctl1;
+	int8_t rs_rssi_ctl2;
+	int8_t rs_rssi_ext0;
+	int8_t rs_rssi_ext1;
+	int8_t rs_rssi_ext2;
+	u8 rs_isaggr;
+	u8 rs_moreaggr;
+	u8 rs_num_delims;
+	u8 rs_flags;
+	u32 evm0;
+	u32 evm1;
+	u32 evm2;
+};
+
+#define ATH9K_RXERR_CRC           0x01
+#define ATH9K_RXERR_PHY           0x02
+#define ATH9K_RXERR_FIFO          0x04
+#define ATH9K_RXERR_DECRYPT       0x08
+#define ATH9K_RXERR_MIC           0x10
+
+#define ATH9K_RX_MORE             0x01
+#define ATH9K_RX_MORE_AGGR        0x02
+#define ATH9K_RX_GI               0x04
+#define ATH9K_RX_2040             0x08
+#define ATH9K_RX_DELIM_CRC_PRE    0x10
+#define ATH9K_RX_DELIM_CRC_POST   0x20
+#define ATH9K_RX_DECRYPT_BUSY     0x40
+
+#define ATH9K_RXKEYIX_INVALID	((u8)-1)
+#define ATH9K_TXKEYIX_INVALID	((u32)-1)
+
+struct ath_desc {
+	u32 ds_link;
+	u32 ds_data;
+	u32 ds_ctl0;
+	u32 ds_ctl1;
+	u32 ds_hw[20];
+	union {
+		struct ath_tx_status tx;
+		struct ath_rx_status rx;
+		void *stats;
+	} ds_us;
+	void *ds_vdata;
+} __packed;
+
+#define	ds_txstat	ds_us.tx
+#define	ds_rxstat	ds_us.rx
+#define ds_stat		ds_us.stats
+
+#define ATH9K_TXDESC_CLRDMASK		0x0001
+#define ATH9K_TXDESC_NOACK		0x0002
+#define ATH9K_TXDESC_RTSENA		0x0004
+#define ATH9K_TXDESC_CTSENA		0x0008
+/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for
+ * the descriptor its marked on.  We take a tx interrupt to reap
+ * descriptors when the h/w hits an EOL condition or
+ * when the descriptor is specifically marked to generate
+ * an interrupt with this flag. Descriptors should be
+ * marked periodically to insure timely replenishing of the
+ * supply needed for sending frames. Defering interrupts
+ * reduces system load and potentially allows more concurrent
+ * work to be done but if done to aggressively can cause
+ * senders to backup. When the hardware queue is left too
+ * large rate control information may also be too out of
+ * date. An Alternative for this is TX interrupt mitigation
+ * but this needs more testing. */
+#define ATH9K_TXDESC_INTREQ		0x0010
+#define ATH9K_TXDESC_VEOL		0x0020
+#define ATH9K_TXDESC_EXT_ONLY		0x0040
+#define ATH9K_TXDESC_EXT_AND_CTL	0x0080
+#define ATH9K_TXDESC_VMF		0x0100
+#define ATH9K_TXDESC_FRAG_IS_ON 	0x0200
+#define ATH9K_TXDESC_CAB		0x0400
+
+#define ATH9K_RXDESC_INTREQ		0x0020
+
+struct ar5416_desc {
+	u32 ds_link;
+	u32 ds_data;
+	u32 ds_ctl0;
+	u32 ds_ctl1;
+	union {
+		struct {
+			u32 ctl2;
+			u32 ctl3;
+			u32 ctl4;
+			u32 ctl5;
+			u32 ctl6;
+			u32 ctl7;
+			u32 ctl8;
+			u32 ctl9;
+			u32 ctl10;
+			u32 ctl11;
+			u32 status0;
+			u32 status1;
+			u32 status2;
+			u32 status3;
+			u32 status4;
+			u32 status5;
+			u32 status6;
+			u32 status7;
+			u32 status8;
+			u32 status9;
+		} tx;
+		struct {
+			u32 status0;
+			u32 status1;
+			u32 status2;
+			u32 status3;
+			u32 status4;
+			u32 status5;
+			u32 status6;
+			u32 status7;
+			u32 status8;
+		} rx;
+	} u;
+} __packed;
+
+#define AR5416DESC(_ds)         ((struct ar5416_desc *)(_ds))
+#define AR5416DESC_CONST(_ds)   ((const struct ar5416_desc *)(_ds))
+
+#define ds_ctl2     u.tx.ctl2
+#define ds_ctl3     u.tx.ctl3
+#define ds_ctl4     u.tx.ctl4
+#define ds_ctl5     u.tx.ctl5
+#define ds_ctl6     u.tx.ctl6
+#define ds_ctl7     u.tx.ctl7
+#define ds_ctl8     u.tx.ctl8
+#define ds_ctl9     u.tx.ctl9
+#define ds_ctl10    u.tx.ctl10
+#define ds_ctl11    u.tx.ctl11
+
+#define ds_txstatus0    u.tx.status0
+#define ds_txstatus1    u.tx.status1
+#define ds_txstatus2    u.tx.status2
+#define ds_txstatus3    u.tx.status3
+#define ds_txstatus4    u.tx.status4
+#define ds_txstatus5    u.tx.status5
+#define ds_txstatus6    u.tx.status6
+#define ds_txstatus7    u.tx.status7
+#define ds_txstatus8    u.tx.status8
+#define ds_txstatus9    u.tx.status9
+
+#define ds_rxstatus0    u.rx.status0
+#define ds_rxstatus1    u.rx.status1
+#define ds_rxstatus2    u.rx.status2
+#define ds_rxstatus3    u.rx.status3
+#define ds_rxstatus4    u.rx.status4
+#define ds_rxstatus5    u.rx.status5
+#define ds_rxstatus6    u.rx.status6
+#define ds_rxstatus7    u.rx.status7
+#define ds_rxstatus8    u.rx.status8
+
+#define AR_FrameLen         0x00000fff
+#define AR_VirtMoreFrag     0x00001000
+#define AR_TxCtlRsvd00      0x0000e000
+#define AR_XmitPower        0x003f0000
+#define AR_XmitPower_S      16
+#define AR_RTSEnable        0x00400000
+#define AR_VEOL             0x00800000
+#define AR_ClrDestMask      0x01000000
+#define AR_TxCtlRsvd01      0x1e000000
+#define AR_TxIntrReq        0x20000000
+#define AR_DestIdxValid     0x40000000
+#define AR_CTSEnable        0x80000000
+
+#define AR_BufLen           0x00000fff
+#define AR_TxMore           0x00001000
+#define AR_DestIdx          0x000fe000
+#define AR_DestIdx_S        13
+#define AR_FrameType        0x00f00000
+#define AR_FrameType_S      20
+#define AR_NoAck            0x01000000
+#define AR_InsertTS         0x02000000
+#define AR_CorruptFCS       0x04000000
+#define AR_ExtOnly          0x08000000
+#define AR_ExtAndCtl        0x10000000
+#define AR_MoreAggr         0x20000000
+#define AR_IsAggr           0x40000000
+
+#define AR_BurstDur         0x00007fff
+#define AR_BurstDur_S       0
+#define AR_DurUpdateEna     0x00008000
+#define AR_XmitDataTries0   0x000f0000
+#define AR_XmitDataTries0_S 16
+#define AR_XmitDataTries1   0x00f00000
+#define AR_XmitDataTries1_S 20
+#define AR_XmitDataTries2   0x0f000000
+#define AR_XmitDataTries2_S 24
+#define AR_XmitDataTries3   0xf0000000
+#define AR_XmitDataTries3_S 28
+
+#define AR_XmitRate0        0x000000ff
+#define AR_XmitRate0_S      0
+#define AR_XmitRate1        0x0000ff00
+#define AR_XmitRate1_S      8
+#define AR_XmitRate2        0x00ff0000
+#define AR_XmitRate2_S      16
+#define AR_XmitRate3        0xff000000
+#define AR_XmitRate3_S      24
+
+#define AR_PacketDur0       0x00007fff
+#define AR_PacketDur0_S     0
+#define AR_RTSCTSQual0      0x00008000
+#define AR_PacketDur1       0x7fff0000
+#define AR_PacketDur1_S     16
+#define AR_RTSCTSQual1      0x80000000
+
+#define AR_PacketDur2       0x00007fff
+#define AR_PacketDur2_S     0
+#define AR_RTSCTSQual2      0x00008000
+#define AR_PacketDur3       0x7fff0000
+#define AR_PacketDur3_S     16
+#define AR_RTSCTSQual3      0x80000000
+
+#define AR_AggrLen          0x0000ffff
+#define AR_AggrLen_S        0
+#define AR_TxCtlRsvd60      0x00030000
+#define AR_PadDelim         0x03fc0000
+#define AR_PadDelim_S       18
+#define AR_EncrType         0x0c000000
+#define AR_EncrType_S       26
+#define AR_TxCtlRsvd61      0xf0000000
+
+#define AR_2040_0           0x00000001
+#define AR_GI0              0x00000002
+#define AR_ChainSel0        0x0000001c
+#define AR_ChainSel0_S      2
+#define AR_2040_1           0x00000020
+#define AR_GI1              0x00000040
+#define AR_ChainSel1        0x00000380
+#define AR_ChainSel1_S      7
+#define AR_2040_2           0x00000400
+#define AR_GI2              0x00000800
+#define AR_ChainSel2        0x00007000
+#define AR_ChainSel2_S      12
+#define AR_2040_3           0x00008000
+#define AR_GI3              0x00010000
+#define AR_ChainSel3        0x000e0000
+#define AR_ChainSel3_S      17
+#define AR_RTSCTSRate       0x0ff00000
+#define AR_RTSCTSRate_S     20
+#define AR_TxCtlRsvd70      0xf0000000
+
+#define AR_TxRSSIAnt00      0x000000ff
+#define AR_TxRSSIAnt00_S    0
+#define AR_TxRSSIAnt01      0x0000ff00
+#define AR_TxRSSIAnt01_S    8
+#define AR_TxRSSIAnt02      0x00ff0000
+#define AR_TxRSSIAnt02_S    16
+#define AR_TxStatusRsvd00   0x3f000000
+#define AR_TxBaStatus       0x40000000
+#define AR_TxStatusRsvd01   0x80000000
+
+#define AR_FrmXmitOK            0x00000001
+#define AR_ExcessiveRetries     0x00000002
+#define AR_FIFOUnderrun         0x00000004
+#define AR_Filtered             0x00000008
+#define AR_RTSFailCnt           0x000000f0
+#define AR_RTSFailCnt_S         4
+#define AR_DataFailCnt          0x00000f00
+#define AR_DataFailCnt_S        8
+#define AR_VirtRetryCnt         0x0000f000
+#define AR_VirtRetryCnt_S       12
+#define AR_TxDelimUnderrun      0x00010000
+#define AR_TxDataUnderrun       0x00020000
+#define AR_DescCfgErr           0x00040000
+#define AR_TxTimerExpired       0x00080000
+#define AR_TxStatusRsvd10       0xfff00000
+
+#define AR_SendTimestamp    ds_txstatus2
+#define AR_BaBitmapLow      ds_txstatus3
+#define AR_BaBitmapHigh     ds_txstatus4
+
+#define AR_TxRSSIAnt10      0x000000ff
+#define AR_TxRSSIAnt10_S    0
+#define AR_TxRSSIAnt11      0x0000ff00
+#define AR_TxRSSIAnt11_S    8
+#define AR_TxRSSIAnt12      0x00ff0000
+#define AR_TxRSSIAnt12_S    16
+#define AR_TxRSSICombined   0xff000000
+#define AR_TxRSSICombined_S 24
+
+#define AR_TxEVM0           ds_txstatus5
+#define AR_TxEVM1           ds_txstatus6
+#define AR_TxEVM2           ds_txstatus7
+
+#define AR_TxDone           0x00000001
+#define AR_SeqNum           0x00001ffe
+#define AR_SeqNum_S         1
+#define AR_TxStatusRsvd80   0x0001e000
+#define AR_TxOpExceeded     0x00020000
+#define AR_TxStatusRsvd81   0x001c0000
+#define AR_FinalTxIdx       0x00600000
+#define AR_FinalTxIdx_S     21
+#define AR_TxStatusRsvd82   0x01800000
+#define AR_PowerMgmt        0x02000000
+#define AR_TxStatusRsvd83   0xfc000000
+
+#define AR_RxCTLRsvd00  0xffffffff
+
+#define AR_BufLen       0x00000fff
+#define AR_RxCtlRsvd00  0x00001000
+#define AR_RxIntrReq    0x00002000
+#define AR_RxCtlRsvd01  0xffffc000
+
+#define AR_RxRSSIAnt00      0x000000ff
+#define AR_RxRSSIAnt00_S    0
+#define AR_RxRSSIAnt01      0x0000ff00
+#define AR_RxRSSIAnt01_S    8
+#define AR_RxRSSIAnt02      0x00ff0000
+#define AR_RxRSSIAnt02_S    16
+#define AR_RxRate           0xff000000
+#define AR_RxRate_S         24
+#define AR_RxStatusRsvd00   0xff000000
+
+#define AR_DataLen          0x00000fff
+#define AR_RxMore           0x00001000
+#define AR_NumDelim         0x003fc000
+#define AR_NumDelim_S       14
+#define AR_RxStatusRsvd10   0xff800000
+
+#define AR_RcvTimestamp     ds_rxstatus2
+
+#define AR_GI               0x00000001
+#define AR_2040             0x00000002
+#define AR_Parallel40       0x00000004
+#define AR_Parallel40_S     2
+#define AR_RxStatusRsvd30   0x000000f8
+#define AR_RxAntenna	    0xffffff00
+#define AR_RxAntenna_S	    8
+
+#define AR_RxRSSIAnt10            0x000000ff
+#define AR_RxRSSIAnt10_S          0
+#define AR_RxRSSIAnt11            0x0000ff00
+#define AR_RxRSSIAnt11_S          8
+#define AR_RxRSSIAnt12            0x00ff0000
+#define AR_RxRSSIAnt12_S          16
+#define AR_RxRSSICombined         0xff000000
+#define AR_RxRSSICombined_S       24
+
+#define AR_RxEVM0           ds_rxstatus4
+#define AR_RxEVM1           ds_rxstatus5
+#define AR_RxEVM2           ds_rxstatus6
+
+#define AR_RxDone           0x00000001
+#define AR_RxFrameOK        0x00000002
+#define AR_CRCErr           0x00000004
+#define AR_DecryptCRCErr    0x00000008
+#define AR_PHYErr           0x00000010
+#define AR_MichaelErr       0x00000020
+#define AR_PreDelimCRCErr   0x00000040
+#define AR_RxStatusRsvd70   0x00000080
+#define AR_RxKeyIdxValid    0x00000100
+#define AR_KeyIdx           0x0000fe00
+#define AR_KeyIdx_S         9
+#define AR_PHYErrCode       0x0000ff00
+#define AR_PHYErrCode_S     8
+#define AR_RxMoreAggr       0x00010000
+#define AR_RxAggr           0x00020000
+#define AR_PostDelimCRCErr  0x00040000
+#define AR_RxStatusRsvd71   0x3ff80000
+#define AR_DecryptBusyErr   0x40000000
+#define AR_KeyMiss          0x80000000
+
+enum ath9k_tx_queue {
+	ATH9K_TX_QUEUE_INACTIVE = 0,
+	ATH9K_TX_QUEUE_DATA,
+	ATH9K_TX_QUEUE_BEACON,
+	ATH9K_TX_QUEUE_CAB,
+	ATH9K_TX_QUEUE_UAPSD,
+	ATH9K_TX_QUEUE_PSPOLL
+};
+
+#define	ATH9K_NUM_TX_QUEUES 10
+
+enum ath9k_tx_queue_subtype {
+	ATH9K_WME_AC_BK = 0,
+	ATH9K_WME_AC_BE,
+	ATH9K_WME_AC_VI,
+	ATH9K_WME_AC_VO,
+	ATH9K_WME_UPSD
+};
+
+enum ath9k_tx_queue_flags {
+	TXQ_FLAG_TXOKINT_ENABLE = 0x0001,
+	TXQ_FLAG_TXERRINT_ENABLE = 0x0001,
+	TXQ_FLAG_TXDESCINT_ENABLE = 0x0002,
+	TXQ_FLAG_TXEOLINT_ENABLE = 0x0004,
+	TXQ_FLAG_TXURNINT_ENABLE = 0x0008,
+	TXQ_FLAG_BACKOFF_DISABLE = 0x0010,
+	TXQ_FLAG_COMPRESSION_ENABLE = 0x0020,
+	TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040,
+	TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080,
+};
+
+#define ATH9K_TXQ_USEDEFAULT ((u32) -1)
+#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001
+
+#define ATH9K_DECOMP_MASK_SIZE     128
+#define ATH9K_READY_TIME_LO_BOUND  50
+#define ATH9K_READY_TIME_HI_BOUND  96
+
+enum ath9k_pkt_type {
+	ATH9K_PKT_TYPE_NORMAL = 0,
+	ATH9K_PKT_TYPE_ATIM,
+	ATH9K_PKT_TYPE_PSPOLL,
+	ATH9K_PKT_TYPE_BEACON,
+	ATH9K_PKT_TYPE_PROBE_RESP,
+	ATH9K_PKT_TYPE_CHIRP,
+	ATH9K_PKT_TYPE_GRP_POLL,
+};
+
+struct ath9k_tx_queue_info {
+	u32 tqi_ver;
+	enum ath9k_tx_queue tqi_type;
+	enum ath9k_tx_queue_subtype tqi_subtype;
+	enum ath9k_tx_queue_flags tqi_qflags;
+	u32 tqi_priority;
+	u32 tqi_aifs;
+	u32 tqi_cwmin;
+	u32 tqi_cwmax;
+	u16 tqi_shretry;
+	u16 tqi_lgretry;
+	u32 tqi_cbrPeriod;
+	u32 tqi_cbrOverflowLimit;
+	u32 tqi_burstTime;
+	u32 tqi_readyTime;
+	u32 tqi_physCompBuf;
+	u32 tqi_intFlags;
+};
+
+enum ath9k_rx_filter {
+	ATH9K_RX_FILTER_UCAST = 0x00000001,
+	ATH9K_RX_FILTER_MCAST = 0x00000002,
+	ATH9K_RX_FILTER_BCAST = 0x00000004,
+	ATH9K_RX_FILTER_CONTROL = 0x00000008,
+	ATH9K_RX_FILTER_BEACON = 0x00000010,
+	ATH9K_RX_FILTER_PROM = 0x00000020,
+	ATH9K_RX_FILTER_PROBEREQ = 0x00000080,
+	ATH9K_RX_FILTER_PSPOLL = 0x00004000,
+	ATH9K_RX_FILTER_PHYERR = 0x00000100,
+	ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
+};
+
+#define ATH9K_RATESERIES_RTS_CTS  0x0001
+#define ATH9K_RATESERIES_2040     0x0002
+#define ATH9K_RATESERIES_HALFGI   0x0004
+
+struct ath9k_11n_rate_series {
+	u32 Tries;
+	u32 Rate;
+	u32 PktDuration;
+	u32 ChSel;
+	u32 RateFlags;
+};
+
+struct ath9k_keyval {
+	u8 kv_type;
+	u8 kv_pad;
+	u16 kv_len;
+	u8 kv_val[16];
+	u8 kv_mic[8];
+	u8 kv_txmic[8];
+};
+
+enum ath9k_key_type {
+	ATH9K_KEY_TYPE_CLEAR,
+	ATH9K_KEY_TYPE_WEP,
+	ATH9K_KEY_TYPE_AES,
+	ATH9K_KEY_TYPE_TKIP,
+};
+
+enum ath9k_cipher {
+	ATH9K_CIPHER_WEP = 0,
+	ATH9K_CIPHER_AES_OCB = 1,
+	ATH9K_CIPHER_AES_CCM = 2,
+	ATH9K_CIPHER_CKIP = 3,
+	ATH9K_CIPHER_TKIP = 4,
+	ATH9K_CIPHER_CLR = 5,
+	ATH9K_CIPHER_MIC = 127
+};
+
+enum ath9k_ht_macmode {
+	ATH9K_HT_MACMODE_20 = 0,
+	ATH9K_HT_MACMODE_2040 = 1,
+};
+
+enum ath9k_ht_extprotspacing {
+	ATH9K_HT_EXTPROTSPACING_20 = 0,
+	ATH9K_HT_EXTPROTSPACING_25 = 1,
+};
+
+struct ath_hw;
+struct ath9k_channel;
+struct ath_rate_table;
+
+u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
+bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
+bool ath9k_hw_txstart(struct ath_hw *ah, u32 q);
+u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
+bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
+bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
+bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
+			 u32 segLen, bool firstSeg,
+			 bool lastSeg, const struct ath_desc *ds0);
+void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds);
+int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
+			    u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+			    u32 keyIx, enum ath9k_key_type keyType, u32 flags);
+void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
+				  struct ath_desc *lastds,
+				  u32 durUpdateEn, u32 rtsctsRate,
+				  u32 rtsctsDuration,
+				  struct ath9k_11n_rate_series series[],
+				  u32 nseries, u32 flags);
+void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
+				u32 aggrLen);
+void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
+				 u32 numDelims);
+void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds);
+void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
+				   u32 burstDuration);
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
+				     u32 vmf);
+void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
+bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
+			    const struct ath9k_tx_queue_info *qinfo);
+bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
+			    struct ath9k_tx_queue_info *qinfo);
+int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
+			  const struct ath9k_tx_queue_info *qinfo);
+bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
+bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
+int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
+			u32 pa, struct ath_desc *nds, u64 tsf);
+bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
+			  u32 size, u32 flags);
+bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
+void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
+void ath9k_hw_rxena(struct ath_hw *ah);
+void ath9k_hw_startpcureceive(struct ath_hw *ah);
+void ath9k_hw_stoppcurecv(struct ath_hw *ah);
+bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
+
+#endif /* MAC_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 1c0f893..fc3460f 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -15,9 +15,7 @@
  */
 
 #include <linux/nl80211.h>
-#include "core.h"
-#include "reg.h"
-#include "hw.h"
+#include "ath9k.h"
 
 #define ATH_PCI_VERSION "0.1"
 
@@ -139,14 +137,14 @@
 
 static void ath_update_txpow(struct ath_softc *sc)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	u32 txpow;
 
-	if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
-		ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
+	if (sc->curtxpow != sc->config.txpowlimit) {
+		ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit);
 		/* read back in case value is clamped */
 		ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
-		sc->sc_curtxpow = txpow;
+		sc->curtxpow = txpow;
 	}
 }
 
@@ -236,7 +234,7 @@
 */
 static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	bool fastcc = true, stopped;
 	struct ieee80211_hw *hw = sc->hw;
 	struct ieee80211_channel *channel = hw->conf.channel;
@@ -269,7 +267,7 @@
 
 	DPRINTF(sc, ATH_DBG_CONFIG,
 		"(%u MHz) -> (%u MHz), chanwidth: %d\n",
-		sc->sc_ah->ah_curchan->channel,
+		sc->sc_ah->curchan->channel,
 		channel->center_freq, sc->tx_chan_width);
 
 	spin_lock_bh(&sc->sc_resetlock);
@@ -296,7 +294,7 @@
 
 	ath_cache_conf_rate(sc, &hw->conf);
 	ath_update_txpow(sc);
-	ath9k_hw_set_interrupts(ah, sc->sc_imask);
+	ath9k_hw_set_interrupts(ah, sc->imask);
 	ath9k_ps_restore(sc);
 	return 0;
 }
@@ -311,7 +309,7 @@
 static void ath_ani_calibrate(unsigned long data)
 {
 	struct ath_softc *sc;
-	struct ath_hal *ah;
+	struct ath_hw *ah;
 	bool longcal = false;
 	bool shortcal = false;
 	bool aniflag = false;
@@ -329,68 +327,68 @@
 		return;
 
 	/* Long calibration runs independently of short calibration. */
-	if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
+	if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
 		longcal = true;
 		DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
-		sc->sc_ani.sc_longcal_timer = timestamp;
+		sc->ani.longcal_timer = timestamp;
 	}
 
-	/* Short calibration applies only while sc_caldone is false */
-	if (!sc->sc_ani.sc_caldone) {
-		if ((timestamp - sc->sc_ani.sc_shortcal_timer) >=
+	/* Short calibration applies only while caldone is false */
+	if (!sc->ani.caldone) {
+		if ((timestamp - sc->ani.shortcal_timer) >=
 		    ATH_SHORT_CALINTERVAL) {
 			shortcal = true;
 			DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies);
-			sc->sc_ani.sc_shortcal_timer = timestamp;
-			sc->sc_ani.sc_resetcal_timer = timestamp;
+			sc->ani.shortcal_timer = timestamp;
+			sc->ani.resetcal_timer = timestamp;
 		}
 	} else {
-		if ((timestamp - sc->sc_ani.sc_resetcal_timer) >=
+		if ((timestamp - sc->ani.resetcal_timer) >=
 		    ATH_RESTART_CALINTERVAL) {
-			sc->sc_ani.sc_caldone = ath9k_hw_reset_calvalid(ah);
-			if (sc->sc_ani.sc_caldone)
-				sc->sc_ani.sc_resetcal_timer = timestamp;
+			sc->ani.caldone = ath9k_hw_reset_calvalid(ah);
+			if (sc->ani.caldone)
+				sc->ani.resetcal_timer = timestamp;
 		}
 	}
 
 	/* Verify whether we must check ANI */
-	if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
+	if ((timestamp - sc->ani.checkani_timer) >=
 	   ATH_ANI_POLLINTERVAL) {
 		aniflag = true;
-		sc->sc_ani.sc_checkani_timer = timestamp;
+		sc->ani.checkani_timer = timestamp;
 	}
 
 	/* Skip all processing if there's nothing to do. */
 	if (longcal || shortcal || aniflag) {
 		/* Call ANI routine if necessary */
 		if (aniflag)
-			ath9k_hw_ani_monitor(ah, &sc->sc_halstats,
-					     ah->ah_curchan);
+			ath9k_hw_ani_monitor(ah, &sc->nodestats,
+					     ah->curchan);
 
 		/* Perform calibration if necessary */
 		if (longcal || shortcal) {
 			bool iscaldone = false;
 
-			if (ath9k_hw_calibrate(ah, ah->ah_curchan,
-					       sc->sc_rx_chainmask, longcal,
+			if (ath9k_hw_calibrate(ah, ah->curchan,
+					       sc->rx_chainmask, longcal,
 					       &iscaldone)) {
 				if (longcal)
-					sc->sc_ani.sc_noise_floor =
+					sc->ani.noise_floor =
 						ath9k_hw_getchan_noise(ah,
-							       ah->ah_curchan);
+							       ah->curchan);
 
 				DPRINTF(sc, ATH_DBG_ANI,
 					"calibrate chan %u/%x nf: %d\n",
-					ah->ah_curchan->channel,
-					ah->ah_curchan->channelFlags,
-					sc->sc_ani.sc_noise_floor);
+					ah->curchan->channel,
+					ah->curchan->channelFlags,
+					sc->ani.noise_floor);
 			} else {
 				DPRINTF(sc, ATH_DBG_ANY,
 					"calibrate chan %u/%x failed\n",
-					ah->ah_curchan->channel,
-					ah->ah_curchan->channelFlags);
+					ah->curchan->channel,
+					ah->curchan->channelFlags);
 			}
-			sc->sc_ani.sc_caldone = iscaldone;
+			sc->ani.caldone = iscaldone;
 		}
 	}
 
@@ -400,12 +398,12 @@
 	* short calibration and long calibration.
 	*/
 	cal_interval = ATH_LONG_CALINTERVAL;
-	if (sc->sc_ah->ah_config.enable_ani)
+	if (sc->sc_ah->config.enable_ani)
 		cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
-	if (!sc->sc_ani.sc_caldone)
+	if (!sc->ani.caldone)
 		cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
 
-	mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+	mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
 }
 
 /*
@@ -418,16 +416,16 @@
 {
 	sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
 	if (is_ht ||
-	    (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
-		sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
-		sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
+	    (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
+		sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
+		sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
 	} else {
-		sc->sc_tx_chainmask = 1;
-		sc->sc_rx_chainmask = 1;
+		sc->tx_chainmask = 1;
+		sc->rx_chainmask = 1;
 	}
 
 	DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n",
-		sc->sc_tx_chainmask, sc->sc_rx_chainmask);
+		sc->tx_chainmask, sc->rx_chainmask);
 }
 
 static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
@@ -455,7 +453,7 @@
 static void ath9k_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
-	u32 status = sc->sc_intrstatus;
+	u32 status = sc->intrstatus;
 
 	if (status & ATH9K_INT_FATAL) {
 		/* need a chip reset */
@@ -475,13 +473,13 @@
 	}
 
 	/* re-enable hardware interrupt */
-	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 }
 
 irqreturn_t ath_isr(int irq, void *dev)
 {
 	struct ath_softc *sc = dev;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	enum ath9k_int status;
 	bool sched = false;
 
@@ -506,7 +504,7 @@
 		 */
 		ath9k_hw_getisr(ah, &status);	/* NB: clears ISR too */
 
-		status &= sc->sc_imask;	/* discard unasked-for bits */
+		status &= sc->imask;	/* discard unasked-for bits */
 
 		/*
 		 * If there are no status bits set, then this interrupt was not
@@ -515,7 +513,7 @@
 		if (!status)
 			return IRQ_NONE;
 
-		sc->sc_intrstatus = status;
+		sc->intrstatus = status;
 
 		if (status & ATH9K_INT_FATAL) {
 			/* need a chip reset */
@@ -562,11 +560,11 @@
 				 * it will clear whatever condition caused
 				 * the interrupt.
 				 */
-				ath9k_hw_procmibevent(ah, &sc->sc_halstats);
-				ath9k_hw_set_interrupts(ah, sc->sc_imask);
+				ath9k_hw_procmibevent(ah, &sc->nodestats);
+				ath9k_hw_set_interrupts(ah, sc->imask);
 			}
 			if (status & ATH9K_INT_TIM_TIMER) {
-				if (!(ah->ah_caps.hw_caps &
+				if (!(ah->caps.hw_caps &
 				      ATH9K_HW_CAP_AUTOSLEEP)) {
 					/* Clear RxAbort bit so that we can
 					 * receive frames */
@@ -583,7 +581,7 @@
 
 	if (sched) {
 		/* turn off every interrupt except SWBA */
-		ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
+		ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA));
 		tasklet_schedule(&sc->intr_tq);
 	}
 
@@ -658,7 +656,7 @@
 		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
 		return ath_keyset(sc, keyix, hk, addr);
 	}
-	if (!sc->sc_splitmic) {
+	if (!sc->splitmic) {
 		/*
 		 * data key goes at first index,
 		 * the hal handles the MIC keys at index+64.
@@ -688,13 +686,13 @@
 {
 	int i;
 
-	for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
-		if (test_bit(i, sc->sc_keymap) ||
-		    test_bit(i + 64, sc->sc_keymap))
+	for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) {
+		if (test_bit(i, sc->keymap) ||
+		    test_bit(i + 64, sc->keymap))
 			continue; /* At least one part of TKIP key allocated */
-		if (sc->sc_splitmic &&
-		    (test_bit(i + 32, sc->sc_keymap) ||
-		     test_bit(i + 64 + 32, sc->sc_keymap)))
+		if (sc->splitmic &&
+		    (test_bit(i + 32, sc->keymap) ||
+		     test_bit(i + 64 + 32, sc->keymap)))
 			continue; /* At least one part of TKIP key allocated */
 
 		/* Found a free slot for a TKIP key */
@@ -708,55 +706,55 @@
 	int i;
 
 	/* First, try to find slots that would not be available for TKIP. */
-	if (sc->sc_splitmic) {
-		for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) {
-			if (!test_bit(i, sc->sc_keymap) &&
-			    (test_bit(i + 32, sc->sc_keymap) ||
-			     test_bit(i + 64, sc->sc_keymap) ||
-			     test_bit(i + 64 + 32, sc->sc_keymap)))
+	if (sc->splitmic) {
+		for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) {
+			if (!test_bit(i, sc->keymap) &&
+			    (test_bit(i + 32, sc->keymap) ||
+			     test_bit(i + 64, sc->keymap) ||
+			     test_bit(i + 64 + 32, sc->keymap)))
 				return i;
-			if (!test_bit(i + 32, sc->sc_keymap) &&
-			    (test_bit(i, sc->sc_keymap) ||
-			     test_bit(i + 64, sc->sc_keymap) ||
-			     test_bit(i + 64 + 32, sc->sc_keymap)))
+			if (!test_bit(i + 32, sc->keymap) &&
+			    (test_bit(i, sc->keymap) ||
+			     test_bit(i + 64, sc->keymap) ||
+			     test_bit(i + 64 + 32, sc->keymap)))
 				return i + 32;
-			if (!test_bit(i + 64, sc->sc_keymap) &&
-			    (test_bit(i , sc->sc_keymap) ||
-			     test_bit(i + 32, sc->sc_keymap) ||
-			     test_bit(i + 64 + 32, sc->sc_keymap)))
+			if (!test_bit(i + 64, sc->keymap) &&
+			    (test_bit(i , sc->keymap) ||
+			     test_bit(i + 32, sc->keymap) ||
+			     test_bit(i + 64 + 32, sc->keymap)))
 				return i + 64;
-			if (!test_bit(i + 64 + 32, sc->sc_keymap) &&
-			    (test_bit(i, sc->sc_keymap) ||
-			     test_bit(i + 32, sc->sc_keymap) ||
-			     test_bit(i + 64, sc->sc_keymap)))
+			if (!test_bit(i + 64 + 32, sc->keymap) &&
+			    (test_bit(i, sc->keymap) ||
+			     test_bit(i + 32, sc->keymap) ||
+			     test_bit(i + 64, sc->keymap)))
 				return i + 64 + 32;
 		}
 	} else {
-		for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
-			if (!test_bit(i, sc->sc_keymap) &&
-			    test_bit(i + 64, sc->sc_keymap))
+		for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) {
+			if (!test_bit(i, sc->keymap) &&
+			    test_bit(i + 64, sc->keymap))
 				return i;
-			if (test_bit(i, sc->sc_keymap) &&
-			    !test_bit(i + 64, sc->sc_keymap))
+			if (test_bit(i, sc->keymap) &&
+			    !test_bit(i + 64, sc->keymap))
 				return i + 64;
 		}
 	}
 
 	/* No partially used TKIP slots, pick any available slot */
-	for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) {
+	for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) {
 		/* Do not allow slots that could be needed for TKIP group keys
 		 * to be used. This limitation could be removed if we know that
 		 * TKIP will not be used. */
 		if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
 			continue;
-		if (sc->sc_splitmic) {
+		if (sc->splitmic) {
 			if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
 				continue;
 			if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
 				continue;
 		}
 
-		if (!test_bit(i, sc->sc_keymap))
+		if (!test_bit(i, sc->keymap))
 			return i; /* Found a free slot for a key */
 	}
 
@@ -803,7 +801,7 @@
 			return -EOPNOTSUPP;
 		mac = sta->addr;
 
-		vif = sc->sc_vaps[0];
+		vif = sc->vifs[0];
 		if (vif->type != NL80211_IFTYPE_AP) {
 			/* Only keyidx 0 should be used with unicast key, but
 			 * allow this for client mode for now. */
@@ -831,12 +829,12 @@
 	if (!ret)
 		return -EIO;
 
-	set_bit(idx, sc->sc_keymap);
+	set_bit(idx, sc->keymap);
 	if (key->alg == ALG_TKIP) {
-		set_bit(idx + 64, sc->sc_keymap);
-		if (sc->sc_splitmic) {
-			set_bit(idx + 32, sc->sc_keymap);
-			set_bit(idx + 64 + 32, sc->sc_keymap);
+		set_bit(idx + 64, sc->keymap);
+		if (sc->splitmic) {
+			set_bit(idx + 32, sc->keymap);
+			set_bit(idx + 64 + 32, sc->keymap);
 		}
 	}
 
@@ -849,14 +847,14 @@
 	if (key->hw_key_idx < IEEE80211_WEP_NKID)
 		return;
 
-	clear_bit(key->hw_key_idx, sc->sc_keymap);
+	clear_bit(key->hw_key_idx, sc->keymap);
 	if (key->alg != ALG_TKIP)
 		return;
 
-	clear_bit(key->hw_key_idx + 64, sc->sc_keymap);
-	if (sc->sc_splitmic) {
-		clear_bit(key->hw_key_idx + 32, sc->sc_keymap);
-		clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap);
+	clear_bit(key->hw_key_idx + 64, sc->keymap);
+	if (sc->splitmic) {
+		clear_bit(key->hw_key_idx + 32, sc->keymap);
+		clear_bit(key->hw_key_idx + 64 + 32, sc->keymap);
 	}
 }
 
@@ -878,7 +876,7 @@
 	/* set up supported mcs set */
 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
 
-	switch(sc->sc_rx_chainmask) {
+	switch(sc->rx_chainmask) {
 	case 1:
 		ht_info->mcs.rx_mask[0] = 0xff;
 		break;
@@ -898,17 +896,16 @@
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *bss_conf)
 {
-	struct ath_vap *avp = (void *)vif->drv_priv;
+	struct ath_vif *avp = (void *)vif->drv_priv;
 
 	if (bss_conf->assoc) {
 		DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
-			bss_conf->aid, sc->sc_curbssid);
+			bss_conf->aid, sc->curbssid);
 
 		/* New association, store aid */
 		if (avp->av_opmode == NL80211_IFTYPE_STATION) {
-			sc->sc_curaid = bss_conf->aid;
-			ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
-					       sc->sc_curaid);
+			sc->curaid = bss_conf->aid;
+			ath9k_hw_write_associd(sc);
 		}
 
 		/* Configure the beacon */
@@ -916,18 +913,18 @@
 		sc->sc_flags |= SC_OP_BEACONS;
 
 		/* Reset rssi stats */
-		sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
+		sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
+		sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
+		sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
+		sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
 
 		/* Start ANI */
-		mod_timer(&sc->sc_ani.timer,
+		mod_timer(&sc->ani.timer,
 			jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
 
 	} else {
 		DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n");
-		sc->sc_curaid = 0;
+		sc->curaid = 0;
 	}
 }
 
@@ -1094,14 +1091,14 @@
 
 static void ath_radio_enable(struct ath_softc *sc)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ieee80211_channel *channel = sc->hw->conf.channel;
 	int r;
 
 	ath9k_ps_wakeup(sc);
 	spin_lock_bh(&sc->sc_resetlock);
 
-	r = ath9k_hw_reset(ah, ah->ah_curchan, false);
+	r = ath9k_hw_reset(ah, ah->curchan, false);
 
 	if (r) {
 		DPRINTF(sc, ATH_DBG_FATAL,
@@ -1122,7 +1119,7 @@
 		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
 
 	/* Re-Enable  interrupts */
-	ath9k_hw_set_interrupts(ah, sc->sc_imask);
+	ath9k_hw_set_interrupts(ah, sc->imask);
 
 	/* Enable LED */
 	ath9k_hw_cfg_output(ah, ATH_LED_PIN,
@@ -1135,7 +1132,7 @@
 
 static void ath_radio_disable(struct ath_softc *sc)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ieee80211_channel *channel = sc->hw->conf.channel;
 	int r;
 
@@ -1154,7 +1151,7 @@
 	ath_flushrecv(sc);		/* flush recv queue */
 
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, ah->ah_curchan, false);
+	r = ath9k_hw_reset(ah, ah->curchan, false);
 	if (r) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"Unable to reset channel %u (%uMhz) "
@@ -1170,10 +1167,10 @@
 
 static bool ath_is_rfkill_set(struct ath_softc *sc)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 
-	return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) ==
-				  ah->ah_rfkill_polarity;
+	return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
+				  ah->rfkill_polarity;
 }
 
 /* h/w rfkill poll function */
@@ -1270,7 +1267,7 @@
 /* Deinitialize rfkill */
 static void ath_deinit_rfkill(struct ath_softc *sc)
 {
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
 
 	if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
@@ -1282,7 +1279,7 @@
 
 static int ath_start_rfkill_poll(struct ath_softc *sc)
 {
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		queue_delayed_work(sc->hw->workqueue,
 				   &sc->rf_kill.rfkill_poll, 0);
 
@@ -1348,7 +1345,7 @@
 
 static int ath_init(u16 devid, struct ath_softc *sc)
 {
-	struct ath_hal *ah = NULL;
+	struct ath_hw *ah = NULL;
 	int status;
 	int error = 0, i;
 	int csz = 0;
@@ -1371,9 +1368,9 @@
 	 */
 	ath_read_cachesize(sc, &csz);
 	/* XXX assert csz is non-zero */
-	sc->sc_cachelsz = csz << 2;	/* convert to bytes */
+	sc->cachelsz = csz << 2;	/* convert to bytes */
 
-	ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
+	ah = ath9k_hw_attach(devid, sc, &status);
 	if (ah == NULL) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"Unable to attach hardware; HAL status %d\n", status);
@@ -1383,26 +1380,26 @@
 	sc->sc_ah = ah;
 
 	/* Get the hardware key cache size. */
-	sc->sc_keymax = ah->ah_caps.keycache_size;
-	if (sc->sc_keymax > ATH_KEYMAX) {
+	sc->keymax = ah->caps.keycache_size;
+	if (sc->keymax > ATH_KEYMAX) {
 		DPRINTF(sc, ATH_DBG_KEYCACHE,
 			"Warning, using only %u entries in %u key cache\n",
-			ATH_KEYMAX, sc->sc_keymax);
-		sc->sc_keymax = ATH_KEYMAX;
+			ATH_KEYMAX, sc->keymax);
+		sc->keymax = ATH_KEYMAX;
 	}
 
 	/*
 	 * Reset the key cache since some parts do not
 	 * reset the contents on initial power up.
 	 */
-	for (i = 0; i < sc->sc_keymax; i++)
+	for (i = 0; i < sc->keymax; i++)
 		ath9k_hw_keyreset(ah, (u16) i);
 
 	if (ath9k_regd_init(sc->sc_ah))
 		goto bad;
 
 	/* default to MONITOR mode */
-	sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR;
+	sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
 
 	/* Setup rate tables */
 
@@ -1431,7 +1428,7 @@
 		goto bad2;
 	}
 
-	sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
+	sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
 	ath_cabq_update(sc);
 
 	for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
@@ -1468,8 +1465,8 @@
 	/* Initializes the noise floor to a reasonable default value.
 	 * Later on this will be updated during ANI processing. */
 
-	sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
-	setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
+	sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
+	setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc);
 
 	if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
 				   ATH9K_CIPHER_TKIP, NULL)) {
@@ -1495,33 +1492,31 @@
 				      ATH9K_CIPHER_MIC, NULL)
 	    && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
 				      0, NULL))
-		sc->sc_splitmic = 1;
+		sc->splitmic = 1;
 
 	/* turn on mcast key search if possible */
 	if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
 		(void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
 					     1, NULL);
 
-	sc->sc_config.txpowlimit = ATH_TXPOWER_MAX;
-	sc->sc_config.txpowlimit_override = 0;
+	sc->config.txpowlimit = ATH_TXPOWER_MAX;
 
 	/* 11n Capabilities */
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
 		sc->sc_flags |= SC_OP_TXAGGR;
 		sc->sc_flags |= SC_OP_RXAGGR;
 	}
 
-	sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
-	sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
+	sc->tx_chainmask = ah->caps.tx_chainmask;
+	sc->rx_chainmask = ah->caps.rx_chainmask;
 
 	ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
 	sc->rx.defant = ath9k_hw_getdefantenna(ah);
 
-	ath9k_hw_getmac(ah, sc->sc_myaddr);
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
-		ath9k_hw_getbssidmask(ah, sc->sc_bssidmask);
-		ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
-		ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
+		memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
+		ATH_SET_VIF_BSSID_MASK(sc->bssidmask);
+		ath9k_hw_setbssidmask(sc);
 	}
 
 	sc->beacon.slottime = ATH9K_SLOT_TIME_9;	/* default to short slot time */
@@ -1531,7 +1526,7 @@
 		sc->beacon.bslot[i] = ATH_IF_ID_ANY;
 
 	/* save MISC configurations */
-	sc->sc_config.swBeaconProcess = 1;
+	sc->config.swBeaconProcess = 1;
 
 	/* setup channels and rates */
 
@@ -1542,7 +1537,7 @@
 	sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
 		ARRAY_SIZE(ath9k_2ghz_chantable);
 
-	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
+	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
 		sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
 		sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
 			sc->rates[IEEE80211_BAND_5GHZ];
@@ -1551,7 +1546,7 @@
 			ARRAY_SIZE(ath9k_5ghz_chantable);
 	}
 
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_BT_COEX)
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)
 		ath9k_hw_btcoex_enable(sc->sc_ah);
 
 	return 0;
@@ -1580,7 +1575,7 @@
 
 	/* get mac address from hardware and set in mac80211 */
 
-	SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
+	SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
 
 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
@@ -1604,18 +1599,18 @@
 	hw->max_rates = 4;
 	hw->max_rate_tries = ATH_11N_TXMAXTRY;
 	hw->sta_data_size = sizeof(struct ath_node);
-	hw->vif_data_size = sizeof(struct ath_vap);
+	hw->vif_data_size = sizeof(struct ath_vif);
 
 	hw->rate_control_algorithm = "ath9k_rate_control";
 
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
 		setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
-		if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+		if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
 			setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
 	}
 
 	hw->wiphy->bands[IEEE80211_BAND_2GHZ] =	&sc->sbands[IEEE80211_BAND_2GHZ];
-	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
 		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
 			&sc->sbands[IEEE80211_BAND_5GHZ];
 
@@ -1630,7 +1625,7 @@
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	/* Initialze h/w Rfkill */
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
 
 	/* Initialize s/w rfkill */
@@ -1662,7 +1657,7 @@
 	error = ieee80211_register_hw(hw);
 
 	if (!ath9k_is_world_regd(sc->sc_ah))
-		regulatory_hint(hw->wiphy, sc->sc_ah->alpha2);
+		regulatory_hint(hw->wiphy, sc->sc_ah->regulatory.alpha2);
 
 	/* Initialize LED control */
 	ath_init_leds(sc);
@@ -1676,7 +1671,7 @@
 
 int ath_reset(struct ath_softc *sc, bool retry_tx)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ieee80211_hw *hw = sc->hw;
 	int r;
 
@@ -1686,7 +1681,7 @@
 	ath_flushrecv(sc);
 
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, false);
+	r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
 	if (r)
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"Unable to reset hardware; reset status %u\n", r);
@@ -1707,7 +1702,7 @@
 	if (sc->sc_flags & SC_OP_BEACONS)
 		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
 
-	ath9k_hw_set_interrupts(ah, sc->sc_imask);
+	ath9k_hw_set_interrupts(ah, sc->imask);
 
 	if (retry_tx) {
 		int i;
@@ -1760,7 +1755,7 @@
 	 * descriptors that cross the 4K page boundary. Assume
 	 * one skipped descriptor per 4K page.
 	 */
-	if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+	if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
 		u32 ndesc_skipped =
 			ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
 		u32 dma_len;
@@ -1800,7 +1795,7 @@
 		bf->bf_desc = ds;
 		bf->bf_daddr = DS2PHYS(dd, ds);
 
-		if (!(sc->sc_ah->ah_caps.hw_caps &
+		if (!(sc->sc_ah->caps.hw_caps &
 		      ATH9K_HW_CAP_4KB_SPLITTRANS)) {
 			/*
 			 * Skip descriptor addresses which can cause 4KB
@@ -1938,11 +1933,13 @@
 	DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with "
 		"initial channel: %d MHz\n", curchan->center_freq);
 
+	mutex_lock(&sc->mutex);
+
 	/* setup initial channel */
 
 	pos = curchan->hw_value;
 
-	init_channel = &sc->sc_ah->ah_channels[pos];
+	init_channel = &sc->sc_ah->channels[pos];
 	ath9k_update_ichannel(sc, init_channel);
 
 	/* Reset SERDES registers */
@@ -1963,7 +1960,7 @@
 			"(freq %u MHz)\n", r,
 			curchan->center_freq);
 		spin_unlock_bh(&sc->sc_resetlock);
-		return r;
+		goto mutex_unlock;
 	}
 	spin_unlock_bh(&sc->sc_resetlock);
 
@@ -1983,33 +1980,38 @@
 	if (ath_startrecv(sc) != 0) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"Unable to start recv logic\n");
-		return -EIO;
+		r = -EIO;
+		goto mutex_unlock;
 	}
 
 	/* Setup our intr mask. */
-	sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
+	sc->imask = ATH9K_INT_RX | ATH9K_INT_TX
 		| ATH9K_INT_RXEOL | ATH9K_INT_RXORN
 		| ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
 
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
-		sc->sc_imask |= ATH9K_INT_GTT;
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
+		sc->imask |= ATH9K_INT_GTT;
 
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-		sc->sc_imask |= ATH9K_INT_CST;
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
+		sc->imask |= ATH9K_INT_CST;
 
 	ath_cache_conf_rate(sc, &hw->conf);
 
 	sc->sc_flags &= ~SC_OP_INVALID;
 
 	/* Disable BMISS interrupt when we're not associated */
-	sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+	sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
 	ieee80211_wake_queues(sc->hw);
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	r = ath_start_rfkill_poll(sc);
 #endif
+
+mutex_unlock:
+	mutex_unlock(&sc->mutex);
+
 	return r;
 }
 
@@ -2074,7 +2076,7 @@
 		return;
 	}
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n");
+	mutex_lock(&sc->mutex);
 
 	ieee80211_stop_queues(sc->hw);
 
@@ -2090,7 +2092,7 @@
 		sc->rx.rxlink = NULL;
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
 #endif
 	/* disable HAL and put h/w to sleep */
@@ -2099,6 +2101,8 @@
 
 	sc->sc_flags |= SC_OP_INVALID;
 
+	mutex_unlock(&sc->mutex);
+
 	DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n");
 }
 
@@ -2106,14 +2110,16 @@
 			       struct ieee80211_if_init_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_vap *avp = (void *)conf->vif->drv_priv;
+	struct ath_vif *avp = (void *)conf->vif->drv_priv;
 	enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
 
-	/* Support only vap for now */
+	/* Support only vif for now */
 
-	if (sc->sc_nvaps)
+	if (sc->nvifs)
 		return -ENOBUFS;
 
+	mutex_lock(&sc->mutex);
+
 	switch (conf->type) {
 	case NL80211_IFTYPE_STATION:
 		ic_opmode = NL80211_IFTYPE_STATION;
@@ -2130,20 +2136,20 @@
 		return -EOPNOTSUPP;
 	}
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode);
+	DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode);
 
-	/* Set the VAP opmode */
+	/* Set the VIF opmode */
 	avp->av_opmode = ic_opmode;
 	avp->av_bslot = -1;
 
 	if (ic_opmode == NL80211_IFTYPE_AP)
 		ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
 
-	sc->sc_vaps[0] = conf->vif;
-	sc->sc_nvaps++;
+	sc->vifs[0] = conf->vif;
+	sc->nvifs++;
 
 	/* Set the device opmode */
-	sc->sc_ah->ah_opmode = ic_opmode;
+	sc->sc_ah->opmode = ic_opmode;
 
 	/*
 	 * Enable MIB interrupts when there are hardware phy counters.
@@ -2152,27 +2158,29 @@
 	if (ath9k_hw_phycounters(sc->sc_ah) &&
 	    ((conf->type == NL80211_IFTYPE_STATION) ||
 	     (conf->type == NL80211_IFTYPE_ADHOC)))
-		sc->sc_imask |= ATH9K_INT_MIB;
+		sc->imask |= ATH9K_INT_MIB;
 	/*
 	 * Some hardware processes the TIM IE and fires an
 	 * interrupt when the TIM bit is set.  For hardware
 	 * that does, if not overridden by configuration,
 	 * enable the TIM interrupt when operating as station.
 	 */
-	if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
+	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
 	    (conf->type == NL80211_IFTYPE_STATION) &&
-	    !sc->sc_config.swBeaconProcess)
-		sc->sc_imask |= ATH9K_INT_TIM;
+	    !sc->config.swBeaconProcess)
+		sc->imask |= ATH9K_INT_TIM;
 
-	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
 	if (conf->type == NL80211_IFTYPE_AP) {
 		/* TODO: is this a suitable place to start ANI for AP mode? */
 		/* Start ANI */
-		mod_timer(&sc->sc_ani.timer,
+		mod_timer(&sc->ani.timer,
 			  jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
 	}
 
+	mutex_unlock(&sc->mutex);
+
 	return 0;
 }
 
@@ -2180,24 +2188,28 @@
 				   struct ieee80211_if_init_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_vap *avp = (void *)conf->vif->drv_priv;
+	struct ath_vif *avp = (void *)conf->vif->drv_priv;
 
 	DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
 
+	mutex_lock(&sc->mutex);
+
 	/* Stop ANI */
-	del_timer_sync(&sc->sc_ani.timer);
+	del_timer_sync(&sc->ani.timer);
 
 	/* Reclaim beacon resources */
-	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP ||
-	    sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) {
+	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
+	    sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) {
 		ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 		ath_beacon_return(sc, avp);
 	}
 
 	sc->sc_flags &= ~SC_OP_BEACONS;
 
-	sc->sc_vaps[0] = NULL;
-	sc->sc_nvaps--;
+	sc->vifs[0] = NULL;
+	sc->nvifs--;
+
+	mutex_unlock(&sc->mutex);
 }
 
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -2206,12 +2218,13 @@
 	struct ieee80211_conf *conf = &hw->conf;
 
 	mutex_lock(&sc->mutex);
+
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
 		if (conf->flags & IEEE80211_CONF_PS) {
-			if ((sc->sc_imask & ATH9K_INT_TIM_TIMER) == 0) {
-				sc->sc_imask |= ATH9K_INT_TIM_TIMER;
+			if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
+				sc->imask |= ATH9K_INT_TIM_TIMER;
 				ath9k_hw_set_interrupts(sc->sc_ah,
-						sc->sc_imask);
+						sc->imask);
 			}
 			ath9k_hw_setrxabort(sc->sc_ah, 1);
 			ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
@@ -2219,10 +2232,10 @@
 			ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 			ath9k_hw_setrxabort(sc->sc_ah, 0);
 			sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
-			if (sc->sc_imask & ATH9K_INT_TIM_TIMER) {
-				sc->sc_imask &= ~ATH9K_INT_TIM_TIMER;
+			if (sc->imask & ATH9K_INT_TIM_TIMER) {
+				sc->imask &= ~ATH9K_INT_TIM_TIMER;
 				ath9k_hw_set_interrupts(sc->sc_ah,
-						sc->sc_imask);
+						sc->imask);
 			}
 		}
 	}
@@ -2235,11 +2248,11 @@
 			curchan->center_freq);
 
 		/* XXX: remove me eventualy */
-		ath9k_update_ichannel(sc, &sc->sc_ah->ah_channels[pos]);
+		ath9k_update_ichannel(sc, &sc->sc_ah->channels[pos]);
 
 		ath_update_chainmask(sc, conf_is_ht(conf));
 
-		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
+		if (ath_set_channel(sc, &sc->sc_ah->channels[pos]) < 0) {
 			DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
 			mutex_unlock(&sc->mutex);
 			return -EINVAL;
@@ -2247,9 +2260,10 @@
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER)
-		sc->sc_config.txpowlimit = 2 * conf->power_level;
+		sc->config.txpowlimit = 2 * conf->power_level;
 
 	mutex_unlock(&sc->mutex);
+
 	return 0;
 }
 
@@ -2258,18 +2272,20 @@
 				  struct ieee80211_if_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_hal *ah = sc->sc_ah;
-	struct ath_vap *avp = (void *)vif->drv_priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_vif *avp = (void *)vif->drv_priv;
 	u32 rfilt = 0;
 	int error, i;
 
 	/* TODO: Need to decide which hw opmode to use for multi-interface
 	 * cases */
 	if (vif->type == NL80211_IFTYPE_AP &&
-	    ah->ah_opmode != NL80211_IFTYPE_AP) {
-		ah->ah_opmode = NL80211_IFTYPE_STATION;
+	    ah->opmode != NL80211_IFTYPE_AP) {
+		ah->opmode = NL80211_IFTYPE_STATION;
 		ath9k_hw_setopmode(ah);
-		ath9k_hw_write_associd(ah, sc->sc_myaddr, 0);
+		memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN);
+		sc->curaid = 0;
+		ath9k_hw_write_associd(sc);
 		/* Request full reset to get hw opmode changed properly */
 		sc->sc_flags |= SC_OP_FULL_RESET;
 	}
@@ -2280,17 +2296,16 @@
 		case NL80211_IFTYPE_STATION:
 		case NL80211_IFTYPE_ADHOC:
 			/* Set BSSID */
-			memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
-			sc->sc_curaid = 0;
-			ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
-					       sc->sc_curaid);
+			memcpy(sc->curbssid, conf->bssid, ETH_ALEN);
+			sc->curaid = 0;
+			ath9k_hw_write_associd(sc);
 
 			/* Set aggregation protection mode parameters */
-			sc->sc_config.ath_aggr_prot = 0;
+			sc->config.ath_aggr_prot = 0;
 
 			DPRINTF(sc, ATH_DBG_CONFIG,
 				"RX filter 0x%x bssid %pM aid 0x%x\n",
-				rfilt, sc->sc_curbssid, sc->sc_curaid);
+				rfilt, sc->curbssid, sc->curaid);
 
 			/* need to reconfigure the beacon */
 			sc->sc_flags &= ~SC_OP_BEACONS ;
@@ -2330,7 +2345,7 @@
 			if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
 				ath9k_hw_keysetmac(sc->sc_ah,
 						   (u16)i,
-						   sc->sc_curbssid);
+						   sc->curbssid);
 	}
 
 	/* Only legacy IBSS for now */
@@ -2366,8 +2381,11 @@
 	ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
 
 	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
-			ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0);
+		if (*total_flags & FIF_BCN_PRBRESP_PROMISC) {
+			memcpy(sc->curbssid, ath_bcast_mac, ETH_ALEN);
+			sc->curaid = 0;
+			ath9k_hw_write_associd(sc);
+		}
 	}
 
 	DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
@@ -2392,8 +2410,7 @@
 	}
 }
 
-static int ath9k_conf_tx(struct ieee80211_hw *hw,
-			 u16 queue,
+static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
 			 const struct ieee80211_tx_queue_params *params)
 {
 	struct ath_softc *sc = hw->priv;
@@ -2403,6 +2420,8 @@
 	if (queue >= WME_NUM_AC)
 		return 0;
 
+	mutex_lock(&sc->mutex);
+
 	qi.tqi_aifs = params->aifs;
 	qi.tqi_cwmin = params->cw_min;
 	qi.tqi_cwmax = params->cw_max;
@@ -2419,6 +2438,8 @@
 	if (ret)
 		DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n");
 
+	mutex_unlock(&sc->mutex);
+
 	return ret;
 }
 
@@ -2431,6 +2452,7 @@
 	struct ath_softc *sc = hw->priv;
 	int ret = 0;
 
+	mutex_lock(&sc->mutex);
 	ath9k_ps_wakeup(sc);
 	DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n");
 
@@ -2456,6 +2478,8 @@
 	}
 
 	ath9k_ps_restore(sc);
+	mutex_unlock(&sc->mutex);
+
 	return ret;
 }
 
@@ -2466,6 +2490,8 @@
 {
 	struct ath_softc *sc = hw->priv;
 
+	mutex_lock(&sc->mutex);
+
 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
 		DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
 			bss_conf->use_short_preamble);
@@ -2490,15 +2516,18 @@
 			bss_conf->assoc);
 		ath9k_bss_assoc_info(sc, vif, bss_conf);
 	}
+
+	mutex_unlock(&sc->mutex);
 }
 
 static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
 {
 	u64 tsf;
 	struct ath_softc *sc = hw->priv;
-	struct ath_hal *ah = sc->sc_ah;
 
-	tsf = ath9k_hw_gettsf64(ah);
+	mutex_lock(&sc->mutex);
+	tsf = ath9k_hw_gettsf64(sc->sc_ah);
+	mutex_unlock(&sc->mutex);
 
 	return tsf;
 }
@@ -2506,23 +2535,25 @@
 static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_hal *ah = sc->sc_ah;
 
-	ath9k_hw_settsf64(ah, tsf);
+	mutex_lock(&sc->mutex);
+	ath9k_hw_settsf64(sc->sc_ah, tsf);
+	mutex_unlock(&sc->mutex);
 }
 
 static void ath9k_reset_tsf(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_hal *ah = sc->sc_ah;
 
-	ath9k_hw_reset_tsf(ah);
+	mutex_lock(&sc->mutex);
+	ath9k_hw_reset_tsf(sc->sc_ah);
+	mutex_unlock(&sc->mutex);
 }
 
 static int ath9k_ampdu_action(struct ieee80211_hw *hw,
-		       enum ieee80211_ampdu_mlme_action action,
-		       struct ieee80211_sta *sta,
-		       u16 tid, u16 *ssn)
+			      enum ieee80211_ampdu_mlme_action action,
+			      struct ieee80211_sta *sta,
+			      u16 tid, u16 *ssn)
 {
 	struct ath_softc *sc = hw->priv;
 	int ret = 0;
diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath9k/pci.c
index 05612bf..c28afe4 100644
--- a/drivers/net/wireless/ath9k/pci.c
+++ b/drivers/net/wireless/ath9k/pci.c
@@ -16,9 +16,7 @@
 
 #include <linux/nl80211.h>
 #include <linux/pci.h>
-#include "core.h"
-#include "reg.h"
-#include "hw.h"
+#include "ath9k.h"
 
 static struct pci_device_id ath_pci_id_table[] __devinitdata = {
 	{ PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI   */
@@ -58,7 +56,7 @@
 	pci_disable_device(pdev);
 }
 
-static bool ath_pci_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
+static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
 {
 	(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
 
@@ -89,7 +87,7 @@
 	u8 csz;
 	u32 val;
 	int ret = 0;
-	struct ath_hal *ah;
+	struct ath_hw *ah;
 
 	if (pci_enable_device(pdev))
 		return -EIO;
@@ -192,10 +190,10 @@
 	       "%s: Atheros AR%s MAC/BB Rev:%x "
 	       "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
 	       wiphy_name(hw->wiphy),
-	       ath_mac_bb_name(ah->ah_macVersion),
-	       ah->ah_macRev,
-	       ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
-	       ah->ah_phyRev,
+	       ath_mac_bb_name(ah->hw_version.macVersion),
+	       ah->hw_version.macRev,
+	       ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)),
+	       ah->hw_version.phyRev,
 	       (unsigned long)mem, pdev->irq);
 
 	return 0;
@@ -230,7 +228,7 @@
 	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
 #endif
 
@@ -271,7 +269,7 @@
 	 * check the h/w rfkill state on resume
 	 * and start the rfkill poll timer
 	 */
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		queue_delayed_work(sc->hw->workqueue,
 				   &sc->rf_kill.rfkill_poll, 0);
 #endif
diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c
index 766982a..52aa2a7 100644
--- a/drivers/net/wireless/ath9k/phy.c
+++ b/drivers/net/wireless/ath9k/phy.c
@@ -14,22 +14,17 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
-#include "hw.h"
-#include "reg.h"
-#include "phy.h"
+#include "ath9k.h"
 
 void
-ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, u32 freqIndex,
+ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex,
 		    int regWrites)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	REG_WRITE_ARRAY(&ahp->ah_iniBB_RfGain, freqIndex, regWrites);
+	REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites);
 }
 
 bool
-ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan)
+ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	u32 channelSel = 0;
 	u32 bModeSynth = 0;
@@ -95,15 +90,14 @@
 
 	REG_WRITE(ah, AR_PHY(0x37), reg32);
 
-	ah->ah_curchan = chan;
-
-	AH5416(ah)->ah_curchanRadIndex = -1;
+	ah->curchan = chan;
+	ah->curchan_rad_index = -1;
 
 	return true;
 }
 
 bool
-ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
+ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
 			    struct ath9k_channel *chan)
 {
 	u16 bMode, fracMode, aModeRefSel = 0;
@@ -166,9 +160,8 @@
 
 	REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
 
-	ah->ah_curchan = chan;
-
-	AH5416(ah)->ah_curchanRadIndex = -1;
+	ah->curchan = chan;
+	ah->curchan_rad_index = -1;
 
 	return true;
 }
@@ -201,11 +194,9 @@
 }
 
 bool
-ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan,
 		     u16 modesIndex)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	u32 eepMinorRev;
 	u32 ob5GHz = 0, db5GHz = 0;
 	u32 ob2GHz = 0, db2GHz = 0;
@@ -214,161 +205,156 @@
 	if (AR_SREV_9280_10_OR_LATER(ah))
 		return true;
 
-	eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV);
+	eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
 
-	RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
+	RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1);
 
-	RF_BANK_SETUP(ahp->ah_analogBank1Data, &ahp->ah_iniBank1, 1);
+	RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1);
 
-	RF_BANK_SETUP(ahp->ah_analogBank2Data, &ahp->ah_iniBank2, 1);
+	RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1);
 
-	RF_BANK_SETUP(ahp->ah_analogBank3Data, &ahp->ah_iniBank3,
+	RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3,
 		      modesIndex);
 	{
 		int i;
-		for (i = 0; i < ahp->ah_iniBank6TPC.ia_rows; i++) {
-			ahp->ah_analogBank6Data[i] =
-			    INI_RA(&ahp->ah_iniBank6TPC, i, modesIndex);
+		for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) {
+			ah->analogBank6Data[i] =
+			    INI_RA(&ah->iniBank6TPC, i, modesIndex);
 		}
 	}
 
 	if (eepMinorRev >= 2) {
 		if (IS_CHAN_2GHZ(chan)) {
-			ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2);
-			db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2);
-			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
+			ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2);
+			db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2);
+			ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
 						   ob2GHz, 3, 197, 0);
-			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
+			ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
 						   db2GHz, 3, 194, 0);
 		} else {
-			ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5);
-			db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5);
-			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
+			ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5);
+			db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5);
+			ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
 						   ob5GHz, 3, 203, 0);
-			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
+			ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
 						   db5GHz, 3, 200, 0);
 		}
 	}
 
-	RF_BANK_SETUP(ahp->ah_analogBank7Data, &ahp->ah_iniBank7, 1);
+	RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1);
 
-	REG_WRITE_RF_ARRAY(&ahp->ah_iniBank0, ahp->ah_analogBank0Data,
+	REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
 			   regWrites);
-	REG_WRITE_RF_ARRAY(&ahp->ah_iniBank1, ahp->ah_analogBank1Data,
+	REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data,
 			   regWrites);
-	REG_WRITE_RF_ARRAY(&ahp->ah_iniBank2, ahp->ah_analogBank2Data,
+	REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data,
 			   regWrites);
-	REG_WRITE_RF_ARRAY(&ahp->ah_iniBank3, ahp->ah_analogBank3Data,
+	REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data,
 			   regWrites);
-	REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6TPC, ahp->ah_analogBank6Data,
+	REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data,
 			   regWrites);
-	REG_WRITE_RF_ARRAY(&ahp->ah_iniBank7, ahp->ah_analogBank7Data,
+	REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data,
 			   regWrites);
 
 	return true;
 }
 
 void
-ath9k_hw_rfdetach(struct ath_hal *ah)
+ath9k_hw_rfdetach(struct ath_hw *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (ahp->ah_analogBank0Data != NULL) {
-		kfree(ahp->ah_analogBank0Data);
-		ahp->ah_analogBank0Data = NULL;
+	if (ah->analogBank0Data != NULL) {
+		kfree(ah->analogBank0Data);
+		ah->analogBank0Data = NULL;
 	}
-	if (ahp->ah_analogBank1Data != NULL) {
-		kfree(ahp->ah_analogBank1Data);
-		ahp->ah_analogBank1Data = NULL;
+	if (ah->analogBank1Data != NULL) {
+		kfree(ah->analogBank1Data);
+		ah->analogBank1Data = NULL;
 	}
-	if (ahp->ah_analogBank2Data != NULL) {
-		kfree(ahp->ah_analogBank2Data);
-		ahp->ah_analogBank2Data = NULL;
+	if (ah->analogBank2Data != NULL) {
+		kfree(ah->analogBank2Data);
+		ah->analogBank2Data = NULL;
 	}
-	if (ahp->ah_analogBank3Data != NULL) {
-		kfree(ahp->ah_analogBank3Data);
-		ahp->ah_analogBank3Data = NULL;
+	if (ah->analogBank3Data != NULL) {
+		kfree(ah->analogBank3Data);
+		ah->analogBank3Data = NULL;
 	}
-	if (ahp->ah_analogBank6Data != NULL) {
-		kfree(ahp->ah_analogBank6Data);
-		ahp->ah_analogBank6Data = NULL;
+	if (ah->analogBank6Data != NULL) {
+		kfree(ah->analogBank6Data);
+		ah->analogBank6Data = NULL;
 	}
-	if (ahp->ah_analogBank6TPCData != NULL) {
-		kfree(ahp->ah_analogBank6TPCData);
-		ahp->ah_analogBank6TPCData = NULL;
+	if (ah->analogBank6TPCData != NULL) {
+		kfree(ah->analogBank6TPCData);
+		ah->analogBank6TPCData = NULL;
 	}
-	if (ahp->ah_analogBank7Data != NULL) {
-		kfree(ahp->ah_analogBank7Data);
-		ahp->ah_analogBank7Data = NULL;
+	if (ah->analogBank7Data != NULL) {
+		kfree(ah->analogBank7Data);
+		ah->analogBank7Data = NULL;
 	}
-	if (ahp->ah_addac5416_21 != NULL) {
-		kfree(ahp->ah_addac5416_21);
-		ahp->ah_addac5416_21 = NULL;
+	if (ah->addac5416_21 != NULL) {
+		kfree(ah->addac5416_21);
+		ah->addac5416_21 = NULL;
 	}
-	if (ahp->ah_bank6Temp != NULL) {
-		kfree(ahp->ah_bank6Temp);
-		ahp->ah_bank6Temp = NULL;
+	if (ah->bank6Temp != NULL) {
+		kfree(ah->bank6Temp);
+		ah->bank6Temp = NULL;
 	}
 }
 
-bool ath9k_hw_init_rf(struct ath_hal *ah, int *status)
+bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
 	if (!AR_SREV_9280_10_OR_LATER(ah)) {
+		ah->analogBank0Data =
+		    kzalloc((sizeof(u32) *
+			     ah->iniBank0.ia_rows), GFP_KERNEL);
+		ah->analogBank1Data =
+		    kzalloc((sizeof(u32) *
+			     ah->iniBank1.ia_rows), GFP_KERNEL);
+		ah->analogBank2Data =
+		    kzalloc((sizeof(u32) *
+			     ah->iniBank2.ia_rows), GFP_KERNEL);
+		ah->analogBank3Data =
+		    kzalloc((sizeof(u32) *
+			     ah->iniBank3.ia_rows), GFP_KERNEL);
+		ah->analogBank6Data =
+		    kzalloc((sizeof(u32) *
+			     ah->iniBank6.ia_rows), GFP_KERNEL);
+		ah->analogBank6TPCData =
+		    kzalloc((sizeof(u32) *
+			     ah->iniBank6TPC.ia_rows), GFP_KERNEL);
+		ah->analogBank7Data =
+		    kzalloc((sizeof(u32) *
+			     ah->iniBank7.ia_rows), GFP_KERNEL);
 
-		ahp->ah_analogBank0Data =
-		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniBank0.ia_rows), GFP_KERNEL);
-		ahp->ah_analogBank1Data =
-		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniBank1.ia_rows), GFP_KERNEL);
-		ahp->ah_analogBank2Data =
-		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniBank2.ia_rows), GFP_KERNEL);
-		ahp->ah_analogBank3Data =
-		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniBank3.ia_rows), GFP_KERNEL);
-		ahp->ah_analogBank6Data =
-		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
-		ahp->ah_analogBank6TPCData =
-		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniBank6TPC.ia_rows), GFP_KERNEL);
-		ahp->ah_analogBank7Data =
-		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniBank7.ia_rows), GFP_KERNEL);
-
-		if (ahp->ah_analogBank0Data == NULL
-		    || ahp->ah_analogBank1Data == NULL
-		    || ahp->ah_analogBank2Data == NULL
-		    || ahp->ah_analogBank3Data == NULL
-		    || ahp->ah_analogBank6Data == NULL
-		    || ahp->ah_analogBank6TPCData == NULL
-		    || ahp->ah_analogBank7Data == NULL) {
+		if (ah->analogBank0Data == NULL
+		    || ah->analogBank1Data == NULL
+		    || ah->analogBank2Data == NULL
+		    || ah->analogBank3Data == NULL
+		    || ah->analogBank6Data == NULL
+		    || ah->analogBank6TPCData == NULL
+		    || ah->analogBank7Data == NULL) {
 			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
 				"Cannot allocate RF banks\n");
 			*status = -ENOMEM;
 			return false;
 		}
 
-		ahp->ah_addac5416_21 =
+		ah->addac5416_21 =
 		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniAddac.ia_rows *
-			     ahp->ah_iniAddac.ia_columns), GFP_KERNEL);
-		if (ahp->ah_addac5416_21 == NULL) {
+			     ah->iniAddac.ia_rows *
+			     ah->iniAddac.ia_columns), GFP_KERNEL);
+		if (ah->addac5416_21 == NULL) {
 			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-				"Cannot allocate ah_addac5416_21\n");
+				"Cannot allocate addac5416_21\n");
 			*status = -ENOMEM;
 			return false;
 		}
 
-		ahp->ah_bank6Temp =
+		ah->bank6Temp =
 		    kzalloc((sizeof(u32) *
-			     ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
-		if (ahp->ah_bank6Temp == NULL) {
+			     ah->iniBank6.ia_rows), GFP_KERNEL);
+		if (ah->bank6Temp == NULL) {
 			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-				"Cannot allocate ah_bank6Temp\n");
+				"Cannot allocate bank6Temp\n");
 			*status = -ENOMEM;
 			return false;
 		}
@@ -378,24 +364,23 @@
 }
 
 void
-ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan)
+ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	int i, regWrites = 0;
-	struct ath_hal_5416 *ahp = AH5416(ah);
 	u32 bank6SelMask;
-	u32 *bank6Temp = ahp->ah_bank6Temp;
+	u32 *bank6Temp = ah->bank6Temp;
 
-	switch (ahp->ah_diversityControl) {
+	switch (ah->diversity_control) {
 	case ATH9K_ANT_FIXED_A:
 		bank6SelMask =
-		    (ahp->
-		     ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
+		    (ah->
+		     antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
 		    REDUCE_CHAIN_1;
 		break;
 	case ATH9K_ANT_FIXED_B:
 		bank6SelMask =
-		    (ahp->
-		     ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
+		    (ah->
+		     antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
 		    REDUCE_CHAIN_0;
 		break;
 	case ATH9K_ANT_VARIABLE:
@@ -406,8 +391,8 @@
 		break;
 	}
 
-	for (i = 0; i < ahp->ah_iniBank6.ia_rows; i++)
-		bank6Temp[i] = ahp->ah_analogBank6Data[i];
+	for (i = 0; i < ah->iniBank6.ia_rows; i++)
+		bank6Temp[i] = ah->analogBank6Data[i];
 
 	REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask);
 
@@ -421,7 +406,7 @@
 	ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0);
 	ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0);
 
-	REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6, bank6Temp, regWrites);
+	REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites);
 
 	REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053);
 #ifdef ALTER_SWITCH
diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h
index 3a406a5..837a598 100644
--- a/drivers/net/wireless/ath9k/phy.h
+++ b/drivers/net/wireless/ath9k/phy.h
@@ -17,19 +17,19 @@
 #ifndef PHY_H
 #define PHY_H
 
-bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
+bool ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
 				 struct ath9k_channel
 				 *chan);
-bool ath9k_hw_set_channel(struct ath_hal *ah,
+bool ath9k_hw_set_channel(struct ath_hw *ah,
 			  struct ath9k_channel *chan);
-void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex,
+void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex,
 			 u32 freqIndex, int regWrites);
-bool ath9k_hw_set_rf_regs(struct ath_hal *ah,
+bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
 			  struct ath9k_channel *chan,
 			  u16 modesIndex);
-void ath9k_hw_decrease_chain_power(struct ath_hal *ah,
+void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
 				   struct ath9k_channel *chan);
-bool ath9k_hw_init_rf(struct ath_hal *ah,
+bool ath9k_hw_init_rf(struct ath_hw *ah,
 		      int *status);
 
 #define AR_PHY_BASE     0x9800
@@ -533,7 +533,7 @@
 #define ATH9K_KEY_XOR                 0xaa
 
 #define ATH9K_IS_MIC_ENABLED(ah)					\
-	(AH5416(ah)->ah_staId1Defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
+	((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
 
 #define ANTSWAP_AB 0x0001
 #define REDUCE_CHAIN_0 0x00000050
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index 704b627..a4e8631 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -15,7 +15,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
+#include "ath9k.h"
 
 static struct ath_rate_table ar5416_11na_ratetable = {
 	42,
@@ -1267,6 +1267,8 @@
 		ath_rc_priv->per_down_time = now_msec;
 	}
 
+	ath_debug_stat_retries(sc, tx_rate, xretries, retries);
+
 #undef CHK_RSSI
 }
 
@@ -1392,13 +1394,13 @@
 	u8 i, j, k, hi = 0, hthi = 0;
 
 	/* FIXME: Adhoc */
-	if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) ||
-	    (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) {
+	if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) ||
+	    (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) {
 		bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 		rate_table = ath_choose_rate_table(sc, sband->band,
 						   sta->ht_cap.ht_supported,
 						   is_cw_40);
-	} else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
+	} else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
 		/* cur_rate_table would be set on init through config() */
 		rate_table = sc->cur_rate_table;
 	}
@@ -1410,7 +1412,7 @@
 
 	if (sta->ht_cap.ht_supported) {
 		ath_rc_priv->ht_cap = WLAN_RC_HT_FLAG;
-		if (sc->sc_ah->ah_caps.tx_chainmask != 1)
+		if (sc->sc_ah->caps.tx_chainmask != 1)
 			ath_rc_priv->ht_cap |= WLAN_RC_DS_FLAG;
 		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 			ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
@@ -1517,7 +1519,7 @@
 	 */
 	if (tx_info_priv->tx.ts_flags &
 	    (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
-	    ((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) {
+	    ((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) {
 		tx_status = 1;
 		is_underrun = 1;
 	}
@@ -1626,7 +1628,7 @@
 	}
 
 	rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
-	rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max;
+	rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
 
 	return rate_priv;
 }
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h
index a987cb9..d688ec51 100644
--- a/drivers/net/wireless/ath9k/rc.h
+++ b/drivers/net/wireless/ath9k/rc.h
@@ -19,13 +19,12 @@
 #ifndef RC_H
 #define RC_H
 
-#include "ath9k.h"
-
 struct ath_softc;
 
 #define ATH_RATE_MAX     30
 #define RATE_TABLE_SIZE  64
 #define MAX_TX_RATE_PHY  48
+#define WLAN_CTRL_FRAME_SIZE (2+2+6+4)
 
 /* VALID_ALL - valid for 20/40/Legacy,
  * VALID - Legacy only,
@@ -39,6 +38,20 @@
 #define VALID_2040 (VALID_20|VALID_40)
 #define VALID_ALL  (VALID_2040|VALID)
 
+enum {
+	WLAN_RC_PHY_OFDM,
+	WLAN_RC_PHY_CCK,
+	WLAN_RC_PHY_HT_20_SS,
+	WLAN_RC_PHY_HT_20_DS,
+	WLAN_RC_PHY_HT_40_SS,
+	WLAN_RC_PHY_HT_40_DS,
+	WLAN_RC_PHY_HT_20_SS_HGI,
+	WLAN_RC_PHY_HT_20_DS_HGI,
+	WLAN_RC_PHY_HT_40_SS_HGI,
+	WLAN_RC_PHY_HT_40_DS_HGI,
+	WLAN_RC_PHY_MAX
+};
+
 #define WLAN_RC_PHY_DS(_phy)   ((_phy == WLAN_RC_PHY_HT_20_DS)		\
 				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\
 				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)	\
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 8da08f9..08f676a 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
+#include "ath9k.h"
 
 /*
  * Setup and link descriptors.
@@ -26,7 +26,7 @@
  */
 static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_desc *ds;
 	struct sk_buff *skb;
 
@@ -97,11 +97,11 @@
 	 * Unfortunately this means we may get 8 KB here from the
 	 * kernel... and that is actually what is observed on some
 	 * systems :( */
-	skb = dev_alloc_skb(len + sc->sc_cachelsz - 1);
+	skb = dev_alloc_skb(len + sc->cachelsz - 1);
 	if (skb != NULL) {
-		off = ((unsigned long) skb->data) % sc->sc_cachelsz;
+		off = ((unsigned long) skb->data) % sc->cachelsz;
 		if (off != 0)
-			skb_reserve(skb, sc->sc_cachelsz - off);
+			skb_reserve(skb, sc->cachelsz - off);
 	} else {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"skbuff alloc of size %u failed\n", len);
@@ -135,7 +135,7 @@
 		 * discard the frame. Enable this if you want to see
 		 * error frames in Monitor mode.
 		 */
-		if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_MONITOR)
+		if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR)
 			goto rx_next;
 	} else if (ds->ds_rxstat.rs_status != 0) {
 		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
@@ -161,7 +161,7 @@
 		 * decryption and MIC failures. For monitor mode,
 		 * we also ignore the CRC error.
 		 */
-		if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR) {
+		if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) {
 			if (ds->ds_rxstat.rs_status &
 			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
 			      ATH9K_RXERR_CRC))
@@ -210,7 +210,7 @@
 	rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
 	rx_status->band = sc->hw->conf.channel->band;
 	rx_status->freq =  sc->hw->conf.channel->center_freq;
-	rx_status->noise = sc->sc_ani.sc_noise_floor;
+	rx_status->noise = sc->ani.noise_floor;
 	rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
 	rx_status->antenna = ds->ds_rxstat.rs_antenna;
 
@@ -233,7 +233,7 @@
 
 static void ath_opmode_init(struct ath_softc *sc)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	u32 rfilt, mfilt[2];
 
 	/* configure rx filter */
@@ -241,14 +241,14 @@
 	ath9k_hw_setrxfilter(ah, rfilt);
 
 	/* configure bssid mask */
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
-		ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+		ath9k_hw_setbssidmask(sc);
 
 	/* configure operational mode */
 	ath9k_hw_setopmode(ah);
 
 	/* Handle any link-level address change. */
-	ath9k_hw_setmac(ah, sc->sc_myaddr);
+	ath9k_hw_setmac(ah, sc->sc_ah->macaddr);
 
 	/* calculate and install multicast filter */
 	mfilt[0] = mfilt[1] = ~0;
@@ -267,11 +267,11 @@
 		spin_lock_init(&sc->rx.rxbuflock);
 
 		sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
-					   min(sc->sc_cachelsz,
+					   min(sc->cachelsz,
 					       (u16)64));
 
 		DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
-			sc->sc_cachelsz, sc->rx.bufsize);
+			sc->cachelsz, sc->rx.bufsize);
 
 		/* Initialize rx descriptors */
 
@@ -360,25 +360,28 @@
 		| ATH9K_RX_FILTER_MCAST;
 
 	/* If not a STA, enable processing of Probe Requests */
-	if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_STATION)
+	if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
 		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
 
 	/* Can't set HOSTAP into promiscous mode */
-	if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) &&
+	if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) &&
 	     (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) ||
-	    (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) {
+	    (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR)) {
 		rfilt |= ATH9K_RX_FILTER_PROM;
 		/* ??? To prevent from sending ACK */
 		rfilt &= ~ATH9K_RX_FILTER_UCAST;
 	}
 
-	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION ||
-	    sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)
+	if (sc->rx.rxfilter & FIF_CONTROL)
+		rfilt |= ATH9K_RX_FILTER_CONTROL;
+
+	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION ||
+	    sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
 		rfilt |= ATH9K_RX_FILTER_BEACON;
 
 	/* If in HOSTAP mode, want to enable reception of PSPOLL frames
 	   & beacon frames */
-	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP)
+	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP)
 		rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
 
 	return rfilt;
@@ -388,7 +391,7 @@
 
 int ath_startrecv(struct ath_softc *sc)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_buf *bf, *tbf;
 
 	spin_lock_bh(&sc->rx.rxbuflock);
@@ -418,7 +421,7 @@
 
 bool ath_stoprecv(struct ath_softc *sc)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	bool stopped;
 
 	ath9k_hw_stoppcurecv(ah);
@@ -449,7 +452,7 @@
 	struct ath_desc *ds;
 	struct sk_buff *skb = NULL, *requeue_skb;
 	struct ieee80211_rx_status rx_status;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ieee80211_hdr *hdr;
 	int hdrlen, padsize, retval;
 	bool decrypt_error = false;
@@ -590,7 +593,7 @@
 			   && !decrypt_error && skb->len >= hdrlen + 4) {
 			keyix = skb->data[hdrlen + 3] >> 6;
 
-			if (test_bit(keyix, sc->sc_keymap))
+			if (test_bit(keyix, sc->keymap))
 				rx_status.flag |= RX_FLAG_DECRYPTED;
 		}
 		if (ah->sw_mgmt_crypto &&
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h
index c967b79..17ed190 100644
--- a/drivers/net/wireless/ath9k/reg.h
+++ b/drivers/net/wireless/ath9k/reg.h
@@ -160,6 +160,7 @@
 
 #define AR_SREV_VERSION_9100                  0x014
 
+#define AR_SREV_9100(ah) ((ah->hw_version.macVersion) == AR_SREV_VERSION_9100)
 #define AR_SREV_5416_V20_OR_LATER(_ah) \
 	(AR_SREV_9100((_ah)) || AR_SREV_5416_20_OR_LATER(_ah))
 #define AR_SREV_5416_V22_OR_LATER(_ah) \
@@ -746,44 +747,50 @@
 #define AR_SREV_REVISION_9285_12              2
 
 #define AR_SREV_9100_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE))
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_5416_PCIE))
 #define AR_SREV_5416_20_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion >= AR_SREV_VERSION_9160) || \
-		((_ah)->ah_macRev >= AR_SREV_REVISION_5416_20))
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160) || \
+		((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20))
 #define AR_SREV_5416_22_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion >= AR_SREV_VERSION_9160) || \
-		((_ah)->ah_macRev >= AR_SREV_REVISION_5416_22))
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160) || \
+		((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22))
 #define AR_SREV_9160(_ah) \
-	(((_ah)->ah_macVersion == AR_SREV_VERSION_9160))
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9160))
 #define AR_SREV_9160_10_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion >= AR_SREV_VERSION_9160))
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160))
 #define AR_SREV_9160_11(_ah) \
-	(AR_SREV_9160(_ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9160_11))
+	(AR_SREV_9160(_ah) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9160_11))
 #define AR_SREV_9280(_ah) \
-	(((_ah)->ah_macVersion == AR_SREV_VERSION_9280))
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280))
 #define AR_SREV_9280_10_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion >= AR_SREV_VERSION_9280))
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9280))
 #define AR_SREV_9280_20(_ah) \
-	(((_ah)->ah_macVersion == AR_SREV_VERSION_9280) && \
-		((_ah)->ah_macRev >= AR_SREV_REVISION_9280_20))
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \
+		((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20))
 #define AR_SREV_9280_20_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion > AR_SREV_VERSION_9280) || \
-	(((_ah)->ah_macVersion == AR_SREV_VERSION_9280) && \
-	((_ah)->ah_macRev >= AR_SREV_REVISION_9280_20)))
+	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9280) || \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \
+	((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20)))
 
-#define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285))
+#define AR_SREV_9285(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285))
 #define AR_SREV_9285_10_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion >= AR_SREV_VERSION_9285))
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285))
 #define AR_SREV_9285_11(_ah) \
-	(AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_11))
+	(AR_SREV_9280(ah) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_11))
 #define AR_SREV_9285_11_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \
-	 (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_11)))
+	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \
+	 (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
+			       AR_SREV_REVISION_9285_11)))
 #define AR_SREV_9285_12(_ah) \
-	(AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_12))
+	(AR_SREV_9280(ah) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_12))
 #define AR_SREV_9285_12_OR_LATER(_ah) \
-	(((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \
-	 (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_12)))
+	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \
+	 (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
+			       AR_SREV_REVISION_9285_12)))
 
 #define AR_RADIO_SREV_MAJOR                   0xf0
 #define AR_RAD5133_SREV_MAJOR                 0xc0
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c
index fe08a4f..8c2b56a 100644
--- a/drivers/net/wireless/ath9k/regd.c
+++ b/drivers/net/wireless/ath9k/regd.c
@@ -16,9 +16,7 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include "core.h"
-#include "hw.h"
-#include "regd.h"
+#include "ath9k.h"
 #include "regd_common.h"
 
 /*
@@ -108,17 +106,17 @@
 	}
 };
 
-static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah)
+static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
 {
-	return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG;
+	return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
 }
 
-u16 ath9k_regd_get_rd(struct ath_hal *ah)
+u16 ath9k_regd_get_rd(struct ath_hw *ah)
 {
 	return ath9k_regd_get_eepromRD(ah);
 }
 
-bool ath9k_is_world_regd(struct ath_hal *ah)
+bool ath9k_is_world_regd(struct ath_hw *ah)
 {
 	return isWwrSKU(ah);
 }
@@ -129,9 +127,9 @@
 	return &ath9k_world_regdom_64;
 }
 
-const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hal *ah)
+const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah)
 {
-	switch (ah->regpair->regDmnEnum) {
+	switch (ah->regulatory.regpair->regDmnEnum) {
 	case 0x60:
 	case 0x61:
 	case 0x62:
@@ -284,9 +282,9 @@
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ath_softc *sc = hw->priv;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 
-	switch (ah->regpair->regDmnEnum) {
+	switch (ah->regulatory.regpair->regDmnEnum) {
 	case 0x60:
 	case 0x63:
 	case 0x66:
@@ -324,7 +322,7 @@
 	return 0;
 }
 
-bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah)
+bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah)
 {
 	u16 rd = ath9k_regd_get_eepromRD(ah);
 	int i;
@@ -373,7 +371,7 @@
 }
 
 /* Returns the map of the EEPROM set RD to a country code */
-static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
+static u16 ath9k_regd_get_default_country(struct ath_hw *ah)
 {
 	u16 rd;
 
@@ -404,7 +402,7 @@
 	return NULL;
 }
 
-int ath9k_regd_init(struct ath_hal *ah)
+int ath9k_regd_init(struct ath_hw *ah)
 {
 	struct country_code_to_enum_rd *country = NULL;
 	int regdmn;
@@ -415,30 +413,30 @@
 		return -EINVAL;
 	}
 
-	ah->ah_countryCode = ath9k_regd_get_default_country(ah);
+	ah->regulatory.country_code = ath9k_regd_get_default_country(ah);
 
-	if (ah->ah_countryCode == CTRY_DEFAULT &&
+	if (ah->regulatory.country_code == CTRY_DEFAULT &&
 	    ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)
-		ah->ah_countryCode = CTRY_UNITED_STATES;
+		ah->regulatory.country_code = CTRY_UNITED_STATES;
 
-	if (ah->ah_countryCode == CTRY_DEFAULT) {
+	if (ah->regulatory.country_code == CTRY_DEFAULT) {
 		regdmn = ath9k_regd_get_eepromRD(ah);
 		country = NULL;
 	} else {
-		country = ath9k_regd_find_country(ah->ah_countryCode);
+		country = ath9k_regd_find_country(ah->regulatory.country_code);
 		if (country == NULL) {
 			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
 				"Country is NULL!!!!, cc= %d\n",
-				ah->ah_countryCode);
+				ah->regulatory.country_code);
 			return -EINVAL;
 		} else
 			regdmn = country->regDmnEnum;
 	}
 
-	ah->ah_currentRDInUse = regdmn;
-	ah->regpair = ath9k_get_regpair(regdmn);
+	ah->regulatory.current_rd_inuse = regdmn;
+	ah->regulatory.regpair = ath9k_get_regpair(regdmn);
 
-	if (!ah->regpair) {
+	if (!ah->regulatory.regpair) {
 		DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
 			"No regulatory domain pair found, cannot continue\n");
 		return -EINVAL;
@@ -448,28 +446,28 @@
 		country = ath9k_regd_find_country_by_rd(regdmn);
 
 	if (country) {
-		ah->alpha2[0] = country->isoName[0];
-		ah->alpha2[1] = country->isoName[1];
+		ah->regulatory.alpha2[0] = country->isoName[0];
+		ah->regulatory.alpha2[1] = country->isoName[1];
 	} else {
-		ah->alpha2[0] = '0';
-		ah->alpha2[1] = '0';
+		ah->regulatory.alpha2[0] = '0';
+		ah->regulatory.alpha2[1] = '0';
 	}
 
 	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
 		"Country alpha2 being used: %c%c\n"
-		"Regpair detected: 0x%0x\n",
-		ah->alpha2[0], ah->alpha2[1],
-		ah->regpair->regDmnEnum);
+		"Regulatory.Regpair detected: 0x%0x\n",
+		ah->regulatory.alpha2[0], ah->regulatory.alpha2[1],
+		ah->regulatory.regpair->regDmnEnum);
 
 	return 0;
 }
 
-u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
+u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	u32 ctl = NO_CTL;
 
-	if (!ah->regpair ||
-	    (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah))) {
+	if (!ah->regulatory.regpair ||
+	    (ah->regulatory.country_code == CTRY_DEFAULT && isWwrSKU(ah))) {
 		if (IS_CHAN_B(chan))
 			ctl = SD_NO_CTL | CTL_11B;
 		else if (IS_CHAN_G(chan))
@@ -480,11 +478,11 @@
 	}
 
 	if (IS_CHAN_B(chan))
-		ctl = ah->regpair->reg_2ghz_ctl | CTL_11B;
+		ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B;
 	else if (IS_CHAN_G(chan))
-		ctl = ah->regpair->reg_5ghz_ctl | CTL_11G;
+		ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11G;
 	else
-		ctl = ah->regpair->reg_5ghz_ctl | CTL_11A;
+		ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A;
 
 	return ctl;
 }
diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h
index ba2d2df..39420de 100644
--- a/drivers/net/wireless/ath9k/regd.h
+++ b/drivers/net/wireless/ath9k/regd.h
@@ -17,8 +17,6 @@
 #ifndef REGD_H
 #define REGD_H
 
-#include "ath9k.h"
-
 #define COUNTRY_ERD_FLAG        0x8000
 #define WORLDWIDE_ROAMING_FLAG  0x4000
 
@@ -47,6 +45,18 @@
 	const char *isoName;
 };
 
+struct ath9k_regulatory {
+	char alpha2[2];
+	u16 country_code;
+	u16 max_power_level;
+	u32 tp_scale;
+	u16 current_rd;
+	u16 current_rd_ext;
+	u16 current_rd_inuse;
+	int16_t power_limit;
+	struct reg_dmn_pair_mapping *regpair;
+};
+
 enum CountryCode {
 	CTRY_ALBANIA = 8,
 	CTRY_ALGERIA = 12,
@@ -229,7 +239,17 @@
 	CTRY_BELGIUM2 = 5002
 };
 
-void ath9k_regd_get_current_country(struct ath_hal *ah,
+u16 ath9k_regd_get_rd(struct ath_hw *ah);
+bool ath9k_is_world_regd(struct ath_hw *ah);
+const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah);
+const struct ieee80211_regdomain *ath9k_default_world_regdomain(void);
+void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby);
+void ath9k_reg_apply_radar_flags(struct wiphy *wiphy);
+int ath9k_regd_init(struct ath_hw *ah);
+bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah);
+u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan);
+int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+void ath9k_regd_get_current_country(struct ath_hw *ah,
 				    struct ath9k_country_entry *ctry);
 
 #endif
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index e14bcea..3f70b1e 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
+#include "ath9k.h"
 
 #define BITS_PER_BYTE           8
 #define OFDM_PLCP_BITS          22
@@ -308,7 +308,7 @@
 			 * when perform internal reset in this routine.
 			 * Only enable reset in STA mode for now.
 			 */
-			if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION)
+			if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
 				needreset = 1;
 		}
 	}
@@ -809,7 +809,7 @@
 
 struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath9k_tx_queue_info qi;
 	int qnum;
 
@@ -926,7 +926,7 @@
 int ath_txq_update(struct ath_softc *sc, int qnum,
 		   struct ath9k_tx_queue_info *qinfo)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	int error = 0;
 	struct ath9k_tx_queue_info qi;
 
@@ -970,14 +970,14 @@
 	/*
 	 * Ensure the readytime % is within the bounds.
 	 */
-	if (sc->sc_config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
-		sc->sc_config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
-	else if (sc->sc_config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
-		sc->sc_config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
+	if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
+		sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
+	else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
+		sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
 
 	ath_get_beaconconfig(sc, ATH_IF_ID_ANY, &conf);
 	qi.tqi_readyTime =
-		(conf.beacon_interval * sc->sc_config.cabqReadytime) / 100;
+		(conf.beacon_interval * sc->config.cabqReadytime) / 100;
 	ath_txq_update(sc, qnum, &qi);
 
 	return 0;
@@ -1047,7 +1047,7 @@
 
 void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_txq *txq;
 	int i, npend = 0;
 
@@ -1072,7 +1072,7 @@
 		DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n");
 
 		spin_lock_bh(&sc->sc_resetlock);
-		r = ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, true);
+		r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);
 		if (r)
 			DPRINTF(sc, ATH_DBG_FATAL,
 				"Unable to reset hardware; reset status %u\n",
@@ -1165,7 +1165,7 @@
 static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 			     struct list_head *head)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_buf *bf;
 
 	/*
@@ -1436,14 +1436,18 @@
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *tx_info;
 	struct ieee80211_tx_rate *rates;
+	struct ieee80211_hdr *hdr;
 	int i, flags = 0;
 	u8 rix = 0, ctsrate = 0;
+	bool is_pspoll;
 
 	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
 
 	skb = (struct sk_buff *)bf->bf_mpdu;
 	tx_info = IEEE80211_SKB_CB(skb);
 	rates = tx_info->control.rates;
+	hdr = (struct ieee80211_hdr *)skb->data;
+	is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
 
 	/*
 	 * We check if Short Preamble is needed for the CTS rate by
@@ -1467,13 +1471,13 @@
 		flags = ATH9K_TXDESC_RTSENA;
 
 	/* FIXME: Handle aggregation protection */
-	if (sc->sc_config.ath_aggr_prot &&
+	if (sc->config.ath_aggr_prot &&
 	    (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
 		flags = ATH9K_TXDESC_RTSENA;
 	}
 
 	/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
-	if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->ah_caps.rts_aggr_limit))
+	if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
 		flags &= ~(ATH9K_TXDESC_RTSENA);
 
 	for (i = 0; i < 4; i++) {
@@ -1482,7 +1486,7 @@
 
 		rix = rates[i].idx;
 		series[i].Tries = rates[i].count;
-		series[i].ChSel = sc->sc_tx_chainmask;
+		series[i].ChSel = sc->tx_chainmask;
 
 		if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
 			series[i].Rate = rt->info[rix].ratecode |
@@ -1506,10 +1510,10 @@
 	/* set dur_update_en for l-sig computation except for PS-Poll frames */
 	ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
 				     bf->bf_lastbf->bf_desc,
-				     !bf_ispspoll(bf), ctsrate,
+				     !is_pspoll, ctsrate,
 				     0, series, 4, flags);
 
-	if (sc->sc_config.ath_aggr_prot && flags)
+	if (sc->config.ath_aggr_prot && flags)
 		ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
 }
 
@@ -1534,12 +1538,6 @@
 
 	bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
 
-	if (ieee80211_is_data(fc))
-		bf->bf_state.bf_type |= BUF_DATA;
-	if (ieee80211_is_back_req(fc))
-		bf->bf_state.bf_type |= BUF_BAR;
-	if (ieee80211_is_pspoll(fc))
-		bf->bf_state.bf_type |= BUF_PSPOLL;
 	if ((conf_is_ht(&sc->hw->conf) && !is_pae(skb) &&
 	     (tx_info->flags & IEEE80211_TX_CTL_AMPDU)))
 		bf->bf_state.bf_type |= BUF_HT;
@@ -1582,7 +1580,7 @@
 	struct list_head bf_head;
 	struct ath_desc *ds;
 	struct ath_atx_tid *tid;
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	int frm_type;
 
 	frm_type = get_hw_packet_type(skb);
@@ -1843,6 +1841,7 @@
 static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad)
 {
 	struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
 
@@ -1852,7 +1851,7 @@
 
 	if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
 	    (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
-		if (bf_isdata(bf)) {
+		if (ieee80211_is_data(hdr->frame_control)) {
 			memcpy(&tx_info_priv->tx, &ds->ds_txstat,
 			       sizeof(tx_info_priv->tx));
 			tx_info_priv->n_frames = bf->bf_nframes;
@@ -1880,7 +1879,7 @@
 
 static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 {
-	struct ath_hal *ah = sc->sc_ah;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_buf *bf, *lastbf, *bf_held = NULL;
 	struct list_head bf_head;
 	struct ath_desc *ds;
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index e9d60f091..b457310 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -120,6 +120,9 @@
 #define B43_MMIO_IFSCTL			0x688 /* Interframe space control */
 #define  B43_MMIO_IFSCTL_USE_EDCF	0x0004
 #define B43_MMIO_POWERUP_DELAY		0x6A8
+#define B43_MMIO_BTCOEX_CTL		0x6B4 /* Bluetooth Coexistence Control */
+#define B43_MMIO_BTCOEX_STAT		0x6B6 /* Bluetooth Coexistence Status */
+#define B43_MMIO_BTCOEX_TXCTL		0x6B8 /* Bluetooth Coexistence Transmit Control */
 
 /* SPROM boardflags_lo values */
 #define B43_BFL_BTCOEXIST		0x0001	/* implements Bluetooth coexistance */
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 94d9e8b..58e319d 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -23,6 +23,7 @@
 */
 
 #include "b43.h"
+#include "main.h"
 #include "phy_lp.h"
 #include "phy_common.h"
 #include "tables_lpphy.h"
@@ -267,13 +268,185 @@
 	}
 }
 
+/* Read the TX power control mode from hardware. */
+static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	u16 ctl;
+
+	ctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD);
+	switch (ctl & B43_LPPHY_TX_PWR_CTL_CMD_MODE) {
+	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF:
+		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_OFF;
+		break;
+	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW:
+		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_SW;
+		break;
+	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW:
+		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_HW;
+		break;
+	default:
+		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_UNKNOWN;
+		B43_WARN_ON(1);
+		break;
+	}
+}
+
+/* Set the TX power control mode in hardware. */
+static void lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	u16 ctl;
+
+	switch (lpphy->txpctl_mode) {
+	case B43_LPPHY_TXPCTL_OFF:
+		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF;
+		break;
+	case B43_LPPHY_TXPCTL_HW:
+		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW;
+		break;
+	case B43_LPPHY_TXPCTL_SW:
+		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW;
+		break;
+	default:
+		ctl = 0;
+		B43_WARN_ON(1);
+	}
+	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
+			(u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, ctl);
+}
+
+static void lpphy_set_tx_power_control(struct b43_wldev *dev,
+				       enum b43_lpphy_txpctl_mode mode)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	enum b43_lpphy_txpctl_mode oldmode;
+
+	oldmode = lpphy->txpctl_mode;
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
+	if (lpphy->txpctl_mode == mode)
+		return;
+	lpphy->txpctl_mode = mode;
+
+	if (oldmode == B43_LPPHY_TXPCTL_HW) {
+		//TODO Update TX Power NPT
+		//TODO Clear all TX Power offsets
+	} else {
+		if (mode == B43_LPPHY_TXPCTL_HW) {
+			//TODO Recalculate target TX power
+			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
+					0xFF80, lpphy->tssi_idx);
+			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
+					0x8FFF, ((u16)lpphy->tssi_npt << 16));
+			//TODO Set "TSSI Transmit Count" variable to total transmitted frame count
+			//TODO Disable TX gain override
+			lpphy->tx_pwr_idx_over = -1;
+		}
+	}
+	if (dev->phy.rev >= 2) {
+		if (mode == B43_LPPHY_TXPCTL_HW)
+			b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0x2);
+		else
+			b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0);
+	}
+	lpphy_write_tx_pctl_mode_to_hardware(dev);
+}
+
+static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+
+	lpphy->tx_pwr_idx_over = index;
+	if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
+		lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);
+
+	//TODO
+}
+
+static void lpphy_btcoex_override(struct b43_wldev *dev)
+{
+	b43_write16(dev, B43_MMIO_BTCOEX_CTL, 0x3);
+	b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
+}
+
+static void lpphy_pr41573_workaround(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	u32 *saved_tab;
+	const unsigned int saved_tab_size = 256;
+	enum b43_lpphy_txpctl_mode txpctl_mode;
+	s8 tx_pwr_idx_over;
+	u16 tssi_npt, tssi_idx;
+
+	saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL);
+	if (!saved_tab) {
+		b43err(dev->wl, "PR41573 failed. Out of memory!\n");
+		return;
+	}
+
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
+	txpctl_mode = lpphy->txpctl_mode;
+	tx_pwr_idx_over = lpphy->tx_pwr_idx_over;
+	tssi_npt = lpphy->tssi_npt;
+	tssi_idx = lpphy->tssi_idx;
+
+	if (dev->phy.rev < 2) {
+		b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140),
+				    saved_tab_size, saved_tab);
+	} else {
+		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
+				    saved_tab_size, saved_tab);
+	}
+	//TODO
+
+	kfree(saved_tab);
+}
+
+static void lpphy_calibration(struct b43_wldev *dev)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	enum b43_lpphy_txpctl_mode saved_pctl_mode;
+
+	b43_mac_suspend(dev);
+
+	lpphy_btcoex_override(dev);
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
+	saved_pctl_mode = lpphy->txpctl_mode;
+	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+	//TODO Perform transmit power table I/Q LO calibration
+	if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
+		lpphy_pr41573_workaround(dev);
+	//TODO If a full calibration has not been performed on this channel yet, perform PAPD TX-power calibration
+	lpphy_set_tx_power_control(dev, saved_pctl_mode);
+	//TODO Perform I/Q calibration with a single control value set
+
+	b43_mac_enable(dev);
+}
+
+/* Initialize TX power control */
+static void lpphy_tx_pctl_init(struct b43_wldev *dev)
+{
+	if (0/*FIXME HWPCTL capable */) {
+		//TODO
+	} else { /* This device is only software TX power control capable. */
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+			//TODO
+		} else {
+			//TODO
+		}
+		//TODO set BB multiplier to 0x0096
+	}
+}
+
 static int b43_lpphy_op_init(struct b43_wldev *dev)
 {
 	/* TODO: band SPROM */
 	lpphy_baseband_init(dev);
 	lpphy_radio_init(dev);
-
-	//TODO
+	//TODO calibrate RC
+	//TODO set channel
+	lpphy_tx_pctl_init(dev);
+	//TODO full calib
 
 	return 0;
 }
diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h
index 80703c5..18370b4 100644
--- a/drivers/net/wireless/b43/phy_lp.h
+++ b/drivers/net/wireless/b43/phy_lp.h
@@ -247,6 +247,10 @@
 #define B43_LPPHY_FOURWIRE_CTL			B43_PHY_OFDM(0xA2) /* fourwire Control */
 #define B43_LPPHY_CPA_TAILCOUNT_VAL		B43_PHY_OFDM(0xA3) /* CPA TailCount Value */
 #define B43_LPPHY_TX_PWR_CTL_CMD		B43_PHY_OFDM(0xA4) /* TX Power Control Cmd */
+#define  B43_LPPHY_TX_PWR_CTL_CMD_MODE		0xE000 /* TX power control mode mask */
+#define   B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF	0x0000 /* TX power control is OFF */
+#define   B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW	0x8000 /* TX power control is SOFTWARE */
+#define   B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW	0xE000 /* TX power control is HARDWARE */
 #define B43_LPPHY_TX_PWR_CTL_NNUM		B43_PHY_OFDM(0xA5) /* TX Power Control Nnum */
 #define B43_LPPHY_TX_PWR_CTL_IDLETSSI		B43_PHY_OFDM(0xA6) /* TX Power Control IdleTssi */
 #define B43_LPPHY_TX_PWR_CTL_TARGETPWR		B43_PHY_OFDM(0xA7) /* TX Power Control TargetPower */
@@ -802,7 +806,17 @@
 
 
 
+enum b43_lpphy_txpctl_mode {
+	B43_LPPHY_TXPCTL_UNKNOWN = 0,
+	B43_LPPHY_TXPCTL_OFF,	/* TX power control is OFF */
+	B43_LPPHY_TXPCTL_SW,	/* TX power control is set to Software */
+	B43_LPPHY_TXPCTL_HW,	/* TX power control is set to Hardware */
+};
+
 struct b43_phy_lp {
+	/* Current TX power control mode. */
+	enum b43_lpphy_txpctl_mode txpctl_mode;
+
 	/* Transmit isolation medium band */
 	u8 tx_isolation_med_band; /* FIXME initial value? */
 	/* Transmit isolation low band */
@@ -814,7 +828,7 @@
 	u8 rx_pwr_offset; /* FIXME initial value? */
 
 	/* TSSI transmit count */
-	u16 tssi_tx_count; /* FIXME initial value? */
+	u16 tssi_tx_count;
 	/* TSSI index */
 	u16 tssi_idx; /* FIXME initial value? */
 	/* TSSI npt */
diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c
index 18f6e32..4ea734d 100644
--- a/drivers/net/wireless/b43/tables_lpphy.c
+++ b/drivers/net/wireless/b43/tables_lpphy.c
@@ -303,6 +303,36 @@
 	return value;
 }
 
+void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset,
+			 unsigned int nr_elements, void *_data)
+{
+	u32 type, value;
+	u8 *data = _data;
+	unsigned int i;
+
+	type = offset & B43_LPTAB_TYPEMASK;
+	for (i = 0; i < nr_elements; i++) {
+		value = b43_lptab_read(dev, offset);
+		switch (type) {
+		case B43_LPTAB_8BIT:
+			*data = value;
+			data++;
+			break;
+		case B43_LPTAB_16BIT:
+			*((u16 *)data) = value;
+			data += 2;
+			break;
+		case B43_LPTAB_32BIT:
+			*((u32 *)data) = value;
+			data += 4;
+			break;
+		default:
+			B43_WARN_ON(1);
+		}
+		offset++;
+	}
+}
+
 void b43_lptab_write(struct b43_wldev *dev, u32 offset, u32 value)
 {
 	u32 type;
@@ -331,3 +361,34 @@
 		B43_WARN_ON(1);
 	}
 }
+
+void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset,
+			  unsigned int nr_elements, const void *_data)
+{
+	u32 type, value;
+	const u8 *data = _data;
+	unsigned int i;
+
+	type = offset & B43_LPTAB_TYPEMASK;
+	for (i = 0; i < nr_elements; i++) {
+		switch (type) {
+		case B43_LPTAB_8BIT:
+			value = *data;
+			data++;
+			break;
+		case B43_LPTAB_16BIT:
+			value = *((u16 *)data);
+			data += 2;
+			break;
+		case B43_LPTAB_32BIT:
+			value = *((u32 *)data);
+			data += 4;
+			break;
+		default:
+			B43_WARN_ON(1);
+			value = 0;
+		}
+		b43_lptab_write(dev, offset, value);
+		offset++;
+	}
+}
diff --git a/drivers/net/wireless/b43/tables_lpphy.h b/drivers/net/wireless/b43/tables_lpphy.h
index 03ea2ff..0b8d028 100644
--- a/drivers/net/wireless/b43/tables_lpphy.h
+++ b/drivers/net/wireless/b43/tables_lpphy.h
@@ -17,6 +17,14 @@
 u32 b43_lptab_read(struct b43_wldev *dev, u32 offset);
 void b43_lptab_write(struct b43_wldev *dev, u32 offset, u32 value);
 
+/* Bulk table access. Note that these functions return the bulk data in
+ * host endianness! The returned data is _not_ a bytearray, but an array
+ * consisting of nr_elements of the data type. */
+void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset,
+			 unsigned int nr_elements, void *data);
+void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset,
+			  unsigned int nr_elements, const void *data);
+
 void b2062_upload_init_table(struct b43_wldev *dev);
 
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 1327b2a..205603d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -229,12 +229,6 @@
 
 /* End of EEPROM */
 
-
-#define PCI_LINK_CTRL      0x0F0
-#define PCI_POWER_SOURCE   0x0C8
-#define PCI_REG_WUM8       0x0E8
-#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
-
 #define PCI_CFG_REV_ID_BIT_BASIC_SKU                (0x40)	/* bit 6    */
 #define PCI_CFG_REV_ID_BIT_RTP                      (0x80)	/* bit 7    */
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index cb6db45..d49e48b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -905,22 +905,18 @@
 
 static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
 {
-	int rc;
+	int ret;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
+	ret = iwl_grab_nic_access(priv);
+	if (ret) {
 		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
+		return ret;
 	}
 
 	if (src == IWL_PWR_SRC_VAUX) {
-		u32 val;
-
-		rc = pci_read_config_dword(priv->pci_dev,
-				PCI_POWER_SOURCE, &val);
-		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
+		if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) {
 			iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 					APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
 					~APMG_PS_CTRL_MSK_PWR_SRC);
@@ -929,8 +925,9 @@
 			iwl_poll_bit(priv, CSR_GPIO_IN,
 				     CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
 				     CSR_GPIO_IN_BIT_AUX_POWER, 5000);
-		} else
+		} else {
 			iwl_release_nic_access(priv);
+		}
 	} else {
 		iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
@@ -942,7 +939,7 @@
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return rc;
+	return ret;
 }
 
 static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
@@ -2741,8 +2738,8 @@
 			EEPROM_REGULATORY_BAND_3_CHANNELS,
 			EEPROM_REGULATORY_BAND_4_CHANNELS,
 			EEPROM_REGULATORY_BAND_5_CHANNELS,
-			IWL3945_EEPROM_IMG_SIZE,
-			IWL3945_EEPROM_IMG_SIZE,
+			EEPROM_REGULATORY_BAND_NO_FAT,
+			EEPROM_REGULATORY_BAND_NO_FAT,
 		},
 		.verify_signature  = iwlcore_eeprom_verify_signature,
 		.acquire_semaphore = iwl3945_eeprom_acquire_semaphore,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index af4c1bb..a71a489 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -92,19 +92,12 @@
 #define IWL49_RSSI_OFFSET	44
 
 
-
 /* PCI registers */
 #define PCI_CFG_RETRY_TIMEOUT	0x041
-#define PCI_CFG_POWER_SOURCE	0x0C8
-#define PCI_REG_WUM8		0x0E8
-#define PCI_CFG_LINK_CTRL	0x0F0
 
 /* PCI register values */
 #define PCI_CFG_LINK_CTRL_VAL_L0S_EN	0x01
 #define PCI_CFG_LINK_CTRL_VAL_L1_EN	0x02
-#define PCI_CFG_CMD_REG_INT_DIS_MSK	0x04
-#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
-
 
 #define IWL_NUM_SCAN_RATES         (2)
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 0638f3e..bd0140b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -381,27 +381,20 @@
 static void iwl4965_nic_config(struct iwl_priv *priv)
 {
 	unsigned long flags;
-	u32 val;
 	u16 radio_cfg;
-	u16 link;
+	u16 lctl;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	if ((priv->rev_id & 0x80) == 0x80 && (priv->rev_id & 0x7f) < 8) {
-		pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
-		/* Enable No Snoop field */
-		pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
-				       val & ~(1 << 11));
-	}
+	lctl = iwl_pcie_link_ctl(priv);
 
-	pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
-
-	/* L1 is enabled by BIOS */
-	if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
-		/* disable L0S disabled L1A enabled */
+	/* HW bug W/A - negligible power consumption */
+	/* L1-ASPM is enabled by BIOS */
+	if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
+		/* L1-ASPM enabled: disable L0S  */
 		iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 	else
-		/* L0S enabled L1A disabled */
+		/* L1-ASPM disabled: enable L0S */
 		iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 
 	radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index e3cba61..ab39f4a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -219,18 +219,19 @@
 {
 	unsigned long flags;
 	u16 radio_cfg;
-	u16 link;
+	u16 lctl;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
+	lctl = iwl_pcie_link_ctl(priv);
 
-	/* L1 is enabled by BIOS */
-	if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
-		/* disable L0S disabled L1A enabled */
+	/* HW bug W/A */
+	/* L1-ASPM is enabled by BIOS */
+	if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
+		/* L1-APSM enabled: disable L0S  */
 		iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 	else
-		/* L0S enabled L1A disabled */
+		/* L1-ASPM disabled: enable L0S */
 		iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 
 	radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index c196abc..397577c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -940,11 +940,7 @@
 		goto err;
 
 	if (src == IWL_PWR_SRC_VAUX) {
-		u32 val;
-		ret = pci_read_config_dword(priv->pci_dev, PCI_CFG_POWER_SOURCE,
-					    &val);
-
-		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
+		if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
 			iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 					       APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
 					       ~APMG_PS_CTRL_MSK_PWR_SRC);
@@ -2678,11 +2674,19 @@
 
 }
 
-static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw,
+			   struct cfg80211_scan_request *req)
 {
 	unsigned long flags;
 	struct iwl_priv *priv = hw->priv;
 	int ret;
+	u8 *ssid = NULL;
+	size_t ssid_len = 0;
+
+	if (req->n_ssids) {
+		ssid = req->ssids[0].ssid;
+		ssid_len = req->ssids[0].ssid_len;
+	}
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 
@@ -2718,7 +2722,7 @@
 
 	if (ssid_len) {
 		priv->one_direct_scan = 1;
-		priv->direct_ssid_len =  min_t(u8, ssid_len, IW_ESSID_MAX_SIZE);
+		priv->direct_ssid_len = ssid_len;
 		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
 	} else {
 		priv->one_direct_scan = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index e18c3f3..260bf90 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1271,6 +1271,7 @@
 		BIT(NL80211_IFTYPE_ADHOC);
 
 	hw->wiphy->custom_regulatory = true;
+	hw->wiphy->max_scan_ssids = 1;
 
 	/* Default value; 4 EDCA QOS priorities */
 	hw->queues = 4;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index d79912b..9d464ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -410,6 +410,14 @@
  *****************************************************/
 void iwl_disable_interrupts(struct iwl_priv *priv);
 void iwl_enable_interrupts(struct iwl_priv *priv);
+static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
+{
+	int pos;
+	u16 pci_lnk_ctl;
+	pos = pci_find_capability(priv->pci_dev, PCI_CAP_ID_EXP);
+	pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
+	return pci_lnk_ctl;
+}
 
 /*****************************************************
 *  Error Handling Debugging
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index d1d1d9b..75517d0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -532,10 +532,10 @@
 	}
 
 	/* Check if we do have FAT channels */
-	if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] >=
-	    priv->cfg->eeprom_size &&
-	    priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] >=
-	    priv->cfg->eeprom_size)
+	if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] ==
+	    EEPROM_REGULATORY_BAND_NO_FAT &&
+	    priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] ==
+	    EEPROM_REGULATORY_BAND_NO_FAT)
 		return 0;
 
 	/* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 17fed49..3479153 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -370,6 +370,8 @@
  */
 #define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8)	/* 22 bytes */
 
+#define EEPROM_REGULATORY_BAND_NO_FAT			(0)
+
 struct iwl_eeprom_ops {
 	const u32 regulatory_bands[7];
 	int (*verify_signature) (struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 4c5a775..18b7e41 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -141,7 +141,7 @@
 	int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX;
 	struct iwl_powertable_cmd *cmd;
 	int i;
-	u16 pci_pm;
+	u16 lctl;
 
 	IWL_DEBUG_POWER(priv, "Initialize power \n");
 
@@ -153,14 +153,14 @@
 	memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
 	memcpy(&pow_data->pwr_range_2[0], &range_2[0], size);
 
-	pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &pci_pm);
+	lctl = iwl_pcie_link_ctl(priv);
 
 	IWL_DEBUG_POWER(priv, "adjust power command flags\n");
 
 	for (i = 0; i < IWL_POWER_MAX; i++) {
 		cmd = &pow_data->pwr_range_0[i].cmd;
 
-		if (pci_pm & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
+		if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
 			cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
 		else
 			cmd->flags |= IWL_POWER_PCI_PM_MSK;
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 22bad3c..1ec2b20 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -860,7 +860,7 @@
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	ieee80211_scan_completed(priv->hw);
+	ieee80211_scan_completed(priv->hw, false);
 
 	/* Since setting the TXPOWER may have been deferred while
 	 * performing the scan, fire one off */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 42cc288..0cd8cb9 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -4442,15 +4442,23 @@
 
 }
 
-static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw,
+			       struct cfg80211_scan_request *req)
 {
 	int rc = 0;
 	unsigned long flags;
 	struct iwl_priv *priv = hw->priv;
+	size_t len = 0;
+	u8 *ssid = NULL;
 	DECLARE_SSID_BUF(ssid_buf);
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 
+	if (req->n_ssids) {
+		ssid = req->ssids[0].ssid;
+		len = req->ssids[0].ssid_len;
+	}
+
 	mutex_lock(&priv->mutex);
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -4478,9 +4486,8 @@
 			       print_ssid(ssid_buf, ssid, len), len);
 
 		priv->one_direct_scan = 1;
-		priv->direct_ssid_len = (u8)
-		    min((u8) len, (u8) IW_ESSID_MAX_SIZE);
-		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+		priv->direct_ssid_len = len;
+		memcpy(priv->direct_ssid, ssid, len);
 	} else
 		priv->one_direct_scan = 0;
 
@@ -5412,6 +5419,8 @@
 
 	hw->wiphy->custom_regulatory = true;
 
+	hw->wiphy->max_scan_ssids = 1;
+
 	/* 4 EDCA QOS priorities */
 	hw->queues = 4;
 
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
index 791366e..1fc7409 100644
--- a/drivers/net/wireless/orinoco/Makefile
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -1,8 +1,9 @@
 #
 # Makefile for the orinoco wireless device drivers.
 #
+orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o
 
-obj-$(CONFIG_HERMES)		+= orinoco.o hermes.o hermes_dld.o
+obj-$(CONFIG_HERMES)		+= orinoco.o
 obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o
 obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
 obj-$(CONFIG_PLX_HERMES)	+= orinoco_plx.o
diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index 5582dca..8c4065f 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -3,7 +3,7 @@
  * A driver for "Hermes" chipset based Apple Airport wireless
  * card.
  *
- * Copyright notice & release notes in file orinoco.c
+ * Copyright notice & release notes in file main.c
  *
  * Note specific to airport stub:
  *
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
new file mode 100644
index 0000000..7d2292d
--- /dev/null
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -0,0 +1,340 @@
+/* Firmware file reading and download helpers
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+
+#include "hermes.h"
+#include "hermes_dld.h"
+#include "orinoco.h"
+
+#include "fw.h"
+
+/* End markers (for Symbol firmware only) */
+#define TEXT_END	0x1A		/* End of text header */
+
+struct fw_info {
+	char *pri_fw;
+	char *sta_fw;
+	char *ap_fw;
+	u32 pda_addr;
+	u16 pda_size;
+};
+
+static const struct fw_info orinoco_fw[] = {
+	{ NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
+	{ NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
+	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
+};
+
+/* Structure used to access fields in FW
+ * Make sure LE decoding macros are used
+ */
+struct orinoco_fw_header {
+	char hdr_vers[6];       /* ASCII string for header version */
+	__le16 headersize;      /* Total length of header */
+	__le32 entry_point;     /* NIC entry point */
+	__le32 blocks;          /* Number of blocks to program */
+	__le32 block_offset;    /* Offset of block data from eof header */
+	__le32 pdr_offset;      /* Offset to PDR data from eof header */
+	__le32 pri_offset;      /* Offset to primary plug data */
+	__le32 compat_offset;   /* Offset to compatibility data*/
+	char signature[0];      /* FW signature length headersize-20 */
+} __attribute__ ((packed));
+
+/* Download either STA or AP firmware into the card. */
+static int
+orinoco_dl_firmware(struct orinoco_private *priv,
+		    const struct fw_info *fw,
+		    int ap)
+{
+	/* Plug Data Area (PDA) */
+	__le16 *pda;
+
+	hermes_t *hw = &priv->hw;
+	const struct firmware *fw_entry;
+	const struct orinoco_fw_header *hdr;
+	const unsigned char *first_block;
+	const unsigned char *end;
+	const char *firmware;
+	struct net_device *dev = priv->ndev;
+	int err = 0;
+
+	pda = kzalloc(fw->pda_size, GFP_KERNEL);
+	if (!pda)
+		return -ENOMEM;
+
+	if (ap)
+		firmware = fw->ap_fw;
+	else
+		firmware = fw->sta_fw;
+
+	printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
+	       dev->name, firmware);
+
+	/* Read current plug data */
+	err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
+	printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
+	if (err)
+		goto free;
+
+	if (!priv->cached_fw) {
+		err = request_firmware(&fw_entry, firmware, priv->dev);
+
+		if (err) {
+			printk(KERN_ERR "%s: Cannot find firmware %s\n",
+			       dev->name, firmware);
+			err = -ENOENT;
+			goto free;
+		}
+	} else
+		fw_entry = priv->cached_fw;
+
+	hdr = (const struct orinoco_fw_header *) fw_entry->data;
+
+	/* Enable aux port to allow programming */
+	err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
+	printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
+	if (err != 0)
+		goto abort;
+
+	/* Program data */
+	first_block = (fw_entry->data +
+		       le16_to_cpu(hdr->headersize) +
+		       le32_to_cpu(hdr->block_offset));
+	end = fw_entry->data + fw_entry->size;
+
+	err = hermes_program(hw, first_block, end);
+	printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
+	if (err != 0)
+		goto abort;
+
+	/* Update production data */
+	first_block = (fw_entry->data +
+		       le16_to_cpu(hdr->headersize) +
+		       le32_to_cpu(hdr->pdr_offset));
+
+	err = hermes_apply_pda_with_defaults(hw, first_block, pda);
+	printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
+	if (err)
+		goto abort;
+
+	/* Tell card we've finished */
+	err = hermesi_program_end(hw);
+	printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
+	if (err != 0)
+		goto abort;
+
+	/* Check if we're running */
+	printk(KERN_DEBUG "%s: hermes_present returned %d\n",
+	       dev->name, hermes_present(hw));
+
+abort:
+	/* If we requested the firmware, release it. */
+	if (!priv->cached_fw)
+		release_firmware(fw_entry);
+
+free:
+	kfree(pda);
+	return err;
+}
+
+/*
+ * Process a firmware image - stop the card, load the firmware, reset
+ * the card and make sure it responds.  For the secondary firmware take
+ * care of the PDA - read it and then write it on top of the firmware.
+ */
+static int
+symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
+		const unsigned char *image, const unsigned char *end,
+		int secondary)
+{
+	hermes_t *hw = &priv->hw;
+	int ret = 0;
+	const unsigned char *ptr;
+	const unsigned char *first_block;
+
+	/* Plug Data Area (PDA) */
+	__le16 *pda = NULL;
+
+	/* Binary block begins after the 0x1A marker */
+	ptr = image;
+	while (*ptr++ != TEXT_END);
+	first_block = ptr;
+
+	/* Read the PDA from EEPROM */
+	if (secondary) {
+		pda = kzalloc(fw->pda_size, GFP_KERNEL);
+		if (!pda)
+			return -ENOMEM;
+
+		ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
+		if (ret)
+			goto free;
+	}
+
+	/* Stop the firmware, so that it can be safely rewritten */
+	if (priv->stop_fw) {
+		ret = priv->stop_fw(priv, 1);
+		if (ret)
+			goto free;
+	}
+
+	/* Program the adapter with new firmware */
+	ret = hermes_program(hw, first_block, end);
+	if (ret)
+		goto free;
+
+	/* Write the PDA to the adapter */
+	if (secondary) {
+		size_t len = hermes_blocks_length(first_block);
+		ptr = first_block + len;
+		ret = hermes_apply_pda(hw, ptr, pda);
+		kfree(pda);
+		if (ret)
+			return ret;
+	}
+
+	/* Run the firmware */
+	if (priv->stop_fw) {
+		ret = priv->stop_fw(priv, 0);
+		if (ret)
+			return ret;
+	}
+
+	/* Reset hermes chip and make sure it responds */
+	ret = hermes_init(hw);
+
+	/* hermes_reset() should return 0 with the secondary firmware */
+	if (secondary && ret != 0)
+		return -ENODEV;
+
+	/* And this should work with any firmware */
+	if (!hermes_present(hw))
+		return -ENODEV;
+
+	return 0;
+
+free:
+	kfree(pda);
+	return ret;
+}
+
+
+/*
+ * Download the firmware into the card, this also does a PCMCIA soft
+ * reset on the card, to make sure it's in a sane state.
+ */
+static int
+symbol_dl_firmware(struct orinoco_private *priv,
+		   const struct fw_info *fw)
+{
+	struct net_device *dev = priv->ndev;
+	int ret;
+	const struct firmware *fw_entry;
+
+	if (!priv->cached_pri_fw) {
+		if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
+			printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+			       dev->name, fw->pri_fw);
+			return -ENOENT;
+		}
+	} else
+		fw_entry = priv->cached_pri_fw;
+
+	/* Load primary firmware */
+	ret = symbol_dl_image(priv, fw, fw_entry->data,
+			      fw_entry->data + fw_entry->size, 0);
+
+	if (!priv->cached_pri_fw)
+		release_firmware(fw_entry);
+	if (ret) {
+		printk(KERN_ERR "%s: Primary firmware download failed\n",
+		       dev->name);
+		return ret;
+	}
+
+	if (!priv->cached_fw) {
+		if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
+			printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+			       dev->name, fw->sta_fw);
+			return -ENOENT;
+		}
+	} else
+		fw_entry = priv->cached_fw;
+
+	/* Load secondary firmware */
+	ret = symbol_dl_image(priv, fw, fw_entry->data,
+			      fw_entry->data + fw_entry->size, 1);
+	if (!priv->cached_fw)
+		release_firmware(fw_entry);
+	if (ret) {
+		printk(KERN_ERR "%s: Secondary firmware download failed\n",
+		       dev->name);
+	}
+
+	return ret;
+}
+
+int orinoco_download(struct orinoco_private *priv)
+{
+	int err = 0;
+	/* Reload firmware */
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		/* case FIRMWARE_TYPE_INTERSIL: */
+		err = orinoco_dl_firmware(priv,
+					  &orinoco_fw[priv->firmware_type], 0);
+		break;
+
+	case FIRMWARE_TYPE_SYMBOL:
+		err = symbol_dl_firmware(priv,
+					 &orinoco_fw[priv->firmware_type]);
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		break;
+	}
+	/* TODO: if we fail we probably need to reinitialise
+	 * the driver */
+
+	return err;
+}
+
+void orinoco_cache_fw(struct orinoco_private *priv, int ap)
+{
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
+	const struct firmware *fw_entry = NULL;
+	const char *pri_fw;
+	const char *fw;
+
+	pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
+	if (ap)
+		fw = orinoco_fw[priv->firmware_type].ap_fw;
+	else
+		fw = orinoco_fw[priv->firmware_type].sta_fw;
+
+	if (pri_fw) {
+		if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
+			priv->cached_pri_fw = fw_entry;
+	}
+
+	if (fw) {
+		if (request_firmware(&fw_entry, fw, priv->dev) == 0)
+			priv->cached_fw = fw_entry;
+	}
+#endif
+}
+
+void orinoco_uncache_fw(struct orinoco_private *priv)
+{
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
+	if (priv->cached_pri_fw)
+		release_firmware(priv->cached_pri_fw);
+	if (priv->cached_fw)
+		release_firmware(priv->cached_fw);
+
+	priv->cached_pri_fw = NULL;
+	priv->cached_fw = NULL;
+#endif
+}
diff --git a/drivers/net/wireless/orinoco/fw.h b/drivers/net/wireless/orinoco/fw.h
new file mode 100644
index 0000000..2290f08
--- /dev/null
+++ b/drivers/net/wireless/orinoco/fw.h
@@ -0,0 +1,16 @@
+/* Firmware file reading and download helpers
+ *
+ * See copyright notice in main.c
+ */
+#ifndef _ORINOCO_FW_H_
+#define _ORINOCO_FW_H_
+
+/* Forward declations */
+struct orinoco_private;
+
+int orinoco_download(struct orinoco_private *priv);
+
+void orinoco_cache_fw(struct orinoco_private *priv, int ap);
+void orinoco_uncache_fw(struct orinoco_private *priv);
+
+#endif /* _ORINOCO_FW_H_ */
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index f48358f..f2c918c 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -45,12 +45,6 @@
 
 #include "hermes.h"
 
-MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset"
-		   " and Prism II HFA384x wireless MAC controller");
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"
-	" & David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_LICENSE("Dual MPL/GPL");
-
 /* These are maximum timeouts. Most often, card wil react much faster */
 #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
 #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
@@ -540,15 +534,3 @@
 	return err;
 }
 EXPORT_SYMBOL(hermes_write_ltv);
-
-static int __init init_hermes(void)
-{
-	return 0;
-}
-
-static void __exit exit_hermes(void)
-{
-}
-
-module_init(init_hermes);
-module_exit(exit_hermes);
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index 45aed14..5260ceb 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -1,13 +1,7 @@
 /*
- * Hermes download helper driver.
+ * Hermes download helper.
  *
- * This could be entirely merged into hermes.c.
- *
- * I'm keeping it separate to minimise the amount of merging between
- * kernel upgrades. It also means the memory overhead for drivers that
- * don't need firmware download low.
- *
- * This driver:
+ * This helper:
  *  - is capable of writing to the volatile area of the hermes device
  *  - is currently not capable of writing to non-volatile areas
  *  - provide helpers to identify and update plugin data
@@ -50,10 +44,6 @@
 #include "hermes.h"
 #include "hermes_dld.h"
 
-MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset");
-MODULE_AUTHOR("David Kilroy <kilroyd@gmail.com>");
-MODULE_LICENSE("Dual MPL/GPL");
-
 #define PFX "hermes_dld: "
 
 /*
@@ -347,7 +337,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(hermes_read_pda);
 
 /* Parse PDA and write the records into the adapter
  *
@@ -376,7 +365,6 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL(hermes_apply_pda);
 
 /* Identify the total number of bytes in all blocks
  * including the header data.
@@ -398,7 +386,6 @@
 
 	return total_len;
 }
-EXPORT_SYMBOL(hermes_blocks_length);
 
 /*** Hermes programming ***/
 
@@ -452,7 +439,6 @@
 
 	return err;
 }
-EXPORT_SYMBOL(hermesi_program_init);
 
 /* Done programming data (Hermes I)
  *
@@ -488,7 +474,6 @@
 
 	return rc ? rc : err;
 }
-EXPORT_SYMBOL(hermesi_program_end);
 
 /* Program the data blocks */
 int hermes_program(hermes_t *hw, const char *first_block, const char *end)
@@ -550,19 +535,6 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL(hermes_program);
-
-static int __init init_hermes_dld(void)
-{
-	return 0;
-}
-
-static void __exit exit_hermes_dld(void)
-{
-}
-
-module_init(init_hermes_dld);
-module_exit(exit_hermes_dld);
 
 /*** Default plugging data for Hermes I ***/
 /* Values from wl_lkm_718/hcf/dhf.c */
@@ -727,4 +699,3 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL(hermes_apply_pda_with_defaults);
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
new file mode 100644
index 0000000..081428d
--- /dev/null
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -0,0 +1,586 @@
+/* Encapsulate basic setting changes and retrieval on Hermes hardware
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/ieee80211.h>
+#include <linux/wireless.h>
+
+#include "hermes.h"
+#include "hermes_rid.h"
+#include "orinoco.h"
+
+#include "hw.h"
+
+/********************************************************************/
+/* Data tables                                                      */
+/********************************************************************/
+
+/* This tables gives the actual meanings of the bitrate IDs returned
+ * by the firmware. */
+static const struct {
+	int bitrate; /* in 100s of kilobits */
+	int automatic;
+	u16 agere_txratectrl;
+	u16 intersil_txratectrl;
+} bitrate_table[] = {
+	{110, 1,  3, 15}, /* Entry 0 is the default */
+	{10,  0,  1,  1},
+	{10,  1,  1,  1},
+	{20,  0,  2,  2},
+	{20,  1,  6,  3},
+	{55,  0,  4,  4},
+	{55,  1,  7,  7},
+	{110, 0,  5,  8},
+};
+#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
+
+int orinoco_get_bitratemode(int bitrate, int automatic)
+{
+	int ratemode = -1;
+	int i;
+
+	if ((bitrate != 10) && (bitrate != 20) &&
+	    (bitrate != 55) && (bitrate != 110))
+		return ratemode;
+
+	for (i = 0; i < BITRATE_TABLE_SIZE; i++) {
+		if ((bitrate_table[i].bitrate == bitrate) &&
+		    (bitrate_table[i].automatic == automatic)) {
+			ratemode = i;
+			break;
+		}
+	}
+	return ratemode;
+}
+
+void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
+{
+	BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
+
+	*bitrate = bitrate_table[ratemode].bitrate * 100000;
+	*automatic = bitrate_table[ratemode].automatic;
+}
+
+/* Get tsc from the firmware */
+int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE];
+
+	if ((key < 0) || (key > 4))
+		return -EINVAL;
+
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
+			      sizeof(tsc_arr), NULL, &tsc_arr);
+	if (!err)
+		memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
+
+	return err;
+}
+
+int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int ratemode = priv->bitratemode;
+	int err = 0;
+
+	if (ratemode >= BITRATE_TABLE_SIZE) {
+		printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
+		       priv->ndev->name, ratemode);
+		return -EINVAL;
+	}
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		err = hermes_write_wordrec(hw, USER_BAP,
+				HERMES_RID_CNFTXRATECONTROL,
+				bitrate_table[ratemode].agere_txratectrl);
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+	case FIRMWARE_TYPE_SYMBOL:
+		err = hermes_write_wordrec(hw, USER_BAP,
+				HERMES_RID_CNFTXRATECONTROL,
+				bitrate_table[ratemode].intersil_txratectrl);
+		break;
+	default:
+		BUG();
+	}
+
+	return err;
+}
+
+int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
+{
+	hermes_t *hw = &priv->hw;
+	int i;
+	int err = 0;
+	u16 val;
+
+	err = hermes_read_wordrec(hw, USER_BAP,
+				  HERMES_RID_CURRENTTXRATE, &val);
+	if (err)
+		return err;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
+		/* Note : in Lucent firmware, the return value of
+		 * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
+		 * and therefore is totally different from the
+		 * encoding of HERMES_RID_CNFTXRATECONTROL.
+		 * Don't forget that 6Mb/s is really 5.5Mb/s */
+		if (val == 6)
+			*bitrate = 5500000;
+		else
+			*bitrate = val * 1000000;
+		break;
+	case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
+	case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
+		for (i = 0; i < BITRATE_TABLE_SIZE; i++)
+			if (bitrate_table[i].intersil_txratectrl == val)
+				break;
+
+		if (i >= BITRATE_TABLE_SIZE)
+			printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
+			       priv->ndev->name, val);
+
+		*bitrate = bitrate_table[i].bitrate * 100000;
+		break;
+	default:
+		BUG();
+	}
+
+	return err;
+}
+
+/* Set fixed AP address */
+int __orinoco_hw_set_wap(struct orinoco_private *priv)
+{
+	int roaming_flag;
+	int err = 0;
+	hermes_t *hw = &priv->hw;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		/* not supported */
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		if (priv->bssid_fixed)
+			roaming_flag = 2;
+		else
+			roaming_flag = 1;
+
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFROAMINGMODE,
+					   roaming_flag);
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		err = HERMES_WRITE_RECORD(hw, USER_BAP,
+					  HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
+					  &priv->desired_bssid);
+		break;
+	}
+	return err;
+}
+
+/* Change the WEP keys and/or the current keys.  Can be called
+ * either from __orinoco_hw_setup_enc() or directly from
+ * orinoco_ioctl_setiwencode().  In the later case the association
+ * with the AP is not broken (if the firmware can handle it),
+ * which is needed for 802.1x implementations. */
+int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		err = HERMES_WRITE_RECORD(hw, USER_BAP,
+					  HERMES_RID_CNFWEPKEYS_AGERE,
+					  &priv->keys);
+		if (err)
+			return err;
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFTXKEY_AGERE,
+					   priv->tx_key);
+		if (err)
+			return err;
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+	case FIRMWARE_TYPE_SYMBOL:
+		{
+			int keylen;
+			int i;
+
+			/* Force uniform key length to work around
+			 * firmware bugs */
+			keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
+
+			if (keylen > LARGE_KEY_SIZE) {
+				printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
+				       priv->ndev->name, priv->tx_key, keylen);
+				return -E2BIG;
+			}
+
+			/* Write all 4 keys */
+			for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
+				err = hermes_write_ltv(hw, USER_BAP,
+						HERMES_RID_CNFDEFAULTKEY0 + i,
+						HERMES_BYTES_TO_RECLEN(keylen),
+						priv->keys[i].data);
+				if (err)
+					return err;
+			}
+
+			/* Write the index of the key used in transmission */
+			err = hermes_write_wordrec(hw, USER_BAP,
+						HERMES_RID_CNFWEPDEFAULTKEYID,
+						priv->tx_key);
+			if (err)
+				return err;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+int __orinoco_hw_setup_enc(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	int master_wep_flag;
+	int auth_flag;
+	int enc_flag;
+
+	/* Setup WEP keys for WEP and WPA */
+	if (priv->encode_alg)
+		__orinoco_hw_setup_wepkeys(priv);
+
+	if (priv->wep_restrict)
+		auth_flag = HERMES_AUTH_SHARED_KEY;
+	else
+		auth_flag = HERMES_AUTH_OPEN;
+
+	if (priv->wpa_enabled)
+		enc_flag = 2;
+	else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
+		enc_flag = 1;
+	else
+		enc_flag = 0;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
+		if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
+			/* Enable the shared-key authentication. */
+			err = hermes_write_wordrec(hw, USER_BAP,
+					HERMES_RID_CNFAUTHENTICATION_AGERE,
+					auth_flag);
+		}
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFWEPENABLED_AGERE,
+					   enc_flag);
+		if (err)
+			return err;
+
+		if (priv->has_wpa) {
+			/* Set WPA key management */
+			err = hermes_write_wordrec(hw, USER_BAP,
+				  HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
+				  priv->key_mgmt);
+			if (err)
+				return err;
+		}
+
+		break;
+
+	case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
+	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
+		if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
+			if (priv->wep_restrict ||
+			    (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
+				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
+						  HERMES_WEP_EXCL_UNENCRYPTED;
+			else
+				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
+
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFAUTHENTICATION,
+						   auth_flag);
+			if (err)
+				return err;
+		} else
+			master_wep_flag = 0;
+
+		if (priv->iw_mode == IW_MODE_MONITOR)
+			master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
+
+		/* Master WEP setting : on/off */
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFWEPFLAGS_INTERSIL,
+					   master_wep_flag);
+		if (err)
+			return err;
+
+		break;
+	}
+
+	return 0;
+}
+
+/* key must be 32 bytes, including the tx and rx MIC keys.
+ * rsc must be 8 bytes
+ * tsc must be 8 bytes or NULL
+ */
+int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
+			      u8 *key, u8 *rsc, u8 *tsc)
+{
+	struct {
+		__le16 idx;
+		u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
+		u8 key[TKIP_KEYLEN];
+		u8 tx_mic[MIC_KEYLEN];
+		u8 rx_mic[MIC_KEYLEN];
+		u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
+	} __attribute__ ((packed)) buf;
+	int ret;
+	int err;
+	int k;
+	u16 xmitting;
+
+	key_idx &= 0x3;
+
+	if (set_tx)
+		key_idx |= 0x8000;
+
+	buf.idx = cpu_to_le16(key_idx);
+	memcpy(buf.key, key,
+	       sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
+
+	if (rsc == NULL)
+		memset(buf.rsc, 0, sizeof(buf.rsc));
+	else
+		memcpy(buf.rsc, rsc, sizeof(buf.rsc));
+
+	if (tsc == NULL) {
+		memset(buf.tsc, 0, sizeof(buf.tsc));
+		buf.tsc[4] = 0x10;
+	} else {
+		memcpy(buf.tsc, tsc, sizeof(buf.tsc));
+	}
+
+	/* Wait upto 100ms for tx queue to empty */
+	k = 100;
+	do {
+		k--;
+		udelay(1000);
+		ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
+					  &xmitting);
+		if (ret)
+			break;
+	} while ((k > 0) && xmitting);
+
+	if (k == 0)
+		ret = -ETIMEDOUT;
+
+	err = HERMES_WRITE_RECORD(hw, USER_BAP,
+				  HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
+				  &buf);
+
+	return ret ? ret : err;
+}
+
+int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
+{
+	hermes_t *hw = &priv->hw;
+	int err;
+
+	memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
+	err = hermes_write_wordrec(hw, USER_BAP,
+				   HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
+				   key_idx);
+	if (err)
+		printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
+		       priv->ndev->name, err, key_idx);
+	return err;
+}
+
+int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
+				    struct dev_addr_list *mc_list,
+				    int mc_count, int promisc)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+
+	if (promisc != priv->promiscuous) {
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFPROMISCUOUSMODE,
+					   promisc);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
+			       priv->ndev->name, err);
+		} else
+			priv->promiscuous = promisc;
+	}
+
+	/* If we're not in promiscuous mode, then we need to set the
+	 * group address if either we want to multicast, or if we were
+	 * multicasting and want to stop */
+	if (!promisc && (mc_count || priv->mc_count)) {
+		struct dev_mc_list *p = mc_list;
+		struct hermes_multicast mclist;
+		int i;
+
+		for (i = 0; i < mc_count; i++) {
+			/* paranoia: is list shorter than mc_count? */
+			BUG_ON(!p);
+			/* paranoia: bad address size in list? */
+			BUG_ON(p->dmi_addrlen != ETH_ALEN);
+
+			memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
+			p = p->next;
+		}
+
+		if (p)
+			printk(KERN_WARNING "%s: Multicast list is "
+			       "longer than mc_count\n", priv->ndev->name);
+
+		err = hermes_write_ltv(hw, USER_BAP,
+				   HERMES_RID_CNFGROUPADDRESSES,
+				   HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
+				   &mclist);
+		if (err)
+			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
+			       priv->ndev->name, err);
+		else
+			priv->mc_count = mc_count;
+	}
+	return err;
+}
+
+/* Return : < 0 -> error code ; >= 0 -> length */
+int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
+			 char buf[IW_ESSID_MAX_SIZE+1])
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	struct hermes_idstring essidbuf;
+	char *p = (char *)(&essidbuf.val);
+	int len;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if (strlen(priv->desired_essid) > 0) {
+		/* We read the desired SSID from the hardware rather
+		   than from priv->desired_essid, just in case the
+		   firmware is allowed to change it on us. I'm not
+		   sure about this */
+		/* My guess is that the OWNSSID should always be whatever
+		 * we set to the card, whereas CURRENT_SSID is the one that
+		 * may change... - Jean II */
+		u16 rid;
+
+		*active = 1;
+
+		rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
+			HERMES_RID_CNFDESIREDSSID;
+
+		err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
+				      NULL, &essidbuf);
+		if (err)
+			goto fail_unlock;
+	} else {
+		*active = 0;
+
+		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
+				      sizeof(essidbuf), NULL, &essidbuf);
+		if (err)
+			goto fail_unlock;
+	}
+
+	len = le16_to_cpu(essidbuf.len);
+	BUG_ON(len > IW_ESSID_MAX_SIZE);
+
+	memset(buf, 0, IW_ESSID_MAX_SIZE);
+	memcpy(buf, p, len);
+	err = len;
+
+ fail_unlock:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+int orinoco_hw_get_freq(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	u16 channel;
+	int freq = 0;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL,
+				  &channel);
+	if (err)
+		goto out;
+
+	/* Intersil firmware 1.3.5 returns 0 when the interface is down */
+	if (channel == 0) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if ((channel < 1) || (channel > NUM_CHANNELS)) {
+		printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
+		       priv->ndev->name, channel);
+		err = -EBUSY;
+		goto out;
+
+	}
+	freq = ieee80211_dsss_chan_to_freq(channel);
+
+ out:
+	orinoco_unlock(priv, &flags);
+
+	if (err > 0)
+		err = -EBUSY;
+	return err ? err : freq;
+}
+
+int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
+			       int *numrates, s32 *rates, int max)
+{
+	hermes_t *hw = &priv->hw;
+	struct hermes_idstring list;
+	unsigned char *p = (unsigned char *)&list.val;
+	int err = 0;
+	int num;
+	int i;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
+			      sizeof(list), NULL, &list);
+	orinoco_unlock(priv, &flags);
+
+	if (err)
+		return err;
+
+	num = le16_to_cpu(list.len);
+	*numrates = num;
+	num = min(num, max);
+
+	for (i = 0; i < num; i++)
+		rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
+
+	return 0;
+}
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h
new file mode 100644
index 0000000..dc3f23a
--- /dev/null
+++ b/drivers/net/wireless/orinoco/hw.h
@@ -0,0 +1,47 @@
+/* Encapsulate basic setting changes on Hermes hardware
+ *
+ * See copyright notice in main.c
+ */
+#ifndef _ORINOCO_HW_H_
+#define _ORINOCO_HW_H_
+
+#include <linux/types.h>
+#include <linux/wireless.h>
+
+/* Hardware BAPs */
+#define USER_BAP 0
+#define IRQ_BAP  1
+
+/* WEP key sizes */
+#define SMALL_KEY_SIZE 5
+#define LARGE_KEY_SIZE 13
+
+/* Number of supported channels */
+#define NUM_CHANNELS 14
+
+/* Forward declarations */
+struct orinoco_private;
+struct dev_addr_list;
+
+int orinoco_get_bitratemode(int bitrate, int automatic);
+void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
+
+int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
+int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
+int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
+int __orinoco_hw_set_wap(struct orinoco_private *priv);
+int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
+int __orinoco_hw_setup_enc(struct orinoco_private *priv);
+int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
+			      u8 *key, u8 *rsc, u8 *tsc);
+int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
+int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
+				    struct dev_addr_list *mc_list,
+				    int mc_count, int promisc);
+int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
+			 char buf[IW_ESSID_MAX_SIZE+1]);
+int orinoco_hw_get_freq(struct orinoco_private *priv);
+int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
+			       int *numrates, s32 *rates, int max);
+
+#endif /* _ORINOCO_HW_H_ */
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
new file mode 100644
index 0000000..54dfc45
--- /dev/null
+++ b/drivers/net/wireless/orinoco/main.c
@@ -0,0 +1,2654 @@
+/* main.c - (formerly known as dldwd_cs.c, orinoco_cs.c and orinoco.c)
+ *
+ * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
+ * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
+ *
+ * Current maintainers (as of 29 September 2003) are:
+ * 	Pavel Roskin <proski AT gnu.org>
+ * and	David Gibson <hermes AT gibson.dropbear.id.au>
+ *
+ * (C) Copyright David Gibson, IBM Corporation 2001-2003.
+ * Copyright (C) 2000 David Gibson, Linuxcare Australia.
+ *	With some help from :
+ * Copyright (C) 2001 Jean Tourrilhes, HP Labs
+ * Copyright (C) 2001 Benjamin Herrenschmidt
+ *
+ * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
+ *
+ * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy
+ * AT fasta.fh-dortmund.de>
+ *      http://www.stud.fh-dortmund.de/~andy/wvlan/
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds AT users.sourceforge.net>.  Portions created by David
+ * A. Hinds are Copyright (C) 1999 David A. Hinds.  All Rights
+ * Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.  */
+
+/*
+ * TODO
+ *	o Handle de-encapsulation within network layer, provide 802.11
+ *	  headers (patch from Thomas 'Dent' Mirlacher)
+ *	o Fix possible races in SPY handling.
+ *	o Disconnect wireless extensions from fundamental configuration.
+ *	o (maybe) Software WEP support (patch from Stano Meduna).
+ *	o (maybe) Use multiple Tx buffers - driver handling queue
+ *	  rather than firmware.
+ */
+
+/* Locking and synchronization:
+ *
+ * The basic principle is that everything is serialized through a
+ * single spinlock, priv->lock.  The lock is used in user, bh and irq
+ * context, so when taken outside hardirq context it should always be
+ * taken with interrupts disabled.  The lock protects both the
+ * hardware and the struct orinoco_private.
+ *
+ * Another flag, priv->hw_unavailable indicates that the hardware is
+ * unavailable for an extended period of time (e.g. suspended, or in
+ * the middle of a hard reset).  This flag is protected by the
+ * spinlock.  All code which touches the hardware should check the
+ * flag after taking the lock, and if it is set, give up on whatever
+ * they are doing and drop the lock again.  The orinoco_lock()
+ * function handles this (it unlocks and returns -EBUSY if
+ * hw_unavailable is non-zero).
+ */
+
+#define DRIVER_NAME "orinoco"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/suspend.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "hermes_rid.h"
+#include "hermes_dld.h"
+#include "hw.h"
+#include "scan.h"
+#include "mic.h"
+#include "fw.h"
+#include "wext.h"
+#include "main.h"
+
+#include "orinoco.h"
+
+/********************************************************************/
+/* Module information                                               */
+/********************************************************************/
+
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & "
+	      "David Gibson <hermes@gibson.dropbear.id.au>");
+MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based "
+		   "and similar wireless cards");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/* Level of debugging. Used in the macros in orinoco.h */
+#ifdef ORINOCO_DEBUG
+int orinoco_debug = ORINOCO_DEBUG;
+EXPORT_SYMBOL(orinoco_debug);
+module_param(orinoco_debug, int, 0644);
+MODULE_PARM_DESC(orinoco_debug, "Debug level");
+#endif
+
+static int suppress_linkstatus; /* = 0 */
+module_param(suppress_linkstatus, bool, 0644);
+MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
+
+static int ignore_disconnect; /* = 0 */
+module_param(ignore_disconnect, int, 0644);
+MODULE_PARM_DESC(ignore_disconnect,
+		 "Don't report lost link to the network layer");
+
+int force_monitor; /* = 0 */
+module_param(force_monitor, int, 0644);
+MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
+
+/********************************************************************/
+/* Internal constants                                               */
+/********************************************************************/
+
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
+
+#define ORINOCO_MIN_MTU		256
+#define ORINOCO_MAX_MTU		(IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
+
+#define SYMBOL_MAX_VER_LEN	(14)
+#define MAX_IRQLOOPS_PER_IRQ	10
+#define MAX_IRQLOOPS_PER_JIFFY	(20000/HZ) /* Based on a guestimate of
+					    * how many events the
+					    * device could
+					    * legitimately generate */
+#define TX_NICBUF_SIZE_BUG	1585		/* Bug in Symbol firmware */
+
+#define DUMMY_FID		0xFFFF
+
+/*#define MAX_MULTICAST(priv)	(priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
+  HERMES_MAX_MULTICAST : 0)*/
+#define MAX_MULTICAST(priv)	(HERMES_MAX_MULTICAST)
+
+#define ORINOCO_INTEN	 	(HERMES_EV_RX | HERMES_EV_ALLOC \
+				 | HERMES_EV_TX | HERMES_EV_TXEXC \
+				 | HERMES_EV_WTERR | HERMES_EV_INFO \
+				 | HERMES_EV_INFDROP)
+
+static const struct ethtool_ops orinoco_ethtool_ops;
+
+/********************************************************************/
+/* Data types                                                       */
+/********************************************************************/
+
+/* Beginning of the Tx descriptor, used in TxExc handling */
+struct hermes_txexc_data {
+	struct hermes_tx_descriptor desc;
+	__le16 frame_ctl;
+	__le16 duration_id;
+	u8 addr1[ETH_ALEN];
+} __attribute__ ((packed));
+
+/* Rx frame header except compatibility 802.3 header */
+struct hermes_rx_descriptor {
+	/* Control */
+	__le16 status;
+	__le32 time;
+	u8 silence;
+	u8 signal;
+	u8 rate;
+	u8 rxflow;
+	__le32 reserved;
+
+	/* 802.11 header */
+	__le16 frame_ctl;
+	__le16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	__le16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+
+	/* Data length */
+	__le16 data_len;
+} __attribute__ ((packed));
+
+struct orinoco_rx_data {
+	struct hermes_rx_descriptor *desc;
+	struct sk_buff *skb;
+	struct list_head list;
+};
+
+/********************************************************************/
+/* Function prototypes                                              */
+/********************************************************************/
+
+static void __orinoco_set_multicast_list(struct net_device *dev);
+
+/********************************************************************/
+/* Internal helper functions                                        */
+/********************************************************************/
+
+void set_port_type(struct orinoco_private *priv)
+{
+	switch (priv->iw_mode) {
+	case IW_MODE_INFRA:
+		priv->port_type = 1;
+		priv->createibss = 0;
+		break;
+	case IW_MODE_ADHOC:
+		if (priv->prefer_port3) {
+			priv->port_type = 3;
+			priv->createibss = 0;
+		} else {
+			priv->port_type = priv->ibss_port;
+			priv->createibss = 1;
+		}
+		break;
+	case IW_MODE_MONITOR:
+		priv->port_type = 3;
+		priv->createibss = 0;
+		break;
+	default:
+		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
+		       priv->ndev->name);
+	}
+}
+
+/********************************************************************/
+/* Device methods                                                   */
+/********************************************************************/
+
+static int orinoco_open(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	int err;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = __orinoco_up(dev);
+
+	if (!err)
+		priv->open = 1;
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_stop(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+
+	/* We mustn't use orinoco_lock() here, because we need to be
+	   able to close the interface even if hw_unavailable is set
+	   (e.g. as we're released after a PC Card removal) */
+	spin_lock_irq(&priv->lock);
+
+	priv->open = 0;
+
+	err = __orinoco_down(dev);
+
+	spin_unlock_irq(&priv->lock);
+
+	return err;
+}
+
+static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	return &priv->stats;
+}
+
+static void orinoco_set_multicast_list(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0) {
+		printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
+		       "called when hw_unavailable\n", dev->name);
+		return;
+	}
+
+	__orinoco_set_multicast_list(dev);
+	orinoco_unlock(priv, &flags);
+}
+
+static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU))
+		return -EINVAL;
+
+	/* MTU + encapsulation + header length */
+	if ((new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
+	     (priv->nicbuf_size - ETH_HLEN))
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+
+	return 0;
+}
+
+/********************************************************************/
+/* Tx path                                                          */
+/********************************************************************/
+
+static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	u16 txfid = priv->txfid;
+	struct ethhdr *eh;
+	int tx_control;
+	unsigned long flags;
+
+	if (!netif_running(dev)) {
+		printk(KERN_ERR "%s: Tx on stopped device!\n",
+		       dev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (netif_queue_stopped(dev)) {
+		printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
+		       dev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (orinoco_lock(priv, &flags) != 0) {
+		printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
+		       dev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
+		/* Oops, the firmware hasn't established a connection,
+		   silently drop the packet (this seems to be the
+		   safest approach). */
+		goto drop;
+	}
+
+	/* Check packet length */
+	if (skb->len < ETH_HLEN)
+		goto drop;
+
+	tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
+
+	if (priv->encode_alg == IW_ENCODE_ALG_TKIP)
+		tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
+			HERMES_TXCTRL_MIC;
+
+	if (priv->has_alt_txcntl) {
+		/* WPA enabled firmwares have tx_cntl at the end of
+		 * the 802.11 header.  So write zeroed descriptor and
+		 * 802.11 header at the same time
+		 */
+		char desc[HERMES_802_3_OFFSET];
+		__le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
+
+		memset(&desc, 0, sizeof(desc));
+
+		*txcntl = cpu_to_le16(tx_control);
+		err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+					txfid, 0);
+		if (err) {
+			if (net_ratelimit())
+				printk(KERN_ERR "%s: Error %d writing Tx "
+				       "descriptor to BAP\n", dev->name, err);
+			goto busy;
+		}
+	} else {
+		struct hermes_tx_descriptor desc;
+
+		memset(&desc, 0, sizeof(desc));
+
+		desc.tx_control = cpu_to_le16(tx_control);
+		err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+					txfid, 0);
+		if (err) {
+			if (net_ratelimit())
+				printk(KERN_ERR "%s: Error %d writing Tx "
+				       "descriptor to BAP\n", dev->name, err);
+			goto busy;
+		}
+
+		/* Clear the 802.11 header and data length fields - some
+		 * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
+		 * if this isn't done. */
+		hermes_clear_words(hw, HERMES_DATA0,
+				   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
+	}
+
+	eh = (struct ethhdr *)skb->data;
+
+	/* Encapsulate Ethernet-II frames */
+	if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
+		struct header_struct {
+			struct ethhdr eth;	/* 802.3 header */
+			u8 encap[6];		/* 802.2 header */
+		} __attribute__ ((packed)) hdr;
+
+		/* Strip destination and source from the data */
+		skb_pull(skb, 2 * ETH_ALEN);
+
+		/* And move them to a separate header */
+		memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
+		hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
+		memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
+
+		/* Insert the SNAP header */
+		if (skb_headroom(skb) < sizeof(hdr)) {
+			printk(KERN_ERR
+			       "%s: Not enough headroom for 802.2 headers %d\n",
+			       dev->name, skb_headroom(skb));
+			goto drop;
+		}
+		eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
+		memcpy(eh, &hdr, sizeof(hdr));
+	}
+
+	err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
+				txfid, HERMES_802_3_OFFSET);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
+		       dev->name, err);
+		goto busy;
+	}
+
+	/* Calculate Michael MIC */
+	if (priv->encode_alg == IW_ENCODE_ALG_TKIP) {
+		u8 mic_buf[MICHAEL_MIC_LEN + 1];
+		u8 *mic;
+		size_t offset;
+		size_t len;
+
+		if (skb->len % 2) {
+			/* MIC start is on an odd boundary */
+			mic_buf[0] = skb->data[skb->len - 1];
+			mic = &mic_buf[1];
+			offset = skb->len - 1;
+			len = MICHAEL_MIC_LEN + 1;
+		} else {
+			mic = &mic_buf[0];
+			offset = skb->len;
+			len = MICHAEL_MIC_LEN;
+		}
+
+		orinoco_mic(priv->tx_tfm_mic,
+			    priv->tkip_key[priv->tx_key].tx_mic,
+			    eh->h_dest, eh->h_source, 0 /* priority */,
+			    skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
+
+		/* Write the MIC */
+		err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
+					txfid, HERMES_802_3_OFFSET + offset);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
+			       dev->name, err);
+			goto busy;
+		}
+	}
+
+	/* Finally, we actually initiate the send */
+	netif_stop_queue(dev);
+
+	err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
+				txfid, NULL);
+	if (err) {
+		netif_start_queue(dev);
+		if (net_ratelimit())
+			printk(KERN_ERR "%s: Error %d transmitting packet\n",
+				dev->name, err);
+		goto busy;
+	}
+
+	dev->trans_start = jiffies;
+	stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
+	goto ok;
+
+ drop:
+	stats->tx_errors++;
+	stats->tx_dropped++;
+
+ ok:
+	orinoco_unlock(priv, &flags);
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+
+ busy:
+	if (err == -EIO)
+		schedule_work(&priv->reset_work);
+	orinoco_unlock(priv, &flags);
+	return NETDEV_TX_BUSY;
+}
+
+static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	u16 fid = hermes_read_regn(hw, ALLOCFID);
+
+	if (fid != priv->txfid) {
+		if (fid != DUMMY_FID)
+			printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
+			       dev->name, fid);
+		return;
+	}
+
+	hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
+}
+
+static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+
+	stats->tx_packets++;
+
+	netif_wake_queue(dev);
+
+	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+}
+
+static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
+	u16 status;
+	struct hermes_txexc_data hdr;
+	int err = 0;
+
+	if (fid == DUMMY_FID)
+		return; /* Nothing's really happened */
+
+	/* Read part of the frame header - we need status and addr1 */
+	err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
+			       sizeof(struct hermes_txexc_data),
+			       fid, 0);
+
+	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+	stats->tx_errors++;
+
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
+		       "(FID=%04X error %d)\n",
+		       dev->name, fid, err);
+		return;
+	}
+
+	DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
+	      err, fid);
+
+	/* We produce a TXDROP event only for retry or lifetime
+	 * exceeded, because that's the only status that really mean
+	 * that this particular node went away.
+	 * Other errors means that *we* screwed up. - Jean II */
+	status = le16_to_cpu(hdr.desc.status);
+	if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
+		union iwreq_data	wrqu;
+
+		/* Copy 802.11 dest address.
+		 * We use the 802.11 header because the frame may
+		 * not be 802.3 or may be mangled...
+		 * In Ad-Hoc mode, it will be the node address.
+		 * In managed mode, it will be most likely the AP addr
+		 * User space will figure out how to convert it to
+		 * whatever it needs (IP address or else).
+		 * - Jean II */
+		memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
+		wrqu.addr.sa_family = ARPHRD_ETHER;
+
+		/* Send event to user space */
+		wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+	}
+
+	netif_wake_queue(dev);
+}
+
+static void orinoco_tx_timeout(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	struct hermes *hw = &priv->hw;
+
+	printk(KERN_WARNING "%s: Tx timeout! "
+	       "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
+	       dev->name, hermes_read_regn(hw, ALLOCFID),
+	       hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
+
+	stats->tx_errors++;
+
+	schedule_work(&priv->reset_work);
+}
+
+/********************************************************************/
+/* Rx path (data frames)                                            */
+/********************************************************************/
+
+/* Does the frame have a SNAP header indicating it should be
+ * de-encapsulated to Ethernet-II? */
+static inline int is_ethersnap(void *_hdr)
+{
+	u8 *hdr = _hdr;
+
+	/* We de-encapsulate all packets which, a) have SNAP headers
+	 * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
+	 * and where b) the OUI of the SNAP header is 00:00:00 or
+	 * 00:00:f8 - we need both because different APs appear to use
+	 * different OUIs for some reason */
+	return (memcmp(hdr, &encaps_hdr, 5) == 0)
+		&& ((hdr[5] == 0x00) || (hdr[5] == 0xf8));
+}
+
+static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
+				      int level, int noise)
+{
+	struct iw_quality wstats;
+	wstats.level = level - 0x95;
+	wstats.noise = noise - 0x95;
+	wstats.qual = (level > noise) ? (level - noise) : 0;
+	wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+	/* Update spy records */
+	wireless_spy_update(dev, mac, &wstats);
+}
+
+static void orinoco_stat_gather(struct net_device *dev,
+				struct sk_buff *skb,
+				struct hermes_rx_descriptor *desc)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	/* Using spy support with lots of Rx packets, like in an
+	 * infrastructure (AP), will really slow down everything, because
+	 * the MAC address must be compared to each entry of the spy list.
+	 * If the user really asks for it (set some address in the
+	 * spy list), we do it, but he will pay the price.
+	 * Note that to get here, you need both WIRELESS_SPY
+	 * compiled in AND some addresses in the list !!!
+	 */
+	/* Note : gcc will optimise the whole section away if
+	 * WIRELESS_SPY is not defined... - Jean II */
+	if (SPY_NUMBER(priv)) {
+		orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
+				   desc->signal, desc->silence);
+	}
+}
+
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ *	dev		network device
+ *	rxfid		received FID
+ *	desc		rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+			       struct hermes_rx_descriptor *desc)
+{
+	u32 hdrlen = 30;	/* return full header by default */
+	u32 datalen = 0;
+	u16 fc;
+	int err;
+	int len;
+	struct sk_buff *skb;
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	hermes_t *hw = &priv->hw;
+
+	len = le16_to_cpu(desc->data_len);
+
+	/* Determine the size of the header and the data */
+	fc = le16_to_cpu(desc->frame_ctl);
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_DATA:
+		if ((fc & IEEE80211_FCTL_TODS)
+		    && (fc & IEEE80211_FCTL_FROMDS))
+			hdrlen = 30;
+		else
+			hdrlen = 24;
+		datalen = len;
+		break;
+	case IEEE80211_FTYPE_MGMT:
+		hdrlen = 24;
+		datalen = len;
+		break;
+	case IEEE80211_FTYPE_CTL:
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_PSPOLL:
+		case IEEE80211_STYPE_RTS:
+		case IEEE80211_STYPE_CFEND:
+		case IEEE80211_STYPE_CFENDACK:
+			hdrlen = 16;
+			break;
+		case IEEE80211_STYPE_CTS:
+		case IEEE80211_STYPE_ACK:
+			hdrlen = 10;
+			break;
+		}
+		break;
+	default:
+		/* Unknown frame type */
+		break;
+	}
+
+	/* sanity check the length */
+	if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
+		printk(KERN_DEBUG "%s: oversized monitor frame, "
+		       "data length = %d\n", dev->name, datalen);
+		stats->rx_length_errors++;
+		goto update_stats;
+	}
+
+	skb = dev_alloc_skb(hdrlen + datalen);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+		       dev->name);
+		goto update_stats;
+	}
+
+	/* Copy the 802.11 header to the skb */
+	memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+	skb_reset_mac_header(skb);
+
+	/* If any, copy the data from the card to the skb */
+	if (datalen > 0) {
+		err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+				       ALIGN(datalen, 2), rxfid,
+				       HERMES_802_2_OFFSET);
+		if (err) {
+			printk(KERN_ERR "%s: error %d reading monitor frame\n",
+			       dev->name, err);
+			goto drop;
+		}
+	}
+
+	skb->dev = dev;
+	skb->ip_summed = CHECKSUM_NONE;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = cpu_to_be16(ETH_P_802_2);
+
+	stats->rx_packets++;
+	stats->rx_bytes += skb->len;
+
+	netif_rx(skb);
+	return;
+
+ drop:
+	dev_kfree_skb_irq(skb);
+ update_stats:
+	stats->rx_errors++;
+	stats->rx_dropped++;
+}
+
+static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	struct iw_statistics *wstats = &priv->wstats;
+	struct sk_buff *skb = NULL;
+	u16 rxfid, status;
+	int length;
+	struct hermes_rx_descriptor *desc;
+	struct orinoco_rx_data *rx_data;
+	int err;
+
+	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+	if (!desc) {
+		printk(KERN_WARNING
+		       "%s: Can't allocate space for RX descriptor\n",
+		       dev->name);
+		goto update_stats;
+	}
+
+	rxfid = hermes_read_regn(hw, RXFID);
+
+	err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
+			       rxfid, 0);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading Rx descriptor. "
+		       "Frame dropped.\n", dev->name, err);
+		goto update_stats;
+	}
+
+	status = le16_to_cpu(desc->status);
+
+	if (status & HERMES_RXSTAT_BADCRC) {
+		DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+		      dev->name);
+		stats->rx_crc_errors++;
+		goto update_stats;
+	}
+
+	/* Handle frames in monitor mode */
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		orinoco_rx_monitor(dev, rxfid, desc);
+		goto out;
+	}
+
+	if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+		DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+		      dev->name);
+		wstats->discard.code++;
+		goto update_stats;
+	}
+
+	length = le16_to_cpu(desc->data_len);
+
+	/* Sanity checks */
+	if (length < 3) { /* No for even an 802.2 LLC header */
+		/* At least on Symbol firmware with PCF we get quite a
+		   lot of these legitimately - Poll frames with no
+		   data. */
+		goto out;
+	}
+	if (length > IEEE80211_MAX_DATA_LEN) {
+		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
+		       dev->name, length);
+		stats->rx_length_errors++;
+		goto update_stats;
+	}
+
+	/* Payload size does not include Michael MIC. Increase payload
+	 * size to read it together with the data. */
+	if (status & HERMES_RXSTAT_MIC)
+		length += MICHAEL_MIC_LEN;
+
+	/* We need space for the packet data itself, plus an ethernet
+	   header, plus 2 bytes so we can align the IP header on a
+	   32bit boundary, plus 1 byte so we can read in odd length
+	   packets from the card, which has an IO granularity of 16
+	   bits */
+	skb = dev_alloc_skb(length+ETH_HLEN+2+1);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
+		       dev->name);
+		goto update_stats;
+	}
+
+	/* We'll prepend the header, so reserve space for it.  The worst
+	   case is no decapsulation, when 802.3 header is prepended and
+	   nothing is removed.  2 is for aligning the IP header.  */
+	skb_reserve(skb, ETH_HLEN + 2);
+
+	err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+			       ALIGN(length, 2), rxfid,
+			       HERMES_802_2_OFFSET);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading frame. "
+		       "Frame dropped.\n", dev->name, err);
+		goto drop;
+	}
+
+	/* Add desc and skb to rx queue */
+	rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
+	if (!rx_data) {
+		printk(KERN_WARNING "%s: Can't allocate RX packet\n",
+			dev->name);
+		goto drop;
+	}
+	rx_data->desc = desc;
+	rx_data->skb = skb;
+	list_add_tail(&rx_data->list, &priv->rx_list);
+	tasklet_schedule(&priv->rx_tasklet);
+
+	return;
+
+drop:
+	dev_kfree_skb_irq(skb);
+update_stats:
+	stats->rx_errors++;
+	stats->rx_dropped++;
+out:
+	kfree(desc);
+}
+
+static void orinoco_rx(struct net_device *dev,
+		       struct hermes_rx_descriptor *desc,
+		       struct sk_buff *skb)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	u16 status, fc;
+	int length;
+	struct ethhdr *hdr;
+
+	status = le16_to_cpu(desc->status);
+	length = le16_to_cpu(desc->data_len);
+	fc = le16_to_cpu(desc->frame_ctl);
+
+	/* Calculate and check MIC */
+	if (status & HERMES_RXSTAT_MIC) {
+		int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
+			      HERMES_MIC_KEY_ID_SHIFT);
+		u8 mic[MICHAEL_MIC_LEN];
+		u8 *rxmic;
+		u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
+			desc->addr3 : desc->addr2;
+
+		/* Extract Michael MIC from payload */
+		rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
+
+		skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
+		length -= MICHAEL_MIC_LEN;
+
+		orinoco_mic(priv->rx_tfm_mic,
+			    priv->tkip_key[key_id].rx_mic,
+			    desc->addr1,
+			    src,
+			    0, /* priority or QoS? */
+			    skb->data,
+			    skb->len,
+			    &mic[0]);
+
+		if (memcmp(mic, rxmic,
+			   MICHAEL_MIC_LEN)) {
+			union iwreq_data wrqu;
+			struct iw_michaelmicfailure wxmic;
+
+			printk(KERN_WARNING "%s: "
+			       "Invalid Michael MIC in data frame from %pM, "
+			       "using key %i\n",
+			       dev->name, src, key_id);
+
+			/* TODO: update stats */
+
+			/* Notify userspace */
+			memset(&wxmic, 0, sizeof(wxmic));
+			wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
+			wxmic.flags |= (desc->addr1[0] & 1) ?
+				IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
+			wxmic.src_addr.sa_family = ARPHRD_ETHER;
+			memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
+
+			(void) orinoco_hw_get_tkip_iv(priv, key_id,
+						      &wxmic.tsc[0]);
+
+			memset(&wrqu, 0, sizeof(wrqu));
+			wrqu.data.length = sizeof(wxmic);
+			wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
+					    (char *) &wxmic);
+
+			goto drop;
+		}
+	}
+
+	/* Handle decapsulation
+	 * In most cases, the firmware tell us about SNAP frames.
+	 * For some reason, the SNAP frames sent by LinkSys APs
+	 * are not properly recognised by most firmwares.
+	 * So, check ourselves */
+	if (length >= ENCAPS_OVERHEAD &&
+	    (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+	     ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+	     is_ethersnap(skb->data))) {
+		/* These indicate a SNAP within 802.2 LLC within
+		   802.11 frame which we'll need to de-encapsulate to
+		   the original EthernetII frame. */
+		hdr = (struct ethhdr *)skb_push(skb,
+						ETH_HLEN - ENCAPS_OVERHEAD);
+	} else {
+		/* 802.3 frame - prepend 802.3 header as is */
+		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+		hdr->h_proto = htons(length);
+	}
+	memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
+	if (fc & IEEE80211_FCTL_FROMDS)
+		memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
+	else
+		memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
+
+	skb->protocol = eth_type_trans(skb, dev);
+	skb->ip_summed = CHECKSUM_NONE;
+	if (fc & IEEE80211_FCTL_TODS)
+		skb->pkt_type = PACKET_OTHERHOST;
+
+	/* Process the wireless stats if needed */
+	orinoco_stat_gather(dev, skb, desc);
+
+	/* Pass the packet to the networking stack */
+	netif_rx(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += length;
+
+	return;
+
+ drop:
+	dev_kfree_skb(skb);
+	stats->rx_errors++;
+	stats->rx_dropped++;
+}
+
+static void orinoco_rx_isr_tasklet(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *) data;
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct orinoco_rx_data *rx_data, *temp;
+	struct hermes_rx_descriptor *desc;
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	/* orinoco_rx requires the driver lock, and we also need to
+	 * protect priv->rx_list, so just hold the lock over the
+	 * lot.
+	 *
+	 * If orinoco_lock fails, we've unplugged the card. In this
+	 * case just abort. */
+	if (orinoco_lock(priv, &flags) != 0)
+		return;
+
+	/* extract desc and skb from queue */
+	list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
+		desc = rx_data->desc;
+		skb = rx_data->skb;
+		list_del(&rx_data->list);
+		kfree(rx_data);
+
+		orinoco_rx(dev, desc, skb);
+
+		kfree(desc);
+	}
+
+	orinoco_unlock(priv, &flags);
+}
+
+/********************************************************************/
+/* Rx path (info frames)                                            */
+/********************************************************************/
+
+static void print_linkstatus(struct net_device *dev, u16 status)
+{
+	char *s;
+
+	if (suppress_linkstatus)
+		return;
+
+	switch (status) {
+	case HERMES_LINKSTATUS_NOT_CONNECTED:
+		s = "Not Connected";
+		break;
+	case HERMES_LINKSTATUS_CONNECTED:
+		s = "Connected";
+		break;
+	case HERMES_LINKSTATUS_DISCONNECTED:
+		s = "Disconnected";
+		break;
+	case HERMES_LINKSTATUS_AP_CHANGE:
+		s = "AP Changed";
+		break;
+	case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
+		s = "AP Out of Range";
+		break;
+	case HERMES_LINKSTATUS_AP_IN_RANGE:
+		s = "AP In Range";
+		break;
+	case HERMES_LINKSTATUS_ASSOC_FAILED:
+		s = "Association Failed";
+		break;
+	default:
+		s = "UNKNOWN";
+	}
+
+	printk(KERN_DEBUG "%s: New link status: %s (%04x)\n",
+	       dev->name, s, status);
+}
+
+/* Search scan results for requested BSSID, join it if found */
+static void orinoco_join_ap(struct work_struct *work)
+{
+	struct orinoco_private *priv =
+		container_of(work, struct orinoco_private, join_work);
+	struct net_device *dev = priv->ndev;
+	struct hermes *hw = &priv->hw;
+	int err;
+	unsigned long flags;
+	struct join_req {
+		u8 bssid[ETH_ALEN];
+		__le16 channel;
+	} __attribute__ ((packed)) req;
+	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
+	struct prism2_scan_apinfo *atom = NULL;
+	int offset = 4;
+	int found = 0;
+	u8 *buf;
+	u16 len;
+
+	/* Allocate buffer for scan results */
+	buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		goto fail_lock;
+
+	/* Sanity checks in case user changed something in the meantime */
+	if (!priv->bssid_fixed)
+		goto out;
+
+	if (strlen(priv->desired_essid) == 0)
+		goto out;
+
+	/* Read scan results from the firmware */
+	err = hermes_read_ltv(hw, USER_BAP,
+			      HERMES_RID_SCANRESULTSTABLE,
+			      MAX_SCAN_LEN, &len, buf);
+	if (err) {
+		printk(KERN_ERR "%s: Cannot read scan results\n",
+		       dev->name);
+		goto out;
+	}
+
+	len = HERMES_RECLEN_TO_BYTES(len);
+
+	/* Go through the scan results looking for the channel of the AP
+	 * we were requested to join */
+	for (; offset + atom_len <= len; offset += atom_len) {
+		atom = (struct prism2_scan_apinfo *) (buf + offset);
+		if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		DEBUG(1, "%s: Requested AP not found in scan results\n",
+		      dev->name);
+		goto out;
+	}
+
+	memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
+	req.channel = atom->channel;	/* both are little-endian */
+	err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
+				  &req);
+	if (err)
+		printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
+
+ out:
+	orinoco_unlock(priv, &flags);
+
+ fail_lock:
+	kfree(buf);
+}
+
+/* Send new BSSID to userspace */
+static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
+{
+	struct net_device *dev = priv->ndev;
+	struct hermes *hw = &priv->hw;
+	union iwreq_data wrqu;
+	int err;
+
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+	if (err != 0)
+		return;
+
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+	/* Send event to user space */
+	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
+{
+	struct net_device *dev = priv->ndev;
+	struct hermes *hw = &priv->hw;
+	union iwreq_data wrqu;
+	int err;
+	u8 buf[88];
+	u8 *ie;
+
+	if (!priv->has_wpa)
+		return;
+
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+			      sizeof(buf), NULL, &buf);
+	if (err != 0)
+		return;
+
+	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
+	if (ie) {
+		int rem = sizeof(buf) - (ie - &buf[0]);
+		wrqu.data.length = ie[1] + 2;
+		if (wrqu.data.length > rem)
+			wrqu.data.length = rem;
+
+		if (wrqu.data.length)
+			/* Send event to user space */
+			wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
+	}
+}
+
+static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
+{
+	struct net_device *dev = priv->ndev;
+	struct hermes *hw = &priv->hw;
+	union iwreq_data wrqu;
+	int err;
+	u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
+	u8 *ie;
+
+	if (!priv->has_wpa)
+		return;
+
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+			      sizeof(buf), NULL, &buf);
+	if (err != 0)
+		return;
+
+	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
+	if (ie) {
+		int rem = sizeof(buf) - (ie - &buf[0]);
+		wrqu.data.length = ie[1] + 2;
+		if (wrqu.data.length > rem)
+			wrqu.data.length = rem;
+
+		if (wrqu.data.length)
+			/* Send event to user space */
+			wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
+	}
+}
+
+static void orinoco_send_wevents(struct work_struct *work)
+{
+	struct orinoco_private *priv =
+		container_of(work, struct orinoco_private, wevent_work);
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return;
+
+	orinoco_send_assocreqie_wevent(priv);
+	orinoco_send_assocrespie_wevent(priv);
+	orinoco_send_bssid_wevent(priv);
+
+	orinoco_unlock(priv, &flags);
+}
+
+static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	u16 infofid;
+	struct {
+		__le16 len;
+		__le16 type;
+	} __attribute__ ((packed)) info;
+	int len, type;
+	int err;
+
+	/* This is an answer to an INQUIRE command that we did earlier,
+	 * or an information "event" generated by the card
+	 * The controller return to us a pseudo frame containing
+	 * the information in question - Jean II */
+	infofid = hermes_read_regn(hw, INFOFID);
+
+	/* Read the info frame header - don't try too hard */
+	err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
+			       infofid, 0);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading info frame. "
+		       "Frame dropped.\n", dev->name, err);
+		return;
+	}
+
+	len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
+	type = le16_to_cpu(info.type);
+
+	switch (type) {
+	case HERMES_INQ_TALLIES: {
+		struct hermes_tallies_frame tallies;
+		struct iw_statistics *wstats = &priv->wstats;
+
+		if (len > sizeof(tallies)) {
+			printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
+			       dev->name, len);
+			len = sizeof(tallies);
+		}
+
+		err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
+				       infofid, sizeof(info));
+		if (err)
+			break;
+
+		/* Increment our various counters */
+		/* wstats->discard.nwid - no wrong BSSID stuff */
+		wstats->discard.code +=
+			le16_to_cpu(tallies.RxWEPUndecryptable);
+		if (len == sizeof(tallies))
+			wstats->discard.code +=
+				le16_to_cpu(tallies.RxDiscards_WEPICVError) +
+				le16_to_cpu(tallies.RxDiscards_WEPExcluded);
+		wstats->discard.misc +=
+			le16_to_cpu(tallies.TxDiscardsWrongSA);
+		wstats->discard.fragment +=
+			le16_to_cpu(tallies.RxMsgInBadMsgFragments);
+		wstats->discard.retries +=
+			le16_to_cpu(tallies.TxRetryLimitExceeded);
+		/* wstats->miss.beacon - no match */
+	}
+	break;
+	case HERMES_INQ_LINKSTATUS: {
+		struct hermes_linkstatus linkstatus;
+		u16 newstatus;
+		int connected;
+
+		if (priv->iw_mode == IW_MODE_MONITOR)
+			break;
+
+		if (len != sizeof(linkstatus)) {
+			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
+			       dev->name, len);
+			break;
+		}
+
+		err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
+				       infofid, sizeof(info));
+		if (err)
+			break;
+		newstatus = le16_to_cpu(linkstatus.linkstatus);
+
+		/* Symbol firmware uses "out of range" to signal that
+		 * the hostscan frame can be requested.  */
+		if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
+		    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
+		    priv->has_hostscan && priv->scan_inprogress) {
+			hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
+			break;
+		}
+
+		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
+			|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
+			|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
+
+		if (connected)
+			netif_carrier_on(dev);
+		else if (!ignore_disconnect)
+			netif_carrier_off(dev);
+
+		if (newstatus != priv->last_linkstatus) {
+			priv->last_linkstatus = newstatus;
+			print_linkstatus(dev, newstatus);
+			/* The info frame contains only one word which is the
+			 * status (see hermes.h). The status is pretty boring
+			 * in itself, that's why we export the new BSSID...
+			 * Jean II */
+			schedule_work(&priv->wevent_work);
+		}
+	}
+	break;
+	case HERMES_INQ_SCAN:
+		if (!priv->scan_inprogress && priv->bssid_fixed &&
+		    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+			schedule_work(&priv->join_work);
+			break;
+		}
+		/* fall through */
+	case HERMES_INQ_HOSTSCAN:
+	case HERMES_INQ_HOSTSCAN_SYMBOL: {
+		/* Result of a scanning. Contains information about
+		 * cells in the vicinity - Jean II */
+		union iwreq_data	wrqu;
+		unsigned char *buf;
+
+		/* Scan is no longer in progress */
+		priv->scan_inprogress = 0;
+
+		/* Sanity check */
+		if (len > 4096) {
+			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
+			       dev->name, len);
+			break;
+		}
+
+		/* Allocate buffer for results */
+		buf = kmalloc(len, GFP_ATOMIC);
+		if (buf == NULL)
+			/* No memory, so can't printk()... */
+			break;
+
+		/* Read scan data */
+		err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
+				       infofid, sizeof(info));
+		if (err) {
+			kfree(buf);
+			break;
+		}
+
+#ifdef ORINOCO_DEBUG
+		{
+			int	i;
+			printk(KERN_DEBUG "Scan result [%02X", buf[0]);
+			for (i = 1; i < (len * 2); i++)
+				printk(":%02X", buf[i]);
+			printk("]\n");
+		}
+#endif	/* ORINOCO_DEBUG */
+
+		if (orinoco_process_scan_results(priv, buf, len) == 0) {
+			/* Send an empty event to user space.
+			 * We don't send the received data on the event because
+			 * it would require us to do complex transcoding, and
+			 * we want to minimise the work done in the irq handler
+			 * Use a request to extract the data - Jean II */
+			wrqu.data.length = 0;
+			wrqu.data.flags = 0;
+			wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+		}
+		kfree(buf);
+	}
+	break;
+	case HERMES_INQ_CHANNELINFO:
+	{
+		struct agere_ext_scan_info *bss;
+
+		if (!priv->scan_inprogress) {
+			printk(KERN_DEBUG "%s: Got chaninfo without scan, "
+			       "len=%d\n", dev->name, len);
+			break;
+		}
+
+		/* An empty result indicates that the scan is complete */
+		if (len == 0) {
+			union iwreq_data	wrqu;
+
+			/* Scan is no longer in progress */
+			priv->scan_inprogress = 0;
+
+			wrqu.data.length = 0;
+			wrqu.data.flags = 0;
+			wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+			break;
+		}
+
+		/* Sanity check */
+		else if (len > sizeof(*bss)) {
+			printk(KERN_WARNING
+			       "%s: Ext scan results too large (%d bytes). "
+			       "Truncating results to %zd bytes.\n",
+			       dev->name, len, sizeof(*bss));
+			len = sizeof(*bss);
+		} else if (len < (offsetof(struct agere_ext_scan_info,
+					   data) + 2)) {
+			/* Drop this result now so we don't have to
+			 * keep checking later */
+			printk(KERN_WARNING
+			       "%s: Ext scan results too short (%d bytes)\n",
+			       dev->name, len);
+			break;
+		}
+
+		bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+		if (bss == NULL)
+			break;
+
+		/* Read scan data */
+		err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
+				       infofid, sizeof(info));
+		if (err) {
+			kfree(bss);
+			break;
+		}
+
+		orinoco_add_ext_scan_result(priv, bss);
+
+		kfree(bss);
+		break;
+	}
+	case HERMES_INQ_SEC_STAT_AGERE:
+		/* Security status (Agere specific) */
+		/* Ignore this frame for now */
+		if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+			break;
+		/* fall through */
+	default:
+		printk(KERN_DEBUG "%s: Unknown information frame received: "
+		       "type 0x%04x, length %d\n", dev->name, type, len);
+		/* We don't actually do anything about it */
+		break;
+	}
+}
+
+static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
+{
+	if (net_ratelimit())
+		printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
+}
+
+/********************************************************************/
+/* Internal hardware control routines                               */
+/********************************************************************/
+
+int __orinoco_up(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	int err;
+
+	netif_carrier_off(dev); /* just to make sure */
+
+	err = __orinoco_program_rids(dev);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d configuring card\n",
+		       dev->name, err);
+		return err;
+	}
+
+	/* Fire things up again */
+	hermes_set_irqmask(hw, ORINOCO_INTEN);
+	err = hermes_enable_port(hw, 0);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d enabling MAC port\n",
+		       dev->name, err);
+		return err;
+	}
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(__orinoco_up);
+
+int __orinoco_down(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	int err;
+
+	netif_stop_queue(dev);
+
+	if (!priv->hw_unavailable) {
+		if (!priv->broken_disableport) {
+			err = hermes_disable_port(hw, 0);
+			if (err) {
+				/* Some firmwares (e.g. Intersil 1.3.x) seem
+				 * to have problems disabling the port, oh
+				 * well, too bad. */
+				printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
+				       dev->name, err);
+				priv->broken_disableport = 1;
+			}
+		}
+		hermes_set_irqmask(hw, 0);
+		hermes_write_regn(hw, EVACK, 0xffff);
+	}
+
+	/* firmware will have to reassociate */
+	netif_carrier_off(dev);
+	priv->last_linkstatus = 0xffff;
+
+	return 0;
+}
+EXPORT_SYMBOL(__orinoco_down);
+
+static int orinoco_allocate_fid(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	int err;
+
+	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+	if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
+		/* Try workaround for old Symbol firmware bug */
+		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+
+		printk(KERN_WARNING "%s: firmware ALLOC bug detected "
+		       "(old Symbol firmware?). Work around %s\n",
+		       dev->name, err ? "failed!" : "ok.");
+	}
+
+	return err;
+}
+
+int orinoco_reinit_firmware(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	int err;
+
+	err = hermes_init(hw);
+	if (priv->do_fw_download && !err) {
+		err = orinoco_download(priv);
+		if (err)
+			priv->do_fw_download = 0;
+	}
+	if (!err)
+		err = orinoco_allocate_fid(dev);
+
+	return err;
+}
+EXPORT_SYMBOL(orinoco_reinit_firmware);
+
+int __orinoco_program_rids(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int err;
+	struct hermes_idstring idbuf;
+
+	/* Set the MAC address */
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+			       HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting MAC address\n",
+		       dev->name, err);
+		return err;
+	}
+
+	/* Set up the link mode */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
+				   priv->port_type);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting port type\n",
+		       dev->name, err);
+		return err;
+	}
+	/* Set the channel/frequency */
+	if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFOWNCHANNEL,
+					   priv->channel);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting channel %d\n",
+			       dev->name, err, priv->channel);
+			return err;
+		}
+	}
+
+	if (priv->has_ibss) {
+		u16 createibss;
+
+		if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
+			printk(KERN_WARNING "%s: This firmware requires an "
+			       "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
+			/* With wvlan_cs, in this case, we would crash.
+			 * hopefully, this driver will behave better...
+			 * Jean II */
+			createibss = 0;
+		} else {
+			createibss = priv->createibss;
+		}
+
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFCREATEIBSS,
+					   createibss);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+			       dev->name, err);
+			return err;
+		}
+	}
+
+	/* Set the desired BSSID */
+	err = __orinoco_hw_set_wap(priv);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting AP address\n",
+		       dev->name, err);
+		return err;
+	}
+	/* Set the desired ESSID */
+	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
+	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
+	/* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+			HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+			&idbuf);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
+		       dev->name, err);
+		return err;
+	}
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+			HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+			&idbuf);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
+		       dev->name, err);
+		return err;
+	}
+
+	/* Set the station name */
+	idbuf.len = cpu_to_le16(strlen(priv->nick));
+	memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+			       HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+			       &idbuf);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting nickname\n",
+		       dev->name, err);
+		return err;
+	}
+
+	/* Set AP density */
+	if (priv->has_sensitivity) {
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFSYSTEMSCALE,
+					   priv->ap_density);
+		if (err) {
+			printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
+			       "Disabling sensitivity control\n",
+			       dev->name, err);
+
+			priv->has_sensitivity = 0;
+		}
+	}
+
+	/* Set RTS threshold */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+				   priv->rts_thresh);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
+		       dev->name, err);
+		return err;
+	}
+
+	/* Set fragmentation threshold or MWO robustness */
+	if (priv->has_mwo)
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFMWOROBUST_AGERE,
+					   priv->mwo_robust);
+	else
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+					   priv->frag_thresh);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting fragmentation\n",
+		       dev->name, err);
+		return err;
+	}
+
+	/* Set bitrate */
+	err = __orinoco_hw_set_bitrate(priv);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting bitrate\n",
+		       dev->name, err);
+		return err;
+	}
+
+	/* Set power management */
+	if (priv->has_pm) {
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFPMENABLED,
+					   priv->pm_on);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting up PM\n",
+			       dev->name, err);
+			return err;
+		}
+
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFMULTICASTRECEIVE,
+					   priv->pm_mcast);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting up PM\n",
+			       dev->name, err);
+			return err;
+		}
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFMAXSLEEPDURATION,
+					   priv->pm_period);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting up PM\n",
+			       dev->name, err);
+			return err;
+		}
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFPMHOLDOVERDURATION,
+					   priv->pm_timeout);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting up PM\n",
+			       dev->name, err);
+			return err;
+		}
+	}
+
+	/* Set preamble - only for Symbol so far... */
+	if (priv->has_preamble) {
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFPREAMBLE_SYMBOL,
+					   priv->preamble);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting preamble\n",
+			       dev->name, err);
+			return err;
+		}
+	}
+
+	/* Set up encryption */
+	if (priv->has_wep || priv->has_wpa) {
+		err = __orinoco_hw_setup_enc(priv);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d activating encryption\n",
+			       dev->name, err);
+			return err;
+		}
+	}
+
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		/* Enable monitor mode */
+		dev->type = ARPHRD_IEEE80211;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+					    HERMES_TEST_MONITOR, 0, NULL);
+	} else {
+		/* Disable monitor mode */
+		dev->type = ARPHRD_ETHER;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+					    HERMES_TEST_STOP, 0, NULL);
+	}
+	if (err)
+		return err;
+
+	/* Set promiscuity / multicast*/
+	priv->promiscuous = 0;
+	priv->mc_count = 0;
+
+	/* FIXME: what about netif_tx_lock */
+	__orinoco_set_multicast_list(dev);
+
+	return 0;
+}
+
+/* FIXME: return int? */
+static void
+__orinoco_set_multicast_list(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+	int promisc, mc_count;
+
+	/* The Hermes doesn't seem to have an allmulti mode, so we go
+	 * into promiscuous mode and let the upper levels deal. */
+	if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+	    (dev->mc_count > MAX_MULTICAST(priv))) {
+		promisc = 1;
+		mc_count = 0;
+	} else {
+		promisc = 0;
+		mc_count = dev->mc_count;
+	}
+
+	err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count,
+					      promisc);
+}
+
+/* This must be called from user context, without locks held - use
+ * schedule_work() */
+void orinoco_reset(struct work_struct *work)
+{
+	struct orinoco_private *priv =
+		container_of(work, struct orinoco_private, reset_work);
+	struct net_device *dev = priv->ndev;
+	struct hermes *hw = &priv->hw;
+	int err;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		/* When the hardware becomes available again, whatever
+		 * detects that is responsible for re-initializing
+		 * it. So no need for anything further */
+		return;
+
+	netif_stop_queue(dev);
+
+	/* Shut off interrupts.  Depending on what state the hardware
+	 * is in, this might not work, but we'll try anyway */
+	hermes_set_irqmask(hw, 0);
+	hermes_write_regn(hw, EVACK, 0xffff);
+
+	priv->hw_unavailable++;
+	priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
+	netif_carrier_off(dev);
+
+	orinoco_unlock(priv, &flags);
+
+	/* Scanning support: Cleanup of driver struct */
+	orinoco_clear_scan_results(priv, 0);
+	priv->scan_inprogress = 0;
+
+	if (priv->hard_reset) {
+		err = (*priv->hard_reset)(priv);
+		if (err) {
+			printk(KERN_ERR "%s: orinoco_reset: Error %d "
+			       "performing hard reset\n", dev->name, err);
+			goto disable;
+		}
+	}
+
+	err = orinoco_reinit_firmware(dev);
+	if (err) {
+		printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
+		       dev->name, err);
+		goto disable;
+	}
+
+	/* This has to be called from user context */
+	spin_lock_irq(&priv->lock);
+
+	priv->hw_unavailable--;
+
+	/* priv->open or priv->hw_unavailable might have changed while
+	 * we dropped the lock */
+	if (priv->open && (!priv->hw_unavailable)) {
+		err = __orinoco_up(dev);
+		if (err) {
+			printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
+			       dev->name, err);
+		} else
+			dev->trans_start = jiffies;
+	}
+
+	spin_unlock_irq(&priv->lock);
+
+	return;
+ disable:
+	hermes_set_irqmask(hw, 0);
+	netif_device_detach(dev);
+	printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
+}
+
+/********************************************************************/
+/* Interrupt handler                                                */
+/********************************************************************/
+
+static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
+{
+	printk(KERN_DEBUG "%s: TICK\n", dev->name);
+}
+
+static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
+{
+	/* This seems to happen a fair bit under load, but ignoring it
+	   seems to work fine...*/
+	printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
+	       dev->name);
+}
+
+irqreturn_t orinoco_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int count = MAX_IRQLOOPS_PER_IRQ;
+	u16 evstat, events;
+	/* These are used to detect a runaway interrupt situation.
+	 *
+	 * If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
+	 * we panic and shut down the hardware
+	 */
+	/* jiffies value the last time we were called */
+	static int last_irq_jiffy; /* = 0 */
+	static int loops_this_jiffy; /* = 0 */
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0) {
+		/* If hw is unavailable - we don't know if the irq was
+		 * for us or not */
+		return IRQ_HANDLED;
+	}
+
+	evstat = hermes_read_regn(hw, EVSTAT);
+	events = evstat & hw->inten;
+	if (!events) {
+		orinoco_unlock(priv, &flags);
+		return IRQ_NONE;
+	}
+
+	if (jiffies != last_irq_jiffy)
+		loops_this_jiffy = 0;
+	last_irq_jiffy = jiffies;
+
+	while (events && count--) {
+		if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
+			printk(KERN_WARNING "%s: IRQ handler is looping too "
+			       "much! Resetting.\n", dev->name);
+			/* Disable interrupts for now */
+			hermes_set_irqmask(hw, 0);
+			schedule_work(&priv->reset_work);
+			break;
+		}
+
+		/* Check the card hasn't been removed */
+		if (!hermes_present(hw)) {
+			DEBUG(0, "orinoco_interrupt(): card removed\n");
+			break;
+		}
+
+		if (events & HERMES_EV_TICK)
+			__orinoco_ev_tick(dev, hw);
+		if (events & HERMES_EV_WTERR)
+			__orinoco_ev_wterr(dev, hw);
+		if (events & HERMES_EV_INFDROP)
+			__orinoco_ev_infdrop(dev, hw);
+		if (events & HERMES_EV_INFO)
+			__orinoco_ev_info(dev, hw);
+		if (events & HERMES_EV_RX)
+			__orinoco_ev_rx(dev, hw);
+		if (events & HERMES_EV_TXEXC)
+			__orinoco_ev_txexc(dev, hw);
+		if (events & HERMES_EV_TX)
+			__orinoco_ev_tx(dev, hw);
+		if (events & HERMES_EV_ALLOC)
+			__orinoco_ev_alloc(dev, hw);
+
+		hermes_write_regn(hw, EVACK, evstat);
+
+		evstat = hermes_read_regn(hw, EVSTAT);
+		events = evstat & hw->inten;
+	};
+
+	orinoco_unlock(priv, &flags);
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(orinoco_interrupt);
+
+/********************************************************************/
+/* Power management                                                 */
+/********************************************************************/
+#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
+static int orinoco_pm_notifier(struct notifier_block *notifier,
+			       unsigned long pm_event,
+			       void *unused)
+{
+	struct orinoco_private *priv = container_of(notifier,
+						    struct orinoco_private,
+						    pm_notifier);
+
+	/* All we need to do is cache the firmware before suspend, and
+	 * release it when we come out.
+	 *
+	 * Only need to do this if we're downloading firmware. */
+	if (!priv->do_fw_download)
+		return NOTIFY_DONE;
+
+	switch (pm_event) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		orinoco_cache_fw(priv, 0);
+		break;
+
+	case PM_POST_RESTORE:
+		/* Restore from hibernation failed. We need to clean
+		 * up in exactly the same way, so fall through. */
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		orinoco_uncache_fw(priv);
+		break;
+
+	case PM_RESTORE_PREPARE:
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
+#define orinoco_pm_notifier NULL
+#endif
+
+/********************************************************************/
+/* Initialization                                                   */
+/********************************************************************/
+
+struct comp_id {
+	u16 id, variant, major, minor;
+} __attribute__ ((packed));
+
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
+{
+	if (nic_id->id < 0x8000)
+		return FIRMWARE_TYPE_AGERE;
+	else if (nic_id->id == 0x8000 && nic_id->major == 0)
+		return FIRMWARE_TYPE_SYMBOL;
+	else
+		return FIRMWARE_TYPE_INTERSIL;
+}
+
+/* Set priv->firmware type, determine firmware properties */
+static int determine_firmware(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int err;
+	struct comp_id nic_id, sta_id;
+	unsigned int firmver;
+	char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
+
+	/* Get the hardware version */
+	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+	if (err) {
+		printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
+		       dev->name, err);
+		return err;
+	}
+
+	le16_to_cpus(&nic_id.id);
+	le16_to_cpus(&nic_id.variant);
+	le16_to_cpus(&nic_id.major);
+	le16_to_cpus(&nic_id.minor);
+	printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
+	       dev->name, nic_id.id, nic_id.variant,
+	       nic_id.major, nic_id.minor);
+
+	priv->firmware_type = determine_firmware_type(&nic_id);
+
+	/* Get the firmware version */
+	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
+	if (err) {
+		printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
+		       dev->name, err);
+		return err;
+	}
+
+	le16_to_cpus(&sta_id.id);
+	le16_to_cpus(&sta_id.variant);
+	le16_to_cpus(&sta_id.major);
+	le16_to_cpus(&sta_id.minor);
+	printk(KERN_DEBUG "%s: Station identity  %04x:%04x:%04x:%04x\n",
+	       dev->name, sta_id.id, sta_id.variant,
+	       sta_id.major, sta_id.minor);
+
+	switch (sta_id.id) {
+	case 0x15:
+		printk(KERN_ERR "%s: Primary firmware is active\n",
+		       dev->name);
+		return -ENODEV;
+	case 0x14b:
+		printk(KERN_ERR "%s: Tertiary firmware is active\n",
+		       dev->name);
+		return -ENODEV;
+	case 0x1f:	/* Intersil, Agere, Symbol Spectrum24 */
+	case 0x21:	/* Symbol Spectrum24 Trilogy */
+		break;
+	default:
+		printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
+		       dev->name);
+		break;
+	}
+
+	/* Default capabilities */
+	priv->has_sensitivity = 1;
+	priv->has_mwo = 0;
+	priv->has_preamble = 0;
+	priv->has_port3 = 1;
+	priv->has_ibss = 1;
+	priv->has_wep = 0;
+	priv->has_big_wep = 0;
+	priv->has_alt_txcntl = 0;
+	priv->has_ext_scan = 0;
+	priv->has_wpa = 0;
+	priv->do_fw_download = 0;
+
+	/* Determine capabilities from the firmware version */
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
+		   ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
+
+		firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
+
+		priv->has_ibss = (firmver >= 0x60006);
+		priv->has_wep = (firmver >= 0x40020);
+		priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+					  Gold cards from the others? */
+		priv->has_mwo = (firmver >= 0x60000);
+		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
+		priv->ibss_port = 1;
+		priv->has_hostscan = (firmver >= 0x8000a);
+		priv->do_fw_download = 1;
+		priv->broken_monitor = (firmver >= 0x80000);
+		priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
+		priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
+		priv->has_wpa = (firmver >= 0x9002a);
+		/* Tested with Agere firmware :
+		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
+		 * Tested CableTron firmware : 4.32 => Anton */
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+		/* Intel MAC : 00:02:B3:* */
+		/* 3Com MAC : 00:50:DA:* */
+		memset(tmp, 0, sizeof(tmp));
+		/* Get the Symbol firmware version */
+		err = hermes_read_ltv(hw, USER_BAP,
+				      HERMES_RID_SECONDARYVERSION_SYMBOL,
+				      SYMBOL_MAX_VER_LEN, NULL, &tmp);
+		if (err) {
+			printk(KERN_WARNING
+			       "%s: Error %d reading Symbol firmware info. "
+			       "Wildly guessing capabilities...\n",
+			       dev->name, err);
+			firmver = 0;
+			tmp[0] = '\0';
+		} else {
+			/* The firmware revision is a string, the format is
+			 * something like : "V2.20-01".
+			 * Quick and dirty parsing... - Jean II
+			 */
+			firmver = ((tmp[1] - '0') << 16)
+				| ((tmp[3] - '0') << 12)
+				| ((tmp[4] - '0') << 8)
+				| ((tmp[6] - '0') << 4)
+				| (tmp[7] - '0');
+
+			tmp[SYMBOL_MAX_VER_LEN] = '\0';
+		}
+
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Symbol %s", tmp);
+
+		priv->has_ibss = (firmver >= 0x20000);
+		priv->has_wep = (firmver >= 0x15012);
+		priv->has_big_wep = (firmver >= 0x20000);
+		priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
+			       (firmver >= 0x29000 && firmver < 0x30000) ||
+			       firmver >= 0x31000;
+		priv->has_preamble = (firmver >= 0x20000);
+		priv->ibss_port = 4;
+
+		/* Symbol firmware is found on various cards, but
+		 * there has been no attempt to check firmware
+		 * download on non-spectrum_cs based cards.
+		 *
+		 * Given that the Agere firmware download works
+		 * differently, we should avoid doing a firmware
+		 * download with the Symbol algorithm on non-spectrum
+		 * cards.
+		 *
+		 * For now we can identify a spectrum_cs based card
+		 * because it has a firmware reset function.
+		 */
+		priv->do_fw_download = (priv->stop_fw != NULL);
+
+		priv->broken_disableport = (firmver == 0x25013) ||
+				(firmver >= 0x30000 && firmver <= 0x31000);
+		priv->has_hostscan = (firmver >= 0x31001) ||
+				     (firmver >= 0x29057 && firmver < 0x30000);
+		/* Tested with Intel firmware : 0x20015 => Jean II */
+		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		/* D-Link, Linksys, Adtron, ZoomAir, and many others...
+		 * Samsung, Compaq 100/200 and Proxim are slightly
+		 * different and less well tested */
+		/* D-Link MAC : 00:40:05:* */
+		/* Addtron MAC : 00:90:D1:* */
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+			 sta_id.variant);
+
+		firmver = ((unsigned long)sta_id.major << 16) |
+			((unsigned long)sta_id.minor << 8) | sta_id.variant;
+
+		priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+		priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+		priv->has_pm = (firmver >= 0x000700);
+		priv->has_hostscan = (firmver >= 0x010301);
+
+		if (firmver >= 0x000800)
+			priv->ibss_port = 0;
+		else {
+			printk(KERN_NOTICE "%s: Intersil firmware earlier "
+			       "than v0.8.x - several features not supported\n",
+			       dev->name);
+			priv->ibss_port = 1;
+		}
+		break;
+	}
+	printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
+	       priv->fw_name);
+
+	return 0;
+}
+
+static int orinoco_init(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	struct hermes_idstring nickbuf;
+	u16 reclen;
+	int len;
+
+	/* No need to lock, the hw_unavailable flag is already set in
+	 * alloc_orinocodev() */
+	priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
+
+	/* Initialize the firmware */
+	err = hermes_init(hw);
+	if (err != 0) {
+		printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
+		       dev->name, err);
+		goto out;
+	}
+
+	err = determine_firmware(dev);
+	if (err != 0) {
+		printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
+		       dev->name);
+		goto out;
+	}
+
+	if (priv->do_fw_download) {
+#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
+		orinoco_cache_fw(priv, 0);
+#endif
+
+		err = orinoco_download(priv);
+		if (err)
+			priv->do_fw_download = 0;
+
+		/* Check firmware version again */
+		err = determine_firmware(dev);
+		if (err != 0) {
+			printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
+			       dev->name);
+			goto out;
+		}
+	}
+
+	if (priv->has_port3)
+		printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n",
+		       dev->name);
+	if (priv->has_ibss)
+		printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
+		       dev->name);
+	if (priv->has_wep) {
+		printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name,
+		       priv->has_big_wep ? "104" : "40");
+	}
+	if (priv->has_wpa) {
+		printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
+		if (orinoco_mic_init(priv)) {
+			printk(KERN_ERR "%s: Failed to setup MIC crypto "
+			       "algorithm. Disabling WPA support\n", dev->name);
+			priv->has_wpa = 0;
+		}
+	}
+
+	/* Now we have the firmware capabilities, allocate appropiate
+	 * sized scan buffers */
+	if (orinoco_bss_data_allocate(priv))
+		goto out;
+	orinoco_bss_data_init(priv);
+
+	/* Get the MAC address */
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+			      ETH_ALEN, NULL, dev->dev_addr);
+	if (err) {
+		printk(KERN_WARNING "%s: failed to read MAC address!\n",
+		       dev->name);
+		goto out;
+	}
+
+	printk(KERN_DEBUG "%s: MAC address %pM\n",
+	       dev->name, dev->dev_addr);
+
+	/* Get the station name */
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+			      sizeof(nickbuf), &reclen, &nickbuf);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read station name\n",
+		       dev->name);
+		goto out;
+	}
+	if (nickbuf.len)
+		len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
+	else
+		len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
+	memcpy(priv->nick, &nickbuf.val, len);
+	priv->nick[len] = '\0';
+
+	printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
+
+	err = orinoco_allocate_fid(dev);
+	if (err) {
+		printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
+		       dev->name);
+		goto out;
+	}
+
+	/* Get allowed channels */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+				  &priv->channel_mask);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read channel list!\n",
+		       dev->name);
+		goto out;
+	}
+
+	/* Get initial AP density */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+				  &priv->ap_density);
+	if (err || priv->ap_density < 1 || priv->ap_density > 3)
+		priv->has_sensitivity = 0;
+
+	/* Get initial RTS threshold */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+				  &priv->rts_thresh);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read RTS threshold!\n",
+		       dev->name);
+		goto out;
+	}
+
+	/* Get initial fragmentation settings */
+	if (priv->has_mwo)
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFMWOROBUST_AGERE,
+					  &priv->mwo_robust);
+	else
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+					  &priv->frag_thresh);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
+		       dev->name);
+		goto out;
+	}
+
+	/* Power management setup */
+	if (priv->has_pm) {
+		priv->pm_on = 0;
+		priv->pm_mcast = 1;
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFMAXSLEEPDURATION,
+					  &priv->pm_period);
+		if (err) {
+			printk(KERN_ERR "%s: failed to read power management period!\n",
+			       dev->name);
+			goto out;
+		}
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFPMHOLDOVERDURATION,
+					  &priv->pm_timeout);
+		if (err) {
+			printk(KERN_ERR "%s: failed to read power management timeout!\n",
+			       dev->name);
+			goto out;
+		}
+	}
+
+	/* Preamble setup */
+	if (priv->has_preamble) {
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFPREAMBLE_SYMBOL,
+					  &priv->preamble);
+		if (err)
+			goto out;
+	}
+
+	/* Set up the default configuration */
+	priv->iw_mode = IW_MODE_INFRA;
+	/* By default use IEEE/IBSS ad-hoc mode if we have it */
+	priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
+	set_port_type(priv);
+	priv->channel = 0; /* use firmware default */
+
+	priv->promiscuous = 0;
+	priv->encode_alg = IW_ENCODE_ALG_NONE;
+	priv->tx_key = 0;
+	priv->wpa_enabled = 0;
+	priv->tkip_cm_active = 0;
+	priv->key_mgmt = 0;
+	priv->wpa_ie_len = 0;
+	priv->wpa_ie = NULL;
+
+	/* Make the hardware available, as long as it hasn't been
+	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
+	spin_lock_irq(&priv->lock);
+	priv->hw_unavailable--;
+	spin_unlock_irq(&priv->lock);
+
+	printk(KERN_DEBUG "%s: ready\n", dev->name);
+
+ out:
+	return err;
+}
+
+static const struct net_device_ops orinoco_netdev_ops = {
+	.ndo_init		= orinoco_init,
+	.ndo_open		= orinoco_open,
+	.ndo_stop		= orinoco_stop,
+	.ndo_start_xmit		= orinoco_xmit,
+	.ndo_set_multicast_list	= orinoco_set_multicast_list,
+	.ndo_change_mtu		= orinoco_change_mtu,
+	.ndo_tx_timeout		= orinoco_tx_timeout,
+	.ndo_get_stats		= orinoco_get_stats,
+};
+
+struct net_device
+*alloc_orinocodev(int sizeof_card,
+		  struct device *device,
+		  int (*hard_reset)(struct orinoco_private *),
+		  int (*stop_fw)(struct orinoco_private *, int))
+{
+	struct net_device *dev;
+	struct orinoco_private *priv;
+
+	dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
+	if (!dev)
+		return NULL;
+	priv = netdev_priv(dev);
+	priv->ndev = dev;
+	if (sizeof_card)
+		priv->card = (void *)((unsigned long)priv
+				      + sizeof(struct orinoco_private));
+	else
+		priv->card = NULL;
+	priv->dev = device;
+
+	/* Setup / override net_device fields */
+	dev->netdev_ops = &orinoco_netdev_ops;
+	dev->watchdog_timeo = HZ; /* 1 second timeout */
+	dev->ethtool_ops = &orinoco_ethtool_ops;
+	dev->wireless_handlers = &orinoco_handler_def;
+#ifdef WIRELESS_SPY
+	priv->wireless_data.spy_data = &priv->spy_data;
+	dev->wireless_data = &priv->wireless_data;
+#endif
+	/* we use the default eth_mac_addr for setting the MAC addr */
+
+	/* Reserve space in skb for the SNAP header */
+	dev->hard_header_len += ENCAPS_OVERHEAD;
+
+	/* Set up default callbacks */
+	priv->hard_reset = hard_reset;
+	priv->stop_fw = stop_fw;
+
+	spin_lock_init(&priv->lock);
+	priv->open = 0;
+	priv->hw_unavailable = 1; /* orinoco_init() must clear this
+				   * before anything else touches the
+				   * hardware */
+	INIT_WORK(&priv->reset_work, orinoco_reset);
+	INIT_WORK(&priv->join_work, orinoco_join_ap);
+	INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
+
+	INIT_LIST_HEAD(&priv->rx_list);
+	tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
+		     (unsigned long) dev);
+
+	netif_carrier_off(dev);
+	priv->last_linkstatus = 0xffff;
+
+	priv->cached_pri_fw = NULL;
+	priv->cached_fw = NULL;
+
+	/* Register PM notifiers */
+	priv->pm_notifier.notifier_call = orinoco_pm_notifier;
+	register_pm_notifier(&priv->pm_notifier);
+
+	return dev;
+}
+EXPORT_SYMBOL(alloc_orinocodev);
+
+void free_orinocodev(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct orinoco_rx_data *rx_data, *temp;
+
+	/* If the tasklet is scheduled when we call tasklet_kill it
+	 * will run one final time. However the tasklet will only
+	 * drain priv->rx_list if the hw is still available. */
+	tasklet_kill(&priv->rx_tasklet);
+
+	/* Explicitly drain priv->rx_list */
+	list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
+		list_del(&rx_data->list);
+
+		dev_kfree_skb(rx_data->skb);
+		kfree(rx_data->desc);
+		kfree(rx_data);
+	}
+
+	unregister_pm_notifier(&priv->pm_notifier);
+	orinoco_uncache_fw(priv);
+
+	priv->wpa_ie_len = 0;
+	kfree(priv->wpa_ie);
+	orinoco_mic_free(priv);
+	orinoco_bss_data_free(priv);
+	free_netdev(dev);
+}
+EXPORT_SYMBOL(free_orinocodev);
+
+static void orinoco_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *info)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
+	strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+	strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
+	if (dev->dev.parent)
+		strncpy(info->bus_info, dev_name(dev->dev.parent),
+			sizeof(info->bus_info) - 1);
+	else
+		snprintf(info->bus_info, sizeof(info->bus_info) - 1,
+			 "PCMCIA %p", priv->hw.iobase);
+}
+
+static const struct ethtool_ops orinoco_ethtool_ops = {
+	.get_drvinfo = orinoco_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};
+
+/********************************************************************/
+/* Module initialization                                            */
+/********************************************************************/
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+	" (David Gibson <hermes@gibson.dropbear.id.au>, "
+	"Pavel Roskin <proski@gnu.org>, et al)";
+
+static int __init init_orinoco(void)
+{
+	printk(KERN_DEBUG "%s\n", version);
+	return 0;
+}
+
+static void __exit exit_orinoco(void)
+{
+}
+
+module_init(init_orinoco);
+module_exit(exit_orinoco);
diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h
new file mode 100644
index 0000000..af2bae4
--- /dev/null
+++ b/drivers/net/wireless/orinoco/main.h
@@ -0,0 +1,63 @@
+/* Exports from main to helper modules
+ *
+ * See copyright notice in main.c
+ */
+#ifndef _ORINOCO_MAIN_H_
+#define _ORINOCO_MAIN_H_
+
+#include <linux/ieee80211.h>
+#include "orinoco.h"
+
+/********************************************************************/
+/* Compile time configuration and compatibility stuff               */
+/********************************************************************/
+
+/* We do this this way to avoid ifdefs in the actual code */
+#ifdef WIRELESS_SPY
+#define SPY_NUMBER(priv)	(priv->spy_data.spy_number)
+#else
+#define SPY_NUMBER(priv)	0
+#endif /* WIRELESS_SPY */
+
+/********************************************************************/
+
+/* Export module parameter */
+extern int force_monitor;
+
+/* Forward declarations */
+struct net_device;
+struct work_struct;
+
+void set_port_type(struct orinoco_private *priv);
+int __orinoco_program_rids(struct net_device *dev);
+void orinoco_reset(struct work_struct *work);
+
+
+/* Information element helpers - find a home for these... */
+static inline u8 *orinoco_get_ie(u8 *data, size_t len,
+				 enum ieee80211_eid eid)
+{
+	u8 *p = data;
+	while ((p + 2) < (data + len)) {
+		if (p[0] == eid)
+			return p;
+		p += p[1] + 2;
+	}
+	return NULL;
+}
+
+#define WPA_OUI_TYPE	"\x00\x50\xF2\x01"
+#define WPA_SELECTOR_LEN 4
+static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
+{
+	u8 *p = data;
+	while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
+		if ((p[0] == WLAN_EID_GENERIC) &&
+		    (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
+			return p;
+		p += p[1] + 2;
+	}
+	return NULL;
+}
+
+#endif /* _ORINOCO_MAIN_H_ */
diff --git a/drivers/net/wireless/orinoco/mic.c b/drivers/net/wireless/orinoco/mic.c
new file mode 100644
index 0000000..c03e7f5
--- /dev/null
+++ b/drivers/net/wireless/orinoco/mic.c
@@ -0,0 +1,79 @@
+/* Orinoco MIC helpers
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/if_ether.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+
+#include "orinoco.h"
+#include "mic.h"
+
+/********************************************************************/
+/* Michael MIC crypto setup                                         */
+/********************************************************************/
+int orinoco_mic_init(struct orinoco_private *priv)
+{
+	priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
+	if (IS_ERR(priv->tx_tfm_mic)) {
+		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
+		       "crypto API michael_mic\n");
+		priv->tx_tfm_mic = NULL;
+		return -ENOMEM;
+	}
+
+	priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
+	if (IS_ERR(priv->rx_tfm_mic)) {
+		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
+		       "crypto API michael_mic\n");
+		priv->rx_tfm_mic = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void orinoco_mic_free(struct orinoco_private *priv)
+{
+	if (priv->tx_tfm_mic)
+		crypto_free_hash(priv->tx_tfm_mic);
+	if (priv->rx_tfm_mic)
+		crypto_free_hash(priv->rx_tfm_mic);
+}
+
+int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
+		u8 *da, u8 *sa, u8 priority,
+		u8 *data, size_t data_len, u8 *mic)
+{
+	struct hash_desc desc;
+	struct scatterlist sg[2];
+	u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
+
+	if (tfm_michael == NULL) {
+		printk(KERN_WARNING "orinoco_mic: tfm_michael == NULL\n");
+		return -1;
+	}
+
+	/* Copy header into buffer. We need the padding on the end zeroed */
+	memcpy(&hdr[0], da, ETH_ALEN);
+	memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
+	hdr[ETH_ALEN*2] = priority;
+	hdr[ETH_ALEN*2+1] = 0;
+	hdr[ETH_ALEN*2+2] = 0;
+	hdr[ETH_ALEN*2+3] = 0;
+
+	/* Use scatter gather to MIC header and data in one go */
+	sg_init_table(sg, 2);
+	sg_set_buf(&sg[0], hdr, sizeof(hdr));
+	sg_set_buf(&sg[1], data, data_len);
+
+	if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
+		return -1;
+
+	desc.tfm = tfm_michael;
+	desc.flags = 0;
+	return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
+				  mic);
+}
diff --git a/drivers/net/wireless/orinoco/mic.h b/drivers/net/wireless/orinoco/mic.h
new file mode 100644
index 0000000..04d05bc
--- /dev/null
+++ b/drivers/net/wireless/orinoco/mic.h
@@ -0,0 +1,22 @@
+/* Orinoco MIC helpers
+ *
+ * See copyright notice in main.c
+ */
+#ifndef _ORINOCO_MIC_H_
+#define _ORINOCO_MIC_H_
+
+#include <linux/types.h>
+
+#define MICHAEL_MIC_LEN 8
+
+/* Forward declarations */
+struct orinoco_private;
+struct crypto_hash;
+
+int orinoco_mic_init(struct orinoco_private *priv);
+void orinoco_mic_free(struct orinoco_private *priv);
+int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
+		u8 *da, u8 *sa, u8 priority,
+		u8 *data, size_t data_len, u8 *mic);
+
+#endif /* ORINOCO_MIC_H */
diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
deleted file mode 100644
index e082ef0..0000000
--- a/drivers/net/wireless/orinoco/orinoco.c
+++ /dev/null
@@ -1,6153 +0,0 @@
-/* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c)
- *
- * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
- * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
- *
- * Current maintainers (as of 29 September 2003) are:
- * 	Pavel Roskin <proski AT gnu.org>
- * and	David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * (C) Copyright David Gibson, IBM Corporation 2001-2003.
- * Copyright (C) 2000 David Gibson, Linuxcare Australia.
- *	With some help from :
- * Copyright (C) 2001 Jean Tourrilhes, HP Labs
- * Copyright (C) 2001 Benjamin Herrenschmidt
- *
- * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
- *
- * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy
- * AT fasta.fh-dortmund.de>
- *      http://www.stud.fh-dortmund.de/~andy/wvlan/
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds AT users.sourceforge.net>.  Portions created by David
- * A. Hinds are Copyright (C) 1999 David A. Hinds.  All Rights
- * Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.  */
-
-/*
- * TODO
- *	o Handle de-encapsulation within network layer, provide 802.11
- *	  headers (patch from Thomas 'Dent' Mirlacher)
- *	o Fix possible races in SPY handling.
- *	o Disconnect wireless extensions from fundamental configuration.
- *	o (maybe) Software WEP support (patch from Stano Meduna).
- *	o (maybe) Use multiple Tx buffers - driver handling queue
- *	  rather than firmware.
- */
-
-/* Locking and synchronization:
- *
- * The basic principle is that everything is serialized through a
- * single spinlock, priv->lock.  The lock is used in user, bh and irq
- * context, so when taken outside hardirq context it should always be
- * taken with interrupts disabled.  The lock protects both the
- * hardware and the struct orinoco_private.
- *
- * Another flag, priv->hw_unavailable indicates that the hardware is
- * unavailable for an extended period of time (e.g. suspended, or in
- * the middle of a hard reset).  This flag is protected by the
- * spinlock.  All code which touches the hardware should check the
- * flag after taking the lock, and if it is set, give up on whatever
- * they are doing and drop the lock again.  The orinoco_lock()
- * function handles this (it unlocks and returns -EBUSY if
- * hw_unavailable is non-zero).
- */
-
-#define DRIVER_NAME "orinoco"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/firmware.h>
-#include <linux/suspend.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <net/iw_handler.h>
-
-#include <linux/scatterlist.h>
-#include <linux/crypto.h>
-
-#include "hermes_rid.h"
-#include "hermes_dld.h"
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module information                                               */
-/********************************************************************/
-
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Level of debugging. Used in the macros in orinoco.h */
-#ifdef ORINOCO_DEBUG
-int orinoco_debug = ORINOCO_DEBUG;
-module_param(orinoco_debug, int, 0644);
-MODULE_PARM_DESC(orinoco_debug, "Debug level");
-EXPORT_SYMBOL(orinoco_debug);
-#endif
-
-static int suppress_linkstatus; /* = 0 */
-module_param(suppress_linkstatus, bool, 0644);
-MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
-static int ignore_disconnect; /* = 0 */
-module_param(ignore_disconnect, int, 0644);
-MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
-
-static int force_monitor; /* = 0 */
-module_param(force_monitor, int, 0644);
-MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
-
-/********************************************************************/
-/* Compile time configuration and compatibility stuff               */
-/********************************************************************/
-
-/* We do this this way to avoid ifdefs in the actual code */
-#ifdef WIRELESS_SPY
-#define SPY_NUMBER(priv)	(priv->spy_data.spy_number)
-#else
-#define SPY_NUMBER(priv)	0
-#endif /* WIRELESS_SPY */
-
-/********************************************************************/
-/* Internal constants                                               */
-/********************************************************************/
-
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
-
-#define ORINOCO_MIN_MTU		256
-#define ORINOCO_MAX_MTU		(IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
-
-#define SYMBOL_MAX_VER_LEN	(14)
-#define USER_BAP		0
-#define IRQ_BAP			1
-#define MAX_IRQLOOPS_PER_IRQ	10
-#define MAX_IRQLOOPS_PER_JIFFY	(20000/HZ) /* Based on a guestimate of
-					    * how many events the
-					    * device could
-					    * legitimately generate */
-#define SMALL_KEY_SIZE		5
-#define LARGE_KEY_SIZE		13
-#define TX_NICBUF_SIZE_BUG	1585		/* Bug in Symbol firmware */
-
-#define DUMMY_FID		0xFFFF
-
-/*#define MAX_MULTICAST(priv)	(priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
-  HERMES_MAX_MULTICAST : 0)*/
-#define MAX_MULTICAST(priv)	(HERMES_MAX_MULTICAST)
-
-#define ORINOCO_INTEN	 	(HERMES_EV_RX | HERMES_EV_ALLOC \
-				 | HERMES_EV_TX | HERMES_EV_TXEXC \
-				 | HERMES_EV_WTERR | HERMES_EV_INFO \
-				 | HERMES_EV_INFDROP )
-
-#define MAX_RID_LEN 1024
-
-static const struct iw_handler_def orinoco_handler_def;
-static const struct ethtool_ops orinoco_ethtool_ops;
-
-/********************************************************************/
-/* Data tables                                                      */
-/********************************************************************/
-
-#define NUM_CHANNELS 14
-
-/* This tables gives the actual meanings of the bitrate IDs returned
- * by the firmware. */
-static struct {
-	int bitrate; /* in 100s of kilobits */
-	int automatic;
-	u16 agere_txratectrl;
-	u16 intersil_txratectrl;
-} bitrate_table[] = {
-	{110, 1,  3, 15}, /* Entry 0 is the default */
-	{10,  0,  1,  1},
-	{10,  1,  1,  1},
-	{20,  0,  2,  2},
-	{20,  1,  6,  3},
-	{55,  0,  4,  4},
-	{55,  1,  7,  7},
-	{110, 0,  5,  8},
-};
-#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
-
-/********************************************************************/
-/* Data types                                                       */
-/********************************************************************/
-
-/* Beginning of the Tx descriptor, used in TxExc handling */
-struct hermes_txexc_data {
-	struct hermes_tx_descriptor desc;
-	__le16 frame_ctl;
-	__le16 duration_id;
-	u8 addr1[ETH_ALEN];
-} __attribute__ ((packed));
-
-/* Rx frame header except compatibility 802.3 header */
-struct hermes_rx_descriptor {
-	/* Control */
-	__le16 status;
-	__le32 time;
-	u8 silence;
-	u8 signal;
-	u8 rate;
-	u8 rxflow;
-	__le32 reserved;
-
-	/* 802.11 header */
-	__le16 frame_ctl;
-	__le16 duration_id;
-	u8 addr1[ETH_ALEN];
-	u8 addr2[ETH_ALEN];
-	u8 addr3[ETH_ALEN];
-	__le16 seq_ctl;
-	u8 addr4[ETH_ALEN];
-
-	/* Data length */
-	__le16 data_len;
-} __attribute__ ((packed));
-
-struct orinoco_rx_data {
-	struct hermes_rx_descriptor *desc;
-	struct sk_buff *skb;
-	struct list_head list;
-};
-
-/********************************************************************/
-/* Function prototypes                                              */
-/********************************************************************/
-
-static int __orinoco_program_rids(struct net_device *dev);
-static void __orinoco_set_multicast_list(struct net_device *dev);
-
-/********************************************************************/
-/* Michael MIC crypto setup                                         */
-/********************************************************************/
-#define MICHAEL_MIC_LEN 8
-static int orinoco_mic_init(struct orinoco_private *priv)
-{
-	priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
-	if (IS_ERR(priv->tx_tfm_mic)) {
-		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
-		       "crypto API michael_mic\n");
-		priv->tx_tfm_mic = NULL;
-		return -ENOMEM;
-	}
-
-	priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
-	if (IS_ERR(priv->rx_tfm_mic)) {
-		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
-		       "crypto API michael_mic\n");
-		priv->rx_tfm_mic = NULL;
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static void orinoco_mic_free(struct orinoco_private *priv)
-{
-	if (priv->tx_tfm_mic)
-		crypto_free_hash(priv->tx_tfm_mic);
-	if (priv->rx_tfm_mic)
-		crypto_free_hash(priv->rx_tfm_mic);
-}
-
-static int michael_mic(struct crypto_hash *tfm_michael, u8 *key,
-		       u8 *da, u8 *sa, u8 priority,
-		       u8 *data, size_t data_len, u8 *mic)
-{
-	struct hash_desc desc;
-	struct scatterlist sg[2];
-	u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
-
-	if (tfm_michael == NULL) {
-		printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
-		return -1;
-	}
-
-	/* Copy header into buffer. We need the padding on the end zeroed */
-	memcpy(&hdr[0], da, ETH_ALEN);
-	memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
-	hdr[ETH_ALEN*2] = priority;
-	hdr[ETH_ALEN*2+1] = 0;
-	hdr[ETH_ALEN*2+2] = 0;
-	hdr[ETH_ALEN*2+3] = 0;
-
-	/* Use scatter gather to MIC header and data in one go */
-	sg_init_table(sg, 2);
-	sg_set_buf(&sg[0], hdr, sizeof(hdr));
-	sg_set_buf(&sg[1], data, data_len);
-
-	if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
-		return -1;
-
-	desc.tfm = tfm_michael;
-	desc.flags = 0;
-	return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
-				  mic);
-}
-
-/********************************************************************/
-/* Internal helper functions                                        */
-/********************************************************************/
-
-static inline void set_port_type(struct orinoco_private *priv)
-{
-	switch (priv->iw_mode) {
-	case IW_MODE_INFRA:
-		priv->port_type = 1;
-		priv->createibss = 0;
-		break;
-	case IW_MODE_ADHOC:
-		if (priv->prefer_port3) {
-			priv->port_type = 3;
-			priv->createibss = 0;
-		} else {
-			priv->port_type = priv->ibss_port;
-			priv->createibss = 1;
-		}
-		break;
-	case IW_MODE_MONITOR:
-		priv->port_type = 3;
-		priv->createibss = 0;
-		break;
-	default:
-		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
-		       priv->ndev->name);
-	}
-}
-
-#define ORINOCO_MAX_BSS_COUNT	64
-static int orinoco_bss_data_allocate(struct orinoco_private *priv)
-{
-	if (priv->bss_xbss_data)
-		return 0;
-
-	if (priv->has_ext_scan)
-		priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
-					      sizeof(struct xbss_element),
-					      GFP_KERNEL);
-	else
-		priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
-					      sizeof(struct bss_element),
-					      GFP_KERNEL);
-
-	if (!priv->bss_xbss_data) {
-		printk(KERN_WARNING "Out of memory allocating beacons");
-		return -ENOMEM;
-	}
-	return 0;
-}
-
-static void orinoco_bss_data_free(struct orinoco_private *priv)
-{
-	kfree(priv->bss_xbss_data);
-	priv->bss_xbss_data = NULL;
-}
-
-#define PRIV_BSS	((struct bss_element *)priv->bss_xbss_data)
-#define PRIV_XBSS	((struct xbss_element *)priv->bss_xbss_data)
-static void orinoco_bss_data_init(struct orinoco_private *priv)
-{
-	int i;
-
-	INIT_LIST_HEAD(&priv->bss_free_list);
-	INIT_LIST_HEAD(&priv->bss_list);
-	if (priv->has_ext_scan)
-		for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
-			list_add_tail(&(PRIV_XBSS[i].list),
-				      &priv->bss_free_list);
-	else
-		for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
-			list_add_tail(&(PRIV_BSS[i].list),
-				      &priv->bss_free_list);
-
-}
-
-static inline u8 *orinoco_get_ie(u8 *data, size_t len,
-				 enum ieee80211_eid eid)
-{
-	u8 *p = data;
-	while ((p + 2) < (data + len)) {
-		if (p[0] == eid)
-			return p;
-		p += p[1] + 2;
-	}
-	return NULL;
-}
-
-#define WPA_OUI_TYPE	"\x00\x50\xF2\x01"
-#define WPA_SELECTOR_LEN 4
-static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
-{
-	u8 *p = data;
-	while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
-		if ((p[0] == WLAN_EID_GENERIC) &&
-		    (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
-			return p;
-		p += p[1] + 2;
-	}
-	return NULL;
-}
-
-
-/********************************************************************/
-/* Download functionality                                           */
-/********************************************************************/
-
-struct fw_info {
-	char *pri_fw;
-	char *sta_fw;
-	char *ap_fw;
-	u32 pda_addr;
-	u16 pda_size;
-};
-
-const static struct fw_info orinoco_fw[] = {
-	{ NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
-	{ NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
-	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
-};
-
-/* Structure used to access fields in FW
- * Make sure LE decoding macros are used
- */
-struct orinoco_fw_header {
-	char hdr_vers[6];       /* ASCII string for header version */
-	__le16 headersize;      /* Total length of header */
-	__le32 entry_point;     /* NIC entry point */
-	__le32 blocks;          /* Number of blocks to program */
-	__le32 block_offset;    /* Offset of block data from eof header */
-	__le32 pdr_offset;      /* Offset to PDR data from eof header */
-	__le32 pri_offset;      /* Offset to primary plug data */
-	__le32 compat_offset;   /* Offset to compatibility data*/
-	char signature[0];      /* FW signature length headersize-20 */
-} __attribute__ ((packed));
-
-/* Download either STA or AP firmware into the card. */
-static int
-orinoco_dl_firmware(struct orinoco_private *priv,
-		    const struct fw_info *fw,
-		    int ap)
-{
-	/* Plug Data Area (PDA) */
-	__le16 *pda;
-
-	hermes_t *hw = &priv->hw;
-	const struct firmware *fw_entry;
-	const struct orinoco_fw_header *hdr;
-	const unsigned char *first_block;
-	const unsigned char *end;
-	const char *firmware;
-	struct net_device *dev = priv->ndev;
-	int err = 0;
-
-	pda = kzalloc(fw->pda_size, GFP_KERNEL);
-	if (!pda)
-		return -ENOMEM;
-
-	if (ap)
-		firmware = fw->ap_fw;
-	else
-		firmware = fw->sta_fw;
-
-	printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
-	       dev->name, firmware);
-
-	/* Read current plug data */
-	err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
-	printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
-	if (err)
-		goto free;
-
-	if (!priv->cached_fw) {
-		err = request_firmware(&fw_entry, firmware, priv->dev);
-
-		if (err) {
-			printk(KERN_ERR "%s: Cannot find firmware %s\n",
-			       dev->name, firmware);
-			err = -ENOENT;
-			goto free;
-		}
-	} else
-		fw_entry = priv->cached_fw;
-
-	hdr = (const struct orinoco_fw_header *) fw_entry->data;
-
-	/* Enable aux port to allow programming */
-	err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
-	printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
-	if (err != 0)
-		goto abort;
-
-	/* Program data */
-	first_block = (fw_entry->data +
-		       le16_to_cpu(hdr->headersize) +
-		       le32_to_cpu(hdr->block_offset));
-	end = fw_entry->data + fw_entry->size;
-
-	err = hermes_program(hw, first_block, end);
-	printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
-	if (err != 0)
-		goto abort;
-
-	/* Update production data */
-	first_block = (fw_entry->data +
-		       le16_to_cpu(hdr->headersize) +
-		       le32_to_cpu(hdr->pdr_offset));
-
-	err = hermes_apply_pda_with_defaults(hw, first_block, pda);
-	printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
-	if (err)
-		goto abort;
-
-	/* Tell card we've finished */
-	err = hermesi_program_end(hw);
-	printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
-	if (err != 0)
-		goto abort;
-
-	/* Check if we're running */
-	printk(KERN_DEBUG "%s: hermes_present returned %d\n",
-	       dev->name, hermes_present(hw));
-
-abort:
-	/* If we requested the firmware, release it. */
-	if (!priv->cached_fw)
-		release_firmware(fw_entry);
-
-free:
-	kfree(pda);
-	return err;
-}
-
-/* End markers */
-#define TEXT_END	0x1A		/* End of text header */
-
-/*
- * Process a firmware image - stop the card, load the firmware, reset
- * the card and make sure it responds.  For the secondary firmware take
- * care of the PDA - read it and then write it on top of the firmware.
- */
-static int
-symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
-		const unsigned char *image, const unsigned char *end,
-		int secondary)
-{
-	hermes_t *hw = &priv->hw;
-	int ret = 0;
-	const unsigned char *ptr;
-	const unsigned char *first_block;
-
-	/* Plug Data Area (PDA) */
-	__le16 *pda = NULL;
-
-	/* Binary block begins after the 0x1A marker */
-	ptr = image;
-	while (*ptr++ != TEXT_END);
-	first_block = ptr;
-
-	/* Read the PDA from EEPROM */
-	if (secondary) {
-		pda = kzalloc(fw->pda_size, GFP_KERNEL);
-		if (!pda)
-			return -ENOMEM;
-
-		ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
-		if (ret)
-			goto free;
-	}
-
-	/* Stop the firmware, so that it can be safely rewritten */
-	if (priv->stop_fw) {
-		ret = priv->stop_fw(priv, 1);
-		if (ret)
-			goto free;
-	}
-
-	/* Program the adapter with new firmware */
-	ret = hermes_program(hw, first_block, end);
-	if (ret)
-		goto free;
-
-	/* Write the PDA to the adapter */
-	if (secondary) {
-		size_t len = hermes_blocks_length(first_block);
-		ptr = first_block + len;
-		ret = hermes_apply_pda(hw, ptr, pda);
-		kfree(pda);
-		if (ret)
-			return ret;
-	}
-
-	/* Run the firmware */
-	if (priv->stop_fw) {
-		ret = priv->stop_fw(priv, 0);
-		if (ret)
-			return ret;
-	}
-
-	/* Reset hermes chip and make sure it responds */
-	ret = hermes_init(hw);
-
-	/* hermes_reset() should return 0 with the secondary firmware */
-	if (secondary && ret != 0)
-		return -ENODEV;
-
-	/* And this should work with any firmware */
-	if (!hermes_present(hw))
-		return -ENODEV;
-
-	return 0;
-
-free:
-	kfree(pda);
-	return ret;
-}
-
-
-/*
- * Download the firmware into the card, this also does a PCMCIA soft
- * reset on the card, to make sure it's in a sane state.
- */
-static int
-symbol_dl_firmware(struct orinoco_private *priv,
-		   const struct fw_info *fw)
-{
-	struct net_device *dev = priv->ndev;
-	int ret;
-	const struct firmware *fw_entry;
-
-	if (!priv->cached_pri_fw) {
-		if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
-			printk(KERN_ERR "%s: Cannot find firmware: %s\n",
-			       dev->name, fw->pri_fw);
-			return -ENOENT;
-		}
-	} else
-		fw_entry = priv->cached_pri_fw;
-
-	/* Load primary firmware */
-	ret = symbol_dl_image(priv, fw, fw_entry->data,
-			      fw_entry->data + fw_entry->size, 0);
-
-	if (!priv->cached_pri_fw)
-		release_firmware(fw_entry);
-	if (ret) {
-		printk(KERN_ERR "%s: Primary firmware download failed\n",
-		       dev->name);
-		return ret;
-	}
-
-	if (!priv->cached_fw) {
-		if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
-			printk(KERN_ERR "%s: Cannot find firmware: %s\n",
-			       dev->name, fw->sta_fw);
-			return -ENOENT;
-		}
-	} else
-		fw_entry = priv->cached_fw;
-
-	/* Load secondary firmware */
-	ret = symbol_dl_image(priv, fw, fw_entry->data,
-			      fw_entry->data + fw_entry->size, 1);
-	if (!priv->cached_fw)
-		release_firmware(fw_entry);
-	if (ret) {
-		printk(KERN_ERR "%s: Secondary firmware download failed\n",
-		       dev->name);
-	}
-
-	return ret;
-}
-
-static int orinoco_download(struct orinoco_private *priv)
-{
-	int err = 0;
-	/* Reload firmware */
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE:
-		/* case FIRMWARE_TYPE_INTERSIL: */
-		err = orinoco_dl_firmware(priv,
-					  &orinoco_fw[priv->firmware_type], 0);
-		break;
-
-	case FIRMWARE_TYPE_SYMBOL:
-		err = symbol_dl_firmware(priv,
-					 &orinoco_fw[priv->firmware_type]);
-		break;
-	case FIRMWARE_TYPE_INTERSIL:
-		break;
-	}
-	/* TODO: if we fail we probably need to reinitialise
-	 * the driver */
-
-	return err;
-}
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
-static void orinoco_cache_fw(struct orinoco_private *priv, int ap)
-{
-	const struct firmware *fw_entry = NULL;
-	const char *pri_fw;
-	const char *fw;
-
-	pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
-	if (ap)
-		fw = orinoco_fw[priv->firmware_type].ap_fw;
-	else
-		fw = orinoco_fw[priv->firmware_type].sta_fw;
-
-	if (pri_fw) {
-		if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
-			priv->cached_pri_fw = fw_entry;
-	}
-
-	if (fw) {
-		if (request_firmware(&fw_entry, fw, priv->dev) == 0)
-			priv->cached_fw = fw_entry;
-	}
-}
-
-static void orinoco_uncache_fw(struct orinoco_private *priv)
-{
-	if (priv->cached_pri_fw)
-		release_firmware(priv->cached_pri_fw);
-	if (priv->cached_fw)
-		release_firmware(priv->cached_fw);
-
-	priv->cached_pri_fw = NULL;
-	priv->cached_fw = NULL;
-}
-#else
-#define orinoco_cache_fw(priv, ap)
-#define orinoco_uncache_fw(priv)
-#endif
-
-/********************************************************************/
-/* Device methods                                                   */
-/********************************************************************/
-
-static int orinoco_open(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	unsigned long flags;
-	int err;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	err = __orinoco_up(dev);
-
-	if (! err)
-		priv->open = 1;
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_stop(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
-
-	/* We mustn't use orinoco_lock() here, because we need to be
-	   able to close the interface even if hw_unavailable is set
-	   (e.g. as we're released after a PC Card removal) */
-	spin_lock_irq(&priv->lock);
-
-	priv->open = 0;
-
-	err = __orinoco_down(dev);
-
-	spin_unlock_irq(&priv->lock);
-
-	return err;
-}
-
-static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	
-	return &priv->stats;
-}
-
-static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	struct iw_statistics *wstats = &priv->wstats;
-	int err;
-	unsigned long flags;
-
-	if (! netif_device_present(dev)) {
-		printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
-		       dev->name);
-		return NULL; /* FIXME: Can we do better than this? */
-	}
-
-	/* If busy, return the old stats.  Returning NULL may cause
-	 * the interface to disappear from /proc/net/wireless */
-	if (orinoco_lock(priv, &flags) != 0)
-		return wstats;
-
-	/* We can't really wait for the tallies inquiry command to
-	 * complete, so we just use the previous results and trigger
-	 * a new tallies inquiry command for next time - Jean II */
-	/* FIXME: Really we should wait for the inquiry to come back -
-	 * as it is the stats we give don't make a whole lot of sense.
-	 * Unfortunately, it's not clear how to do that within the
-	 * wireless extensions framework: I think we're in user
-	 * context, but a lock seems to be held by the time we get in
-	 * here so we're not safe to sleep here. */
-	hermes_inquire(hw, HERMES_INQ_TALLIES);
-
-	if (priv->iw_mode == IW_MODE_ADHOC) {
-		memset(&wstats->qual, 0, sizeof(wstats->qual));
-		/* If a spy address is defined, we report stats of the
-		 * first spy address - Jean II */
-		if (SPY_NUMBER(priv)) {
-			wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
-			wstats->qual.level = priv->spy_data.spy_stat[0].level;
-			wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
-			wstats->qual.updated = priv->spy_data.spy_stat[0].updated;
-		}
-	} else {
-		struct {
-			__le16 qual, signal, noise, unused;
-		} __attribute__ ((packed)) cq;
-
-		err = HERMES_READ_RECORD(hw, USER_BAP,
-					 HERMES_RID_COMMSQUALITY, &cq);
-
-		if (!err) {
-			wstats->qual.qual = (int)le16_to_cpu(cq.qual);
-			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
-			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
-			wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-		}
-	}
-
-	orinoco_unlock(priv, &flags);
-	return wstats;
-}
-
-static void orinoco_set_multicast_list(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0) {
-		printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
-		       "called when hw_unavailable\n", dev->name);
-		return;
-	}
-
-	__orinoco_set_multicast_list(dev);
-	orinoco_unlock(priv, &flags);
-}
-
-static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-
-	if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
-		return -EINVAL;
-
-	/* MTU + encapsulation + header length */
-	if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
-	     (priv->nicbuf_size - ETH_HLEN) )
-		return -EINVAL;
-
-	dev->mtu = new_mtu;
-
-	return 0;
-}
-
-/********************************************************************/
-/* Tx path                                                          */
-/********************************************************************/
-
-static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct net_device_stats *stats = &priv->stats;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	u16 txfid = priv->txfid;
-	struct ethhdr *eh;
-	int tx_control;
-	unsigned long flags;
-
-	if (! netif_running(dev)) {
-		printk(KERN_ERR "%s: Tx on stopped device!\n",
-		       dev->name);
-		return NETDEV_TX_BUSY;
-	}
-	
-	if (netif_queue_stopped(dev)) {
-		printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", 
-		       dev->name);
-		return NETDEV_TX_BUSY;
-	}
-	
-	if (orinoco_lock(priv, &flags) != 0) {
-		printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
-		       dev->name);
-		return NETDEV_TX_BUSY;
-	}
-
-	if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
-		/* Oops, the firmware hasn't established a connection,
-                   silently drop the packet (this seems to be the
-                   safest approach). */
-		goto drop;
-	}
-
-	/* Check packet length */
-	if (skb->len < ETH_HLEN)
-		goto drop;
-
-	tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
-
-	if (priv->encode_alg == IW_ENCODE_ALG_TKIP)
-		tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
-			HERMES_TXCTRL_MIC;
-
-	if (priv->has_alt_txcntl) {
-		/* WPA enabled firmwares have tx_cntl at the end of
-		 * the 802.11 header.  So write zeroed descriptor and
-		 * 802.11 header at the same time
-		 */
-		char desc[HERMES_802_3_OFFSET];
-		__le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
-
-		memset(&desc, 0, sizeof(desc));
-
-		*txcntl = cpu_to_le16(tx_control);
-		err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-					txfid, 0);
-		if (err) {
-			if (net_ratelimit())
-				printk(KERN_ERR "%s: Error %d writing Tx "
-				       "descriptor to BAP\n", dev->name, err);
-			goto busy;
-		}
-	} else {
-		struct hermes_tx_descriptor desc;
-
-		memset(&desc, 0, sizeof(desc));
-
-		desc.tx_control = cpu_to_le16(tx_control);
-		err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-					txfid, 0);
-		if (err) {
-			if (net_ratelimit())
-				printk(KERN_ERR "%s: Error %d writing Tx "
-				       "descriptor to BAP\n", dev->name, err);
-			goto busy;
-		}
-
-		/* Clear the 802.11 header and data length fields - some
-		 * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
-		 * if this isn't done. */
-		hermes_clear_words(hw, HERMES_DATA0,
-				   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
-	}
-
-	eh = (struct ethhdr *)skb->data;
-
-	/* Encapsulate Ethernet-II frames */
-	if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
-		struct header_struct {
-			struct ethhdr eth;	/* 802.3 header */
-			u8 encap[6];		/* 802.2 header */
-		} __attribute__ ((packed)) hdr;
-
-		/* Strip destination and source from the data */
-		skb_pull(skb, 2 * ETH_ALEN);
-
-		/* And move them to a separate header */
-		memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
-		hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
-		memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
-
-		/* Insert the SNAP header */
-		if (skb_headroom(skb) < sizeof(hdr)) {
-			printk(KERN_ERR
-			       "%s: Not enough headroom for 802.2 headers %d\n",
-			       dev->name, skb_headroom(skb));
-			goto drop;
-		}
-		eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
-		memcpy(eh, &hdr, sizeof(hdr));
-	}
-
-	err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
-				txfid, HERMES_802_3_OFFSET);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
-		       dev->name, err);
-		goto busy;
-	}
-
-	/* Calculate Michael MIC */
-	if (priv->encode_alg == IW_ENCODE_ALG_TKIP) {
-		u8 mic_buf[MICHAEL_MIC_LEN + 1];
-		u8 *mic;
-		size_t offset;
-		size_t len;
-
-		if (skb->len % 2) {
-			/* MIC start is on an odd boundary */
-			mic_buf[0] = skb->data[skb->len - 1];
-			mic = &mic_buf[1];
-			offset = skb->len - 1;
-			len = MICHAEL_MIC_LEN + 1;
-		} else {
-			mic = &mic_buf[0];
-			offset = skb->len;
-			len = MICHAEL_MIC_LEN;
-		}
-
-		michael_mic(priv->tx_tfm_mic,
-			    priv->tkip_key[priv->tx_key].tx_mic,
-			    eh->h_dest, eh->h_source, 0 /* priority */,
-			    skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
-
-		/* Write the MIC */
-		err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
-					txfid, HERMES_802_3_OFFSET + offset);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
-			       dev->name, err);
-			goto busy;
-		}
-	}
-
-	/* Finally, we actually initiate the send */
-	netif_stop_queue(dev);
-
-	err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
-				txfid, NULL);
-	if (err) {
-		netif_start_queue(dev);
-		if (net_ratelimit())
-			printk(KERN_ERR "%s: Error %d transmitting packet\n",
-				dev->name, err);
-		goto busy;
-	}
-
-	dev->trans_start = jiffies;
-	stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
-	goto ok;
-
- drop:
-	stats->tx_errors++;
-	stats->tx_dropped++;
-
- ok:
-	orinoco_unlock(priv, &flags);
-	dev_kfree_skb(skb);
-	return NETDEV_TX_OK;
-
- busy:
-	if (err == -EIO)
-		schedule_work(&priv->reset_work);
-	orinoco_unlock(priv, &flags);
-	return NETDEV_TX_BUSY;
-}
-
-static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	u16 fid = hermes_read_regn(hw, ALLOCFID);
-
-	if (fid != priv->txfid) {
-		if (fid != DUMMY_FID)
-			printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
-			       dev->name, fid);
-		return;
-	}
-
-	hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
-}
-
-static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct net_device_stats *stats = &priv->stats;
-
-	stats->tx_packets++;
-
-	netif_wake_queue(dev);
-
-	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
-}
-
-static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct net_device_stats *stats = &priv->stats;
-	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
-	u16 status;
-	struct hermes_txexc_data hdr;
-	int err = 0;
-
-	if (fid == DUMMY_FID)
-		return; /* Nothing's really happened */
-
-	/* Read part of the frame header - we need status and addr1 */
-	err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
-			       sizeof(struct hermes_txexc_data),
-			       fid, 0);
-
-	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
-	stats->tx_errors++;
-
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
-		       "(FID=%04X error %d)\n",
-		       dev->name, fid, err);
-		return;
-	}
-	
-	DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
-	      err, fid);
-    
-	/* We produce a TXDROP event only for retry or lifetime
-	 * exceeded, because that's the only status that really mean
-	 * that this particular node went away.
-	 * Other errors means that *we* screwed up. - Jean II */
-	status = le16_to_cpu(hdr.desc.status);
-	if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
-		union iwreq_data	wrqu;
-
-		/* Copy 802.11 dest address.
-		 * We use the 802.11 header because the frame may
-		 * not be 802.3 or may be mangled...
-		 * In Ad-Hoc mode, it will be the node address.
-		 * In managed mode, it will be most likely the AP addr
-		 * User space will figure out how to convert it to
-		 * whatever it needs (IP address or else).
-		 * - Jean II */
-		memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
-		wrqu.addr.sa_family = ARPHRD_ETHER;
-
-		/* Send event to user space */
-		wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
-	}
-
-	netif_wake_queue(dev);
-}
-
-static void orinoco_tx_timeout(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct net_device_stats *stats = &priv->stats;
-	struct hermes *hw = &priv->hw;
-
-	printk(KERN_WARNING "%s: Tx timeout! "
-	       "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
-	       dev->name, hermes_read_regn(hw, ALLOCFID),
-	       hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
-
-	stats->tx_errors++;
-
-	schedule_work(&priv->reset_work);
-}
-
-/********************************************************************/
-/* Rx path (data frames)                                            */
-/********************************************************************/
-
-/* Does the frame have a SNAP header indicating it should be
- * de-encapsulated to Ethernet-II? */
-static inline int is_ethersnap(void *_hdr)
-{
-	u8 *hdr = _hdr;
-
-	/* We de-encapsulate all packets which, a) have SNAP headers
-	 * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
-	 * and where b) the OUI of the SNAP header is 00:00:00 or
-	 * 00:00:f8 - we need both because different APs appear to use
-	 * different OUIs for some reason */
-	return (memcmp(hdr, &encaps_hdr, 5) == 0)
-		&& ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) );
-}
-
-static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
-				      int level, int noise)
-{
-	struct iw_quality wstats;
-	wstats.level = level - 0x95;
-	wstats.noise = noise - 0x95;
-	wstats.qual = (level > noise) ? (level - noise) : 0;
-	wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-	/* Update spy records */
-	wireless_spy_update(dev, mac, &wstats);
-}
-
-static void orinoco_stat_gather(struct net_device *dev,
-				struct sk_buff *skb,
-				struct hermes_rx_descriptor *desc)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-
-	/* Using spy support with lots of Rx packets, like in an
-	 * infrastructure (AP), will really slow down everything, because
-	 * the MAC address must be compared to each entry of the spy list.
-	 * If the user really asks for it (set some address in the
-	 * spy list), we do it, but he will pay the price.
-	 * Note that to get here, you need both WIRELESS_SPY
-	 * compiled in AND some addresses in the list !!!
-	 */
-	/* Note : gcc will optimise the whole section away if
-	 * WIRELESS_SPY is not defined... - Jean II */
-	if (SPY_NUMBER(priv)) {
-		orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
-				   desc->signal, desc->silence);
-	}
-}
-
-/*
- * orinoco_rx_monitor - handle received monitor frames.
- *
- * Arguments:
- *	dev		network device
- *	rxfid		received FID
- *	desc		rx descriptor of the frame
- *
- * Call context: interrupt
- */
-static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
-			       struct hermes_rx_descriptor *desc)
-{
-	u32 hdrlen = 30;	/* return full header by default */
-	u32 datalen = 0;
-	u16 fc;
-	int err;
-	int len;
-	struct sk_buff *skb;
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct net_device_stats *stats = &priv->stats;
-	hermes_t *hw = &priv->hw;
-
-	len = le16_to_cpu(desc->data_len);
-
-	/* Determine the size of the header and the data */
-	fc = le16_to_cpu(desc->frame_ctl);
-	switch (fc & IEEE80211_FCTL_FTYPE) {
-	case IEEE80211_FTYPE_DATA:
-		if ((fc & IEEE80211_FCTL_TODS)
-		    && (fc & IEEE80211_FCTL_FROMDS))
-			hdrlen = 30;
-		else
-			hdrlen = 24;
-		datalen = len;
-		break;
-	case IEEE80211_FTYPE_MGMT:
-		hdrlen = 24;
-		datalen = len;
-		break;
-	case IEEE80211_FTYPE_CTL:
-		switch (fc & IEEE80211_FCTL_STYPE) {
-		case IEEE80211_STYPE_PSPOLL:
-		case IEEE80211_STYPE_RTS:
-		case IEEE80211_STYPE_CFEND:
-		case IEEE80211_STYPE_CFENDACK:
-			hdrlen = 16;
-			break;
-		case IEEE80211_STYPE_CTS:
-		case IEEE80211_STYPE_ACK:
-			hdrlen = 10;
-			break;
-		}
-		break;
-	default:
-		/* Unknown frame type */
-		break;
-	}
-
-	/* sanity check the length */
-	if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
-		printk(KERN_DEBUG "%s: oversized monitor frame, "
-		       "data length = %d\n", dev->name, datalen);
-		stats->rx_length_errors++;
-		goto update_stats;
-	}
-
-	skb = dev_alloc_skb(hdrlen + datalen);
-	if (!skb) {
-		printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
-		       dev->name);
-		goto update_stats;
-	}
-
-	/* Copy the 802.11 header to the skb */
-	memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
-	skb_reset_mac_header(skb);
-
-	/* If any, copy the data from the card to the skb */
-	if (datalen > 0) {
-		err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
-				       ALIGN(datalen, 2), rxfid,
-				       HERMES_802_2_OFFSET);
-		if (err) {
-			printk(KERN_ERR "%s: error %d reading monitor frame\n",
-			       dev->name, err);
-			goto drop;
-		}
-	}
-
-	skb->dev = dev;
-	skb->ip_summed = CHECKSUM_NONE;
-	skb->pkt_type = PACKET_OTHERHOST;
-	skb->protocol = cpu_to_be16(ETH_P_802_2);
-	
-	stats->rx_packets++;
-	stats->rx_bytes += skb->len;
-
-	netif_rx(skb);
-	return;
-
- drop:
-	dev_kfree_skb_irq(skb);
- update_stats:
-	stats->rx_errors++;
-	stats->rx_dropped++;
-}
-
-/* Get tsc from the firmware */
-static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key,
-				  u8 *tsc)
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE];
-
-	if ((key < 0) || (key > 4))
-		return -EINVAL;
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
-			      sizeof(tsc_arr), NULL, &tsc_arr);
-	if (!err)
-		memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
-
-	return err;
-}
-
-static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct net_device_stats *stats = &priv->stats;
-	struct iw_statistics *wstats = &priv->wstats;
-	struct sk_buff *skb = NULL;
-	u16 rxfid, status;
-	int length;
-	struct hermes_rx_descriptor *desc;
-	struct orinoco_rx_data *rx_data;
-	int err;
-
-	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
-	if (!desc) {
-		printk(KERN_WARNING
-		       "%s: Can't allocate space for RX descriptor\n",
-		       dev->name);
-		goto update_stats;
-	}
-
-	rxfid = hermes_read_regn(hw, RXFID);
-
-	err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
-			       rxfid, 0);
-	if (err) {
-		printk(KERN_ERR "%s: error %d reading Rx descriptor. "
-		       "Frame dropped.\n", dev->name, err);
-		goto update_stats;
-	}
-
-	status = le16_to_cpu(desc->status);
-
-	if (status & HERMES_RXSTAT_BADCRC) {
-		DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
-		      dev->name);
-		stats->rx_crc_errors++;
-		goto update_stats;
-	}
-
-	/* Handle frames in monitor mode */
-	if (priv->iw_mode == IW_MODE_MONITOR) {
-		orinoco_rx_monitor(dev, rxfid, desc);
-		goto out;
-	}
-
-	if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
-		DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
-		      dev->name);
-		wstats->discard.code++;
-		goto update_stats;
-	}
-
-	length = le16_to_cpu(desc->data_len);
-
-	/* Sanity checks */
-	if (length < 3) { /* No for even an 802.2 LLC header */
-		/* At least on Symbol firmware with PCF we get quite a
-                   lot of these legitimately - Poll frames with no
-                   data. */
-		goto out;
-	}
-	if (length > IEEE80211_MAX_DATA_LEN) {
-		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
-		       dev->name, length);
-		stats->rx_length_errors++;
-		goto update_stats;
-	}
-
-	/* Payload size does not include Michael MIC. Increase payload
-	 * size to read it together with the data. */
-	if (status & HERMES_RXSTAT_MIC)
-		length += MICHAEL_MIC_LEN;
-
-	/* We need space for the packet data itself, plus an ethernet
-	   header, plus 2 bytes so we can align the IP header on a
-	   32bit boundary, plus 1 byte so we can read in odd length
-	   packets from the card, which has an IO granularity of 16
-	   bits */  
-	skb = dev_alloc_skb(length+ETH_HLEN+2+1);
-	if (!skb) {
-		printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
-		       dev->name);
-		goto update_stats;
-	}
-
-	/* We'll prepend the header, so reserve space for it.  The worst
-	   case is no decapsulation, when 802.3 header is prepended and
-	   nothing is removed.  2 is for aligning the IP header.  */
-	skb_reserve(skb, ETH_HLEN + 2);
-
-	err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
-			       ALIGN(length, 2), rxfid,
-			       HERMES_802_2_OFFSET);
-	if (err) {
-		printk(KERN_ERR "%s: error %d reading frame. "
-		       "Frame dropped.\n", dev->name, err);
-		goto drop;
-	}
-
-	/* Add desc and skb to rx queue */
-	rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
-	if (!rx_data) {
-		printk(KERN_WARNING "%s: Can't allocate RX packet\n",
-			dev->name);
-		goto drop;
-	}
-	rx_data->desc = desc;
-	rx_data->skb = skb;
-	list_add_tail(&rx_data->list, &priv->rx_list);
-	tasklet_schedule(&priv->rx_tasklet);
-
-	return;
-
-drop:
-	dev_kfree_skb_irq(skb);
-update_stats:
-	stats->rx_errors++;
-	stats->rx_dropped++;
-out:
-	kfree(desc);
-}
-
-static void orinoco_rx(struct net_device *dev,
-		       struct hermes_rx_descriptor *desc,
-		       struct sk_buff *skb)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct net_device_stats *stats = &priv->stats;
-	u16 status, fc;
-	int length;
-	struct ethhdr *hdr;
-
-	status = le16_to_cpu(desc->status);
-	length = le16_to_cpu(desc->data_len);
-	fc = le16_to_cpu(desc->frame_ctl);
-
-	/* Calculate and check MIC */
-	if (status & HERMES_RXSTAT_MIC) {
-		int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
-			      HERMES_MIC_KEY_ID_SHIFT);
-		u8 mic[MICHAEL_MIC_LEN];
-		u8 *rxmic;
-		u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
-			desc->addr3 : desc->addr2;
-
-		/* Extract Michael MIC from payload */
-		rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
-
-		skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
-		length -= MICHAEL_MIC_LEN;
-
-		michael_mic(priv->rx_tfm_mic,
-			    priv->tkip_key[key_id].rx_mic,
-			    desc->addr1,
-			    src,
-			    0, /* priority or QoS? */
-			    skb->data,
-			    skb->len,
-			    &mic[0]);
-
-		if (memcmp(mic, rxmic,
-			   MICHAEL_MIC_LEN)) {
-			union iwreq_data wrqu;
-			struct iw_michaelmicfailure wxmic;
-
-			printk(KERN_WARNING "%s: "
-			       "Invalid Michael MIC in data frame from %pM, "
-			       "using key %i\n",
-			       dev->name, src, key_id);
-
-			/* TODO: update stats */
-
-			/* Notify userspace */
-			memset(&wxmic, 0, sizeof(wxmic));
-			wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
-			wxmic.flags |= (desc->addr1[0] & 1) ?
-				IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
-			wxmic.src_addr.sa_family = ARPHRD_ETHER;
-			memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
-
-			(void) orinoco_hw_get_tkip_iv(priv, key_id,
-						      &wxmic.tsc[0]);
-
-			memset(&wrqu, 0, sizeof(wrqu));
-			wrqu.data.length = sizeof(wxmic);
-			wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
-					    (char *) &wxmic);
-
-			goto drop;
-		}
-	}
-
-	/* Handle decapsulation
-	 * In most cases, the firmware tell us about SNAP frames.
-	 * For some reason, the SNAP frames sent by LinkSys APs
-	 * are not properly recognised by most firmwares.
-	 * So, check ourselves */
-	if (length >= ENCAPS_OVERHEAD &&
-	    (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
-	     ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-	     is_ethersnap(skb->data))) {
-		/* These indicate a SNAP within 802.2 LLC within
-		   802.11 frame which we'll need to de-encapsulate to
-		   the original EthernetII frame. */
-		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
-	} else {
-		/* 802.3 frame - prepend 802.3 header as is */
-		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
-		hdr->h_proto = htons(length);
-	}
-	memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
-	if (fc & IEEE80211_FCTL_FROMDS)
-		memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
-	else
-		memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
-
-	skb->protocol = eth_type_trans(skb, dev);
-	skb->ip_summed = CHECKSUM_NONE;
-	if (fc & IEEE80211_FCTL_TODS)
-		skb->pkt_type = PACKET_OTHERHOST;
-	
-	/* Process the wireless stats if needed */
-	orinoco_stat_gather(dev, skb, desc);
-
-	/* Pass the packet to the networking stack */
-	netif_rx(skb);
-	stats->rx_packets++;
-	stats->rx_bytes += length;
-
-	return;
-
- drop:
-	dev_kfree_skb(skb);
-	stats->rx_errors++;
-	stats->rx_dropped++;
-}
-
-static void orinoco_rx_isr_tasklet(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *) data;
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct orinoco_rx_data *rx_data, *temp;
-	struct hermes_rx_descriptor *desc;
-	struct sk_buff *skb;
-	unsigned long flags;
-
-	/* orinoco_rx requires the driver lock, and we also need to
-	 * protect priv->rx_list, so just hold the lock over the
-	 * lot.
-	 *
-	 * If orinoco_lock fails, we've unplugged the card. In this
-	 * case just abort. */
-	if (orinoco_lock(priv, &flags) != 0)
-		return;
-
-	/* extract desc and skb from queue */
-	list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
-		desc = rx_data->desc;
-		skb = rx_data->skb;
-		list_del(&rx_data->list);
-		kfree(rx_data);
-
-		orinoco_rx(dev, desc, skb);
-
-		kfree(desc);
-	}
-
-	orinoco_unlock(priv, &flags);
-}
-
-/********************************************************************/
-/* Rx path (info frames)                                            */
-/********************************************************************/
-
-static void print_linkstatus(struct net_device *dev, u16 status)
-{
-	char * s;
-
-	if (suppress_linkstatus)
-		return;
-
-	switch (status) {
-	case HERMES_LINKSTATUS_NOT_CONNECTED:
-		s = "Not Connected";
-		break;
-	case HERMES_LINKSTATUS_CONNECTED:
-		s = "Connected";
-		break;
-	case HERMES_LINKSTATUS_DISCONNECTED:
-		s = "Disconnected";
-		break;
-	case HERMES_LINKSTATUS_AP_CHANGE:
-		s = "AP Changed";
-		break;
-	case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
-		s = "AP Out of Range";
-		break;
-	case HERMES_LINKSTATUS_AP_IN_RANGE:
-		s = "AP In Range";
-		break;
-	case HERMES_LINKSTATUS_ASSOC_FAILED:
-		s = "Association Failed";
-		break;
-	default:
-		s = "UNKNOWN";
-	}
-	
-	printk(KERN_DEBUG "%s: New link status: %s (%04x)\n",
-	       dev->name, s, status);
-}
-
-/* Search scan results for requested BSSID, join it if found */
-static void orinoco_join_ap(struct work_struct *work)
-{
-	struct orinoco_private *priv =
-		container_of(work, struct orinoco_private, join_work);
-	struct net_device *dev = priv->ndev;
-	struct hermes *hw = &priv->hw;
-	int err;
-	unsigned long flags;
-	struct join_req {
-		u8 bssid[ETH_ALEN];
-		__le16 channel;
-	} __attribute__ ((packed)) req;
-	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
-	struct prism2_scan_apinfo *atom = NULL;
-	int offset = 4;
-	int found = 0;
-	u8 *buf;
-	u16 len;
-
-	/* Allocate buffer for scan results */
-	buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
-	if (! buf)
-		return;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		goto fail_lock;
-
-	/* Sanity checks in case user changed something in the meantime */
-	if (! priv->bssid_fixed)
-		goto out;
-
-	if (strlen(priv->desired_essid) == 0)
-		goto out;
-
-	/* Read scan results from the firmware */
-	err = hermes_read_ltv(hw, USER_BAP,
-			      HERMES_RID_SCANRESULTSTABLE,
-			      MAX_SCAN_LEN, &len, buf);
-	if (err) {
-		printk(KERN_ERR "%s: Cannot read scan results\n",
-		       dev->name);
-		goto out;
-	}
-
-	len = HERMES_RECLEN_TO_BYTES(len);
-
-	/* Go through the scan results looking for the channel of the AP
-	 * we were requested to join */
-	for (; offset + atom_len <= len; offset += atom_len) {
-		atom = (struct prism2_scan_apinfo *) (buf + offset);
-		if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
-			found = 1;
-			break;
-		}
-	}
-
-	if (! found) {
-		DEBUG(1, "%s: Requested AP not found in scan results\n",
-		      dev->name);
-		goto out;
-	}
-
-	memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
-	req.channel = atom->channel;	/* both are little-endian */
-	err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
-				  &req);
-	if (err)
-		printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
-
- out:
-	orinoco_unlock(priv, &flags);
-
- fail_lock:
-	kfree(buf);
-}
-
-/* Send new BSSID to userspace */
-static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
-{
-	struct net_device *dev = priv->ndev;
-	struct hermes *hw = &priv->hw;
-	union iwreq_data wrqu;
-	int err;
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
-	if (err != 0)
-		return;
-
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
-	/* Send event to user space */
-	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
-{
-	struct net_device *dev = priv->ndev;
-	struct hermes *hw = &priv->hw;
-	union iwreq_data wrqu;
-	int err;
-	u8 buf[88];
-	u8 *ie;
-
-	if (!priv->has_wpa)
-		return;
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
-			      sizeof(buf), NULL, &buf);
-	if (err != 0)
-		return;
-
-	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
-	if (ie) {
-		int rem = sizeof(buf) - (ie - &buf[0]);
-		wrqu.data.length = ie[1] + 2;
-		if (wrqu.data.length > rem)
-			wrqu.data.length = rem;
-
-		if (wrqu.data.length)
-			/* Send event to user space */
-			wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
-	}
-}
-
-static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
-{
-	struct net_device *dev = priv->ndev;
-	struct hermes *hw = &priv->hw;
-	union iwreq_data wrqu;
-	int err;
-	u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
-	u8 *ie;
-
-	if (!priv->has_wpa)
-		return;
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
-			      sizeof(buf), NULL, &buf);
-	if (err != 0)
-		return;
-
-	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
-	if (ie) {
-		int rem = sizeof(buf) - (ie - &buf[0]);
-		wrqu.data.length = ie[1] + 2;
-		if (wrqu.data.length > rem)
-			wrqu.data.length = rem;
-
-		if (wrqu.data.length)
-			/* Send event to user space */
-			wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
-	}
-}
-
-static void orinoco_send_wevents(struct work_struct *work)
-{
-	struct orinoco_private *priv =
-		container_of(work, struct orinoco_private, wevent_work);
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return;
-
-	orinoco_send_assocreqie_wevent(priv);
-	orinoco_send_assocrespie_wevent(priv);
-	orinoco_send_bssid_wevent(priv);
-
-	orinoco_unlock(priv, &flags);
-}
-
-static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
-					      unsigned long scan_age)
-{
-	if (priv->has_ext_scan) {
-		struct xbss_element *bss;
-		struct xbss_element *tmp_bss;
-
-		/* Blow away current list of scan results */
-		list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
-			if (!scan_age ||
-			    time_after(jiffies, bss->last_scanned + scan_age)) {
-				list_move_tail(&bss->list,
-					       &priv->bss_free_list);
-				/* Don't blow away ->list, just BSS data */
-				memset(&bss->bss, 0, sizeof(bss->bss));
-				bss->last_scanned = 0;
-			}
-		}
-	} else {
-		struct bss_element *bss;
-		struct bss_element *tmp_bss;
-
-		/* Blow away current list of scan results */
-		list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
-			if (!scan_age ||
-			    time_after(jiffies, bss->last_scanned + scan_age)) {
-				list_move_tail(&bss->list,
-					       &priv->bss_free_list);
-				/* Don't blow away ->list, just BSS data */
-				memset(&bss->bss, 0, sizeof(bss->bss));
-				bss->last_scanned = 0;
-			}
-		}
-	}
-}
-
-static void orinoco_add_ext_scan_result(struct orinoco_private *priv,
-					struct agere_ext_scan_info *atom)
-{
-	struct xbss_element *bss = NULL;
-	int found = 0;
-
-	/* Try to update an existing bss first */
-	list_for_each_entry(bss, &priv->bss_list, list) {
-		if (compare_ether_addr(bss->bss.bssid, atom->bssid))
-			continue;
-		/* ESSID lengths */
-		if (bss->bss.data[1] != atom->data[1])
-			continue;
-		if (memcmp(&bss->bss.data[2], &atom->data[2],
-			   atom->data[1]))
-			continue;
-		found = 1;
-		break;
-	}
-
-	/* Grab a bss off the free list */
-	if (!found && !list_empty(&priv->bss_free_list)) {
-		bss = list_entry(priv->bss_free_list.next,
-				 struct xbss_element, list);
-		list_del(priv->bss_free_list.next);
-
-		list_add_tail(&bss->list, &priv->bss_list);
-	}
-
-	if (bss) {
-		/* Always update the BSS to get latest beacon info */
-		memcpy(&bss->bss, atom, sizeof(bss->bss));
-		bss->last_scanned = jiffies;
-	}
-}
-
-static int orinoco_process_scan_results(struct net_device *dev,
-					unsigned char *buf,
-					int len)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int			offset;		/* In the scan data */
-	union hermes_scan_info *atom;
-	int			atom_len;
-
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE:
-		atom_len = sizeof(struct agere_scan_apinfo);
-		offset = 0;
-		break;
-	case FIRMWARE_TYPE_SYMBOL:
-		/* Lack of documentation necessitates this hack.
-		 * Different firmwares have 68 or 76 byte long atoms.
-		 * We try modulo first.  If the length divides by both,
-		 * we check what would be the channel in the second
-		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
-		 * Valid channel cannot be 0.  */
-		if (len % 76)
-			atom_len = 68;
-		else if (len % 68)
-			atom_len = 76;
-		else if (len >= 1292 && buf[68] == 0)
-			atom_len = 76;
-		else
-			atom_len = 68;
-		offset = 0;
-		break;
-	case FIRMWARE_TYPE_INTERSIL:
-		offset = 4;
-		if (priv->has_hostscan) {
-			atom_len = le16_to_cpup((__le16 *)buf);
-			/* Sanity check for atom_len */
-			if (atom_len < sizeof(struct prism2_scan_apinfo)) {
-				printk(KERN_ERR "%s: Invalid atom_len in scan "
-				       "data: %d\n", dev->name, atom_len);
-				return -EIO;
-			}
-		} else
-			atom_len = offsetof(struct prism2_scan_apinfo, atim);
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	/* Check that we got an whole number of atoms */
-	if ((len - offset) % atom_len) {
-		printk(KERN_ERR "%s: Unexpected scan data length %d, "
-		       "atom_len %d, offset %d\n", dev->name, len,
-		       atom_len, offset);
-		return -EIO;
-	}
-
-	orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
-
-	/* Read the entries one by one */
-	for (; offset + atom_len <= len; offset += atom_len) {
-		int found = 0;
-		struct bss_element *bss = NULL;
-
-		/* Get next atom */
-		atom = (union hermes_scan_info *) (buf + offset);
-
-		/* Try to update an existing bss first */
-		list_for_each_entry(bss, &priv->bss_list, list) {
-			if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
-				continue;
-			if (le16_to_cpu(bss->bss.a.essid_len) !=
-			      le16_to_cpu(atom->a.essid_len))
-				continue;
-			if (memcmp(bss->bss.a.essid, atom->a.essid,
-			      le16_to_cpu(atom->a.essid_len)))
-				continue;
-			found = 1;
-			break;
-		}
-
-		/* Grab a bss off the free list */
-		if (!found && !list_empty(&priv->bss_free_list)) {
-			bss = list_entry(priv->bss_free_list.next,
-					 struct bss_element, list);
-			list_del(priv->bss_free_list.next);
-
-			list_add_tail(&bss->list, &priv->bss_list);
-		}
-
-		if (bss) {
-			/* Always update the BSS to get latest beacon info */
-			memcpy(&bss->bss, atom, sizeof(bss->bss));
-			bss->last_scanned = jiffies;
-		}
-	}
-
-	return 0;
-}
-
-static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	u16 infofid;
-	struct {
-		__le16 len;
-		__le16 type;
-	} __attribute__ ((packed)) info;
-	int len, type;
-	int err;
-
-	/* This is an answer to an INQUIRE command that we did earlier,
-	 * or an information "event" generated by the card
-	 * The controller return to us a pseudo frame containing
-	 * the information in question - Jean II */
-	infofid = hermes_read_regn(hw, INFOFID);
-
-	/* Read the info frame header - don't try too hard */
-	err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
-			       infofid, 0);
-	if (err) {
-		printk(KERN_ERR "%s: error %d reading info frame. "
-		       "Frame dropped.\n", dev->name, err);
-		return;
-	}
-	
-	len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
-	type = le16_to_cpu(info.type);
-
-	switch (type) {
-	case HERMES_INQ_TALLIES: {
-		struct hermes_tallies_frame tallies;
-		struct iw_statistics *wstats = &priv->wstats;
-		
-		if (len > sizeof(tallies)) {
-			printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
-			       dev->name, len);
-			len = sizeof(tallies);
-		}
-		
-		err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
-				       infofid, sizeof(info));
-		if (err)
-			break;
-		
-		/* Increment our various counters */
-		/* wstats->discard.nwid - no wrong BSSID stuff */
-		wstats->discard.code +=
-			le16_to_cpu(tallies.RxWEPUndecryptable);
-		if (len == sizeof(tallies))  
-			wstats->discard.code +=
-				le16_to_cpu(tallies.RxDiscards_WEPICVError) +
-				le16_to_cpu(tallies.RxDiscards_WEPExcluded);
-		wstats->discard.misc +=
-			le16_to_cpu(tallies.TxDiscardsWrongSA);
-		wstats->discard.fragment +=
-			le16_to_cpu(tallies.RxMsgInBadMsgFragments);
-		wstats->discard.retries +=
-			le16_to_cpu(tallies.TxRetryLimitExceeded);
-		/* wstats->miss.beacon - no match */
-	}
-	break;
-	case HERMES_INQ_LINKSTATUS: {
-		struct hermes_linkstatus linkstatus;
-		u16 newstatus;
-		int connected;
-
-		if (priv->iw_mode == IW_MODE_MONITOR)
-			break;
-
-		if (len != sizeof(linkstatus)) {
-			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
-			       dev->name, len);
-			break;
-		}
-
-		err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
-				       infofid, sizeof(info));
-		if (err)
-			break;
-		newstatus = le16_to_cpu(linkstatus.linkstatus);
-
-		/* Symbol firmware uses "out of range" to signal that
-		 * the hostscan frame can be requested.  */
-		if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
-		    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
-		    priv->has_hostscan && priv->scan_inprogress) {
-			hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
-			break;
-		}
-
-		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
-			|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
-			|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
-
-		if (connected)
-			netif_carrier_on(dev);
-		else if (!ignore_disconnect)
-			netif_carrier_off(dev);
-
-		if (newstatus != priv->last_linkstatus) {
-			priv->last_linkstatus = newstatus;
-			print_linkstatus(dev, newstatus);
-			/* The info frame contains only one word which is the
-			 * status (see hermes.h). The status is pretty boring
-			 * in itself, that's why we export the new BSSID...
-			 * Jean II */
-			schedule_work(&priv->wevent_work);
-		}
-	}
-	break;
-	case HERMES_INQ_SCAN:
-		if (!priv->scan_inprogress && priv->bssid_fixed &&
-		    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
-			schedule_work(&priv->join_work);
-			break;
-		}
-		/* fall through */
-	case HERMES_INQ_HOSTSCAN:
-	case HERMES_INQ_HOSTSCAN_SYMBOL: {
-		/* Result of a scanning. Contains information about
-		 * cells in the vicinity - Jean II */
-		union iwreq_data	wrqu;
-		unsigned char *buf;
-
-		/* Scan is no longer in progress */
-		priv->scan_inprogress = 0;
-
-		/* Sanity check */
-		if (len > 4096) {
-			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
-			       dev->name, len);
-			break;
-		}
-
-		/* Allocate buffer for results */
-		buf = kmalloc(len, GFP_ATOMIC);
-		if (buf == NULL)
-			/* No memory, so can't printk()... */
-			break;
-
-		/* Read scan data */
-		err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
-				       infofid, sizeof(info));
-		if (err) {
-			kfree(buf);
-			break;
-		}
-
-#ifdef ORINOCO_DEBUG
-		{
-			int	i;
-			printk(KERN_DEBUG "Scan result [%02X", buf[0]);
-			for(i = 1; i < (len * 2); i++)
-				printk(":%02X", buf[i]);
-			printk("]\n");
-		}
-#endif	/* ORINOCO_DEBUG */
-
-		if (orinoco_process_scan_results(dev, buf, len) == 0) {
-			/* Send an empty event to user space.
-			 * We don't send the received data on the event because
-			 * it would require us to do complex transcoding, and
-			 * we want to minimise the work done in the irq handler
-			 * Use a request to extract the data - Jean II */
-			wrqu.data.length = 0;
-			wrqu.data.flags = 0;
-			wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-		}
-		kfree(buf);
-	}
-	break;
-	case HERMES_INQ_CHANNELINFO:
-	{
-		struct agere_ext_scan_info *bss;
-
-		if (!priv->scan_inprogress) {
-			printk(KERN_DEBUG "%s: Got chaninfo without scan, "
-			       "len=%d\n", dev->name, len);
-			break;
-		}
-
-		/* An empty result indicates that the scan is complete */
-		if (len == 0) {
-			union iwreq_data	wrqu;
-
-			/* Scan is no longer in progress */
-			priv->scan_inprogress = 0;
-
-			wrqu.data.length = 0;
-			wrqu.data.flags = 0;
-			wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-			break;
-		}
-
-		/* Sanity check */
-		else if (len > sizeof(*bss)) {
-			printk(KERN_WARNING
-			       "%s: Ext scan results too large (%d bytes). "
-			       "Truncating results to %zd bytes.\n",
-			       dev->name, len, sizeof(*bss));
-			len = sizeof(*bss);
-		} else if (len < (offsetof(struct agere_ext_scan_info,
-					   data) + 2)) {
-			/* Drop this result now so we don't have to
-			 * keep checking later */
-			printk(KERN_WARNING
-			       "%s: Ext scan results too short (%d bytes)\n",
-			       dev->name, len);
-			break;
-		}
-
-		bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
-		if (bss == NULL)
-			break;
-
-		/* Read scan data */
-		err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
-				       infofid, sizeof(info));
-		if (err) {
-			kfree(bss);
-			break;
-		}
-
-		orinoco_add_ext_scan_result(priv, bss);
-
-		kfree(bss);
-		break;
-	}
-	case HERMES_INQ_SEC_STAT_AGERE:
-		/* Security status (Agere specific) */
-		/* Ignore this frame for now */
-		if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
-			break;
-		/* fall through */
-	default:
-		printk(KERN_DEBUG "%s: Unknown information frame received: "
-		       "type 0x%04x, length %d\n", dev->name, type, len);
-		/* We don't actually do anything about it */
-		break;
-	}
-}
-
-static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
-{
-	if (net_ratelimit())
-		printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
-}
-
-/********************************************************************/
-/* Internal hardware control routines                               */
-/********************************************************************/
-
-int __orinoco_up(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct hermes *hw = &priv->hw;
-	int err;
-
-	netif_carrier_off(dev); /* just to make sure */
-
-	err = __orinoco_program_rids(dev);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d configuring card\n",
-		       dev->name, err);
-		return err;
-	}
-
-	/* Fire things up again */
-	hermes_set_irqmask(hw, ORINOCO_INTEN);
-	err = hermes_enable_port(hw, 0);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d enabling MAC port\n",
-		       dev->name, err);
-		return err;
-	}
-
-	netif_start_queue(dev);
-
-	return 0;
-}
-
-int __orinoco_down(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct hermes *hw = &priv->hw;
-	int err;
-
-	netif_stop_queue(dev);
-
-	if (! priv->hw_unavailable) {
-		if (! priv->broken_disableport) {
-			err = hermes_disable_port(hw, 0);
-			if (err) {
-				/* Some firmwares (e.g. Intersil 1.3.x) seem
-				 * to have problems disabling the port, oh
-				 * well, too bad. */
-				printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
-				       dev->name, err);
-				priv->broken_disableport = 1;
-			}
-		}
-		hermes_set_irqmask(hw, 0);
-		hermes_write_regn(hw, EVACK, 0xffff);
-	}
-	
-	/* firmware will have to reassociate */
-	netif_carrier_off(dev);
-	priv->last_linkstatus = 0xffff;
-
-	return 0;
-}
-
-static int orinoco_allocate_fid(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct hermes *hw = &priv->hw;
-	int err;
-
-	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-	if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
-		/* Try workaround for old Symbol firmware bug */
-		printk(KERN_WARNING "%s: firmware ALLOC bug detected "
-		       "(old Symbol firmware?). Trying to work around... ",
-		       dev->name);
-		
-		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-		if (err)
-			printk("failed!\n");
-		else
-			printk("ok.\n");
-	}
-
-	return err;
-}
-
-int orinoco_reinit_firmware(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct hermes *hw = &priv->hw;
-	int err;
-
-	err = hermes_init(hw);
-	if (priv->do_fw_download && !err) {
-		err = orinoco_download(priv);
-		if (err)
-			priv->do_fw_download = 0;
-	}
-	if (!err)
-		err = orinoco_allocate_fid(dev);
-
-	return err;
-}
-
-static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-
-	if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
-		printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
-		       priv->ndev->name, priv->bitratemode);
-		return -EINVAL;
-	}
-
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE:
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFTXRATECONTROL,
-					   bitrate_table[priv->bitratemode].agere_txratectrl);
-		break;
-	case FIRMWARE_TYPE_INTERSIL:
-	case FIRMWARE_TYPE_SYMBOL:
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFTXRATECONTROL,
-					   bitrate_table[priv->bitratemode].intersil_txratectrl);
-		break;
-	default:
-		BUG();
-	}
-
-	return err;
-}
-
-/* Set fixed AP address */
-static int __orinoco_hw_set_wap(struct orinoco_private *priv)
-{
-	int roaming_flag;
-	int err = 0;
-	hermes_t *hw = &priv->hw;
-
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE:
-		/* not supported */
-		break;
-	case FIRMWARE_TYPE_INTERSIL:
-		if (priv->bssid_fixed)
-			roaming_flag = 2;
-		else
-			roaming_flag = 1;
-
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFROAMINGMODE,
-					   roaming_flag);
-		break;
-	case FIRMWARE_TYPE_SYMBOL:
-		err = HERMES_WRITE_RECORD(hw, USER_BAP,
-					  HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
-					  &priv->desired_bssid);
-		break;
-	}
-	return err;
-}
-
-/* Change the WEP keys and/or the current keys.  Can be called
- * either from __orinoco_hw_setup_enc() or directly from
- * orinoco_ioctl_setiwencode().  In the later case the association
- * with the AP is not broken (if the firmware can handle it),
- * which is needed for 802.1x implementations. */
-static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE:
-		err = HERMES_WRITE_RECORD(hw, USER_BAP,
-					  HERMES_RID_CNFWEPKEYS_AGERE,
-					  &priv->keys);
-		if (err)
-			return err;
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFTXKEY_AGERE,
-					   priv->tx_key);
-		if (err)
-			return err;
-		break;
-	case FIRMWARE_TYPE_INTERSIL:
-	case FIRMWARE_TYPE_SYMBOL:
-		{
-			int keylen;
-			int i;
-
-			/* Force uniform key length to work around firmware bugs */
-			keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
-			
-			if (keylen > LARGE_KEY_SIZE) {
-				printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
-				       priv->ndev->name, priv->tx_key, keylen);
-				return -E2BIG;
-			}
-
-			/* Write all 4 keys */
-			for(i = 0; i < ORINOCO_MAX_KEYS; i++) {
-				err = hermes_write_ltv(hw, USER_BAP,
-						       HERMES_RID_CNFDEFAULTKEY0 + i,
-						       HERMES_BYTES_TO_RECLEN(keylen),
-						       priv->keys[i].data);
-				if (err)
-					return err;
-			}
-
-			/* Write the index of the key used in transmission */
-			err = hermes_write_wordrec(hw, USER_BAP,
-						   HERMES_RID_CNFWEPDEFAULTKEYID,
-						   priv->tx_key);
-			if (err)
-				return err;
-		}
-		break;
-	}
-
-	return 0;
-}
-
-static int __orinoco_hw_setup_enc(struct orinoco_private *priv)
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	int master_wep_flag;
-	int auth_flag;
-	int enc_flag;
-
-	/* Setup WEP keys for WEP and WPA */
-	if (priv->encode_alg)
-		__orinoco_hw_setup_wepkeys(priv);
-
-	if (priv->wep_restrict)
-		auth_flag = HERMES_AUTH_SHARED_KEY;
-	else
-		auth_flag = HERMES_AUTH_OPEN;
-
-	if (priv->wpa_enabled)
-		enc_flag = 2;
-	else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
-		enc_flag = 1;
-	else
-		enc_flag = 0;
-
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
-		if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
-			/* Enable the shared-key authentication. */
-			err = hermes_write_wordrec(hw, USER_BAP,
-						   HERMES_RID_CNFAUTHENTICATION_AGERE,
-						   auth_flag);
-		}
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFWEPENABLED_AGERE,
-					   enc_flag);
-		if (err)
-			return err;
-
-		if (priv->has_wpa) {
-			/* Set WPA key management */
-			err = hermes_write_wordrec(hw, USER_BAP,
-				  HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
-				  priv->key_mgmt);
-			if (err)
-				return err;
-		}
-
-		break;
-
-	case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
-	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
-		if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
-			if (priv->wep_restrict ||
-			    (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
-				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
-						  HERMES_WEP_EXCL_UNENCRYPTED;
-			else
-				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
-
-			err = hermes_write_wordrec(hw, USER_BAP,
-						   HERMES_RID_CNFAUTHENTICATION,
-						   auth_flag);
-			if (err)
-				return err;
-		} else
-			master_wep_flag = 0;
-
-		if (priv->iw_mode == IW_MODE_MONITOR)
-			master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
-
-		/* Master WEP setting : on/off */
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFWEPFLAGS_INTERSIL,
-					   master_wep_flag);
-		if (err)
-			return err;	
-
-		break;
-	}
-
-	return 0;
-}
-
-/* key must be 32 bytes, including the tx and rx MIC keys.
- * rsc must be 8 bytes
- * tsc must be 8 bytes or NULL
- */
-static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
-				     u8 *key, u8 *rsc, u8 *tsc)
-{
-	struct {
-		__le16 idx;
-		u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
-		u8 key[TKIP_KEYLEN];
-		u8 tx_mic[MIC_KEYLEN];
-		u8 rx_mic[MIC_KEYLEN];
-		u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
-	} __attribute__ ((packed)) buf;
-	int ret;
-	int err;
-	int k;
-	u16 xmitting;
-
-	key_idx &= 0x3;
-
-	if (set_tx)
-		key_idx |= 0x8000;
-
-	buf.idx = cpu_to_le16(key_idx);
-	memcpy(buf.key, key,
-	       sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
-
-	if (rsc == NULL)
-		memset(buf.rsc, 0, sizeof(buf.rsc));
-	else
-		memcpy(buf.rsc, rsc, sizeof(buf.rsc));
-
-	if (tsc == NULL) {
-		memset(buf.tsc, 0, sizeof(buf.tsc));
-		buf.tsc[4] = 0x10;
-	} else {
-		memcpy(buf.tsc, tsc, sizeof(buf.tsc));
-	}
-
-	/* Wait upto 100ms for tx queue to empty */
-	k = 100;
-	do {
-		k--;
-		udelay(1000);
-		ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
-					  &xmitting);
-		if (ret)
-			break;
-	} while ((k > 0) && xmitting);
-
-	if (k == 0)
-		ret = -ETIMEDOUT;
-
-	err = HERMES_WRITE_RECORD(hw, USER_BAP,
-				  HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
-				  &buf);
-
-	return ret ? ret : err;
-}
-
-static int orinoco_clear_tkip_key(struct orinoco_private *priv,
-				  int key_idx)
-{
-	hermes_t *hw = &priv->hw;
-	int err;
-
-	memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
-	err = hermes_write_wordrec(hw, USER_BAP,
-				   HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
-				   key_idx);
-	if (err)
-		printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
-		       priv->ndev->name, err, key_idx);
-	return err;
-}
-
-static int __orinoco_program_rids(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err;
-	struct hermes_idstring idbuf;
-
-	/* Set the MAC address */
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-			       HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting MAC address\n",
-		       dev->name, err);
-		return err;
-	}
-
-	/* Set up the link mode */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
-				   priv->port_type);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting port type\n",
-		       dev->name, err);
-		return err;
-	}
-	/* Set the channel/frequency */
-	if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFOWNCHANNEL,
-					   priv->channel);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting channel %d\n",
-			       dev->name, err, priv->channel);
-			return err;
-		}
-	}
-
-	if (priv->has_ibss) {
-		u16 createibss;
-
-		if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
-			printk(KERN_WARNING "%s: This firmware requires an "
-			       "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
-			/* With wvlan_cs, in this case, we would crash.
-			 * hopefully, this driver will behave better...
-			 * Jean II */
-			createibss = 0;
-		} else {
-			createibss = priv->createibss;
-		}
-		
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFCREATEIBSS,
-					   createibss);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
-			       dev->name, err);
-			return err;
-		}
-	}
-
-	/* Set the desired BSSID */
-	err = __orinoco_hw_set_wap(priv);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting AP address\n",
-		       dev->name, err);
-		return err;
-	}
-	/* Set the desired ESSID */
-	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
-	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
-	/* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
-			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
-			       &idbuf);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
-		       dev->name, err);
-		return err;
-	}
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
-			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
-			       &idbuf);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
-		       dev->name, err);
-		return err;
-	}
-
-	/* Set the station name */
-	idbuf.len = cpu_to_le16(strlen(priv->nick));
-	memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-			       HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
-			       &idbuf);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting nickname\n",
-		       dev->name, err);
-		return err;
-	}
-
-	/* Set AP density */
-	if (priv->has_sensitivity) {
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFSYSTEMSCALE,
-					   priv->ap_density);
-		if (err) {
-			printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE.  "
-			       "Disabling sensitivity control\n",
-			       dev->name, err);
-
-			priv->has_sensitivity = 0;
-		}
-	}
-
-	/* Set RTS threshold */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
-				   priv->rts_thresh);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
-		       dev->name, err);
-		return err;
-	}
-
-	/* Set fragmentation threshold or MWO robustness */
-	if (priv->has_mwo)
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFMWOROBUST_AGERE,
-					   priv->mwo_robust);
-	else
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-					   priv->frag_thresh);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting fragmentation\n",
-		       dev->name, err);
-		return err;
-	}
-
-	/* Set bitrate */
-	err = __orinoco_hw_set_bitrate(priv);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting bitrate\n",
-		       dev->name, err);
-		return err;
-	}
-
-	/* Set power management */
-	if (priv->has_pm) {
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFPMENABLED,
-					   priv->pm_on);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting up PM\n",
-			       dev->name, err);
-			return err;
-		}
-
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFMULTICASTRECEIVE,
-					   priv->pm_mcast);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting up PM\n",
-			       dev->name, err);
-			return err;
-		}
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFMAXSLEEPDURATION,
-					   priv->pm_period);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting up PM\n",
-			       dev->name, err);
-			return err;
-		}
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFPMHOLDOVERDURATION,
-					   priv->pm_timeout);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting up PM\n",
-			       dev->name, err);
-			return err;
-		}
-	}
-
-	/* Set preamble - only for Symbol so far... */
-	if (priv->has_preamble) {
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFPREAMBLE_SYMBOL,
-					   priv->preamble);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting preamble\n",
-			       dev->name, err);
-			return err;
-		}
-	}
-
-	/* Set up encryption */
-	if (priv->has_wep || priv->has_wpa) {
-		err = __orinoco_hw_setup_enc(priv);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d activating encryption\n",
-			       dev->name, err);
-			return err;
-		}
-	}
-
-	if (priv->iw_mode == IW_MODE_MONITOR) {
-		/* Enable monitor mode */
-		dev->type = ARPHRD_IEEE80211;
-		err = hermes_docmd_wait(hw, HERMES_CMD_TEST | 
-					    HERMES_TEST_MONITOR, 0, NULL);
-	} else {
-		/* Disable monitor mode */
-		dev->type = ARPHRD_ETHER;
-		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
-					    HERMES_TEST_STOP, 0, NULL);
-	}
-	if (err)
-		return err;
-
-	/* Set promiscuity / multicast*/
-	priv->promiscuous = 0;
-	priv->mc_count = 0;
-
-	/* FIXME: what about netif_tx_lock */
-	__orinoco_set_multicast_list(dev);
-
-	return 0;
-}
-
-/* FIXME: return int? */
-static void
-__orinoco_set_multicast_list(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	int promisc, mc_count;
-
-	/* The Hermes doesn't seem to have an allmulti mode, so we go
-	 * into promiscuous mode and let the upper levels deal. */
-	if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
-	     (dev->mc_count > MAX_MULTICAST(priv)) ) {
-		promisc = 1;
-		mc_count = 0;
-	} else {
-		promisc = 0;
-		mc_count = dev->mc_count;
-	}
-
-	if (promisc != priv->promiscuous) {
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFPROMISCUOUSMODE,
-					   promisc);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
-			       dev->name, err);
-		} else 
-			priv->promiscuous = promisc;
-	}
-
-	/* If we're not in promiscuous mode, then we need to set the
-	 * group address if either we want to multicast, or if we were
-	 * multicasting and want to stop */
-	if (! promisc && (mc_count || priv->mc_count) ) {
-		struct dev_mc_list *p = dev->mc_list;
-		struct hermes_multicast mclist;
-		int i;
-
-		for (i = 0; i < mc_count; i++) {
-			/* paranoia: is list shorter than mc_count? */
-			BUG_ON(! p);
-			/* paranoia: bad address size in list? */
-			BUG_ON(p->dmi_addrlen != ETH_ALEN);
-			
-			memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
-			p = p->next;
-		}
-		
-		if (p)
-			printk(KERN_WARNING "%s: Multicast list is "
-			       "longer than mc_count\n", dev->name);
-
-		err = hermes_write_ltv(hw, USER_BAP,
-				   HERMES_RID_CNFGROUPADDRESSES,
-				   HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
-				   &mclist);
-		if (err)
-			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
-			       dev->name, err);
-		else
-			priv->mc_count = mc_count;
-	}
-}
-
-/* This must be called from user context, without locks held - use
- * schedule_work() */
-static void orinoco_reset(struct work_struct *work)
-{
-	struct orinoco_private *priv =
-		container_of(work, struct orinoco_private, reset_work);
-	struct net_device *dev = priv->ndev;
-	struct hermes *hw = &priv->hw;
-	int err;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		/* When the hardware becomes available again, whatever
-		 * detects that is responsible for re-initializing
-		 * it. So no need for anything further */
-		return;
-
-	netif_stop_queue(dev);
-
-	/* Shut off interrupts.  Depending on what state the hardware
-	 * is in, this might not work, but we'll try anyway */
-	hermes_set_irqmask(hw, 0);
-	hermes_write_regn(hw, EVACK, 0xffff);
-
-	priv->hw_unavailable++;
-	priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
-	netif_carrier_off(dev);
-
-	orinoco_unlock(priv, &flags);
-
- 	/* Scanning support: Cleanup of driver struct */
-	orinoco_clear_scan_results(priv, 0);
-	priv->scan_inprogress = 0;
-
-	if (priv->hard_reset) {
-		err = (*priv->hard_reset)(priv);
-		if (err) {
-			printk(KERN_ERR "%s: orinoco_reset: Error %d "
-			       "performing hard reset\n", dev->name, err);
-			goto disable;
-		}
-	}
-
-	err = orinoco_reinit_firmware(dev);
-	if (err) {
-		printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
-		       dev->name, err);
-		goto disable;
-	}
-
-	spin_lock_irq(&priv->lock); /* This has to be called from user context */
-
-	priv->hw_unavailable--;
-
-	/* priv->open or priv->hw_unavailable might have changed while
-	 * we dropped the lock */
-	if (priv->open && (! priv->hw_unavailable)) {
-		err = __orinoco_up(dev);
-		if (err) {
-			printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
-			       dev->name, err);
-		} else
-			dev->trans_start = jiffies;
-	}
-
-	spin_unlock_irq(&priv->lock);
-
-	return;
- disable:
-	hermes_set_irqmask(hw, 0);
-	netif_device_detach(dev);
-	printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
-}
-
-/********************************************************************/
-/* Interrupt handler                                                */
-/********************************************************************/
-
-static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
-{
-	printk(KERN_DEBUG "%s: TICK\n", dev->name);
-}
-
-static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
-{
-	/* This seems to happen a fair bit under load, but ignoring it
-	   seems to work fine...*/
-	printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
-	       dev->name);
-}
-
-irqreturn_t orinoco_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int count = MAX_IRQLOOPS_PER_IRQ;
-	u16 evstat, events;
-	/* These are used to detect a runaway interrupt situation */
-	/* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
-	 * we panic and shut down the hardware */
-	static int last_irq_jiffy = 0; /* jiffies value the last time
-					* we were called */
-	static int loops_this_jiffy = 0;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0) {
-		/* If hw is unavailable - we don't know if the irq was
-		 * for us or not */
-		return IRQ_HANDLED;
-	}
-
-	evstat = hermes_read_regn(hw, EVSTAT);
-	events = evstat & hw->inten;
-	if (! events) {
-		orinoco_unlock(priv, &flags);
-		return IRQ_NONE;
-	}
-	
-	if (jiffies != last_irq_jiffy)
-		loops_this_jiffy = 0;
-	last_irq_jiffy = jiffies;
-
-	while (events && count--) {
-		if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
-			printk(KERN_WARNING "%s: IRQ handler is looping too "
-			       "much! Resetting.\n", dev->name);
-			/* Disable interrupts for now */
-			hermes_set_irqmask(hw, 0);
-			schedule_work(&priv->reset_work);
-			break;
-		}
-
-		/* Check the card hasn't been removed */
-		if (! hermes_present(hw)) {
-			DEBUG(0, "orinoco_interrupt(): card removed\n");
-			break;
-		}
-
-		if (events & HERMES_EV_TICK)
-			__orinoco_ev_tick(dev, hw);
-		if (events & HERMES_EV_WTERR)
-			__orinoco_ev_wterr(dev, hw);
-		if (events & HERMES_EV_INFDROP)
-			__orinoco_ev_infdrop(dev, hw);
-		if (events & HERMES_EV_INFO)
-			__orinoco_ev_info(dev, hw);
-		if (events & HERMES_EV_RX)
-			__orinoco_ev_rx(dev, hw);
-		if (events & HERMES_EV_TXEXC)
-			__orinoco_ev_txexc(dev, hw);
-		if (events & HERMES_EV_TX)
-			__orinoco_ev_tx(dev, hw);
-		if (events & HERMES_EV_ALLOC)
-			__orinoco_ev_alloc(dev, hw);
-		
-		hermes_write_regn(hw, EVACK, evstat);
-
-		evstat = hermes_read_regn(hw, EVSTAT);
-		events = evstat & hw->inten;
-	};
-
-	orinoco_unlock(priv, &flags);
-	return IRQ_HANDLED;
-}
-
-/********************************************************************/
-/* Power management                                                 */
-/********************************************************************/
-#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
-static int orinoco_pm_notifier(struct notifier_block *notifier,
-			       unsigned long pm_event,
-			       void *unused)
-{
-	struct orinoco_private *priv = container_of(notifier,
-						    struct orinoco_private,
-						    pm_notifier);
-
-	/* All we need to do is cache the firmware before suspend, and
-	 * release it when we come out.
-	 *
-	 * Only need to do this if we're downloading firmware. */
-	if (!priv->do_fw_download)
-		return NOTIFY_DONE;
-
-	switch (pm_event) {
-	case PM_HIBERNATION_PREPARE:
-	case PM_SUSPEND_PREPARE:
-		orinoco_cache_fw(priv, 0);
-		break;
-
-	case PM_POST_RESTORE:
-		/* Restore from hibernation failed. We need to clean
-		 * up in exactly the same way, so fall through. */
-	case PM_POST_HIBERNATION:
-	case PM_POST_SUSPEND:
-		orinoco_uncache_fw(priv);
-		break;
-
-	case PM_RESTORE_PREPARE:
-	default:
-		break;
-	}
-
-	return NOTIFY_DONE;
-}
-#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
-#define orinoco_pm_notifier NULL
-#endif
-
-/********************************************************************/
-/* Initialization                                                   */
-/********************************************************************/
-
-struct comp_id {
-	u16 id, variant, major, minor;
-} __attribute__ ((packed));
-
-static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
-{
-	if (nic_id->id < 0x8000)
-		return FIRMWARE_TYPE_AGERE;
-	else if (nic_id->id == 0x8000 && nic_id->major == 0)
-		return FIRMWARE_TYPE_SYMBOL;
-	else
-		return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties */
-static int determine_firmware(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err;
-	struct comp_id nic_id, sta_id;
-	unsigned int firmver;
-	char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
-
-	/* Get the hardware version */
-	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
-	if (err) {
-		printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
-		       dev->name, err);
-		return err;
-	}
-
-	le16_to_cpus(&nic_id.id);
-	le16_to_cpus(&nic_id.variant);
-	le16_to_cpus(&nic_id.major);
-	le16_to_cpus(&nic_id.minor);
-	printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
-	       dev->name, nic_id.id, nic_id.variant,
-	       nic_id.major, nic_id.minor);
-
-	priv->firmware_type = determine_firmware_type(&nic_id);
-
-	/* Get the firmware version */
-	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
-	if (err) {
-		printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
-		       dev->name, err);
-		return err;
-	}
-
-	le16_to_cpus(&sta_id.id);
-	le16_to_cpus(&sta_id.variant);
-	le16_to_cpus(&sta_id.major);
-	le16_to_cpus(&sta_id.minor);
-	printk(KERN_DEBUG "%s: Station identity  %04x:%04x:%04x:%04x\n",
-	       dev->name, sta_id.id, sta_id.variant,
-	       sta_id.major, sta_id.minor);
-
-	switch (sta_id.id) {
-	case 0x15:
-		printk(KERN_ERR "%s: Primary firmware is active\n",
-		       dev->name);
-		return -ENODEV;
-	case 0x14b:
-		printk(KERN_ERR "%s: Tertiary firmware is active\n",
-		       dev->name);
-		return -ENODEV;
-	case 0x1f:	/* Intersil, Agere, Symbol Spectrum24 */
-	case 0x21:	/* Symbol Spectrum24 Trilogy */
-		break;
-	default:
-		printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
-		       dev->name);
-		break;
-	}
-
-	/* Default capabilities */
-	priv->has_sensitivity = 1;
-	priv->has_mwo = 0;
-	priv->has_preamble = 0;
-	priv->has_port3 = 1;
-	priv->has_ibss = 1;
-	priv->has_wep = 0;
-	priv->has_big_wep = 0;
-	priv->has_alt_txcntl = 0;
-	priv->has_ext_scan = 0;
-	priv->has_wpa = 0;
-	priv->do_fw_download = 0;
-
-	/* Determine capabilities from the firmware version */
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE:
-		/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
-		   ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
-		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-			 "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
-
-		firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
-		priv->has_ibss = (firmver >= 0x60006);
-		priv->has_wep = (firmver >= 0x40020);
-		priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
-					  Gold cards from the others? */
-		priv->has_mwo = (firmver >= 0x60000);
-		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
-		priv->ibss_port = 1;
-		priv->has_hostscan = (firmver >= 0x8000a);
-		priv->do_fw_download = 1;
-		priv->broken_monitor = (firmver >= 0x80000);
-		priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
-		priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
-		priv->has_wpa = (firmver >= 0x9002a);
-		/* Tested with Agere firmware :
-		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
-		 * Tested CableTron firmware : 4.32 => Anton */
-		break;
-	case FIRMWARE_TYPE_SYMBOL:
-		/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
-		/* Intel MAC : 00:02:B3:* */
-		/* 3Com MAC : 00:50:DA:* */
-		memset(tmp, 0, sizeof(tmp));
-		/* Get the Symbol firmware version */
-		err = hermes_read_ltv(hw, USER_BAP,
-				      HERMES_RID_SECONDARYVERSION_SYMBOL,
-				      SYMBOL_MAX_VER_LEN, NULL, &tmp);
-		if (err) {
-			printk(KERN_WARNING
-			       "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n",
-			       dev->name, err);
-			firmver = 0;
-			tmp[0] = '\0';
-		} else {
-			/* The firmware revision is a string, the format is
-			 * something like : "V2.20-01".
-			 * Quick and dirty parsing... - Jean II
-			 */
-			firmver = ((tmp[1] - '0') << 16) | ((tmp[3] - '0') << 12)
-				| ((tmp[4] - '0') << 8) | ((tmp[6] - '0') << 4)
-				| (tmp[7] - '0');
-
-			tmp[SYMBOL_MAX_VER_LEN] = '\0';
-		}
-
-		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-			 "Symbol %s", tmp);
-
-		priv->has_ibss = (firmver >= 0x20000);
-		priv->has_wep = (firmver >= 0x15012);
-		priv->has_big_wep = (firmver >= 0x20000);
-		priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || 
-			       (firmver >= 0x29000 && firmver < 0x30000) ||
-			       firmver >= 0x31000;
-		priv->has_preamble = (firmver >= 0x20000);
-		priv->ibss_port = 4;
-
-		/* Symbol firmware is found on various cards, but
-		 * there has been no attempt to check firmware
-		 * download on non-spectrum_cs based cards.
-		 *
-		 * Given that the Agere firmware download works
-		 * differently, we should avoid doing a firmware
-		 * download with the Symbol algorithm on non-spectrum
-		 * cards.
-		 *
-		 * For now we can identify a spectrum_cs based card
-		 * because it has a firmware reset function.
-		 */
-		priv->do_fw_download = (priv->stop_fw != NULL);
-
- 		priv->broken_disableport = (firmver == 0x25013) ||
- 					   (firmver >= 0x30000 && firmver <= 0x31000);
-		priv->has_hostscan = (firmver >= 0x31001) ||
-				     (firmver >= 0x29057 && firmver < 0x30000);
-		/* Tested with Intel firmware : 0x20015 => Jean II */
-		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
-		break;
-	case FIRMWARE_TYPE_INTERSIL:
-		/* D-Link, Linksys, Adtron, ZoomAir, and many others...
-		 * Samsung, Compaq 100/200 and Proxim are slightly
-		 * different and less well tested */
-		/* D-Link MAC : 00:40:05:* */
-		/* Addtron MAC : 00:90:D1:* */
-		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-			 "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
-			 sta_id.variant);
-
-		firmver = ((unsigned long)sta_id.major << 16) |
-			((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
-		priv->has_ibss = (firmver >= 0x000700); /* FIXME */
-		priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
-		priv->has_pm = (firmver >= 0x000700);
-		priv->has_hostscan = (firmver >= 0x010301);
-
-		if (firmver >= 0x000800)
-			priv->ibss_port = 0;
-		else {
-			printk(KERN_NOTICE "%s: Intersil firmware earlier "
-			       "than v0.8.x - several features not supported\n",
-			       dev->name);
-			priv->ibss_port = 1;
-		}
-		break;
-	}
-	printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
-	       priv->fw_name);
-
-	return 0;
-}
-
-static int orinoco_init(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	struct hermes_idstring nickbuf;
-	u16 reclen;
-	int len;
-
-	/* No need to lock, the hw_unavailable flag is already set in
-	 * alloc_orinocodev() */
-	priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
-
-	/* Initialize the firmware */
-	err = hermes_init(hw);
-	if (err != 0) {
-		printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
-		       dev->name, err);
-		goto out;
-	}
-
-	err = determine_firmware(dev);
-	if (err != 0) {
-		printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
-		       dev->name);
-		goto out;
-	}
-
-	if (priv->do_fw_download) {
-#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
-		orinoco_cache_fw(priv, 0);
-#endif
-
-		err = orinoco_download(priv);
-		if (err)
-			priv->do_fw_download = 0;
-
-		/* Check firmware version again */
-		err = determine_firmware(dev);
-		if (err != 0) {
-			printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
-			       dev->name);
-			goto out;
-		}
-	}
-
-	if (priv->has_port3)
-		printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name);
-	if (priv->has_ibss)
-		printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
-		       dev->name);
-	if (priv->has_wep) {
-		printk(KERN_DEBUG "%s: WEP supported, ", dev->name);
-		if (priv->has_big_wep)
-			printk("104-bit key\n");
-		else
-			printk("40-bit key\n");
-	}
-	if (priv->has_wpa) {
-		printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
-		if (orinoco_mic_init(priv)) {
-			printk(KERN_ERR "%s: Failed to setup MIC crypto "
-			       "algorithm. Disabling WPA support\n", dev->name);
-			priv->has_wpa = 0;
-		}
-	}
-
-	/* Now we have the firmware capabilities, allocate appropiate
-	 * sized scan buffers */
-	if (orinoco_bss_data_allocate(priv))
-		goto out;
-	orinoco_bss_data_init(priv);
-
-	/* Get the MAC address */
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-			      ETH_ALEN, NULL, dev->dev_addr);
-	if (err) {
-		printk(KERN_WARNING "%s: failed to read MAC address!\n",
-		       dev->name);
-		goto out;
-	}
-
-	printk(KERN_DEBUG "%s: MAC address %pM\n",
-	       dev->name, dev->dev_addr);
-
-	/* Get the station name */
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-			      sizeof(nickbuf), &reclen, &nickbuf);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read station name\n",
-		       dev->name);
-		goto out;
-	}
-	if (nickbuf.len)
-		len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
-	else
-		len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
-	memcpy(priv->nick, &nickbuf.val, len);
-	priv->nick[len] = '\0';
-
-	printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
-
-	err = orinoco_allocate_fid(dev);
-	if (err) {
-		printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
-		       dev->name);
-		goto out;
-	}
-
-	/* Get allowed channels */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
-				  &priv->channel_mask);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read channel list!\n",
-		       dev->name);
-		goto out;
-	}
-
-	/* Get initial AP density */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
-				  &priv->ap_density);
-	if (err || priv->ap_density < 1 || priv->ap_density > 3) {
-		priv->has_sensitivity = 0;
-	}
-
-	/* Get initial RTS threshold */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
-				  &priv->rts_thresh);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read RTS threshold!\n",
-		       dev->name);
-		goto out;
-	}
-
-	/* Get initial fragmentation settings */
-	if (priv->has_mwo)
-		err = hermes_read_wordrec(hw, USER_BAP,
-					  HERMES_RID_CNFMWOROBUST_AGERE,
-					  &priv->mwo_robust);
-	else
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-					  &priv->frag_thresh);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
-		       dev->name);
-		goto out;
-	}
-
-	/* Power management setup */
-	if (priv->has_pm) {
-		priv->pm_on = 0;
-		priv->pm_mcast = 1;
-		err = hermes_read_wordrec(hw, USER_BAP,
-					  HERMES_RID_CNFMAXSLEEPDURATION,
-					  &priv->pm_period);
-		if (err) {
-			printk(KERN_ERR "%s: failed to read power management period!\n",
-			       dev->name);
-			goto out;
-		}
-		err = hermes_read_wordrec(hw, USER_BAP,
-					  HERMES_RID_CNFPMHOLDOVERDURATION,
-					  &priv->pm_timeout);
-		if (err) {
-			printk(KERN_ERR "%s: failed to read power management timeout!\n",
-			       dev->name);
-			goto out;
-		}
-	}
-
-	/* Preamble setup */
-	if (priv->has_preamble) {
-		err = hermes_read_wordrec(hw, USER_BAP,
-					  HERMES_RID_CNFPREAMBLE_SYMBOL,
-					  &priv->preamble);
-		if (err)
-			goto out;
-	}
-		
-	/* Set up the default configuration */
-	priv->iw_mode = IW_MODE_INFRA;
-	/* By default use IEEE/IBSS ad-hoc mode if we have it */
-	priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
-	set_port_type(priv);
-	priv->channel = 0; /* use firmware default */
-
-	priv->promiscuous = 0;
-	priv->encode_alg = IW_ENCODE_ALG_NONE;
-	priv->tx_key = 0;
-	priv->wpa_enabled = 0;
-	priv->tkip_cm_active = 0;
-	priv->key_mgmt = 0;
-	priv->wpa_ie_len = 0;
-	priv->wpa_ie = NULL;
-
-	/* Make the hardware available, as long as it hasn't been
-	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
-	spin_lock_irq(&priv->lock);
-	priv->hw_unavailable--;
-	spin_unlock_irq(&priv->lock);
-
-	printk(KERN_DEBUG "%s: ready\n", dev->name);
-
- out:
-	return err;
-}
-
-static const struct net_device_ops orinoco_netdev_ops = {
-	.ndo_init		= orinoco_init,
-	.ndo_open		= orinoco_open,
-	.ndo_stop		= orinoco_stop,
-	.ndo_start_xmit		= orinoco_xmit,
-	.ndo_set_multicast_list	= orinoco_set_multicast_list,
-	.ndo_change_mtu		= orinoco_change_mtu,
-	.ndo_tx_timeout		= orinoco_tx_timeout,
-	.ndo_get_stats		= orinoco_get_stats,
-};
-
-struct net_device
-*alloc_orinocodev(int sizeof_card,
-		  struct device *device,
-		  int (*hard_reset)(struct orinoco_private *),
-		  int (*stop_fw)(struct orinoco_private *, int))
-{
-	struct net_device *dev;
-	struct orinoco_private *priv;
-
-	dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
-	if (!dev)
-		return NULL;
-	priv = netdev_priv(dev);
-	priv->ndev = dev;
-	if (sizeof_card)
-		priv->card = (void *)((unsigned long)priv
-				      + sizeof(struct orinoco_private));
-	else
-		priv->card = NULL;
-	priv->dev = device;
-
-	/* Setup / override net_device fields */
-	dev->netdev_ops = &orinoco_netdev_ops;
-	dev->watchdog_timeo = HZ; /* 1 second timeout */
-	dev->ethtool_ops = &orinoco_ethtool_ops;
-	dev->wireless_handlers = &orinoco_handler_def;
-#ifdef WIRELESS_SPY
-	priv->wireless_data.spy_data = &priv->spy_data;
-	dev->wireless_data = &priv->wireless_data;
-#endif
-	/* we use the default eth_mac_addr for setting the MAC addr */
-
-	/* Reserve space in skb for the SNAP header */
-	dev->hard_header_len += ENCAPS_OVERHEAD;
-
-	/* Set up default callbacks */
-	priv->hard_reset = hard_reset;
-	priv->stop_fw = stop_fw;
-
-	spin_lock_init(&priv->lock);
-	priv->open = 0;
-	priv->hw_unavailable = 1; /* orinoco_init() must clear this
-				   * before anything else touches the
-				   * hardware */
-	INIT_WORK(&priv->reset_work, orinoco_reset);
-	INIT_WORK(&priv->join_work, orinoco_join_ap);
-	INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
-
-	INIT_LIST_HEAD(&priv->rx_list);
-	tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
-		     (unsigned long) dev);
-
-	netif_carrier_off(dev);
-	priv->last_linkstatus = 0xffff;
-
-	priv->cached_pri_fw = NULL;
-	priv->cached_fw = NULL;
-
-	/* Register PM notifiers */
-	priv->pm_notifier.notifier_call = orinoco_pm_notifier;
-	register_pm_notifier(&priv->pm_notifier);
-
-	return dev;
-}
-
-void free_orinocodev(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct orinoco_rx_data *rx_data, *temp;
-
-	/* If the tasklet is scheduled when we call tasklet_kill it
-	 * will run one final time. However the tasklet will only
-	 * drain priv->rx_list if the hw is still available. */
-	tasklet_kill(&priv->rx_tasklet);
-
-	/* Explicitly drain priv->rx_list */
-	list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
-		list_del(&rx_data->list);
-
-		dev_kfree_skb(rx_data->skb);
-		kfree(rx_data->desc);
-		kfree(rx_data);
-	}
-
-	unregister_pm_notifier(&priv->pm_notifier);
-	orinoco_uncache_fw(priv);
-
-	priv->wpa_ie_len = 0;
-	kfree(priv->wpa_ie);
-	orinoco_mic_free(priv);
-	orinoco_bss_data_free(priv);
-	free_netdev(dev);
-}
-
-/********************************************************************/
-/* Wireless extensions                                              */
-/********************************************************************/
-
-/* Return : < 0 -> error code ; >= 0 -> length */
-static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
-				char buf[IW_ESSID_MAX_SIZE+1])
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	struct hermes_idstring essidbuf;
-	char *p = (char *)(&essidbuf.val);
-	int len;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if (strlen(priv->desired_essid) > 0) {
-		/* We read the desired SSID from the hardware rather
-		   than from priv->desired_essid, just in case the
-		   firmware is allowed to change it on us. I'm not
-		   sure about this */
-		/* My guess is that the OWNSSID should always be whatever
-		 * we set to the card, whereas CURRENT_SSID is the one that
-		 * may change... - Jean II */
-		u16 rid;
-
-		*active = 1;
-
-		rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
-			HERMES_RID_CNFDESIREDSSID;
-		
-		err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
-				      NULL, &essidbuf);
-		if (err)
-			goto fail_unlock;
-	} else {
-		*active = 0;
-
-		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
-				      sizeof(essidbuf), NULL, &essidbuf);
-		if (err)
-			goto fail_unlock;
-	}
-
-	len = le16_to_cpu(essidbuf.len);
-	BUG_ON(len > IW_ESSID_MAX_SIZE);
-
-	memset(buf, 0, IW_ESSID_MAX_SIZE);
-	memcpy(buf, p, len);
-	err = len;
-
- fail_unlock:
-	orinoco_unlock(priv, &flags);
-
-	return err;       
-}
-
-static int orinoco_hw_get_freq(struct orinoco_private *priv)
-{
-	
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	u16 channel;
-	int freq = 0;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel);
-	if (err)
-		goto out;
-
-	/* Intersil firmware 1.3.5 returns 0 when the interface is down */
-	if (channel == 0) {
-		err = -EBUSY;
-		goto out;
-	}
-
-	if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
-		printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
-		       priv->ndev->name, channel);
-		err = -EBUSY;
-		goto out;
-
-	}
-	freq = ieee80211_dsss_chan_to_freq(channel);
-
- out:
-	orinoco_unlock(priv, &flags);
-
-	if (err > 0)
-		err = -EBUSY;
-	return err ? err : freq;
-}
-
-static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
-				      int *numrates, s32 *rates, int max)
-{
-	hermes_t *hw = &priv->hw;
-	struct hermes_idstring list;
-	unsigned char *p = (unsigned char *)&list.val;
-	int err = 0;
-	int num;
-	int i;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
-			      sizeof(list), NULL, &list);
-	orinoco_unlock(priv, &flags);
-
-	if (err)
-		return err;
-	
-	num = le16_to_cpu(list.len);
-	*numrates = num;
-	num = min(num, max);
-
-	for (i = 0; i < num; i++) {
-		rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
-	}
-
-	return 0;
-}
-
-static int orinoco_ioctl_getname(struct net_device *dev,
-				 struct iw_request_info *info,
-				 char *name,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int numrates;
-	int err;
-
-	err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
-
-	if (!err && (numrates > 2))
-		strcpy(name, "IEEE 802.11b");
-	else
-		strcpy(name, "IEEE 802.11-DS");
-
-	return 0;
-}
-
-static int orinoco_ioctl_setwap(struct net_device *dev,
-				struct iw_request_info *info,
-				struct sockaddr *ap_addr,
-				char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int err = -EINPROGRESS;		/* Call commit handler */
-	unsigned long flags;
-	static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-	static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* Enable automatic roaming - no sanity checks are needed */
-	if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
-	    memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
-		priv->bssid_fixed = 0;
-		memset(priv->desired_bssid, 0, ETH_ALEN);
-
-		/* "off" means keep existing connection */
-		if (ap_addr->sa_data[0] == 0) {
-			__orinoco_hw_set_wap(priv);
-			err = 0;
-		}
-		goto out;
-	}
-
-	if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
-		printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
-		       "support manual roaming\n",
-		       dev->name);
-		err = -EOPNOTSUPP;
-		goto out;
-	}
-
-	if (priv->iw_mode != IW_MODE_INFRA) {
-		printk(KERN_WARNING "%s: Manual roaming supported only in "
-		       "managed mode\n", dev->name);
-		err = -EOPNOTSUPP;
-		goto out;
-	}
-
-	/* Intersil firmware hangs without Desired ESSID */
-	if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
-	    strlen(priv->desired_essid) == 0) {
-		printk(KERN_WARNING "%s: Desired ESSID must be set for "
-		       "manual roaming\n", dev->name);
-		err = -EOPNOTSUPP;
-		goto out;
-	}
-
-	/* Finally, enable manual roaming */
-	priv->bssid_fixed = 1;
-	memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
-
- out:
-	orinoco_unlock(priv, &flags);
-	return err;
-}
-
-static int orinoco_ioctl_getwap(struct net_device *dev,
-				struct iw_request_info *info,
-				struct sockaddr *ap_addr,
-				char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	ap_addr->sa_family = ARPHRD_ETHER;
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-			      ETH_ALEN, NULL, ap_addr->sa_data);
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_setmode(struct net_device *dev,
-				 struct iw_request_info *info,
-				 u32 *mode,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int err = -EINPROGRESS;		/* Call commit handler */
-	unsigned long flags;
-
-	if (priv->iw_mode == *mode)
-		return 0;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	switch (*mode) {
-	case IW_MODE_ADHOC:
-		if (!priv->has_ibss && !priv->has_port3)
-			err = -EOPNOTSUPP;
-		break;
-
-	case IW_MODE_INFRA:
-		break;
-
-	case IW_MODE_MONITOR:
-		if (priv->broken_monitor && !force_monitor) {
-			printk(KERN_WARNING "%s: Monitor mode support is "
-			       "buggy in this firmware, not enabling\n",
-			       dev->name);
-			err = -EOPNOTSUPP;
-		}
-		break;
-
-	default:
-		err = -EOPNOTSUPP;
-		break;
-	}
-
-	if (err == -EINPROGRESS) {
-		priv->iw_mode = *mode;
-		set_port_type(priv);
-	}
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_getmode(struct net_device *dev,
-				 struct iw_request_info *info,
-				 u32 *mode,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-
-	*mode = priv->iw_mode;
-	return 0;
-}
-
-static int orinoco_ioctl_getiwrange(struct net_device *dev,
-				    struct iw_request_info *info,
-				    struct iw_point *rrq,
-				    char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
-	struct iw_range *range = (struct iw_range *) extra;
-	int numrates;
-	int i, k;
-
-	rrq->length = sizeof(struct iw_range);
-	memset(range, 0, sizeof(struct iw_range));
-
-	range->we_version_compiled = WIRELESS_EXT;
-	range->we_version_source = 22;
-
-	/* Set available channels/frequencies */
-	range->num_channels = NUM_CHANNELS;
-	k = 0;
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		if (priv->channel_mask & (1 << i)) {
-			range->freq[k].i = i + 1;
-			range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) *
-					    100000);
-			range->freq[k].e = 1;
-			k++;
-		}
-		
-		if (k >= IW_MAX_FREQUENCIES)
-			break;
-	}
-	range->num_frequency = k;
-	range->sensitivity = 3;
-
-	if (priv->has_wep) {
-		range->max_encoding_tokens = ORINOCO_MAX_KEYS;
-		range->encoding_size[0] = SMALL_KEY_SIZE;
-		range->num_encoding_sizes = 1;
-
-		if (priv->has_big_wep) {
-			range->encoding_size[1] = LARGE_KEY_SIZE;
-			range->num_encoding_sizes = 2;
-		}
-	}
-
-	if (priv->has_wpa)
-		range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
-
-	if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){
-		/* Quality stats meaningless in ad-hoc mode */
-	} else {
-		range->max_qual.qual = 0x8b - 0x2f;
-		range->max_qual.level = 0x2f - 0x95 - 1;
-		range->max_qual.noise = 0x2f - 0x95 - 1;
-		/* Need to get better values */
-		range->avg_qual.qual = 0x24;
-		range->avg_qual.level = 0xC2;
-		range->avg_qual.noise = 0x9E;
-	}
-
-	err = orinoco_hw_get_bitratelist(priv, &numrates,
-					 range->bitrate, IW_MAX_BITRATES);
-	if (err)
-		return err;
-	range->num_bitrates = numrates;
-
-	/* Set an indication of the max TCP throughput in bit/s that we can
-	 * expect using this interface. May be use for QoS stuff...
-	 * Jean II */
-	if (numrates > 2)
-		range->throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
-	else
-		range->throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
-
-	range->min_rts = 0;
-	range->max_rts = 2347;
-	range->min_frag = 256;
-	range->max_frag = 2346;
-
-	range->min_pmp = 0;
-	range->max_pmp = 65535000;
-	range->min_pmt = 0;
-	range->max_pmt = 65535 * 1000;	/* ??? */
-	range->pmp_flags = IW_POWER_PERIOD;
-	range->pmt_flags = IW_POWER_TIMEOUT;
-	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
-	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-	range->retry_flags = IW_RETRY_LIMIT;
-	range->r_time_flags = IW_RETRY_LIFETIME;
-	range->min_retry = 0;
-	range->max_retry = 65535;	/* ??? */
-	range->min_r_time = 0;
-	range->max_r_time = 65535 * 1000;	/* ??? */
-
-	if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
-		range->scan_capa = IW_SCAN_CAPA_ESSID;
-	else
-		range->scan_capa = IW_SCAN_CAPA_NONE;
-
-	/* Event capability (kernel) */
-	IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
-	/* Event capability (driver) */
-	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
-	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
-	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
-	IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
-
-	return 0;
-}
-
-static int orinoco_ioctl_setiwencode(struct net_device *dev,
-				     struct iw_request_info *info,
-				     struct iw_point *erq,
-				     char *keybuf)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
-	int setindex = priv->tx_key;
-	int encode_alg = priv->encode_alg;
-	int restricted = priv->wep_restrict;
-	u16 xlen = 0;
-	int err = -EINPROGRESS;		/* Call commit handler */
-	unsigned long flags;
-
-	if (! priv->has_wep)
-		return -EOPNOTSUPP;
-
-	if (erq->pointer) {
-		/* We actually have a key to set - check its length */
-		if (erq->length > LARGE_KEY_SIZE)
-			return -E2BIG;
-
-		if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
-			return -E2BIG;
-	}
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* Clear any TKIP key we have */
-	if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP))
-		(void) orinoco_clear_tkip_key(priv, setindex);
-
-	if (erq->length > 0) {
-		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
-			index = priv->tx_key;
-
-		/* Adjust key length to a supported value */
-		if (erq->length > SMALL_KEY_SIZE) {
-			xlen = LARGE_KEY_SIZE;
-		} else if (erq->length > 0) {
-			xlen = SMALL_KEY_SIZE;
-		} else
-			xlen = 0;
-
-		/* Switch on WEP if off */
-		if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) {
-			setindex = index;
-			encode_alg = IW_ENCODE_ALG_WEP;
-		}
-	} else {
-		/* Important note : if the user do "iwconfig eth0 enc off",
-		 * we will arrive there with an index of -1. This is valid
-		 * but need to be taken care off... Jean II */
-		if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
-			if((index != -1) || (erq->flags == 0)) {
-				err = -EINVAL;
-				goto out;
-			}
-		} else {
-			/* Set the index : Check that the key is valid */
-			if(priv->keys[index].len == 0) {
-				err = -EINVAL;
-				goto out;
-			}
-			setindex = index;
-		}
-	}
-
-	if (erq->flags & IW_ENCODE_DISABLED)
-		encode_alg = IW_ENCODE_ALG_NONE;
-	if (erq->flags & IW_ENCODE_OPEN)
-		restricted = 0;
-	if (erq->flags & IW_ENCODE_RESTRICTED)
-		restricted = 1;
-
-	if (erq->pointer && erq->length > 0) {
-		priv->keys[index].len = cpu_to_le16(xlen);
-		memset(priv->keys[index].data, 0,
-		       sizeof(priv->keys[index].data));
-		memcpy(priv->keys[index].data, keybuf, erq->length);
-	}
-	priv->tx_key = setindex;
-
-	/* Try fast key change if connected and only keys are changed */
-	if ((priv->encode_alg == encode_alg) &&
-	    (priv->wep_restrict == restricted) &&
-	    netif_carrier_ok(dev)) {
-		err = __orinoco_hw_setup_wepkeys(priv);
-		/* No need to commit if successful */
-		goto out;
-	}
-
-	priv->encode_alg = encode_alg;
-	priv->wep_restrict = restricted;
-
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_getiwencode(struct net_device *dev,
-				     struct iw_request_info *info,
-				     struct iw_point *erq,
-				     char *keybuf)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
-	u16 xlen = 0;
-	unsigned long flags;
-
-	if (! priv->has_wep)
-		return -EOPNOTSUPP;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
-		index = priv->tx_key;
-
-	erq->flags = 0;
-	if (!priv->encode_alg)
-		erq->flags |= IW_ENCODE_DISABLED;
-	erq->flags |= index + 1;
-
-	if (priv->wep_restrict)
-		erq->flags |= IW_ENCODE_RESTRICTED;
-	else
-		erq->flags |= IW_ENCODE_OPEN;
-
-	xlen = le16_to_cpu(priv->keys[index].len);
-
-	erq->length = xlen;
-
-	memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
-
-	orinoco_unlock(priv, &flags);
-	return 0;
-}
-
-static int orinoco_ioctl_setessid(struct net_device *dev,
-				  struct iw_request_info *info,
-				  struct iw_point *erq,
-				  char *essidbuf)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
-	 * anyway... - Jean II */
-
-	/* Hum... Should not use Wireless Extension constant (may change),
-	 * should use our own... - Jean II */
-	if (erq->length > IW_ESSID_MAX_SIZE)
-		return -E2BIG;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
-	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
-
-	/* If not ANY, get the new ESSID */
-	if (erq->flags) {
-		memcpy(priv->desired_essid, essidbuf, erq->length);
-	}
-
-	orinoco_unlock(priv, &flags);
-
-	return -EINPROGRESS;		/* Call commit handler */
-}
-
-static int orinoco_ioctl_getessid(struct net_device *dev,
-				  struct iw_request_info *info,
-				  struct iw_point *erq,
-				  char *essidbuf)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int active;
-	int err = 0;
-	unsigned long flags;
-
-	if (netif_running(dev)) {
-		err = orinoco_hw_get_essid(priv, &active, essidbuf);
-		if (err < 0)
-			return err;
-		erq->length = err;
-	} else {
-		if (orinoco_lock(priv, &flags) != 0)
-			return -EBUSY;
-		memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
-		erq->length = strlen(priv->desired_essid);
-		orinoco_unlock(priv, &flags);
-	}
-
-	erq->flags = 1;
-
-	return 0;
-}
-
-static int orinoco_ioctl_setnick(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_point *nrq,
-				 char *nickbuf)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	if (nrq->length > IW_ESSID_MAX_SIZE)
-		return -E2BIG;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	memset(priv->nick, 0, sizeof(priv->nick));
-	memcpy(priv->nick, nickbuf, nrq->length);
-
-	orinoco_unlock(priv, &flags);
-
-	return -EINPROGRESS;		/* Call commit handler */
-}
-
-static int orinoco_ioctl_getnick(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_point *nrq,
-				 char *nickbuf)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
-	orinoco_unlock(priv, &flags);
-
-	nrq->length = strlen(priv->nick);
-
-	return 0;
-}
-
-static int orinoco_ioctl_setfreq(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_freq *frq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int chan = -1;
-	unsigned long flags;
-	int err = -EINPROGRESS;		/* Call commit handler */
-
-	/* In infrastructure mode the AP sets the channel */
-	if (priv->iw_mode == IW_MODE_INFRA)
-		return -EBUSY;
-
-	if ( (frq->e == 0) && (frq->m <= 1000) ) {
-		/* Setting by channel number */
-		chan = frq->m;
-	} else {
-		/* Setting by frequency */
-		int denom = 1;
-		int i;
-
-		/* Calculate denominator to rescale to MHz */
-		for (i = 0; i < (6 - frq->e); i++)
-			denom *= 10;
-
-		chan = ieee80211_freq_to_dsss_chan(frq->m / denom);
-	}
-
-	if ( (chan < 1) || (chan > NUM_CHANNELS) ||
-	     ! (priv->channel_mask & (1 << (chan-1)) ) )
-		return -EINVAL;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	priv->channel = chan;
-	if (priv->iw_mode == IW_MODE_MONITOR) {
-		/* Fast channel change - no commit if successful */
-		hermes_t *hw = &priv->hw;
-		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
-					    HERMES_TEST_SET_CHANNEL,
-					chan, NULL);
-	}
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_getfreq(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_freq *frq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int tmp;
-
-	/* Locking done in there */
-	tmp = orinoco_hw_get_freq(priv);
-	if (tmp < 0) {
-		return tmp;
-	}
-
-	frq->m = tmp * 100000;
-	frq->e = 1;
-
-	return 0;
-}
-
-static int orinoco_ioctl_getsens(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_param *srq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	u16 val;
-	int err;
-	unsigned long flags;
-
-	if (!priv->has_sensitivity)
-		return -EOPNOTSUPP;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-	err = hermes_read_wordrec(hw, USER_BAP,
-				  HERMES_RID_CNFSYSTEMSCALE, &val);
-	orinoco_unlock(priv, &flags);
-
-	if (err)
-		return err;
-
-	srq->value = val;
-	srq->fixed = 0; /* auto */
-
-	return 0;
-}
-
-static int orinoco_ioctl_setsens(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_param *srq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int val = srq->value;
-	unsigned long flags;
-
-	if (!priv->has_sensitivity)
-		return -EOPNOTSUPP;
-
-	if ((val < 1) || (val > 3))
-		return -EINVAL;
-	
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-	priv->ap_density = val;
-	orinoco_unlock(priv, &flags);
-
-	return -EINPROGRESS;		/* Call commit handler */
-}
-
-static int orinoco_ioctl_setrts(struct net_device *dev,
-				struct iw_request_info *info,
-				struct iw_param *rrq,
-				char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int val = rrq->value;
-	unsigned long flags;
-
-	if (rrq->disabled)
-		val = 2347;
-
-	if ( (val < 0) || (val > 2347) )
-		return -EINVAL;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	priv->rts_thresh = val;
-	orinoco_unlock(priv, &flags);
-
-	return -EINPROGRESS;		/* Call commit handler */
-}
-
-static int orinoco_ioctl_getrts(struct net_device *dev,
-				struct iw_request_info *info,
-				struct iw_param *rrq,
-				char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-
-	rrq->value = priv->rts_thresh;
-	rrq->disabled = (rrq->value == 2347);
-	rrq->fixed = 1;
-
-	return 0;
-}
-
-static int orinoco_ioctl_setfrag(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_param *frq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int err = -EINPROGRESS;		/* Call commit handler */
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if (priv->has_mwo) {
-		if (frq->disabled)
-			priv->mwo_robust = 0;
-		else {
-			if (frq->fixed)
-				printk(KERN_WARNING "%s: Fixed fragmentation is "
-				       "not supported on this firmware. "
-				       "Using MWO robust instead.\n", dev->name);
-			priv->mwo_robust = 1;
-		}
-	} else {
-		if (frq->disabled)
-			priv->frag_thresh = 2346;
-		else {
-			if ( (frq->value < 256) || (frq->value > 2346) )
-				err = -EINVAL;
-			else
-				priv->frag_thresh = frq->value & ~0x1; /* must be even */
-		}
-	}
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_getfrag(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_param *frq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err;
-	u16 val;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-	
-	if (priv->has_mwo) {
-		err = hermes_read_wordrec(hw, USER_BAP,
-					  HERMES_RID_CNFMWOROBUST_AGERE,
-					  &val);
-		if (err)
-			val = 0;
-
-		frq->value = val ? 2347 : 0;
-		frq->disabled = ! val;
-		frq->fixed = 0;
-	} else {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-					  &val);
-		if (err)
-			val = 0;
-
-		frq->value = val;
-		frq->disabled = (val >= 2346);
-		frq->fixed = 1;
-	}
-
-	orinoco_unlock(priv, &flags);
-	
-	return err;
-}
-
-static int orinoco_ioctl_setrate(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_param *rrq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int ratemode = -1;
-	int bitrate; /* 100s of kilobits */
-	int i;
-	unsigned long flags;
-	
-	/* As the user space doesn't know our highest rate, it uses -1
-	 * to ask us to set the highest rate.  Test it using "iwconfig
-	 * ethX rate auto" - Jean II */
-	if (rrq->value == -1)
-		bitrate = 110;
-	else {
-		if (rrq->value % 100000)
-			return -EINVAL;
-		bitrate = rrq->value / 100000;
-	}
-
-	if ( (bitrate != 10) && (bitrate != 20) &&
-	     (bitrate != 55) && (bitrate != 110) )
-		return -EINVAL;
-
-	for (i = 0; i < BITRATE_TABLE_SIZE; i++)
-		if ( (bitrate_table[i].bitrate == bitrate) &&
-		     (bitrate_table[i].automatic == ! rrq->fixed) ) {
-			ratemode = i;
-			break;
-		}
-	
-	if (ratemode == -1)
-		return -EINVAL;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-	priv->bitratemode = ratemode;
-	orinoco_unlock(priv, &flags);
-
-	return -EINPROGRESS;
-}
-
-static int orinoco_ioctl_getrate(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_param *rrq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	int ratemode;
-	int i;
-	u16 val;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	ratemode = priv->bitratemode;
-
-	BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
-
-	rrq->value = bitrate_table[ratemode].bitrate * 100000;
-	rrq->fixed = ! bitrate_table[ratemode].automatic;
-	rrq->disabled = 0;
-
-	/* If the interface is running we try to find more about the
-	   current mode */
-	if (netif_running(dev)) {
-		err = hermes_read_wordrec(hw, USER_BAP,
-					  HERMES_RID_CURRENTTXRATE, &val);
-		if (err)
-			goto out;
-		
-		switch (priv->firmware_type) {
-		case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
-			/* Note : in Lucent firmware, the return value of
-			 * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
-			 * and therefore is totally different from the
-			 * encoding of HERMES_RID_CNFTXRATECONTROL.
-			 * Don't forget that 6Mb/s is really 5.5Mb/s */
-			if (val == 6)
-				rrq->value = 5500000;
-			else
-				rrq->value = val * 1000000;
-			break;
-		case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
-		case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
-			for (i = 0; i < BITRATE_TABLE_SIZE; i++)
-				if (bitrate_table[i].intersil_txratectrl == val) {
-					ratemode = i;
-					break;
-				}
-			if (i >= BITRATE_TABLE_SIZE)
-				printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
-				       dev->name, val);
-
-			rrq->value = bitrate_table[ratemode].bitrate * 100000;
-			break;
-		default:
-			BUG();
-		}
-	}
-
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_setpower(struct net_device *dev,
-				  struct iw_request_info *info,
-				  struct iw_param *prq,
-				  char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int err = -EINPROGRESS;		/* Call commit handler */
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if (prq->disabled) {
-		priv->pm_on = 0;
-	} else {
-		switch (prq->flags & IW_POWER_MODE) {
-		case IW_POWER_UNICAST_R:
-			priv->pm_mcast = 0;
-			priv->pm_on = 1;
-			break;
-		case IW_POWER_ALL_R:
-			priv->pm_mcast = 1;
-			priv->pm_on = 1;
-			break;
-		case IW_POWER_ON:
-			/* No flags : but we may have a value - Jean II */
-			break;
-		default:
-			err = -EINVAL;
-			goto out;
-		}
-		
-		if (prq->flags & IW_POWER_TIMEOUT) {
-			priv->pm_on = 1;
-			priv->pm_timeout = prq->value / 1000;
-		}
-		if (prq->flags & IW_POWER_PERIOD) {
-			priv->pm_on = 1;
-			priv->pm_period = prq->value / 1000;
-		}
-		/* It's valid to not have a value if we are just toggling
-		 * the flags... Jean II */
-		if(!priv->pm_on) {
-			err = -EINVAL;
-			goto out;
-		}			
-	}
-
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_getpower(struct net_device *dev,
-				  struct iw_request_info *info,
-				  struct iw_param *prq,
-				  char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	u16 enable, period, timeout, mcast;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP,
-				  HERMES_RID_CNFMAXSLEEPDURATION, &period);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
-	if (err)
-		goto out;
-
-	prq->disabled = !enable;
-	/* Note : by default, display the period */
-	if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-		prq->flags = IW_POWER_TIMEOUT;
-		prq->value = timeout * 1000;
-	} else {
-		prq->flags = IW_POWER_PERIOD;
-		prq->value = period * 1000;
-	}
-	if (mcast)
-		prq->flags |= IW_POWER_ALL_R;
-	else
-		prq->flags |= IW_POWER_UNICAST_R;
-
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_set_encodeext(struct net_device *dev,
-				       struct iw_request_info *info,
-				       union iwreq_data *wrqu,
-				       char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct iw_point *encoding = &wrqu->encoding;
-	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-	int idx, alg = ext->alg, set_key = 1;
-	unsigned long flags;
-	int err = -EINVAL;
-	u16 key_len;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* Determine and validate the key index */
-	idx = encoding->flags & IW_ENCODE_INDEX;
-	if (idx) {
-		if ((idx < 1) || (idx > 4))
-			goto out;
-		idx--;
-	} else
-		idx = priv->tx_key;
-
-	if (encoding->flags & IW_ENCODE_DISABLED)
-	    alg = IW_ENCODE_ALG_NONE;
-
-	if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
-		/* Clear any TKIP TX key we had */
-		(void) orinoco_clear_tkip_key(priv, priv->tx_key);
-	}
-
-	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
-		priv->tx_key = idx;
-		set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
-			   (ext->key_len > 0)) ? 1 : 0;
-	}
-
-	if (set_key) {
-		/* Set the requested key first */
-		switch (alg) {
-		case IW_ENCODE_ALG_NONE:
-			priv->encode_alg = alg;
-			priv->keys[idx].len = 0;
-			break;
-
-		case IW_ENCODE_ALG_WEP:
-			if (ext->key_len > SMALL_KEY_SIZE)
-				key_len = LARGE_KEY_SIZE;
-			else if (ext->key_len > 0)
-				key_len = SMALL_KEY_SIZE;
-			else
-				goto out;
-
-			priv->encode_alg = alg;
-			priv->keys[idx].len = cpu_to_le16(key_len);
-
-			key_len = min(ext->key_len, key_len);
-
-			memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
-			memcpy(priv->keys[idx].data, ext->key, key_len);
-			break;
-
-		case IW_ENCODE_ALG_TKIP:
-		{
-			hermes_t *hw = &priv->hw;
-			u8 *tkip_iv = NULL;
-
-			if (!priv->has_wpa ||
-			    (ext->key_len > sizeof(priv->tkip_key[0])))
-				goto out;
-
-			priv->encode_alg = alg;
-			memset(&priv->tkip_key[idx], 0,
-			       sizeof(priv->tkip_key[idx]));
-			memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
-
-			if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
-				tkip_iv = &ext->rx_seq[0];
-
-			err = __orinoco_hw_set_tkip_key(hw, idx,
-				 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
-				 (u8 *) &priv->tkip_key[idx],
-				 tkip_iv, NULL);
-			if (err)
-				printk(KERN_ERR "%s: Error %d setting TKIP key"
-				       "\n", dev->name, err);
-
-			goto out;
-		}
-		default:
-			goto out;
-		}
-	}
-	err = -EINPROGRESS;
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_get_encodeext(struct net_device *dev,
-				       struct iw_request_info *info,
-				       union iwreq_data *wrqu,
-				       char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct iw_point *encoding = &wrqu->encoding;
-	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-	int idx, max_key_len;
-	unsigned long flags;
-	int err;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	err = -EINVAL;
-	max_key_len = encoding->length - sizeof(*ext);
-	if (max_key_len < 0)
-		goto out;
-
-	idx = encoding->flags & IW_ENCODE_INDEX;
-	if (idx) {
-		if ((idx < 1) || (idx > 4))
-			goto out;
-		idx--;
-	} else
-		idx = priv->tx_key;
-
-	encoding->flags = idx + 1;
-	memset(ext, 0, sizeof(*ext));
-
-	ext->alg = priv->encode_alg;
-	switch (priv->encode_alg) {
-	case IW_ENCODE_ALG_NONE:
-		ext->key_len = 0;
-		encoding->flags |= IW_ENCODE_DISABLED;
-		break;
-	case IW_ENCODE_ALG_WEP:
-		ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len),
-				     max_key_len);
-		memcpy(ext->key, priv->keys[idx].data, ext->key_len);
-		encoding->flags |= IW_ENCODE_ENABLED;
-		break;
-	case IW_ENCODE_ALG_TKIP:
-		ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key),
-				     max_key_len);
-		memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
-		encoding->flags |= IW_ENCODE_ENABLED;
-		break;
-	}
-
-	err = 0;
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_set_auth(struct net_device *dev,
-				  struct iw_request_info *info,
-				  union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	struct iw_param *param = &wrqu->param;
-	unsigned long flags;
-	int ret = -EINPROGRESS;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	switch (param->flags & IW_AUTH_INDEX) {
-	case IW_AUTH_WPA_VERSION:
-	case IW_AUTH_CIPHER_PAIRWISE:
-	case IW_AUTH_CIPHER_GROUP:
-	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-	case IW_AUTH_PRIVACY_INVOKED:
-	case IW_AUTH_DROP_UNENCRYPTED:
-		/*
-		 * orinoco does not use these parameters
-		 */
-		break;
-
-	case IW_AUTH_KEY_MGMT:
-		/* wl_lkm implies value 2 == PSK for Hermes I
-		 * which ties in with WEXT
-		 * no other hints tho :(
-		 */
-		priv->key_mgmt = param->value;
-		break;
-
-	case IW_AUTH_TKIP_COUNTERMEASURES:
-		/* When countermeasures are enabled, shut down the
-		 * card; when disabled, re-enable the card. This must
-		 * take effect immediately.
-		 *
-		 * TODO: Make sure that the EAPOL message is getting
-		 *       out before card disabled
-		 */
-		if (param->value) {
-			priv->tkip_cm_active = 1;
-			ret = hermes_enable_port(hw, 0);
-		} else {
-			priv->tkip_cm_active = 0;
-			ret = hermes_disable_port(hw, 0);
-		}
-		break;
-
-	case IW_AUTH_80211_AUTH_ALG:
-		if (param->value & IW_AUTH_ALG_SHARED_KEY)
-			priv->wep_restrict = 1;
-		else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
-			priv->wep_restrict = 0;
-		else
-			ret = -EINVAL;
-		break;
-
-	case IW_AUTH_WPA_ENABLED:
-		if (priv->has_wpa) {
-			priv->wpa_enabled = param->value ? 1 : 0;
-		} else {
-			if (param->value)
-				ret = -EOPNOTSUPP;
-			/* else silently accept disable of WPA */
-			priv->wpa_enabled = 0;
-		}
-		break;
-
-	default:
-		ret = -EOPNOTSUPP;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return ret;
-}
-
-static int orinoco_ioctl_get_auth(struct net_device *dev,
-				  struct iw_request_info *info,
-				  union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct iw_param *param = &wrqu->param;
-	unsigned long flags;
-	int ret = 0;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	switch (param->flags & IW_AUTH_INDEX) {
-	case IW_AUTH_KEY_MGMT:
-		param->value = priv->key_mgmt;
-		break;
-
-	case IW_AUTH_TKIP_COUNTERMEASURES:
-		param->value = priv->tkip_cm_active;
-		break;
-
-	case IW_AUTH_80211_AUTH_ALG:
-		if (priv->wep_restrict)
-			param->value = IW_AUTH_ALG_SHARED_KEY;
-		else
-			param->value = IW_AUTH_ALG_OPEN_SYSTEM;
-		break;
-
-	case IW_AUTH_WPA_ENABLED:
-		param->value = priv->wpa_enabled;
-		break;
-
-	default:
-		ret = -EOPNOTSUPP;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return ret;
-}
-
-static int orinoco_ioctl_set_genie(struct net_device *dev,
-				   struct iw_request_info *info,
-				   union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	u8 *buf;
-	unsigned long flags;
-
-	/* cut off at IEEE80211_MAX_DATA_LEN */
-	if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
-	    (wrqu->data.length && (extra == NULL)))
-		return -EINVAL;
-
-	if (wrqu->data.length) {
-		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
-		if (buf == NULL)
-			return -ENOMEM;
-
-		memcpy(buf, extra, wrqu->data.length);
-	} else
-		buf = NULL;
-
-	if (orinoco_lock(priv, &flags) != 0) {
-		kfree(buf);
-		return -EBUSY;
-	}
-
-	kfree(priv->wpa_ie);
-	priv->wpa_ie = buf;
-	priv->wpa_ie_len = wrqu->data.length;
-
-	if (priv->wpa_ie) {
-		/* Looks like wl_lkm wants to check the auth alg, and
-		 * somehow pass it to the firmware.
-		 * Instead it just calls the key mgmt rid
-		 *   - we do this in set auth.
-		 */
-	}
-
-	orinoco_unlock(priv, &flags);
-	return 0;
-}
-
-static int orinoco_ioctl_get_genie(struct net_device *dev,
-				   struct iw_request_info *info,
-				   union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	unsigned long flags;
-	int err = 0;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
-		wrqu->data.length = 0;
-		goto out;
-	}
-
-	if (wrqu->data.length < priv->wpa_ie_len) {
-		err = -E2BIG;
-		goto out;
-	}
-
-	wrqu->data.length = priv->wpa_ie_len;
-	memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
-
-out:
-	orinoco_unlock(priv, &flags);
-	return err;
-}
-
-static int orinoco_ioctl_set_mlme(struct net_device *dev,
-				  struct iw_request_info *info,
-				  union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	struct iw_mlme *mlme = (struct iw_mlme *)extra;
-	unsigned long flags;
-	int ret = 0;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	switch (mlme->cmd) {
-	case IW_MLME_DEAUTH:
-		/* silently ignore */
-		break;
-
-	case IW_MLME_DISASSOC:
-	{
-		struct {
-			u8 addr[ETH_ALEN];
-			__le16 reason_code;
-		} __attribute__ ((packed)) buf;
-
-		memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN);
-		buf.reason_code = cpu_to_le16(mlme->reason_code);
-		ret = HERMES_WRITE_RECORD(hw, USER_BAP,
-					  HERMES_RID_CNFDISASSOCIATE,
-					  &buf);
-		break;
-	}
-	default:
-		ret = -EOPNOTSUPP;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return ret;
-}
-
-static int orinoco_ioctl_getretry(struct net_device *dev,
-				  struct iw_request_info *info,
-				  struct iw_param *rrq,
-				  char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	u16 short_limit, long_limit, lifetime;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
-				  &short_limit);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
-				  &long_limit);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
-				  &lifetime);
-	if (err)
-		goto out;
-
-	rrq->disabled = 0;		/* Can't be disabled */
-
-	/* Note : by default, display the retry number */
-	if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-		rrq->flags = IW_RETRY_LIFETIME;
-		rrq->value = lifetime * 1000;	/* ??? */
-	} else {
-		/* By default, display the min number */
-		if ((rrq->flags & IW_RETRY_LONG)) {
-			rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
-			rrq->value = long_limit;
-		} else {
-			rrq->flags = IW_RETRY_LIMIT;
-			rrq->value = short_limit;
-			if(short_limit != long_limit)
-				rrq->flags |= IW_RETRY_SHORT;
-		}
-	}
-
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_reset(struct net_device *dev,
-			       struct iw_request_info *info,
-			       void *wrqu,
-			       char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-
-	if (! capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
-		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
-
-		/* Firmware reset */
-		orinoco_reset(&priv->reset_work);
-	} else {
-		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
-
-		schedule_work(&priv->reset_work);
-	}
-
-	return 0;
-}
-
-static int orinoco_ioctl_setibssport(struct net_device *dev,
-				     struct iw_request_info *info,
-				     void *wrqu,
-				     char *extra)
-
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int val = *( (int *) extra );
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	priv->ibss_port = val ;
-
-	/* Actually update the mode we are using */
-	set_port_type(priv);
-
-	orinoco_unlock(priv, &flags);
-	return -EINPROGRESS;		/* Call commit handler */
-}
-
-static int orinoco_ioctl_getibssport(struct net_device *dev,
-				     struct iw_request_info *info,
-				     void *wrqu,
-				     char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int *val = (int *) extra;
-
-	*val = priv->ibss_port;
-	return 0;
-}
-
-static int orinoco_ioctl_setport3(struct net_device *dev,
-				  struct iw_request_info *info,
-				  void *wrqu,
-				  char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int val = *( (int *) extra );
-	int err = 0;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	switch (val) {
-	case 0: /* Try to do IEEE ad-hoc mode */
-		if (! priv->has_ibss) {
-			err = -EINVAL;
-			break;
-		}
-		priv->prefer_port3 = 0;
-			
-		break;
-
-	case 1: /* Try to do Lucent proprietary ad-hoc mode */
-		if (! priv->has_port3) {
-			err = -EINVAL;
-			break;
-		}
-		priv->prefer_port3 = 1;
-		break;
-
-	default:
-		err = -EINVAL;
-	}
-
-	if (! err) {
-		/* Actually update the mode we are using */
-		set_port_type(priv);
-		err = -EINPROGRESS;
-	}
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_getport3(struct net_device *dev,
-				  struct iw_request_info *info,
-				  void *wrqu,
-				  char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int *val = (int *) extra;
-
-	*val = priv->prefer_port3;
-	return 0;
-}
-
-static int orinoco_ioctl_setpreamble(struct net_device *dev,
-				     struct iw_request_info *info,
-				     void *wrqu,
-				     char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	unsigned long flags;
-	int val;
-
-	if (! priv->has_preamble)
-		return -EOPNOTSUPP;
-
-	/* 802.11b has recently defined some short preamble.
-	 * Basically, the Phy header has been reduced in size.
-	 * This increase performance, especially at high rates
-	 * (the preamble is transmitted at 1Mb/s), unfortunately
-	 * this give compatibility troubles... - Jean II */
-	val = *( (int *) extra );
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if (val)
-		priv->preamble = 1;
-	else
-		priv->preamble = 0;
-
-	orinoco_unlock(priv, &flags);
-
-	return -EINPROGRESS;		/* Call commit handler */
-}
-
-static int orinoco_ioctl_getpreamble(struct net_device *dev,
-				     struct iw_request_info *info,
-				     void *wrqu,
-				     char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int *val = (int *) extra;
-
-	if (! priv->has_preamble)
-		return -EOPNOTSUPP;
-
-	*val = priv->preamble;
-	return 0;
-}
-
-/* ioctl interface to hermes_read_ltv()
- * To use with iwpriv, pass the RID as the token argument, e.g.
- * iwpriv get_rid [0xfc00]
- * At least Wireless Tools 25 is required to use iwpriv.
- * For Wireless Tools 25 and 26 append "dummy" are the end. */
-static int orinoco_ioctl_getrid(struct net_device *dev,
-				struct iw_request_info *info,
-				struct iw_point *data,
-				char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	int rid = data->flags;
-	u16 length;
-	int err;
-	unsigned long flags;
-
-	/* It's a "get" function, but we don't want users to access the
-	 * WEP key and other raw firmware data */
-	if (! capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if (rid < 0xfc00 || rid > 0xffff)
-		return -EINVAL;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
-			      extra);
-	if (err)
-		goto out;
-
-	data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
-			     MAX_RID_LEN);
-
- out:
-	orinoco_unlock(priv, &flags);
-	return err;
-}
-
-/* Trigger a scan (look for other cells in the vicinity) */
-static int orinoco_ioctl_setscan(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_point *srq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	struct iw_scan_req *si = (struct iw_scan_req *) extra;
-	int err = 0;
-	unsigned long flags;
-
-	/* Note : you may have realised that, as this is a SET operation,
-	 * this is privileged and therefore a normal user can't
-	 * perform scanning.
-	 * This is not an error, while the device perform scanning,
-	 * traffic doesn't flow, so it's a perfect DoS...
-	 * Jean II */
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* Scanning with port 0 disabled would fail */
-	if (!netif_running(dev)) {
-		err = -ENETDOWN;
-		goto out;
-	}
-
-	/* In monitor mode, the scan results are always empty.
-	 * Probe responses are passed to the driver as received
-	 * frames and could be processed in software. */
-	if (priv->iw_mode == IW_MODE_MONITOR) {
-		err = -EOPNOTSUPP;
-		goto out;
-	}
-
-	/* Note : because we don't lock out the irq handler, the way
-	 * we access scan variables in priv is critical.
-	 *	o scan_inprogress : not touched by irq handler
-	 *	o scan_mode : not touched by irq handler
-	 * Before modifying anything on those variables, please think hard !
-	 * Jean II */
-
-	/* Save flags */
-	priv->scan_mode = srq->flags;
-
-	/* Always trigger scanning, even if it's in progress.
-	 * This way, if the info frame get lost, we will recover somewhat
-	 * gracefully  - Jean II */
-
-	if (priv->has_hostscan) {
-		switch (priv->firmware_type) {
-		case FIRMWARE_TYPE_SYMBOL:
-			err = hermes_write_wordrec(hw, USER_BAP,
-						   HERMES_RID_CNFHOSTSCAN_SYMBOL,
-						   HERMES_HOSTSCAN_SYMBOL_ONCE |
-						   HERMES_HOSTSCAN_SYMBOL_BCAST);
-			break;
-		case FIRMWARE_TYPE_INTERSIL: {
-			__le16 req[3];
-
-			req[0] = cpu_to_le16(0x3fff);	/* All channels */
-			req[1] = cpu_to_le16(0x0001);	/* rate 1 Mbps */
-			req[2] = 0;			/* Any ESSID */
-			err = HERMES_WRITE_RECORD(hw, USER_BAP,
-						  HERMES_RID_CNFHOSTSCAN, &req);
-		}
-		break;
-		case FIRMWARE_TYPE_AGERE:
-			if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
-				struct hermes_idstring idbuf;
-				size_t len = min(sizeof(idbuf.val),
-						 (size_t) si->essid_len);
-				idbuf.len = cpu_to_le16(len);
-				memcpy(idbuf.val, si->essid, len);
-
-				err = hermes_write_ltv(hw, USER_BAP,
-					       HERMES_RID_CNFSCANSSID_AGERE,
-					       HERMES_BYTES_TO_RECLEN(len + 2),
-					       &idbuf);
-			} else
-				err = hermes_write_wordrec(hw, USER_BAP,
-						   HERMES_RID_CNFSCANSSID_AGERE,
-						   0);	/* Any ESSID */
-			if (err)
-				break;
-
-			if (priv->has_ext_scan) {
-				/* Clear scan results at the start of
-				 * an extended scan */
-				orinoco_clear_scan_results(priv,
-						msecs_to_jiffies(15000));
-
-				/* TODO: Is this available on older firmware?
-				 *   Can we use it to scan specific channels
-				 *   for IW_SCAN_THIS_FREQ? */
-				err = hermes_write_wordrec(hw, USER_BAP,
-						HERMES_RID_CNFSCANCHANNELS2GHZ,
-						0x7FFF);
-				if (err)
-					goto out;
-
-				err = hermes_inquire(hw,
-						     HERMES_INQ_CHANNELINFO);
-			} else
-				err = hermes_inquire(hw, HERMES_INQ_SCAN);
-			break;
-		}
-	} else
-		err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
-	/* One more client */
-	if (! err)
-		priv->scan_inprogress = 1;
-
- out:
-	orinoco_unlock(priv, &flags);
-	return err;
-}
-
-#define MAX_CUSTOM_LEN 64
-
-/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
-static inline char *orinoco_translate_scan(struct net_device *dev,
-					   struct iw_request_info *info,
-					   char *current_ev,
-					   char *end_buf,
-					   union hermes_scan_info *bss,
-					   unsigned long last_scanned)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	u16			capabilities;
-	u16			channel;
-	struct iw_event		iwe;		/* Temporary buffer */
-	char custom[MAX_CUSTOM_LEN];
-
-	memset(&iwe, 0, sizeof(iwe));
-
-	/* First entry *MUST* be the AP MAC address */
-	iwe.cmd = SIOCGIWAP;
-	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-	memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-					  &iwe, IW_EV_ADDR_LEN);
-
-	/* Other entries will be displayed in the order we give them */
-
-	/* Add the ESSID */
-	iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
-	if (iwe.u.data.length > 32)
-		iwe.u.data.length = 32;
-	iwe.cmd = SIOCGIWESSID;
-	iwe.u.data.flags = 1;
-	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-					  &iwe, bss->a.essid);
-
-	/* Add mode */
-	iwe.cmd = SIOCGIWMODE;
-	capabilities = le16_to_cpu(bss->a.capabilities);
-	if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
-		if (capabilities & WLAN_CAPABILITY_ESS)
-			iwe.u.mode = IW_MODE_MASTER;
-		else
-			iwe.u.mode = IW_MODE_ADHOC;
-		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-						  &iwe, IW_EV_UINT_LEN);
-	}
-
-	channel = bss->s.channel;
-	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
-		/* Add channel and frequency */
-		iwe.cmd = SIOCGIWFREQ;
-		iwe.u.freq.m = channel;
-		iwe.u.freq.e = 0;
-		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-						  &iwe, IW_EV_FREQ_LEN);
-
-		iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
-		iwe.u.freq.e = 1;
-		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-						  &iwe, IW_EV_FREQ_LEN);
-	}
-
-	/* Add quality statistics. level and noise in dB. No link quality */
-	iwe.cmd = IWEVQUAL;
-	iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
-	iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
-	iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
-	/* Wireless tools prior to 27.pre22 will show link quality
-	 * anyway, so we provide a reasonable value. */
-	if (iwe.u.qual.level > iwe.u.qual.noise)
-		iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
-	else
-		iwe.u.qual.qual = 0;
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-					  &iwe, IW_EV_QUAL_LEN);
-
-	/* Add encryption capability */
-	iwe.cmd = SIOCGIWENCODE;
-	if (capabilities & WLAN_CAPABILITY_PRIVACY)
-		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-	else
-		iwe.u.data.flags = IW_ENCODE_DISABLED;
-	iwe.u.data.length = 0;
-	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-					  &iwe, NULL);
-
-	/* Bit rate is not available in Lucent/Agere firmwares */
-	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
-		char *current_val = current_ev + iwe_stream_lcp_len(info);
-		int i;
-		int step;
-
-		if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-			step = 2;
-		else
-			step = 1;
-
-		iwe.cmd = SIOCGIWRATE;
-		/* Those two flags are ignored... */
-		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-		/* Max 10 values */
-		for (i = 0; i < 10; i += step) {
-			/* NULL terminated */
-			if (bss->p.rates[i] == 0x0)
-				break;
-			/* Bit rate given in 500 kb/s units (+ 0x80) */
-			iwe.u.bitrate.value =
-				((bss->p.rates[i] & 0x7f) * 500000);
-			current_val = iwe_stream_add_value(info, current_ev,
-							   current_val,
-							   end_buf, &iwe,
-							   IW_EV_PARAM_LEN);
-		}
-		/* Check if we added any event */
-		if ((current_val - current_ev) > iwe_stream_lcp_len(info))
-			current_ev = current_val;
-	}
-
-	/* Beacon interval */
-	iwe.cmd = IWEVCUSTOM;
-	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-				     "bcn_int=%d",
-				     le16_to_cpu(bss->a.beacon_interv));
-	if (iwe.u.data.length)
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, custom);
-
-	/* Capabilites */
-	iwe.cmd = IWEVCUSTOM;
-	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-				     "capab=0x%04x",
-				     capabilities);
-	if (iwe.u.data.length)
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, custom);
-
-	/* Add EXTRA: Age to display seconds since last beacon/probe response
-	 * for given network. */
-	iwe.cmd = IWEVCUSTOM;
-	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-				     " Last beacon: %dms ago",
-				     jiffies_to_msecs(jiffies - last_scanned));
-	if (iwe.u.data.length)
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, custom);
-
-	return current_ev;
-}
-
-static inline char *orinoco_translate_ext_scan(struct net_device *dev,
-					       struct iw_request_info *info,
-					       char *current_ev,
-					       char *end_buf,
-					       struct agere_ext_scan_info *bss,
-					       unsigned long last_scanned)
-{
-	u16			capabilities;
-	u16			channel;
-	struct iw_event		iwe;		/* Temporary buffer */
-	char custom[MAX_CUSTOM_LEN];
-	u8 *ie;
-
-	memset(&iwe, 0, sizeof(iwe));
-
-	/* First entry *MUST* be the AP MAC address */
-	iwe.cmd = SIOCGIWAP;
-	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-					  &iwe, IW_EV_ADDR_LEN);
-
-	/* Other entries will be displayed in the order we give them */
-
-	/* Add the ESSID */
-	ie = bss->data;
-	iwe.u.data.length = ie[1];
-	if (iwe.u.data.length) {
-		if (iwe.u.data.length > 32)
-			iwe.u.data.length = 32;
-		iwe.cmd = SIOCGIWESSID;
-		iwe.u.data.flags = 1;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, &ie[2]);
-	}
-
-	/* Add mode */
-	capabilities = le16_to_cpu(bss->capabilities);
-	if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
-		iwe.cmd = SIOCGIWMODE;
-		if (capabilities & WLAN_CAPABILITY_ESS)
-			iwe.u.mode = IW_MODE_MASTER;
-		else
-			iwe.u.mode = IW_MODE_ADHOC;
-		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-						  &iwe, IW_EV_UINT_LEN);
-	}
-
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
-	channel = ie ? ie[2] : 0;
-	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
-		/* Add channel and frequency */
-		iwe.cmd = SIOCGIWFREQ;
-		iwe.u.freq.m = channel;
-		iwe.u.freq.e = 0;
-		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-						  &iwe, IW_EV_FREQ_LEN);
-
-		iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
-		iwe.u.freq.e = 1;
-		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-						  &iwe, IW_EV_FREQ_LEN);
-	}
-
-	/* Add quality statistics. level and noise in dB. No link quality */
-	iwe.cmd = IWEVQUAL;
-	iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
-	iwe.u.qual.level = bss->level - 0x95;
-	iwe.u.qual.noise = bss->noise - 0x95;
-	/* Wireless tools prior to 27.pre22 will show link quality
-	 * anyway, so we provide a reasonable value. */
-	if (iwe.u.qual.level > iwe.u.qual.noise)
-		iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
-	else
-		iwe.u.qual.qual = 0;
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-					  &iwe, IW_EV_QUAL_LEN);
-
-	/* Add encryption capability */
-	iwe.cmd = SIOCGIWENCODE;
-	if (capabilities & WLAN_CAPABILITY_PRIVACY)
-		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-	else
-		iwe.u.data.flags = IW_ENCODE_DISABLED;
-	iwe.u.data.length = 0;
-	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-					  &iwe, NULL);
-
-	/* WPA IE */
-	ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
-	if (ie) {
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = ie[1] + 2;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, ie);
-	}
-
-	/* RSN IE */
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
-	if (ie) {
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = ie[1] + 2;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, ie);
-	}
-
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
-	if (ie) {
-		char *p = current_ev + iwe_stream_lcp_len(info);
-		int i;
-
-		iwe.cmd = SIOCGIWRATE;
-		/* Those two flags are ignored... */
-		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
-		for (i = 2; i < (ie[1] + 2); i++) {
-			iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
-			p = iwe_stream_add_value(info, current_ev, p, end_buf,
-						 &iwe, IW_EV_PARAM_LEN);
-		}
-		/* Check if we added any event */
-		if (p > (current_ev + iwe_stream_lcp_len(info)))
-			current_ev = p;
-	}
-
-	/* Timestamp */
-	iwe.cmd = IWEVCUSTOM;
-	iwe.u.data.length =
-		snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
-			 (unsigned long long) le64_to_cpu(bss->timestamp));
-	if (iwe.u.data.length)
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, custom);
-
-	/* Beacon interval */
-	iwe.cmd = IWEVCUSTOM;
-	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-				     "bcn_int=%d",
-				     le16_to_cpu(bss->beacon_interval));
-	if (iwe.u.data.length)
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, custom);
-
-	/* Capabilites */
-	iwe.cmd = IWEVCUSTOM;
-	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-				     "capab=0x%04x",
-				     capabilities);
-	if (iwe.u.data.length)
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, custom);
-
-	/* Add EXTRA: Age to display seconds since last beacon/probe response
-	 * for given network. */
-	iwe.cmd = IWEVCUSTOM;
-	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-				     " Last beacon: %dms ago",
-				     jiffies_to_msecs(jiffies - last_scanned));
-	if (iwe.u.data.length)
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, custom);
-
-	return current_ev;
-}
-
-/* Return results of a scan */
-static int orinoco_ioctl_getscan(struct net_device *dev,
-				 struct iw_request_info *info,
-				 struct iw_point *srq,
-				 char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
-	unsigned long flags;
-	char *current_ev = extra;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if (priv->scan_inprogress) {
-		/* Important note : we don't want to block the caller
-		 * until results are ready for various reasons.
-		 * First, managing wait queues is complex and racy.
-		 * Second, we grab some rtnetlink lock before comming
-		 * here (in dev_ioctl()).
-		 * Third, we generate an Wireless Event, so the
-		 * caller can wait itself on that - Jean II */
-		err = -EAGAIN;
-		goto out;
-	}
-
-	if (priv->has_ext_scan) {
-		struct xbss_element *bss;
-
-		list_for_each_entry(bss, &priv->bss_list, list) {
-			/* Translate this entry to WE format */
-			current_ev =
-				orinoco_translate_ext_scan(dev, info,
-							   current_ev,
-							   extra + srq->length,
-							   &bss->bss,
-							   bss->last_scanned);
-
-			/* Check if there is space for one more entry */
-			if ((extra + srq->length - current_ev)
-			    <= IW_EV_ADDR_LEN) {
-				/* Ask user space to try again with a
-				 * bigger buffer */
-				err = -E2BIG;
-				goto out;
-			}
-		}
-
-	} else {
-		struct bss_element *bss;
-
-		list_for_each_entry(bss, &priv->bss_list, list) {
-			/* Translate this entry to WE format */
-			current_ev = orinoco_translate_scan(dev, info,
-							    current_ev,
-							    extra + srq->length,
-							    &bss->bss,
-							    bss->last_scanned);
-
-			/* Check if there is space for one more entry */
-			if ((extra + srq->length - current_ev)
-			    <= IW_EV_ADDR_LEN) {
-				/* Ask user space to try again with a
-				 * bigger buffer */
-				err = -E2BIG;
-				goto out;
-			}
-		}
-	}
-
-	srq->length = (current_ev - extra);
-	srq->flags = (__u16) priv->scan_mode;
-
-out:
-	orinoco_unlock(priv, &flags);
-	return err;
-}
-
-/* Commit handler, called after set operations */
-static int orinoco_ioctl_commit(struct net_device *dev,
-				struct iw_request_info *info,
-				void *wrqu,
-				char *extra)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct hermes *hw = &priv->hw;
-	unsigned long flags;
-	int err = 0;
-
-	if (!priv->open)
-		return 0;
-
-	if (priv->broken_disableport) {
-		orinoco_reset(&priv->reset_work);
-		return 0;
-	}
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return err;
-
-	err = hermes_disable_port(hw, 0);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to disable port "
-		       "while reconfiguring card\n", dev->name);
-		priv->broken_disableport = 1;
-		goto out;
-	}
-
-	err = __orinoco_program_rids(dev);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to reconfigure card\n",
-		       dev->name);
-		goto out;
-	}
-
-	err = hermes_enable_port(hw, 0);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
-		       dev->name);
-		goto out;
-	}
-
- out:
-	if (err) {
-		printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
-		schedule_work(&priv->reset_work);
-		err = 0;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return err;
-}
-
-static const struct iw_priv_args orinoco_privtab[] = {
-	{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
-	{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
-	{ SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-	  0, "set_port3" },
-	{ SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-	  "get_port3" },
-	{ SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-	  0, "set_preamble" },
-	{ SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-	  "get_preamble" },
-	{ SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-	  0, "set_ibssport" },
-	{ SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-	  "get_ibssport" },
-	{ SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
-	  "get_rid" },
-};
-
-
-/*
- * Structures to export the Wireless Handlers
- */
-
-#define STD_IW_HANDLER(id, func) \
-	[IW_IOCTL_IDX(id)] = (iw_handler) func
-static const iw_handler	orinoco_handler[] = {
-	STD_IW_HANDLER(SIOCSIWCOMMIT,	orinoco_ioctl_commit),
-	STD_IW_HANDLER(SIOCGIWNAME,	orinoco_ioctl_getname),
-	STD_IW_HANDLER(SIOCSIWFREQ,	orinoco_ioctl_setfreq),
-	STD_IW_HANDLER(SIOCGIWFREQ,	orinoco_ioctl_getfreq),
-	STD_IW_HANDLER(SIOCSIWMODE,	orinoco_ioctl_setmode),
-	STD_IW_HANDLER(SIOCGIWMODE,	orinoco_ioctl_getmode),
-	STD_IW_HANDLER(SIOCSIWSENS,	orinoco_ioctl_setsens),
-	STD_IW_HANDLER(SIOCGIWSENS,	orinoco_ioctl_getsens),
-	STD_IW_HANDLER(SIOCGIWRANGE,	orinoco_ioctl_getiwrange),
-	STD_IW_HANDLER(SIOCSIWSPY,	iw_handler_set_spy),
-	STD_IW_HANDLER(SIOCGIWSPY,	iw_handler_get_spy),
-	STD_IW_HANDLER(SIOCSIWTHRSPY,	iw_handler_set_thrspy),
-	STD_IW_HANDLER(SIOCGIWTHRSPY,	iw_handler_get_thrspy),
-	STD_IW_HANDLER(SIOCSIWAP,	orinoco_ioctl_setwap),
-	STD_IW_HANDLER(SIOCGIWAP,	orinoco_ioctl_getwap),
-	STD_IW_HANDLER(SIOCSIWSCAN,	orinoco_ioctl_setscan),
-	STD_IW_HANDLER(SIOCGIWSCAN,	orinoco_ioctl_getscan),
-	STD_IW_HANDLER(SIOCSIWESSID,	orinoco_ioctl_setessid),
-	STD_IW_HANDLER(SIOCGIWESSID,	orinoco_ioctl_getessid),
-	STD_IW_HANDLER(SIOCSIWNICKN,	orinoco_ioctl_setnick),
-	STD_IW_HANDLER(SIOCGIWNICKN,	orinoco_ioctl_getnick),
-	STD_IW_HANDLER(SIOCSIWRATE,	orinoco_ioctl_setrate),
-	STD_IW_HANDLER(SIOCGIWRATE,	orinoco_ioctl_getrate),
-	STD_IW_HANDLER(SIOCSIWRTS,	orinoco_ioctl_setrts),
-	STD_IW_HANDLER(SIOCGIWRTS,	orinoco_ioctl_getrts),
-	STD_IW_HANDLER(SIOCSIWFRAG,	orinoco_ioctl_setfrag),
-	STD_IW_HANDLER(SIOCGIWFRAG,	orinoco_ioctl_getfrag),
-	STD_IW_HANDLER(SIOCGIWRETRY,	orinoco_ioctl_getretry),
-	STD_IW_HANDLER(SIOCSIWENCODE,	orinoco_ioctl_setiwencode),
-	STD_IW_HANDLER(SIOCGIWENCODE,	orinoco_ioctl_getiwencode),
-	STD_IW_HANDLER(SIOCSIWPOWER,	orinoco_ioctl_setpower),
-	STD_IW_HANDLER(SIOCGIWPOWER,	orinoco_ioctl_getpower),
-	STD_IW_HANDLER(SIOCSIWGENIE,	orinoco_ioctl_set_genie),
-	STD_IW_HANDLER(SIOCGIWGENIE,	orinoco_ioctl_get_genie),
-	STD_IW_HANDLER(SIOCSIWMLME,	orinoco_ioctl_set_mlme),
-	STD_IW_HANDLER(SIOCSIWAUTH,	orinoco_ioctl_set_auth),
-	STD_IW_HANDLER(SIOCGIWAUTH,	orinoco_ioctl_get_auth),
-	STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
-	STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
-};
-
-
-/*
-  Added typecasting since we no longer use iwreq_data -- Moustafa
- */
-static const iw_handler	orinoco_private_handler[] = {
-	[0] = (iw_handler) orinoco_ioctl_reset,
-	[1] = (iw_handler) orinoco_ioctl_reset,
-	[2] = (iw_handler) orinoco_ioctl_setport3,
-	[3] = (iw_handler) orinoco_ioctl_getport3,
-	[4] = (iw_handler) orinoco_ioctl_setpreamble,
-	[5] = (iw_handler) orinoco_ioctl_getpreamble,
-	[6] = (iw_handler) orinoco_ioctl_setibssport,
-	[7] = (iw_handler) orinoco_ioctl_getibssport,
-	[9] = (iw_handler) orinoco_ioctl_getrid,
-};
-
-static const struct iw_handler_def orinoco_handler_def = {
-	.num_standard = ARRAY_SIZE(orinoco_handler),
-	.num_private = ARRAY_SIZE(orinoco_private_handler),
-	.num_private_args = ARRAY_SIZE(orinoco_privtab),
-	.standard = orinoco_handler,
-	.private = orinoco_private_handler,
-	.private_args = orinoco_privtab,
-	.get_wireless_stats = orinoco_get_wireless_stats,
-};
-
-static void orinoco_get_drvinfo(struct net_device *dev,
-				struct ethtool_drvinfo *info)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-
-	strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
-	strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
-	strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
-	if (dev->dev.parent)
-		strncpy(info->bus_info, dev_name(dev->dev.parent),
-			sizeof(info->bus_info) - 1);
-	else
-		snprintf(info->bus_info, sizeof(info->bus_info) - 1,
-			 "PCMCIA %p", priv->hw.iobase);
-}
-
-static const struct ethtool_ops orinoco_ethtool_ops = {
-	.get_drvinfo = orinoco_get_drvinfo,
-	.get_link = ethtool_op_get_link,
-};
-
-/********************************************************************/
-/* Module initialization                                            */
-/********************************************************************/
-
-EXPORT_SYMBOL(alloc_orinocodev);
-EXPORT_SYMBOL(free_orinocodev);
-
-EXPORT_SYMBOL(__orinoco_up);
-EXPORT_SYMBOL(__orinoco_down);
-EXPORT_SYMBOL(orinoco_reinit_firmware);
-
-EXPORT_SYMBOL(orinoco_interrupt);
-
-/* Can't be declared "const" or the whole __initdata section will
- * become const */
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-	" (David Gibson <hermes@gibson.dropbear.id.au>, "
-	"Pavel Roskin <proski@gnu.org>, et al)";
-
-static int __init init_orinoco(void)
-{
-	printk(KERN_DEBUG "%s\n", version);
-	return 0;
-}
-
-static void __exit exit_orinoco(void)
-{
-}
-
-module_init(init_orinoco);
-module_exit(exit_orinoco);
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index d194b3e..b381aed 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -7,7 +7,7 @@
  * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
  * cards such as the 3Com AirConnect and Ericsson WLAN.
  *
- * Copyright notice & release notes in file orinoco.c
+ * Copyright notice & release notes in file main.c
  */
 
 #define DRIVER_NAME "orinoco_cs"
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h
index 88df3ee..c655b4a 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco/orinoco_pci.h
@@ -4,7 +4,7 @@
  * both native PCI and PCMCIA-to-PCI bridges.
  *
  * Copyright (C) 2005, Pavel Roskin.
- * See orinoco.c for license.
+ * See main.c for license.
  */
 
 #ifndef _ORINOCO_PCI_H
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index e77c404..cda0e6e 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -27,7 +27,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the MPL or the GPL.
  *
- * The actual driving is done by orinoco.c, this is just resource
+ * The actual driving is done by main.c, this is just resource
  * allocation stuff.
  *
  * This driver is modeled after the orinoco_plx driver. The main
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
new file mode 100644
index 0000000..89d699d
--- /dev/null
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -0,0 +1,233 @@
+/* Helpers for managing scan queues
+ *
+ * See copyright notice in main.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/etherdevice.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+#include "scan.h"
+
+#define ORINOCO_MAX_BSS_COUNT	64
+
+#define PRIV_BSS	((struct bss_element *)priv->bss_xbss_data)
+#define PRIV_XBSS	((struct xbss_element *)priv->bss_xbss_data)
+
+int orinoco_bss_data_allocate(struct orinoco_private *priv)
+{
+	if (priv->bss_xbss_data)
+		return 0;
+
+	if (priv->has_ext_scan)
+		priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
+					      sizeof(struct xbss_element),
+					      GFP_KERNEL);
+	else
+		priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
+					      sizeof(struct bss_element),
+					      GFP_KERNEL);
+
+	if (!priv->bss_xbss_data) {
+		printk(KERN_WARNING "Out of memory allocating beacons");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+void orinoco_bss_data_free(struct orinoco_private *priv)
+{
+	kfree(priv->bss_xbss_data);
+	priv->bss_xbss_data = NULL;
+}
+
+void orinoco_bss_data_init(struct orinoco_private *priv)
+{
+	int i;
+
+	INIT_LIST_HEAD(&priv->bss_free_list);
+	INIT_LIST_HEAD(&priv->bss_list);
+	if (priv->has_ext_scan)
+		for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
+			list_add_tail(&(PRIV_XBSS[i].list),
+				      &priv->bss_free_list);
+	else
+		for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
+			list_add_tail(&(PRIV_BSS[i].list),
+				      &priv->bss_free_list);
+
+}
+
+void orinoco_clear_scan_results(struct orinoco_private *priv,
+				unsigned long scan_age)
+{
+	if (priv->has_ext_scan) {
+		struct xbss_element *bss;
+		struct xbss_element *tmp_bss;
+
+		/* Blow away current list of scan results */
+		list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
+			if (!scan_age ||
+			    time_after(jiffies, bss->last_scanned + scan_age)) {
+				list_move_tail(&bss->list,
+					       &priv->bss_free_list);
+				/* Don't blow away ->list, just BSS data */
+				memset(&bss->bss, 0, sizeof(bss->bss));
+				bss->last_scanned = 0;
+			}
+		}
+	} else {
+		struct bss_element *bss;
+		struct bss_element *tmp_bss;
+
+		/* Blow away current list of scan results */
+		list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
+			if (!scan_age ||
+			    time_after(jiffies, bss->last_scanned + scan_age)) {
+				list_move_tail(&bss->list,
+					       &priv->bss_free_list);
+				/* Don't blow away ->list, just BSS data */
+				memset(&bss->bss, 0, sizeof(bss->bss));
+				bss->last_scanned = 0;
+			}
+		}
+	}
+}
+
+void orinoco_add_ext_scan_result(struct orinoco_private *priv,
+				 struct agere_ext_scan_info *atom)
+{
+	struct xbss_element *bss = NULL;
+	int found = 0;
+
+	/* Try to update an existing bss first */
+	list_for_each_entry(bss, &priv->bss_list, list) {
+		if (compare_ether_addr(bss->bss.bssid, atom->bssid))
+			continue;
+		/* ESSID lengths */
+		if (bss->bss.data[1] != atom->data[1])
+			continue;
+		if (memcmp(&bss->bss.data[2], &atom->data[2],
+			   atom->data[1]))
+			continue;
+		found = 1;
+		break;
+	}
+
+	/* Grab a bss off the free list */
+	if (!found && !list_empty(&priv->bss_free_list)) {
+		bss = list_entry(priv->bss_free_list.next,
+				 struct xbss_element, list);
+		list_del(priv->bss_free_list.next);
+
+		list_add_tail(&bss->list, &priv->bss_list);
+	}
+
+	if (bss) {
+		/* Always update the BSS to get latest beacon info */
+		memcpy(&bss->bss, atom, sizeof(bss->bss));
+		bss->last_scanned = jiffies;
+	}
+}
+
+int orinoco_process_scan_results(struct orinoco_private *priv,
+				 unsigned char *buf,
+				 int len)
+{
+	int			offset;		/* In the scan data */
+	union hermes_scan_info *atom;
+	int			atom_len;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		atom_len = sizeof(struct agere_scan_apinfo);
+		offset = 0;
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		/* Lack of documentation necessitates this hack.
+		 * Different firmwares have 68 or 76 byte long atoms.
+		 * We try modulo first.  If the length divides by both,
+		 * we check what would be the channel in the second
+		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
+		 * Valid channel cannot be 0.  */
+		if (len % 76)
+			atom_len = 68;
+		else if (len % 68)
+			atom_len = 76;
+		else if (len >= 1292 && buf[68] == 0)
+			atom_len = 76;
+		else
+			atom_len = 68;
+		offset = 0;
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		offset = 4;
+		if (priv->has_hostscan) {
+			atom_len = le16_to_cpup((__le16 *)buf);
+			/* Sanity check for atom_len */
+			if (atom_len < sizeof(struct prism2_scan_apinfo)) {
+				printk(KERN_ERR "%s: Invalid atom_len in scan "
+				       "data: %d\n", priv->ndev->name,
+				       atom_len);
+				return -EIO;
+			}
+		} else
+			atom_len = offsetof(struct prism2_scan_apinfo, atim);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	/* Check that we got an whole number of atoms */
+	if ((len - offset) % atom_len) {
+		printk(KERN_ERR "%s: Unexpected scan data length %d, "
+		       "atom_len %d, offset %d\n", priv->ndev->name, len,
+		       atom_len, offset);
+		return -EIO;
+	}
+
+	orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
+
+	/* Read the entries one by one */
+	for (; offset + atom_len <= len; offset += atom_len) {
+		int found = 0;
+		struct bss_element *bss = NULL;
+
+		/* Get next atom */
+		atom = (union hermes_scan_info *) (buf + offset);
+
+		/* Try to update an existing bss first */
+		list_for_each_entry(bss, &priv->bss_list, list) {
+			if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
+				continue;
+			if (le16_to_cpu(bss->bss.a.essid_len) !=
+			      le16_to_cpu(atom->a.essid_len))
+				continue;
+			if (memcmp(bss->bss.a.essid, atom->a.essid,
+			      le16_to_cpu(atom->a.essid_len)))
+				continue;
+			found = 1;
+			break;
+		}
+
+		/* Grab a bss off the free list */
+		if (!found && !list_empty(&priv->bss_free_list)) {
+			bss = list_entry(priv->bss_free_list.next,
+					 struct bss_element, list);
+			list_del(priv->bss_free_list.next);
+
+			list_add_tail(&bss->list, &priv->bss_list);
+		}
+
+		if (bss) {
+			/* Always update the BSS to get latest beacon info */
+			memcpy(&bss->bss, atom, sizeof(bss->bss));
+			bss->last_scanned = jiffies;
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h
new file mode 100644
index 0000000..f319f74
--- /dev/null
+++ b/drivers/net/wireless/orinoco/scan.h
@@ -0,0 +1,29 @@
+/* Helpers for managing scan queues
+ *
+ * See copyright notice in main.c
+ */
+#ifndef _ORINOCO_SCAN_H_
+#define _ORINOCO_SCAN_H_
+
+/* Forward declarations */
+struct orinoco_private;
+struct agere_ext_scan_info;
+
+/* Setup and free memory for scan results */
+int orinoco_bss_data_allocate(struct orinoco_private *priv);
+void orinoco_bss_data_free(struct orinoco_private *priv);
+void orinoco_bss_data_init(struct orinoco_private *priv);
+
+/* Add scan results */
+void orinoco_add_ext_scan_result(struct orinoco_private *priv,
+				 struct agere_ext_scan_info *atom);
+int orinoco_process_scan_results(struct orinoco_private *dev,
+				 unsigned char *buf,
+				 int len);
+
+/* Clear scan results */
+void orinoco_clear_scan_results(struct orinoco_private *priv,
+				unsigned long scan_age);
+
+
+#endif /* _ORINOCO_SCAN_H_ */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 9aefe19..38e5198 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -4,7 +4,7 @@
  * Communications and Intel PRO/Wireless 2011B.
  *
  * The driver implements Symbol firmware download.  The rest is handled
- * in hermes.c and orinoco.c.
+ * in hermes.c and main.c.
  *
  * Utilities for downloading the Symbol firmware are available at
  * http://sourceforge.net/projects/orinoco/
@@ -15,7 +15,7 @@
  * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
  * 	Copyright (C) Symbol Technologies.
  *
- * See copyright notice in file orinoco.c.
+ * See copyright notice in file main.c.
  */
 
 #define DRIVER_NAME "spectrum_cs"
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
new file mode 100644
index 0000000..3f08142
--- /dev/null
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -0,0 +1,2325 @@
+/* Wireless extensions support.
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "hermes.h"
+#include "hermes_rid.h"
+#include "orinoco.h"
+
+#include "hw.h"
+#include "mic.h"
+#include "scan.h"
+#include "main.h"
+
+#include "wext.h"
+
+#define MAX_RID_LEN 1024
+
+static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	struct iw_statistics *wstats = &priv->wstats;
+	int err;
+	unsigned long flags;
+
+	if (!netif_device_present(dev)) {
+		printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
+		       dev->name);
+		return NULL; /* FIXME: Can we do better than this? */
+	}
+
+	/* If busy, return the old stats.  Returning NULL may cause
+	 * the interface to disappear from /proc/net/wireless */
+	if (orinoco_lock(priv, &flags) != 0)
+		return wstats;
+
+	/* We can't really wait for the tallies inquiry command to
+	 * complete, so we just use the previous results and trigger
+	 * a new tallies inquiry command for next time - Jean II */
+	/* FIXME: Really we should wait for the inquiry to come back -
+	 * as it is the stats we give don't make a whole lot of sense.
+	 * Unfortunately, it's not clear how to do that within the
+	 * wireless extensions framework: I think we're in user
+	 * context, but a lock seems to be held by the time we get in
+	 * here so we're not safe to sleep here. */
+	hermes_inquire(hw, HERMES_INQ_TALLIES);
+
+	if (priv->iw_mode == IW_MODE_ADHOC) {
+		memset(&wstats->qual, 0, sizeof(wstats->qual));
+		/* If a spy address is defined, we report stats of the
+		 * first spy address - Jean II */
+		if (SPY_NUMBER(priv)) {
+			wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
+			wstats->qual.level = priv->spy_data.spy_stat[0].level;
+			wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
+			wstats->qual.updated =
+				priv->spy_data.spy_stat[0].updated;
+		}
+	} else {
+		struct {
+			__le16 qual, signal, noise, unused;
+		} __attribute__ ((packed)) cq;
+
+		err = HERMES_READ_RECORD(hw, USER_BAP,
+					 HERMES_RID_COMMSQUALITY, &cq);
+
+		if (!err) {
+			wstats->qual.qual = (int)le16_to_cpu(cq.qual);
+			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
+			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
+			wstats->qual.updated =
+				IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+		}
+	}
+
+	orinoco_unlock(priv, &flags);
+	return wstats;
+}
+
+/********************************************************************/
+/* Wireless extensions                                              */
+/********************************************************************/
+
+static int orinoco_ioctl_getname(struct net_device *dev,
+				 struct iw_request_info *info,
+				 char *name,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int numrates;
+	int err;
+
+	err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
+
+	if (!err && (numrates > 2))
+		strcpy(name, "IEEE 802.11b");
+	else
+		strcpy(name, "IEEE 802.11-DS");
+
+	return 0;
+}
+
+static int orinoco_ioctl_setwap(struct net_device *dev,
+				struct iw_request_info *info,
+				struct sockaddr *ap_addr,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = -EINPROGRESS;		/* Call commit handler */
+	unsigned long flags;
+	static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* Enable automatic roaming - no sanity checks are needed */
+	if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
+	    memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+		priv->bssid_fixed = 0;
+		memset(priv->desired_bssid, 0, ETH_ALEN);
+
+		/* "off" means keep existing connection */
+		if (ap_addr->sa_data[0] == 0) {
+			__orinoco_hw_set_wap(priv);
+			err = 0;
+		}
+		goto out;
+	}
+
+	if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
+		printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
+		       "support manual roaming\n",
+		       dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (priv->iw_mode != IW_MODE_INFRA) {
+		printk(KERN_WARNING "%s: Manual roaming supported only in "
+		       "managed mode\n", dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Intersil firmware hangs without Desired ESSID */
+	if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
+	    strlen(priv->desired_essid) == 0) {
+		printk(KERN_WARNING "%s: Desired ESSID must be set for "
+		       "manual roaming\n", dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Finally, enable manual roaming */
+	priv->bssid_fixed = 1;
+	memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
+
+ out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+				struct iw_request_info *info,
+				struct sockaddr *ap_addr,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	ap_addr->sa_family = ARPHRD_ETHER;
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+			      ETH_ALEN, NULL, ap_addr->sa_data);
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_setmode(struct net_device *dev,
+				 struct iw_request_info *info,
+				 u32 *mode,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = -EINPROGRESS;		/* Call commit handler */
+	unsigned long flags;
+
+	if (priv->iw_mode == *mode)
+		return 0;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (*mode) {
+	case IW_MODE_ADHOC:
+		if (!priv->has_ibss && !priv->has_port3)
+			err = -EOPNOTSUPP;
+		break;
+
+	case IW_MODE_INFRA:
+		break;
+
+	case IW_MODE_MONITOR:
+		if (priv->broken_monitor && !force_monitor) {
+			printk(KERN_WARNING "%s: Monitor mode support is "
+			       "buggy in this firmware, not enabling\n",
+			       dev->name);
+			err = -EOPNOTSUPP;
+		}
+		break;
+
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	if (err == -EINPROGRESS) {
+		priv->iw_mode = *mode;
+		set_port_type(priv);
+	}
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_getmode(struct net_device *dev,
+				 struct iw_request_info *info,
+				 u32 *mode,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	*mode = priv->iw_mode;
+	return 0;
+}
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_point *rrq,
+				    char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+	struct iw_range *range = (struct iw_range *) extra;
+	int numrates;
+	int i, k;
+
+	rrq->length = sizeof(struct iw_range);
+	memset(range, 0, sizeof(struct iw_range));
+
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = 22;
+
+	/* Set available channels/frequencies */
+	range->num_channels = NUM_CHANNELS;
+	k = 0;
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (priv->channel_mask & (1 << i)) {
+			range->freq[k].i = i + 1;
+			range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) *
+					    100000);
+			range->freq[k].e = 1;
+			k++;
+		}
+
+		if (k >= IW_MAX_FREQUENCIES)
+			break;
+	}
+	range->num_frequency = k;
+	range->sensitivity = 3;
+
+	if (priv->has_wep) {
+		range->max_encoding_tokens = ORINOCO_MAX_KEYS;
+		range->encoding_size[0] = SMALL_KEY_SIZE;
+		range->num_encoding_sizes = 1;
+
+		if (priv->has_big_wep) {
+			range->encoding_size[1] = LARGE_KEY_SIZE;
+			range->num_encoding_sizes = 2;
+		}
+	}
+
+	if (priv->has_wpa)
+		range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
+
+	if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) {
+		/* Quality stats meaningless in ad-hoc mode */
+	} else {
+		range->max_qual.qual = 0x8b - 0x2f;
+		range->max_qual.level = 0x2f - 0x95 - 1;
+		range->max_qual.noise = 0x2f - 0x95 - 1;
+		/* Need to get better values */
+		range->avg_qual.qual = 0x24;
+		range->avg_qual.level = 0xC2;
+		range->avg_qual.noise = 0x9E;
+	}
+
+	err = orinoco_hw_get_bitratelist(priv, &numrates,
+					 range->bitrate, IW_MAX_BITRATES);
+	if (err)
+		return err;
+	range->num_bitrates = numrates;
+
+	/* Set an indication of the max TCP throughput in bit/s that we can
+	 * expect using this interface. May be use for QoS stuff...
+	 * Jean II */
+	if (numrates > 2)
+		range->throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
+	else
+		range->throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
+
+	range->min_rts = 0;
+	range->max_rts = 2347;
+	range->min_frag = 256;
+	range->max_frag = 2346;
+
+	range->min_pmp = 0;
+	range->max_pmp = 65535000;
+	range->min_pmt = 0;
+	range->max_pmt = 65535 * 1000;	/* ??? */
+	range->pmp_flags = IW_POWER_PERIOD;
+	range->pmt_flags = IW_POWER_TIMEOUT;
+	range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT |
+			  IW_POWER_UNICAST_R);
+
+	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->r_time_flags = IW_RETRY_LIFETIME;
+	range->min_retry = 0;
+	range->max_retry = 65535;	/* ??? */
+	range->min_r_time = 0;
+	range->max_r_time = 65535 * 1000;	/* ??? */
+
+	if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+		range->scan_capa = IW_SCAN_CAPA_ESSID;
+	else
+		range->scan_capa = IW_SCAN_CAPA_NONE;
+
+	/* Event capability (kernel) */
+	IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+	/* Event capability (driver) */
+	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
+	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+	IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
+
+	return 0;
+}
+
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     struct iw_point *erq,
+				     char *keybuf)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+	int setindex = priv->tx_key;
+	int encode_alg = priv->encode_alg;
+	int restricted = priv->wep_restrict;
+	u16 xlen = 0;
+	int err = -EINPROGRESS;		/* Call commit handler */
+	unsigned long flags;
+
+	if (!priv->has_wep)
+		return -EOPNOTSUPP;
+
+	if (erq->pointer) {
+		/* We actually have a key to set - check its length */
+		if (erq->length > LARGE_KEY_SIZE)
+			return -E2BIG;
+
+		if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
+			return -E2BIG;
+	}
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* Clear any TKIP key we have */
+	if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP))
+		(void) orinoco_clear_tkip_key(priv, setindex);
+
+	if (erq->length > 0) {
+		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
+			index = priv->tx_key;
+
+		/* Adjust key length to a supported value */
+		if (erq->length > SMALL_KEY_SIZE)
+			xlen = LARGE_KEY_SIZE;
+		else if (erq->length > 0)
+			xlen = SMALL_KEY_SIZE;
+		else
+			xlen = 0;
+
+		/* Switch on WEP if off */
+		if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) {
+			setindex = index;
+			encode_alg = IW_ENCODE_ALG_WEP;
+		}
+	} else {
+		/* Important note : if the user do "iwconfig eth0 enc off",
+		 * we will arrive there with an index of -1. This is valid
+		 * but need to be taken care off... Jean II */
+		if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
+			if ((index != -1) || (erq->flags == 0)) {
+				err = -EINVAL;
+				goto out;
+			}
+		} else {
+			/* Set the index : Check that the key is valid */
+			if (priv->keys[index].len == 0) {
+				err = -EINVAL;
+				goto out;
+			}
+			setindex = index;
+		}
+	}
+
+	if (erq->flags & IW_ENCODE_DISABLED)
+		encode_alg = IW_ENCODE_ALG_NONE;
+	if (erq->flags & IW_ENCODE_OPEN)
+		restricted = 0;
+	if (erq->flags & IW_ENCODE_RESTRICTED)
+		restricted = 1;
+
+	if (erq->pointer && erq->length > 0) {
+		priv->keys[index].len = cpu_to_le16(xlen);
+		memset(priv->keys[index].data, 0,
+		       sizeof(priv->keys[index].data));
+		memcpy(priv->keys[index].data, keybuf, erq->length);
+	}
+	priv->tx_key = setindex;
+
+	/* Try fast key change if connected and only keys are changed */
+	if ((priv->encode_alg == encode_alg) &&
+	    (priv->wep_restrict == restricted) &&
+	    netif_carrier_ok(dev)) {
+		err = __orinoco_hw_setup_wepkeys(priv);
+		/* No need to commit if successful */
+		goto out;
+	}
+
+	priv->encode_alg = encode_alg;
+	priv->wep_restrict = restricted;
+
+ out:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     struct iw_point *erq,
+				     char *keybuf)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+	u16 xlen = 0;
+	unsigned long flags;
+
+	if (!priv->has_wep)
+		return -EOPNOTSUPP;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
+		index = priv->tx_key;
+
+	erq->flags = 0;
+	if (!priv->encode_alg)
+		erq->flags |= IW_ENCODE_DISABLED;
+	erq->flags |= index + 1;
+
+	if (priv->wep_restrict)
+		erq->flags |= IW_ENCODE_RESTRICTED;
+	else
+		erq->flags |= IW_ENCODE_OPEN;
+
+	xlen = le16_to_cpu(priv->keys[index].len);
+
+	erq->length = xlen;
+
+	memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
+
+	orinoco_unlock(priv, &flags);
+	return 0;
+}
+
+static int orinoco_ioctl_setessid(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_point *erq,
+				  char *essidbuf)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
+	 * anyway... - Jean II */
+
+	/* Hum... Should not use Wireless Extension constant (may change),
+	 * should use our own... - Jean II */
+	if (erq->length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+	/* If not ANY, get the new ESSID */
+	if (erq->flags)
+		memcpy(priv->desired_essid, essidbuf, erq->length);
+
+	orinoco_unlock(priv, &flags);
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getessid(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_point *erq,
+				  char *essidbuf)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int active;
+	int err = 0;
+	unsigned long flags;
+
+	if (netif_running(dev)) {
+		err = orinoco_hw_get_essid(priv, &active, essidbuf);
+		if (err < 0)
+			return err;
+		erq->length = err;
+	} else {
+		if (orinoco_lock(priv, &flags) != 0)
+			return -EBUSY;
+		memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
+		erq->length = strlen(priv->desired_essid);
+		orinoco_unlock(priv, &flags);
+	}
+
+	erq->flags = 1;
+
+	return 0;
+}
+
+static int orinoco_ioctl_setnick(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *nrq,
+				 char *nickbuf)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	if (nrq->length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	memset(priv->nick, 0, sizeof(priv->nick));
+	memcpy(priv->nick, nickbuf, nrq->length);
+
+	orinoco_unlock(priv, &flags);
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getnick(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *nrq,
+				 char *nickbuf)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
+	orinoco_unlock(priv, &flags);
+
+	nrq->length = strlen(priv->nick);
+
+	return 0;
+}
+
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_freq *frq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int chan = -1;
+	unsigned long flags;
+	int err = -EINPROGRESS;		/* Call commit handler */
+
+	/* In infrastructure mode the AP sets the channel */
+	if (priv->iw_mode == IW_MODE_INFRA)
+		return -EBUSY;
+
+	if ((frq->e == 0) && (frq->m <= 1000)) {
+		/* Setting by channel number */
+		chan = frq->m;
+	} else {
+		/* Setting by frequency */
+		int denom = 1;
+		int i;
+
+		/* Calculate denominator to rescale to MHz */
+		for (i = 0; i < (6 - frq->e); i++)
+			denom *= 10;
+
+		chan = ieee80211_freq_to_dsss_chan(frq->m / denom);
+	}
+
+	if ((chan < 1) || (chan > NUM_CHANNELS) ||
+	     !(priv->channel_mask & (1 << (chan-1))))
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	priv->channel = chan;
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		/* Fast channel change - no commit if successful */
+		hermes_t *hw = &priv->hw;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+					    HERMES_TEST_SET_CHANNEL,
+					chan, NULL);
+	}
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_freq *frq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int tmp;
+
+	/* Locking done in there */
+	tmp = orinoco_hw_get_freq(priv);
+	if (tmp < 0)
+		return tmp;
+
+	frq->m = tmp * 100000;
+	frq->e = 1;
+
+	return 0;
+}
+
+static int orinoco_ioctl_getsens(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *srq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	u16 val;
+	int err;
+	unsigned long flags;
+
+	if (!priv->has_sensitivity)
+		return -EOPNOTSUPP;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+	err = hermes_read_wordrec(hw, USER_BAP,
+				  HERMES_RID_CNFSYSTEMSCALE, &val);
+	orinoco_unlock(priv, &flags);
+
+	if (err)
+		return err;
+
+	srq->value = val;
+	srq->fixed = 0; /* auto */
+
+	return 0;
+}
+
+static int orinoco_ioctl_setsens(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *srq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int val = srq->value;
+	unsigned long flags;
+
+	if (!priv->has_sensitivity)
+		return -EOPNOTSUPP;
+
+	if ((val < 1) || (val > 3))
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+	priv->ap_density = val;
+	orinoco_unlock(priv, &flags);
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_setrts(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_param *rrq,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int val = rrq->value;
+	unsigned long flags;
+
+	if (rrq->disabled)
+		val = 2347;
+
+	if ((val < 0) || (val > 2347))
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	priv->rts_thresh = val;
+	orinoco_unlock(priv, &flags);
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getrts(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_param *rrq,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	rrq->value = priv->rts_thresh;
+	rrq->disabled = (rrq->value == 2347);
+	rrq->fixed = 1;
+
+	return 0;
+}
+
+static int orinoco_ioctl_setfrag(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *frq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = -EINPROGRESS;		/* Call commit handler */
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if (priv->has_mwo) {
+		if (frq->disabled)
+			priv->mwo_robust = 0;
+		else {
+			if (frq->fixed)
+				printk(KERN_WARNING "%s: Fixed fragmentation "
+				       "is not supported on this firmware. "
+				       "Using MWO robust instead.\n",
+				       dev->name);
+			priv->mwo_robust = 1;
+		}
+	} else {
+		if (frq->disabled)
+			priv->frag_thresh = 2346;
+		else {
+			if ((frq->value < 256) || (frq->value > 2346))
+				err = -EINVAL;
+			else
+				/* must be even */
+				priv->frag_thresh = frq->value & ~0x1;
+		}
+	}
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_getfrag(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *frq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int err;
+	u16 val;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if (priv->has_mwo) {
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFMWOROBUST_AGERE,
+					  &val);
+		if (err)
+			val = 0;
+
+		frq->value = val ? 2347 : 0;
+		frq->disabled = !val;
+		frq->fixed = 0;
+	} else {
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+					  &val);
+		if (err)
+			val = 0;
+
+		frq->value = val;
+		frq->disabled = (val >= 2346);
+		frq->fixed = 1;
+	}
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_setrate(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *rrq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int ratemode;
+	int bitrate; /* 100s of kilobits */
+	unsigned long flags;
+
+	/* As the user space doesn't know our highest rate, it uses -1
+	 * to ask us to set the highest rate.  Test it using "iwconfig
+	 * ethX rate auto" - Jean II */
+	if (rrq->value == -1)
+		bitrate = 110;
+	else {
+		if (rrq->value % 100000)
+			return -EINVAL;
+		bitrate = rrq->value / 100000;
+	}
+
+	ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed);
+
+	if (ratemode == -1)
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+	priv->bitratemode = ratemode;
+	orinoco_unlock(priv, &flags);
+
+	return -EINPROGRESS;
+}
+
+static int orinoco_ioctl_getrate(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *rrq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+	int bitrate, automatic;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic);
+
+	/* If the interface is running we try to find more about the
+	   current mode */
+	if (netif_running(dev))
+		err = orinoco_hw_get_act_bitrate(priv, &bitrate);
+
+	orinoco_unlock(priv, &flags);
+
+	rrq->value = bitrate;
+	rrq->fixed = !automatic;
+	rrq->disabled = 0;
+
+	return err;
+}
+
+static int orinoco_ioctl_setpower(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *prq,
+				  char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = -EINPROGRESS;		/* Call commit handler */
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if (prq->disabled) {
+		priv->pm_on = 0;
+	} else {
+		switch (prq->flags & IW_POWER_MODE) {
+		case IW_POWER_UNICAST_R:
+			priv->pm_mcast = 0;
+			priv->pm_on = 1;
+			break;
+		case IW_POWER_ALL_R:
+			priv->pm_mcast = 1;
+			priv->pm_on = 1;
+			break;
+		case IW_POWER_ON:
+			/* No flags : but we may have a value - Jean II */
+			break;
+		default:
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (prq->flags & IW_POWER_TIMEOUT) {
+			priv->pm_on = 1;
+			priv->pm_timeout = prq->value / 1000;
+		}
+		if (prq->flags & IW_POWER_PERIOD) {
+			priv->pm_on = 1;
+			priv->pm_period = prq->value / 1000;
+		}
+		/* It's valid to not have a value if we are just toggling
+		 * the flags... Jean II */
+		if (!priv->pm_on) {
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+ out:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_getpower(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *prq,
+				  char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	u16 enable, period, timeout, mcast;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = hermes_read_wordrec(hw, USER_BAP,
+				  HERMES_RID_CNFPMENABLED, &enable);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP,
+				  HERMES_RID_CNFMAXSLEEPDURATION, &period);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP,
+				  HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP,
+				  HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
+	if (err)
+		goto out;
+
+	prq->disabled = !enable;
+	/* Note : by default, display the period */
+	if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		prq->flags = IW_POWER_TIMEOUT;
+		prq->value = timeout * 1000;
+	} else {
+		prq->flags = IW_POWER_PERIOD;
+		prq->value = period * 1000;
+	}
+	if (mcast)
+		prq->flags |= IW_POWER_ALL_R;
+	else
+		prq->flags |= IW_POWER_UNICAST_R;
+
+ out:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_set_encodeext(struct net_device *dev,
+				       struct iw_request_info *info,
+				       union iwreq_data *wrqu,
+				       char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int idx, alg = ext->alg, set_key = 1;
+	unsigned long flags;
+	int err = -EINVAL;
+	u16 key_len;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* Determine and validate the key index */
+	idx = encoding->flags & IW_ENCODE_INDEX;
+	if (idx) {
+		if ((idx < 1) || (idx > 4))
+			goto out;
+		idx--;
+	} else
+		idx = priv->tx_key;
+
+	if (encoding->flags & IW_ENCODE_DISABLED)
+		alg = IW_ENCODE_ALG_NONE;
+
+	if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
+		/* Clear any TKIP TX key we had */
+		(void) orinoco_clear_tkip_key(priv, priv->tx_key);
+	}
+
+	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+		priv->tx_key = idx;
+		set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
+			   (ext->key_len > 0)) ? 1 : 0;
+	}
+
+	if (set_key) {
+		/* Set the requested key first */
+		switch (alg) {
+		case IW_ENCODE_ALG_NONE:
+			priv->encode_alg = alg;
+			priv->keys[idx].len = 0;
+			break;
+
+		case IW_ENCODE_ALG_WEP:
+			if (ext->key_len > SMALL_KEY_SIZE)
+				key_len = LARGE_KEY_SIZE;
+			else if (ext->key_len > 0)
+				key_len = SMALL_KEY_SIZE;
+			else
+				goto out;
+
+			priv->encode_alg = alg;
+			priv->keys[idx].len = cpu_to_le16(key_len);
+
+			key_len = min(ext->key_len, key_len);
+
+			memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
+			memcpy(priv->keys[idx].data, ext->key, key_len);
+			break;
+
+		case IW_ENCODE_ALG_TKIP:
+		{
+			hermes_t *hw = &priv->hw;
+			u8 *tkip_iv = NULL;
+
+			if (!priv->has_wpa ||
+			    (ext->key_len > sizeof(priv->tkip_key[0])))
+				goto out;
+
+			priv->encode_alg = alg;
+			memset(&priv->tkip_key[idx], 0,
+			       sizeof(priv->tkip_key[idx]));
+			memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
+
+			if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+				tkip_iv = &ext->rx_seq[0];
+
+			err = __orinoco_hw_set_tkip_key(hw, idx,
+				 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
+				 (u8 *) &priv->tkip_key[idx],
+				 tkip_iv, NULL);
+			if (err)
+				printk(KERN_ERR "%s: Error %d setting TKIP key"
+				       "\n", dev->name, err);
+
+			goto out;
+		}
+		default:
+			goto out;
+		}
+	}
+	err = -EINPROGRESS;
+ out:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_get_encodeext(struct net_device *dev,
+				       struct iw_request_info *info,
+				       union iwreq_data *wrqu,
+				       char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int idx, max_key_len;
+	unsigned long flags;
+	int err;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = -EINVAL;
+	max_key_len = encoding->length - sizeof(*ext);
+	if (max_key_len < 0)
+		goto out;
+
+	idx = encoding->flags & IW_ENCODE_INDEX;
+	if (idx) {
+		if ((idx < 1) || (idx > 4))
+			goto out;
+		idx--;
+	} else
+		idx = priv->tx_key;
+
+	encoding->flags = idx + 1;
+	memset(ext, 0, sizeof(*ext));
+
+	ext->alg = priv->encode_alg;
+	switch (priv->encode_alg) {
+	case IW_ENCODE_ALG_NONE:
+		ext->key_len = 0;
+		encoding->flags |= IW_ENCODE_DISABLED;
+		break;
+	case IW_ENCODE_ALG_WEP:
+		ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len),
+				     max_key_len);
+		memcpy(ext->key, priv->keys[idx].data, ext->key_len);
+		encoding->flags |= IW_ENCODE_ENABLED;
+		break;
+	case IW_ENCODE_ALG_TKIP:
+		ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key),
+				     max_key_len);
+		memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
+		encoding->flags |= IW_ENCODE_ENABLED;
+		break;
+	}
+
+	err = 0;
+ out:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_set_auth(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	struct iw_param *param = &wrqu->param;
+	unsigned long flags;
+	int ret = -EINPROGRESS;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+	case IW_AUTH_PRIVACY_INVOKED:
+	case IW_AUTH_DROP_UNENCRYPTED:
+		/*
+		 * orinoco does not use these parameters
+		 */
+		break;
+
+	case IW_AUTH_KEY_MGMT:
+		/* wl_lkm implies value 2 == PSK for Hermes I
+		 * which ties in with WEXT
+		 * no other hints tho :(
+		 */
+		priv->key_mgmt = param->value;
+		break;
+
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		/* When countermeasures are enabled, shut down the
+		 * card; when disabled, re-enable the card. This must
+		 * take effect immediately.
+		 *
+		 * TODO: Make sure that the EAPOL message is getting
+		 *       out before card disabled
+		 */
+		if (param->value) {
+			priv->tkip_cm_active = 1;
+			ret = hermes_enable_port(hw, 0);
+		} else {
+			priv->tkip_cm_active = 0;
+			ret = hermes_disable_port(hw, 0);
+		}
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		if (param->value & IW_AUTH_ALG_SHARED_KEY)
+			priv->wep_restrict = 1;
+		else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
+			priv->wep_restrict = 0;
+		else
+			ret = -EINVAL;
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		if (priv->has_wpa) {
+			priv->wpa_enabled = param->value ? 1 : 0;
+		} else {
+			if (param->value)
+				ret = -EOPNOTSUPP;
+			/* else silently accept disable of WPA */
+			priv->wpa_enabled = 0;
+		}
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return ret;
+}
+
+static int orinoco_ioctl_get_auth(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct iw_param *param = &wrqu->param;
+	unsigned long flags;
+	int ret = 0;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_KEY_MGMT:
+		param->value = priv->key_mgmt;
+		break;
+
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		param->value = priv->tkip_cm_active;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		if (priv->wep_restrict)
+			param->value = IW_AUTH_ALG_SHARED_KEY;
+		else
+			param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		param->value = priv->wpa_enabled;
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return ret;
+}
+
+static int orinoco_ioctl_set_genie(struct net_device *dev,
+				   struct iw_request_info *info,
+				   union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	u8 *buf;
+	unsigned long flags;
+
+	/* cut off at IEEE80211_MAX_DATA_LEN */
+	if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
+	    (wrqu->data.length && (extra == NULL)))
+		return -EINVAL;
+
+	if (wrqu->data.length) {
+		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+		if (buf == NULL)
+			return -ENOMEM;
+
+		memcpy(buf, extra, wrqu->data.length);
+	} else
+		buf = NULL;
+
+	if (orinoco_lock(priv, &flags) != 0) {
+		kfree(buf);
+		return -EBUSY;
+	}
+
+	kfree(priv->wpa_ie);
+	priv->wpa_ie = buf;
+	priv->wpa_ie_len = wrqu->data.length;
+
+	if (priv->wpa_ie) {
+		/* Looks like wl_lkm wants to check the auth alg, and
+		 * somehow pass it to the firmware.
+		 * Instead it just calls the key mgmt rid
+		 *   - we do this in set auth.
+		 */
+	}
+
+	orinoco_unlock(priv, &flags);
+	return 0;
+}
+
+static int orinoco_ioctl_get_genie(struct net_device *dev,
+				   struct iw_request_info *info,
+				   union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	int err = 0;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
+		wrqu->data.length = 0;
+		goto out;
+	}
+
+	if (wrqu->data.length < priv->wpa_ie_len) {
+		err = -E2BIG;
+		goto out;
+	}
+
+	wrqu->data.length = priv->wpa_ie_len;
+	memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
+
+out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static int orinoco_ioctl_set_mlme(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu, char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	struct iw_mlme *mlme = (struct iw_mlme *)extra;
+	unsigned long flags;
+	int ret = 0;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (mlme->cmd) {
+	case IW_MLME_DEAUTH:
+		/* silently ignore */
+		break;
+
+	case IW_MLME_DISASSOC:
+	{
+		struct {
+			u8 addr[ETH_ALEN];
+			__le16 reason_code;
+		} __attribute__ ((packed)) buf;
+
+		memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN);
+		buf.reason_code = cpu_to_le16(mlme->reason_code);
+		ret = HERMES_WRITE_RECORD(hw, USER_BAP,
+					  HERMES_RID_CNFDISASSOCIATE,
+					  &buf);
+		break;
+	}
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return ret;
+}
+
+static int orinoco_ioctl_getretry(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *rrq,
+				  char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	u16 short_limit, long_limit, lifetime;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
+				  &short_limit);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
+				  &long_limit);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
+				  &lifetime);
+	if (err)
+		goto out;
+
+	rrq->disabled = 0;		/* Can't be disabled */
+
+	/* Note : by default, display the retry number */
+	if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+		rrq->flags = IW_RETRY_LIFETIME;
+		rrq->value = lifetime * 1000;	/* ??? */
+	} else {
+		/* By default, display the min number */
+		if ((rrq->flags & IW_RETRY_LONG)) {
+			rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+			rrq->value = long_limit;
+		} else {
+			rrq->flags = IW_RETRY_LIMIT;
+			rrq->value = short_limit;
+			if (short_limit != long_limit)
+				rrq->flags |= IW_RETRY_SHORT;
+		}
+	}
+
+ out:
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_reset(struct net_device *dev,
+			       struct iw_request_info *info,
+			       void *wrqu,
+			       char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
+		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+
+		/* Firmware reset */
+		orinoco_reset(&priv->reset_work);
+	} else {
+		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+
+		schedule_work(&priv->reset_work);
+	}
+
+	return 0;
+}
+
+static int orinoco_ioctl_setibssport(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int val = *((int *) extra);
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	priv->ibss_port = val ;
+
+	/* Actually update the mode we are using */
+	set_port_type(priv);
+
+	orinoco_unlock(priv, &flags);
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getibssport(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int *val = (int *) extra;
+
+	*val = priv->ibss_port;
+	return 0;
+}
+
+static int orinoco_ioctl_setport3(struct net_device *dev,
+				  struct iw_request_info *info,
+				  void *wrqu,
+				  char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int val = *((int *) extra);
+	int err = 0;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (val) {
+	case 0: /* Try to do IEEE ad-hoc mode */
+		if (!priv->has_ibss) {
+			err = -EINVAL;
+			break;
+		}
+		priv->prefer_port3 = 0;
+
+		break;
+
+	case 1: /* Try to do Lucent proprietary ad-hoc mode */
+		if (!priv->has_port3) {
+			err = -EINVAL;
+			break;
+		}
+		priv->prefer_port3 = 1;
+		break;
+
+	default:
+		err = -EINVAL;
+	}
+
+	if (!err) {
+		/* Actually update the mode we are using */
+		set_port_type(priv);
+		err = -EINPROGRESS;
+	}
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_getport3(struct net_device *dev,
+				  struct iw_request_info *info,
+				  void *wrqu,
+				  char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int *val = (int *) extra;
+
+	*val = priv->prefer_port3;
+	return 0;
+}
+
+static int orinoco_ioctl_setpreamble(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	int val;
+
+	if (!priv->has_preamble)
+		return -EOPNOTSUPP;
+
+	/* 802.11b has recently defined some short preamble.
+	 * Basically, the Phy header has been reduced in size.
+	 * This increase performance, especially at high rates
+	 * (the preamble is transmitted at 1Mb/s), unfortunately
+	 * this give compatibility troubles... - Jean II */
+	val = *((int *) extra);
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if (val)
+		priv->preamble = 1;
+	else
+		priv->preamble = 0;
+
+	orinoco_unlock(priv, &flags);
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getpreamble(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int *val = (int *) extra;
+
+	if (!priv->has_preamble)
+		return -EOPNOTSUPP;
+
+	*val = priv->preamble;
+	return 0;
+}
+
+/* ioctl interface to hermes_read_ltv()
+ * To use with iwpriv, pass the RID as the token argument, e.g.
+ * iwpriv get_rid [0xfc00]
+ * At least Wireless Tools 25 is required to use iwpriv.
+ * For Wireless Tools 25 and 26 append "dummy" are the end. */
+static int orinoco_ioctl_getrid(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_point *data,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int rid = data->flags;
+	u16 length;
+	int err;
+	unsigned long flags;
+
+	/* It's a "get" function, but we don't want users to access the
+	 * WEP key and other raw firmware data */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (rid < 0xfc00 || rid > 0xffff)
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+			      extra);
+	if (err)
+		goto out;
+
+	data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
+			     MAX_RID_LEN);
+
+ out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+/* Trigger a scan (look for other cells in the vicinity) */
+static int orinoco_ioctl_setscan(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *srq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	struct iw_scan_req *si = (struct iw_scan_req *) extra;
+	int err = 0;
+	unsigned long flags;
+
+	/* Note : you may have realised that, as this is a SET operation,
+	 * this is privileged and therefore a normal user can't
+	 * perform scanning.
+	 * This is not an error, while the device perform scanning,
+	 * traffic doesn't flow, so it's a perfect DoS...
+	 * Jean II */
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* Scanning with port 0 disabled would fail */
+	if (!netif_running(dev)) {
+		err = -ENETDOWN;
+		goto out;
+	}
+
+	/* In monitor mode, the scan results are always empty.
+	 * Probe responses are passed to the driver as received
+	 * frames and could be processed in software. */
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Note : because we don't lock out the irq handler, the way
+	 * we access scan variables in priv is critical.
+	 *	o scan_inprogress : not touched by irq handler
+	 *	o scan_mode : not touched by irq handler
+	 * Before modifying anything on those variables, please think hard !
+	 * Jean II */
+
+	/* Save flags */
+	priv->scan_mode = srq->flags;
+
+	/* Always trigger scanning, even if it's in progress.
+	 * This way, if the info frame get lost, we will recover somewhat
+	 * gracefully  - Jean II */
+
+	if (priv->has_hostscan) {
+		switch (priv->firmware_type) {
+		case FIRMWARE_TYPE_SYMBOL:
+			err = hermes_write_wordrec(hw, USER_BAP,
+						HERMES_RID_CNFHOSTSCAN_SYMBOL,
+						HERMES_HOSTSCAN_SYMBOL_ONCE |
+						HERMES_HOSTSCAN_SYMBOL_BCAST);
+			break;
+		case FIRMWARE_TYPE_INTERSIL: {
+			__le16 req[3];
+
+			req[0] = cpu_to_le16(0x3fff);	/* All channels */
+			req[1] = cpu_to_le16(0x0001);	/* rate 1 Mbps */
+			req[2] = 0;			/* Any ESSID */
+			err = HERMES_WRITE_RECORD(hw, USER_BAP,
+						  HERMES_RID_CNFHOSTSCAN, &req);
+		}
+		break;
+		case FIRMWARE_TYPE_AGERE:
+			if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
+				struct hermes_idstring idbuf;
+				size_t len = min(sizeof(idbuf.val),
+						 (size_t) si->essid_len);
+				idbuf.len = cpu_to_le16(len);
+				memcpy(idbuf.val, si->essid, len);
+
+				err = hermes_write_ltv(hw, USER_BAP,
+					       HERMES_RID_CNFSCANSSID_AGERE,
+					       HERMES_BYTES_TO_RECLEN(len + 2),
+					       &idbuf);
+			} else
+				err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFSCANSSID_AGERE,
+						   0);	/* Any ESSID */
+			if (err)
+				break;
+
+			if (priv->has_ext_scan) {
+				/* Clear scan results at the start of
+				 * an extended scan */
+				orinoco_clear_scan_results(priv,
+						msecs_to_jiffies(15000));
+
+				/* TODO: Is this available on older firmware?
+				 *   Can we use it to scan specific channels
+				 *   for IW_SCAN_THIS_FREQ? */
+				err = hermes_write_wordrec(hw, USER_BAP,
+						HERMES_RID_CNFSCANCHANNELS2GHZ,
+						0x7FFF);
+				if (err)
+					goto out;
+
+				err = hermes_inquire(hw,
+						     HERMES_INQ_CHANNELINFO);
+			} else
+				err = hermes_inquire(hw, HERMES_INQ_SCAN);
+			break;
+		}
+	} else
+		err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+	/* One more client */
+	if (!err)
+		priv->scan_inprogress = 1;
+
+ out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+#define MAX_CUSTOM_LEN 64
+
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline char *orinoco_translate_scan(struct net_device *dev,
+					   struct iw_request_info *info,
+					   char *current_ev,
+					   char *end_buf,
+					   union hermes_scan_info *bss,
+					   unsigned long last_scanned)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	u16			capabilities;
+	u16			channel;
+	struct iw_event		iwe;		/* Temporary buffer */
+	char custom[MAX_CUSTOM_LEN];
+
+	memset(&iwe, 0, sizeof(iwe));
+
+	/* First entry *MUST* be the AP MAC address */
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+					  &iwe, IW_EV_ADDR_LEN);
+
+	/* Other entries will be displayed in the order we give them */
+
+	/* Add the ESSID */
+	iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
+	if (iwe.u.data.length > 32)
+		iwe.u.data.length = 32;
+	iwe.cmd = SIOCGIWESSID;
+	iwe.u.data.flags = 1;
+	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+					  &iwe, bss->a.essid);
+
+	/* Add mode */
+	iwe.cmd = SIOCGIWMODE;
+	capabilities = le16_to_cpu(bss->a.capabilities);
+	if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+		if (capabilities & WLAN_CAPABILITY_ESS)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_UINT_LEN);
+	}
+
+	channel = bss->s.channel;
+	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
+		/* Add channel and frequency */
+		iwe.cmd = SIOCGIWFREQ;
+		iwe.u.freq.m = channel;
+		iwe.u.freq.e = 0;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+
+		iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
+		iwe.u.freq.e = 1;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+	}
+
+	/* Add quality statistics. level and noise in dB. No link quality */
+	iwe.cmd = IWEVQUAL;
+	iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
+	iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
+	iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
+	/* Wireless tools prior to 27.pre22 will show link quality
+	 * anyway, so we provide a reasonable value. */
+	if (iwe.u.qual.level > iwe.u.qual.noise)
+		iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+	else
+		iwe.u.qual.qual = 0;
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+					  &iwe, IW_EV_QUAL_LEN);
+
+	/* Add encryption capability */
+	iwe.cmd = SIOCGIWENCODE;
+	if (capabilities & WLAN_CAPABILITY_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+					  &iwe, NULL);
+
+	/* Bit rate is not available in Lucent/Agere firmwares */
+	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+		char *current_val = current_ev + iwe_stream_lcp_len(info);
+		int i;
+		int step;
+
+		if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+			step = 2;
+		else
+			step = 1;
+
+		iwe.cmd = SIOCGIWRATE;
+		/* Those two flags are ignored... */
+		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+		/* Max 10 values */
+		for (i = 0; i < 10; i += step) {
+			/* NULL terminated */
+			if (bss->p.rates[i] == 0x0)
+				break;
+			/* Bit rate given in 500 kb/s units (+ 0x80) */
+			iwe.u.bitrate.value =
+				((bss->p.rates[i] & 0x7f) * 500000);
+			current_val = iwe_stream_add_value(info, current_ev,
+							   current_val,
+							   end_buf, &iwe,
+							   IW_EV_PARAM_LEN);
+		}
+		/* Check if we added any event */
+		if ((current_val - current_ev) > iwe_stream_lcp_len(info))
+			current_ev = current_val;
+	}
+
+	/* Beacon interval */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     "bcn_int=%d",
+				     le16_to_cpu(bss->a.beacon_interv));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Capabilites */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     "capab=0x%04x",
+				     capabilities);
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Add EXTRA: Age to display seconds since last beacon/probe response
+	 * for given network. */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     " Last beacon: %dms ago",
+				     jiffies_to_msecs(jiffies - last_scanned));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	return current_ev;
+}
+
+static inline char *orinoco_translate_ext_scan(struct net_device *dev,
+					       struct iw_request_info *info,
+					       char *current_ev,
+					       char *end_buf,
+					       struct agere_ext_scan_info *bss,
+					       unsigned long last_scanned)
+{
+	u16			capabilities;
+	u16			channel;
+	struct iw_event		iwe;		/* Temporary buffer */
+	char custom[MAX_CUSTOM_LEN];
+	u8 *ie;
+
+	memset(&iwe, 0, sizeof(iwe));
+
+	/* First entry *MUST* be the AP MAC address */
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+					  &iwe, IW_EV_ADDR_LEN);
+
+	/* Other entries will be displayed in the order we give them */
+
+	/* Add the ESSID */
+	ie = bss->data;
+	iwe.u.data.length = ie[1];
+	if (iwe.u.data.length) {
+		if (iwe.u.data.length > 32)
+			iwe.u.data.length = 32;
+		iwe.cmd = SIOCGIWESSID;
+		iwe.u.data.flags = 1;
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, &ie[2]);
+	}
+
+	/* Add mode */
+	capabilities = le16_to_cpu(bss->capabilities);
+	if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+		iwe.cmd = SIOCGIWMODE;
+		if (capabilities & WLAN_CAPABILITY_ESS)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_UINT_LEN);
+	}
+
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
+	channel = ie ? ie[2] : 0;
+	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
+		/* Add channel and frequency */
+		iwe.cmd = SIOCGIWFREQ;
+		iwe.u.freq.m = channel;
+		iwe.u.freq.e = 0;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+
+		iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
+		iwe.u.freq.e = 1;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+	}
+
+	/* Add quality statistics. level and noise in dB. No link quality */
+	iwe.cmd = IWEVQUAL;
+	iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
+	iwe.u.qual.level = bss->level - 0x95;
+	iwe.u.qual.noise = bss->noise - 0x95;
+	/* Wireless tools prior to 27.pre22 will show link quality
+	 * anyway, so we provide a reasonable value. */
+	if (iwe.u.qual.level > iwe.u.qual.noise)
+		iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+	else
+		iwe.u.qual.qual = 0;
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+					  &iwe, IW_EV_QUAL_LEN);
+
+	/* Add encryption capability */
+	iwe.cmd = SIOCGIWENCODE;
+	if (capabilities & WLAN_CAPABILITY_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+					  &iwe, NULL);
+
+	/* WPA IE */
+	ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
+	if (ie) {
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = ie[1] + 2;
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, ie);
+	}
+
+	/* RSN IE */
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
+	if (ie) {
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = ie[1] + 2;
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, ie);
+	}
+
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
+	if (ie) {
+		char *p = current_ev + iwe_stream_lcp_len(info);
+		int i;
+
+		iwe.cmd = SIOCGIWRATE;
+		/* Those two flags are ignored... */
+		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+		for (i = 2; i < (ie[1] + 2); i++) {
+			iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
+			p = iwe_stream_add_value(info, current_ev, p, end_buf,
+						 &iwe, IW_EV_PARAM_LEN);
+		}
+		/* Check if we added any event */
+		if (p > (current_ev + iwe_stream_lcp_len(info)))
+			current_ev = p;
+	}
+
+	/* Timestamp */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length =
+		snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
+			 (unsigned long long) le64_to_cpu(bss->timestamp));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Beacon interval */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     "bcn_int=%d",
+				     le16_to_cpu(bss->beacon_interval));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Capabilites */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     "capab=0x%04x",
+				     capabilities);
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	/* Add EXTRA: Age to display seconds since last beacon/probe response
+	 * for given network. */
+	iwe.cmd = IWEVCUSTOM;
+	iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+				     " Last beacon: %dms ago",
+				     jiffies_to_msecs(jiffies - last_scanned));
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, custom);
+
+	return current_ev;
+}
+
+/* Return results of a scan */
+static int orinoco_ioctl_getscan(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *srq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+	unsigned long flags;
+	char *current_ev = extra;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if (priv->scan_inprogress) {
+		/* Important note : we don't want to block the caller
+		 * until results are ready for various reasons.
+		 * First, managing wait queues is complex and racy.
+		 * Second, we grab some rtnetlink lock before comming
+		 * here (in dev_ioctl()).
+		 * Third, we generate an Wireless Event, so the
+		 * caller can wait itself on that - Jean II */
+		err = -EAGAIN;
+		goto out;
+	}
+
+	if (priv->has_ext_scan) {
+		struct xbss_element *bss;
+
+		list_for_each_entry(bss, &priv->bss_list, list) {
+			/* Translate this entry to WE format */
+			current_ev =
+				orinoco_translate_ext_scan(dev, info,
+							   current_ev,
+							   extra + srq->length,
+							   &bss->bss,
+							   bss->last_scanned);
+
+			/* Check if there is space for one more entry */
+			if ((extra + srq->length - current_ev)
+			    <= IW_EV_ADDR_LEN) {
+				/* Ask user space to try again with a
+				 * bigger buffer */
+				err = -E2BIG;
+				goto out;
+			}
+		}
+
+	} else {
+		struct bss_element *bss;
+
+		list_for_each_entry(bss, &priv->bss_list, list) {
+			/* Translate this entry to WE format */
+			current_ev = orinoco_translate_scan(dev, info,
+							    current_ev,
+							    extra + srq->length,
+							    &bss->bss,
+							    bss->last_scanned);
+
+			/* Check if there is space for one more entry */
+			if ((extra + srq->length - current_ev)
+			    <= IW_EV_ADDR_LEN) {
+				/* Ask user space to try again with a
+				 * bigger buffer */
+				err = -E2BIG;
+				goto out;
+			}
+		}
+	}
+
+	srq->length = (current_ev - extra);
+	srq->flags = (__u16) priv->scan_mode;
+
+out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+/* Commit handler, called after set operations */
+static int orinoco_ioctl_commit(struct net_device *dev,
+				struct iw_request_info *info,
+				void *wrqu,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	unsigned long flags;
+	int err = 0;
+
+	if (!priv->open)
+		return 0;
+
+	if (priv->broken_disableport) {
+		orinoco_reset(&priv->reset_work);
+		return 0;
+	}
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return err;
+
+	err = hermes_disable_port(hw, 0);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to disable port "
+		       "while reconfiguring card\n", dev->name);
+		priv->broken_disableport = 1;
+		goto out;
+	}
+
+	err = __orinoco_program_rids(dev);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+		       dev->name);
+		goto out;
+	}
+
+	err = hermes_enable_port(hw, 0);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+		       dev->name);
+		goto out;
+	}
+
+ out:
+	if (err) {
+		printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+		schedule_work(&priv->reset_work);
+		err = 0;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static const struct iw_priv_args orinoco_privtab[] = {
+	{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+	{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+	{ SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_port3" },
+	{ SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_port3" },
+	{ SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_preamble" },
+	{ SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_preamble" },
+	{ SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_ibssport" },
+	{ SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_ibssport" },
+	{ SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
+	  "get_rid" },
+};
+
+
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+#define STD_IW_HANDLER(id, func) \
+	[IW_IOCTL_IDX(id)] = (iw_handler) func
+static const iw_handler	orinoco_handler[] = {
+	STD_IW_HANDLER(SIOCSIWCOMMIT,	orinoco_ioctl_commit),
+	STD_IW_HANDLER(SIOCGIWNAME,	orinoco_ioctl_getname),
+	STD_IW_HANDLER(SIOCSIWFREQ,	orinoco_ioctl_setfreq),
+	STD_IW_HANDLER(SIOCGIWFREQ,	orinoco_ioctl_getfreq),
+	STD_IW_HANDLER(SIOCSIWMODE,	orinoco_ioctl_setmode),
+	STD_IW_HANDLER(SIOCGIWMODE,	orinoco_ioctl_getmode),
+	STD_IW_HANDLER(SIOCSIWSENS,	orinoco_ioctl_setsens),
+	STD_IW_HANDLER(SIOCGIWSENS,	orinoco_ioctl_getsens),
+	STD_IW_HANDLER(SIOCGIWRANGE,	orinoco_ioctl_getiwrange),
+	STD_IW_HANDLER(SIOCSIWSPY,	iw_handler_set_spy),
+	STD_IW_HANDLER(SIOCGIWSPY,	iw_handler_get_spy),
+	STD_IW_HANDLER(SIOCSIWTHRSPY,	iw_handler_set_thrspy),
+	STD_IW_HANDLER(SIOCGIWTHRSPY,	iw_handler_get_thrspy),
+	STD_IW_HANDLER(SIOCSIWAP,	orinoco_ioctl_setwap),
+	STD_IW_HANDLER(SIOCGIWAP,	orinoco_ioctl_getwap),
+	STD_IW_HANDLER(SIOCSIWSCAN,	orinoco_ioctl_setscan),
+	STD_IW_HANDLER(SIOCGIWSCAN,	orinoco_ioctl_getscan),
+	STD_IW_HANDLER(SIOCSIWESSID,	orinoco_ioctl_setessid),
+	STD_IW_HANDLER(SIOCGIWESSID,	orinoco_ioctl_getessid),
+	STD_IW_HANDLER(SIOCSIWNICKN,	orinoco_ioctl_setnick),
+	STD_IW_HANDLER(SIOCGIWNICKN,	orinoco_ioctl_getnick),
+	STD_IW_HANDLER(SIOCSIWRATE,	orinoco_ioctl_setrate),
+	STD_IW_HANDLER(SIOCGIWRATE,	orinoco_ioctl_getrate),
+	STD_IW_HANDLER(SIOCSIWRTS,	orinoco_ioctl_setrts),
+	STD_IW_HANDLER(SIOCGIWRTS,	orinoco_ioctl_getrts),
+	STD_IW_HANDLER(SIOCSIWFRAG,	orinoco_ioctl_setfrag),
+	STD_IW_HANDLER(SIOCGIWFRAG,	orinoco_ioctl_getfrag),
+	STD_IW_HANDLER(SIOCGIWRETRY,	orinoco_ioctl_getretry),
+	STD_IW_HANDLER(SIOCSIWENCODE,	orinoco_ioctl_setiwencode),
+	STD_IW_HANDLER(SIOCGIWENCODE,	orinoco_ioctl_getiwencode),
+	STD_IW_HANDLER(SIOCSIWPOWER,	orinoco_ioctl_setpower),
+	STD_IW_HANDLER(SIOCGIWPOWER,	orinoco_ioctl_getpower),
+	STD_IW_HANDLER(SIOCSIWGENIE,	orinoco_ioctl_set_genie),
+	STD_IW_HANDLER(SIOCGIWGENIE,	orinoco_ioctl_get_genie),
+	STD_IW_HANDLER(SIOCSIWMLME,	orinoco_ioctl_set_mlme),
+	STD_IW_HANDLER(SIOCSIWAUTH,	orinoco_ioctl_set_auth),
+	STD_IW_HANDLER(SIOCGIWAUTH,	orinoco_ioctl_get_auth),
+	STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
+	STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
+};
+
+
+/*
+  Added typecasting since we no longer use iwreq_data -- Moustafa
+ */
+static const iw_handler	orinoco_private_handler[] = {
+	[0] = (iw_handler) orinoco_ioctl_reset,
+	[1] = (iw_handler) orinoco_ioctl_reset,
+	[2] = (iw_handler) orinoco_ioctl_setport3,
+	[3] = (iw_handler) orinoco_ioctl_getport3,
+	[4] = (iw_handler) orinoco_ioctl_setpreamble,
+	[5] = (iw_handler) orinoco_ioctl_getpreamble,
+	[6] = (iw_handler) orinoco_ioctl_setibssport,
+	[7] = (iw_handler) orinoco_ioctl_getibssport,
+	[9] = (iw_handler) orinoco_ioctl_getrid,
+};
+
+const struct iw_handler_def orinoco_handler_def = {
+	.num_standard = ARRAY_SIZE(orinoco_handler),
+	.num_private = ARRAY_SIZE(orinoco_private_handler),
+	.num_private_args = ARRAY_SIZE(orinoco_privtab),
+	.standard = orinoco_handler,
+	.private = orinoco_private_handler,
+	.private_args = orinoco_privtab,
+	.get_wireless_stats = orinoco_get_wireless_stats,
+};
diff --git a/drivers/net/wireless/orinoco/wext.h b/drivers/net/wireless/orinoco/wext.h
new file mode 100644
index 0000000..1479f4e
--- /dev/null
+++ b/drivers/net/wireless/orinoco/wext.h
@@ -0,0 +1,13 @@
+/* Wireless extensions support.
+ *
+ * See copyright notice in main.c
+ */
+#ifndef _ORINOCO_WEXT_H_
+#define _ORINOCO_WEXT_H_
+
+#include <net/iw_handler.h>
+
+/* Structure defining all our WEXT handlers */
+extern const struct iw_handler_def orinoco_handler_def;
+
+#endif /* _ORINOCO_WEXT_H_ */
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index 5200db4..6ac597f 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -33,8 +33,13 @@
 #ifdef DEBUG
 #  define dev_dbg_f(dev, fmt, args...) \
 	  dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
+#  define dev_dbg_f_limit(dev, fmt, args...) do { \
+	if (net_ratelimit()) \
+		dev_printk_f(KERN_DEBUG, dev, fmt, ## args); \
+} while (0)
 #else
 #  define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0)
+#  define dev_dbg_f_limit(dev, fmt, args...) do { (void)(dev); } while (0)
 #endif /* DEBUG */
 
 #ifdef DEBUG
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 651807d..7579af2 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -768,13 +768,23 @@
 			if (!beacon)
 				return -ENOMEM;
 			r = zd_mac_config_beacon(hw, beacon);
-			if (r < 0)
-				return r;
-			r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
-					hw->conf.beacon_int);
-			if (r < 0)
-				return r;
 			kfree_skb(beacon);
+
+			if (r < 0)
+				return r;
+		}
+
+		if (conf->changed & IEEE80211_IFCC_BEACON_ENABLED) {
+			u32 interval;
+
+			if (conf->enable_beacon)
+				interval = BCN_MODE_IBSS | hw->conf.beacon_int;
+			else
+				interval = 0;
+
+			r = zd_set_beacon_interval(&mac->chip, interval);
+			if (r < 0)
+				return r;
 		}
 	} else
 		associated = is_valid_ether_addr(conf->bssid);
@@ -793,10 +803,9 @@
 	struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
 
 	int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer+4));
-	if (int_status & INT_CFG_NEXT_BCN) {
-		if (net_ratelimit())
-			dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
-	} else
+	if (int_status & INT_CFG_NEXT_BCN)
+		dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
+	else
 		dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n");
 
 	zd_chip_enable_hwint(&mac->chip);
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 4bc2704..8802d1b 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -143,6 +143,13 @@
  *	added to all specified management frames generated by
  *	kernel/firmware/driver.
  *
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
+ *	NL80211_CMD_GET_SCAN and on the "scan" multicast group)
+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
+ *	partial scan results may be available
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -192,6 +199,11 @@
 
 	NL80211_CMD_GET_REG,
 
+	NL80211_CMD_GET_SCAN,
+	NL80211_CMD_TRIGGER_SCAN,
+	NL80211_CMD_NEW_SCAN_RESULTS,
+	NL80211_CMD_SCAN_ABORTED,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -305,6 +317,18 @@
  * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
  *	%NL80211_CMD_SET_MGMT_EXTRA_IE).
  *
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ *	a single scan request, a wiphy attribute.
+ *
+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ *	scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the
+ *	scan result list changes (BSS expired or added) so that applications
+ *	can verify that they got a single, consistent snapshot (when all dump
+ *	messages carried the same generation number)
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -372,6 +396,13 @@
 	NL80211_ATTR_MGMT_SUBTYPE,
 	NL80211_ATTR_IE,
 
+	NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+	NL80211_ATTR_SCAN_FREQUENCIES,
+	NL80211_ATTR_SCAN_SSIDS,
+	NL80211_ATTR_SCAN_GENERATION,
+	NL80211_ATTR_BSS,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -841,4 +872,38 @@
 	NL80211_CHAN_HT40MINUS,
 	NL80211_CHAN_HT40PLUS
 };
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ *	raw information elements from the probe response/beacon (bin)
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ *	in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ *	in unspecified units, scaled to 0..100 (u8)
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+	__NL80211_BSS_INVALID,
+	NL80211_BSS_BSSID,
+	NL80211_BSS_FREQUENCY,
+	NL80211_BSS_TSF,
+	NL80211_BSS_BEACON_INTERVAL,
+	NL80211_BSS_CAPABILITY,
+	NL80211_BSS_INFORMATION_ELEMENTS,
+	NL80211_BSS_SIGNAL_MBM,
+	NL80211_BSS_SIGNAL_UNSPEC,
+
+	/* keep last */
+	__NL80211_BSS_AFTER_LAST,
+	NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index dd1fd51..c0d1f5b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4,6 +4,10 @@
 #include <linux/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/nl80211.h>
+#include <linux/if_ether.h>
+#include <linux/ieee80211.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
 #include <net/genetlink.h>
 /* remove once we remove the wext stuff */
 #include <net/iw_handler.h>
@@ -505,6 +509,85 @@
 struct ieee80211_channel;
 
 /**
+ * struct cfg80211_ssid - SSID description
+ * @ssid: the SSID
+ * @ssid_len: length of the ssid
+ */
+struct cfg80211_ssid {
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	u8 ssid_len;
+};
+
+/**
+ * struct cfg80211_scan_request - scan request description
+ *
+ * @ssids: SSIDs to scan for (active scan only)
+ * @n_ssids: number of SSIDs
+ * @channels: channels to scan on.
+ * @n_channels: number of channels for each band
+ * @wiphy: the wiphy this was for
+ * @ifidx: the interface index
+ */
+struct cfg80211_scan_request {
+	struct cfg80211_ssid *ssids;
+	int n_ssids;
+	struct ieee80211_channel **channels;
+	u32 n_channels;
+
+	/* internal */
+	struct wiphy *wiphy;
+	int ifidx;
+};
+
+/**
+ * enum cfg80211_signal_type - signal type
+ *
+ * @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available
+ * @CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm)
+ * @CFG80211_SIGNAL_TYPE_UNSPEC: signal strength, increasing from 0 through 100
+ */
+enum cfg80211_signal_type {
+	CFG80211_SIGNAL_TYPE_NONE,
+	CFG80211_SIGNAL_TYPE_MBM,
+	CFG80211_SIGNAL_TYPE_UNSPEC,
+};
+
+/**
+ * struct cfg80211_bss - BSS description
+ *
+ * This structure describes a BSS (which may also be a mesh network)
+ * for use in scan results and similar.
+ *
+ * @bssid: BSSID of the BSS
+ * @tsf: timestamp of last received update
+ * @beacon_interval: the beacon interval as from the frame
+ * @capability: the capability field in host byte order
+ * @information_elements: the information elements (Note that there
+ *	is no guarantee that these are well-formed!)
+ * @len_information_elements: total length of the information elements
+ * @signal: signal strength value
+ * @signal_type: signal type
+ * @free_priv: function pointer to free private data
+ * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
+ */
+struct cfg80211_bss {
+	struct ieee80211_channel *channel;
+
+	u8 bssid[ETH_ALEN];
+	u64 tsf;
+	u16 beacon_interval;
+	u16 capability;
+	u8 *information_elements;
+	size_t len_information_elements;
+
+	s32 signal;
+	enum cfg80211_signal_type signal_type;
+
+	void (*free_priv)(struct cfg80211_bss *bss);
+	u8 priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -571,6 +654,11 @@
  * @set_channel: Set channel
  *
  * @set_mgmt_extra_ie: Set extra IE data for management frames
+ *
+ * @scan: Request to do a scan. If returning zero, the scan request is given
+ *	the driver, and will be valid until passed to cfg80211_scan_done().
+ *	For scan results, call cfg80211_inform_bss(); you can call this outside
+ *	the scan/scan_done bracket too.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy);
@@ -648,6 +736,9 @@
 	int	(*set_mgmt_extra_ie)(struct wiphy *wiphy,
 				     struct net_device *dev,
 				     struct mgmt_extra_ie_params *params);
+
+	int	(*scan)(struct wiphy *wiphy, struct net_device *dev,
+			struct cfg80211_scan_request *request);
 };
 
 /* temporary wext handlers */
@@ -658,5 +749,68 @@
 			  u32 *mode, char *extra);
 int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
 			  u32 *mode, char *extra);
+int cfg80211_wext_siwscan(struct net_device *dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *wrqu, char *extra);
+int cfg80211_wext_giwscan(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_point *data, char *extra);
+
+/**
+ * cfg80211_scan_done - notify that scan finished
+ *
+ * @request: the corresponding scan request
+ * @aborted: set to true if the scan was aborted for any reason,
+ *	userspace will be notified of that
+ */
+void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
+
+/**
+ * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ *
+ * @wiphy: the wiphy reporting the BSS
+ * @bss: the found BSS
+ * @gfp: context flags
+ *
+ * This informs cfg80211 that BSS information was found and
+ * the BSS should be updated/added.
+ */
+struct cfg80211_bss*
+cfg80211_inform_bss_frame(struct wiphy *wiphy,
+			  struct ieee80211_channel *channel,
+			  struct ieee80211_mgmt *mgmt, size_t len,
+			  s32 signal, enum cfg80211_signal_type sigtype,
+			  gfp_t gfp);
+
+struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
+				      struct ieee80211_channel *channel,
+				      const u8 *bssid,
+				      const u8 *ssid, size_t ssid_len,
+				      u16 capa_mask, u16 capa_val);
+static inline struct cfg80211_bss *
+cfg80211_get_ibss(struct wiphy *wiphy,
+		  struct ieee80211_channel *channel,
+		  const u8 *ssid, size_t ssid_len)
+{
+	return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len,
+				WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+}
+
+struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
+				       struct ieee80211_channel *channel,
+				       const u8 *meshid, size_t meshidlen,
+				       const u8 *meshcfg);
+void cfg80211_put_bss(struct cfg80211_bss *bss);
+/**
+ * cfg80211_unlink_bss - unlink BSS from internal data structures
+ * @wiphy: the wiphy
+ * @bss: the bss to remove
+ *
+ * This function removes the given BSS from the internal data structures
+ * thereby making it no longer show up in scan results etc. Use this
+ * function when you detect a BSS is gone. Normally BSSes will also time
+ * out, so it is not necessary to use this function at all.
+ */
+void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
 
 #endif /* __NET_CFG80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 409e2c6..88fa3e0 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1354,11 +1354,11 @@
  *
  * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
  *	this is only used for IBSS mode BSSID merging and debugging. Is not a
- *	required function. Must be atomic.
+ *	required function.
  *
  * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
  *      Currently, this is only used for IBSS mode debugging. Is not a
- *	required function. Must be atomic.
+ *	required function.
  *
  * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
  *	with other STAs in the IBSS. This is only used in IBSS mode. This
@@ -1406,7 +1406,8 @@
 	void (*update_tkip_key)(struct ieee80211_hw *hw,
 			struct ieee80211_key_conf *conf, const u8 *address,
 			u32 iv32, u16 *phase1key);
-	int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
+	int (*hw_scan)(struct ieee80211_hw *hw,
+		       struct cfg80211_scan_request *req);
 	int (*get_stats)(struct ieee80211_hw *hw,
 			 struct ieee80211_low_level_stats *stats);
 	void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
@@ -1844,8 +1845,9 @@
  * mac80211 that the scan finished.
  *
  * @hw: the hardware that finished the scan
+ * @aborted: set to true if scan was aborted
  */
-void ieee80211_scan_completed(struct ieee80211_hw *hw);
+void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
 
 /**
  * ieee80211_iterate_active_interfaces - iterate active interfaces
diff --git a/include/net/wireless.h b/include/net/wireless.h
index a42c156..1c6285e 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -213,6 +213,9 @@
 	bool custom_regulatory;
 	bool strict_regulatory;
 
+	int bss_priv_size;
+	u8 max_scan_ssids;
+
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
 	 * know whether it points to a wiphy your driver has registered
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 58c94bb..3503a3d 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -8,7 +8,7 @@
 	wep.o \
 	wpa.o \
 	scan.o \
-	ht.o \
+	ht.o agg-tx.o agg-rx.o \
 	mlme.o \
 	iface.o \
 	rate.o \
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
new file mode 100644
index 0000000..3112bfd
--- /dev/null
+++ b/net/mac80211/agg-rx.c
@@ -0,0 +1,302 @@
+/*
+ * HT handling
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+				    u16 initiator, u16 reason)
+{
+	struct ieee80211_local *local = sta->local;
+	struct ieee80211_hw *hw = &local->hw;
+	int i;
+
+	/* check if TID is in operational state */
+	spin_lock_bh(&sta->lock);
+	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) {
+		spin_unlock_bh(&sta->lock);
+		return;
+	}
+
+	sta->ampdu_mlme.tid_state_rx[tid] =
+		HT_AGG_STATE_REQ_STOP_BA_MSK |
+		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+	spin_unlock_bh(&sta->lock);
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
+	       sta->sta.addr, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	if (local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
+				     &sta->sta, tid, NULL))
+		printk(KERN_DEBUG "HW problem - can not stop rx "
+				"aggregation for tid %d\n", tid);
+
+	/* shutdown timer has not expired */
+	if (initiator != WLAN_BACK_TIMER)
+		del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
+
+	/* check if this is a self generated aggregation halt */
+	if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
+		ieee80211_send_delba(sta->sdata, sta->sta.addr,
+				     tid, 0, reason);
+
+	/* free the reordering buffer */
+	for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
+		if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
+			/* release the reordered frames */
+			dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
+			sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
+			sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
+		}
+	}
+
+	spin_lock_bh(&sta->lock);
+	/* free resources */
+	kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
+
+	if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) {
+		kfree(sta->ampdu_mlme.tid_rx[tid]);
+		sta->ampdu_mlme.tid_rx[tid] = NULL;
+	}
+
+	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
+	spin_unlock_bh(&sta->lock);
+}
+
+void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
+					u16 initiator, u16 reason)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta;
+
+	/* stop HW Rx aggregation. ampdu_action existence
+	 * already verified in session init so we add the BUG_ON */
+	BUG_ON(!local->ops->ampdu_action);
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
+
+	__ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
+
+	rcu_read_unlock();
+}
+
+/*
+ * After accepting the AddBA Request we activated a timer,
+ * resetting it after each frame that arrives from the originator.
+ * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
+ */
+static void sta_rx_agg_session_timer_expired(unsigned long data)
+{
+	/* not an elegant detour, but there is no choice as the timer passes
+	 * only one argument, and various sta_info are needed here, so init
+	 * flow in sta_info_create gives the TID as data, while the timer_to_id
+	 * array gives the sta through container_of */
+	u8 *ptid = (u8 *)data;
+	u8 *timer_to_id = ptid - *ptid;
+	struct sta_info *sta = container_of(timer_to_id, struct sta_info,
+					 timer_to_tid[0]);
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
+#endif
+	ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
+					 (u16)*ptid, WLAN_BACK_TIMER,
+					 WLAN_REASON_QSTA_TIMEOUT);
+}
+
+static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
+				      u8 dialog_token, u16 status, u16 policy,
+				      u16 buf_size, u16 timeout)
+{
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 capab;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer "
+		       "for addba resp frame\n", sdata->dev->name);
+		return;
+	}
+
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == NL80211_IFTYPE_AP ||
+	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
+	mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
+
+	capab = (u16)(policy << 1);	/* bit 1 aggregation policy */
+	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
+	capab |= (u16)(buf_size << 6);	/* bit 15:6 max size of aggregation */
+
+	mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
+	mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
+	mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
+
+	ieee80211_tx_skb(sdata, skb, 1);
+}
+
+void ieee80211_process_addba_request(struct ieee80211_local *local,
+				     struct sta_info *sta,
+				     struct ieee80211_mgmt *mgmt,
+				     size_t len)
+{
+	struct ieee80211_hw *hw = &local->hw;
+	struct ieee80211_conf *conf = &hw->conf;
+	struct tid_ampdu_rx *tid_agg_rx;
+	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
+	u8 dialog_token;
+	int ret = -EOPNOTSUPP;
+
+	/* extract session parameters from addba request frame */
+	dialog_token = mgmt->u.action.u.addba_req.dialog_token;
+	timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+	start_seq_num =
+		le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
+
+	capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+	ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
+	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+	buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+
+	status = WLAN_STATUS_REQUEST_DECLINED;
+
+	/* sanity check for incoming parameters:
+	 * check if configuration can support the BA policy
+	 * and if buffer size does not exceeds max value */
+	/* XXX: check own ht delayed BA capability?? */
+	if (((ba_policy != 1)
+		&& (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
+		|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
+		status = WLAN_STATUS_INVALID_QOS_PARAM;
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "AddBA Req with bad params from "
+				"%pM on tid %u. policy %d, buffer size %d\n",
+				mgmt->sa, tid, ba_policy,
+				buf_size);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto end_no_lock;
+	}
+	/* determine default buffer size */
+	if (buf_size == 0) {
+		struct ieee80211_supported_band *sband;
+
+		sband = local->hw.wiphy->bands[conf->channel->band];
+		buf_size = IEEE80211_MIN_AMPDU_BUF;
+		buf_size = buf_size << sband->ht_cap.ampdu_factor;
+	}
+
+
+	/* examine state machine */
+	spin_lock_bh(&sta->lock);
+
+	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "unexpected AddBA Req from "
+				"%pM on tid %u\n",
+				mgmt->sa, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto end;
+	}
+
+	/* prepare A-MPDU MLME for Rx aggregation */
+	sta->ampdu_mlme.tid_rx[tid] =
+			kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
+	if (!sta->ampdu_mlme.tid_rx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
+					tid);
+#endif
+		goto end;
+	}
+	/* rx timer */
+	sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
+				sta_rx_agg_session_timer_expired;
+	sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
+				(unsigned long)&sta->timer_to_tid[tid];
+	init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
+
+	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+
+	/* prepare reordering buffer */
+	tid_agg_rx->reorder_buf =
+		kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
+	if (!tid_agg_rx->reorder_buf) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_ERR "can not allocate reordering buffer "
+			       "to tid %d\n", tid);
+#endif
+		kfree(sta->ampdu_mlme.tid_rx[tid]);
+		goto end;
+	}
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
+					       &sta->sta, tid, &start_seq_num);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	if (ret) {
+		kfree(tid_agg_rx->reorder_buf);
+		kfree(tid_agg_rx);
+		sta->ampdu_mlme.tid_rx[tid] = NULL;
+		goto end;
+	}
+
+	/* change state and send addba resp */
+	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
+	tid_agg_rx->dialog_token = dialog_token;
+	tid_agg_rx->ssn = start_seq_num;
+	tid_agg_rx->head_seq_num = start_seq_num;
+	tid_agg_rx->buf_size = buf_size;
+	tid_agg_rx->timeout = timeout;
+	tid_agg_rx->stored_mpdu_num = 0;
+	status = WLAN_STATUS_SUCCESS;
+end:
+	spin_unlock_bh(&sta->lock);
+
+end_no_lock:
+	ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
+				  dialog_token, status, 1, buf_size, timeout);
+}
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
new file mode 100644
index 0000000..1232d9f
--- /dev/null
+++ b/net/mac80211/agg-tx.c
@@ -0,0 +1,636 @@
+/*
+ * HT handling
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2009, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "wme.h"
+
+/**
+ * DOC: TX aggregation
+ *
+ * Aggregation on the TX side requires setting the hardware flag
+ * %IEEE80211_HW_AMPDU_AGGREGATION as well as, if present, the @ampdu_queues
+ * hardware parameter to the number of hardware AMPDU queues. If there are no
+ * hardware queues then the driver will (currently) have to do all frame
+ * buffering.
+ *
+ * When TX aggregation is started by some subsystem (usually the rate control
+ * algorithm would be appropriate) by calling the
+ * ieee80211_start_tx_ba_session() function, the driver will be notified via
+ * its @ampdu_action function, with the %IEEE80211_AMPDU_TX_START action.
+ *
+ * In response to that, the driver is later required to call the
+ * ieee80211_start_tx_ba_cb() (or ieee80211_start_tx_ba_cb_irqsafe())
+ * function, which will start the aggregation session.
+ *
+ * Similarly, when the aggregation session is stopped by
+ * ieee80211_stop_tx_ba_session(), the driver's @ampdu_action function will
+ * be called with the action %IEEE80211_AMPDU_TX_STOP. In this case, the
+ * call must not fail, and the driver must later call ieee80211_stop_tx_ba_cb()
+ * (or ieee80211_stop_tx_ba_cb_irqsafe()).
+ */
+
+static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
+					 const u8 *da, u16 tid,
+					 u8 dialog_token, u16 start_seq_num,
+					 u16 agg_size, u16 timeout)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 capab;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer "
+				"for addba request frame\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == NL80211_IFTYPE_AP ||
+	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
+
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
+
+	mgmt->u.action.u.addba_req.dialog_token = dialog_token;
+	capab = (u16)(1 << 1);		/* bit 1 aggregation policy */
+	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
+	capab |= (u16)(agg_size << 6);	/* bit 15:6 max size of aggergation */
+
+	mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
+
+	mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
+	mgmt->u.action.u.addba_req.start_seq_num =
+					cpu_to_le16(start_seq_num << 4);
+
+	ieee80211_tx_skb(sdata, skb, 1);
+}
+
+void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct ieee80211_bar *bar;
+	u16 bar_control = 0;
+
+	skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer for "
+			"bar frame\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
+	memset(bar, 0, sizeof(*bar));
+	bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+					 IEEE80211_STYPE_BACK_REQ);
+	memcpy(bar->ra, ra, ETH_ALEN);
+	memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
+	bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
+	bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
+	bar_control |= (u16)(tid << 12);
+	bar->control = cpu_to_le16(bar_control);
+	bar->start_seq_num = cpu_to_le16(ssn);
+
+	ieee80211_tx_skb(sdata, skb, 0);
+}
+
+static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
+					   enum ieee80211_back_parties initiator)
+{
+	struct ieee80211_local *local = sta->local;
+	int ret;
+	u8 *state;
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+	if (local->hw.ampdu_queues)
+		ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]);
+
+	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
+		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+
+	ret = local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_STOP,
+				       &sta->sta, tid, NULL);
+
+	/* HW shall not deny going back to legacy */
+	if (WARN_ON(ret)) {
+		*state = HT_AGG_STATE_OPERATIONAL;
+		if (local->hw.ampdu_queues)
+			ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]);
+	}
+
+	return ret;
+}
+
+/*
+ * After sending add Block Ack request we activated a timer until
+ * add Block Ack response will arrive from the recipient.
+ * If this timer expires sta_addba_resp_timer_expired will be executed.
+ */
+static void sta_addba_resp_timer_expired(unsigned long data)
+{
+	/* not an elegant detour, but there is no choice as the timer passes
+	 * only one argument, and both sta_info and TID are needed, so init
+	 * flow in sta_info_create gives the TID as data, while the timer_to_id
+	 * array gives the sta through container_of */
+	u16 tid = *(u8 *)data;
+	struct sta_info *sta = container_of((void *)data,
+		struct sta_info, timer_to_tid[tid]);
+	u8 *state;
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+	/* check if the TID waits for addBA response */
+	spin_lock_bh(&sta->lock);
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		spin_unlock_bh(&sta->lock);
+		*state = HT_AGG_STATE_IDLE;
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "timer expired on tid %d but we are not "
+				"expecting addBA response there", tid);
+#endif
+		return;
+	}
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+#endif
+
+	___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
+	spin_unlock_bh(&sta->lock);
+}
+
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata;
+	u16 start_seq_num;
+	u8 *state;
+	int ret = 0;
+
+	if (WARN_ON(!local->ops->ampdu_action))
+		return -EINVAL;
+
+	if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+		return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
+	       ra, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Could not find the station\n");
+#endif
+		ret = -ENOENT;
+		goto exit;
+	}
+
+	/*
+	 * The aggregation code is not prepared to handle
+	 * anything but STA/AP due to the BSSID handling.
+	 * IBSS could work in the code but isn't supported
+	 * by drivers or the standard.
+	 */
+	if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
+	    sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+	    sta->sdata->vif.type != NL80211_IFTYPE_AP) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	spin_lock_bh(&sta->lock);
+
+	/* we have tried too many times, receiver does not want A-MPDU */
+	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
+		ret = -EBUSY;
+		goto err_unlock_sta;
+	}
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	/* check if the TID is not in aggregation flow already */
+	if (*state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - session is not "
+				 "idle on tid %u\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ret = -EAGAIN;
+		goto err_unlock_sta;
+	}
+
+	/* prepare A-MPDU MLME for Tx aggregation */
+	sta->ampdu_mlme.tid_tx[tid] =
+			kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
+	if (!sta->ampdu_mlme.tid_tx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
+					tid);
+#endif
+		ret = -ENOMEM;
+		goto err_unlock_sta;
+	}
+	/* Tx timer */
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
+			sta_addba_resp_timer_expired;
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
+			(unsigned long)&sta->timer_to_tid[tid];
+	init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+
+	if (hw->ampdu_queues) {
+		/* create a new queue for this aggregation */
+		ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+
+		/* case no queue is available to aggregation
+		 * don't switch to aggregation */
+		if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+			printk(KERN_DEBUG "BA request denied - "
+			       "queue unavailable for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+			goto err_unlock_queue;
+		}
+	}
+	sdata = sta->sdata;
+
+	/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
+	 * call back right away, it must see that the flow has begun */
+	*state |= HT_ADDBA_REQUESTED_MSK;
+
+	/* This is slightly racy because the queue isn't stopped */
+	start_seq_num = sta->tid_seq[tid];
+
+	ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
+				       &sta->sta, tid, &start_seq_num);
+
+	if (ret) {
+		/* No need to requeue the packets in the agg queue, since we
+		 * held the tx lock: no packet could be enqueued to the newly
+		 * allocated queue */
+		if (hw->ampdu_queues)
+			ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - HW unavailable for"
+					" tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		*state = HT_AGG_STATE_IDLE;
+		goto err_unlock_queue;
+	}
+
+	/* Will put all the packets in the new SW queue */
+	if (hw->ampdu_queues)
+		ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+	spin_unlock_bh(&sta->lock);
+
+	/* send an addBA request */
+	sta->ampdu_mlme.dialog_token_allocator++;
+	sta->ampdu_mlme.tid_tx[tid]->dialog_token =
+			sta->ampdu_mlme.dialog_token_allocator;
+	sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+
+
+	ieee80211_send_addba_request(sta->sdata, ra, tid,
+			 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
+			 sta->ampdu_mlme.tid_tx[tid]->ssn,
+			 0x40, 5000);
+	/* activate the timer for the recipient's addBA response */
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
+				jiffies + ADDBA_RESP_INTERVAL;
+	add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+#endif
+	goto exit;
+
+err_unlock_queue:
+	kfree(sta->ampdu_mlme.tid_tx[tid]);
+	sta->ampdu_mlme.tid_tx[tid] = NULL;
+	ret = -EBUSY;
+err_unlock_sta:
+	spin_unlock_bh(&sta->lock);
+exit:
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
+
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+
+	if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+				tid, STA_TID_NUM);
+#endif
+		return;
+	}
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		rcu_read_unlock();
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
+#endif
+		return;
+	}
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	spin_lock_bh(&sta->lock);
+
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
+				*state);
+#endif
+		spin_unlock_bh(&sta->lock);
+		rcu_read_unlock();
+		return;
+	}
+
+	WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+
+	*state |= HT_ADDBA_DRV_READY_MSK;
+
+	if (*state == HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+#endif
+		if (hw->ampdu_queues)
+			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+	}
+	spin_unlock_bh(&sta->lock);
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
+
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+				      const u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_ra_tid *ra_tid;
+	struct sk_buff *skb = dev_alloc_skb(0);
+
+	if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping start BA session", skb->dev->name);
+#endif
+		return;
+	}
+	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+	memcpy(&ra_tid->ra, ra, ETH_ALEN);
+	ra_tid->tid = tid;
+
+	skb->pkt_type = IEEE80211_ADDBA_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+
+int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
+				   enum ieee80211_back_parties initiator)
+{
+	u8 *state;
+	int ret;
+
+	/* check if the TID is in aggregation */
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	spin_lock_bh(&sta->lock);
+
+	if (*state != HT_AGG_STATE_OPERATIONAL) {
+		ret = -ENOENT;
+		goto unlock;
+	}
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
+	       sta->sta.addr, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
+
+ unlock:
+	spin_unlock_bh(&sta->lock);
+	return ret;
+}
+
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+				 u8 *ra, u16 tid,
+				 enum ieee80211_back_parties initiator)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	int ret = 0;
+
+	if (WARN_ON(!local->ops->ampdu_action))
+		return -EINVAL;
+
+	if (tid >= STA_TID_NUM)
+		return -EINVAL;
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+
+	ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator);
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
+
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	int agg_queue;
+
+	if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+				tid, STA_TID_NUM);
+#endif
+		return;
+	}
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
+	       ra, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
+#endif
+		rcu_read_unlock();
+		return;
+	}
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+	/* NOTE: no need to use sta->lock in this state check, as
+	 * ieee80211_stop_tx_ba_session will let only one stop call to
+	 * pass through per sta/tid
+	 */
+	if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
+#endif
+		rcu_read_unlock();
+		return;
+	}
+
+	if (*state & HT_AGG_STATE_INITIATOR_MSK)
+		ieee80211_send_delba(sta->sdata, ra, tid,
+			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+
+	if (hw->ampdu_queues) {
+		agg_queue = sta->tid_to_tx_q[tid];
+		ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+
+		/* We just requeued the all the frames that were in the
+		 * removed queue, and since we might miss a softirq we do
+		 * netif_schedule_queue.  ieee80211_wake_queue is not used
+		 * here as this queue is not necessarily stopped
+		 */
+		netif_schedule_queue(netdev_get_tx_queue(local->mdev,
+							 agg_queue));
+	}
+	spin_lock_bh(&sta->lock);
+	*state = HT_AGG_STATE_IDLE;
+	sta->ampdu_mlme.addba_req_num[tid] = 0;
+	kfree(sta->ampdu_mlme.tid_tx[tid]);
+	sta->ampdu_mlme.tid_tx[tid] = NULL;
+	spin_unlock_bh(&sta->lock);
+
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
+
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+				     const u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_ra_tid *ra_tid;
+	struct sk_buff *skb = dev_alloc_skb(0);
+
+	if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping stop BA session", skb->dev->name);
+#endif
+		return;
+	}
+	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+	memcpy(&ra_tid->ra, ra, ETH_ALEN);
+	ra_tid->tid = tid;
+
+	skb->pkt_type = IEEE80211_DELBA_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
+
+
+void ieee80211_process_addba_resp(struct ieee80211_local *local,
+				  struct sta_info *sta,
+				  struct ieee80211_mgmt *mgmt,
+				  size_t len)
+{
+	struct ieee80211_hw *hw = &local->hw;
+	u16 capab;
+	u16 tid, start_seq_num;
+	u8 *state;
+
+	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+	spin_lock_bh(&sta->lock);
+
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		spin_unlock_bh(&sta->lock);
+		return;
+	}
+
+	if (mgmt->u.action.u.addba_resp.dialog_token !=
+		sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
+		spin_unlock_bh(&sta->lock);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		return;
+	}
+
+	del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
+			== WLAN_STATUS_SUCCESS) {
+		*state |= HT_ADDBA_RECEIVED_MSK;
+		sta->ampdu_mlme.addba_req_num[tid] = 0;
+
+		if (*state == HT_AGG_STATE_OPERATIONAL &&
+		    local->hw.ampdu_queues)
+			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+
+		if (local->ops->ampdu_action) {
+			(void)local->ops->ampdu_action(hw,
+					       IEEE80211_AMPDU_TX_RESUME,
+					       &sta->sta, tid, &start_seq_num);
+		}
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+	} else {
+		sta->ampdu_mlme.addba_req_num[tid]++;
+		___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
+	}
+	spin_unlock_bh(&sta->lock);
+}
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a1a1344..c8d969b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1176,11 +1176,16 @@
 	return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 }
 
-static int set_mgmt_extra_ie_sta(struct ieee80211_if_sta *ifsta, u8 subtype,
-				 u8 *ies, size_t ies_len)
+static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata,
+				 u8 subtype, u8 *ies, size_t ies_len)
 {
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
 	switch (subtype) {
 	case IEEE80211_STYPE_PROBE_REQ >> 4:
+		if (local->ops->hw_scan)
+			break;
 		kfree(ifsta->ie_probereq);
 		ifsta->ie_probereq = ies;
 		ifsta->ie_probereq_len = ies_len;
@@ -1244,7 +1249,7 @@
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_ADHOC:
-		ret = set_mgmt_extra_ie_sta(&sdata->u.sta, params->subtype,
+		ret = set_mgmt_extra_ie_sta(sdata, params->subtype,
 					    ies, ies_len);
 		break;
 	default:
@@ -1272,6 +1277,25 @@
 #define ieee80211_resume NULL
 #endif
 
+static int ieee80211_scan(struct wiphy *wiphy,
+			  struct net_device *dev,
+			  struct cfg80211_scan_request *req)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+		return -EOPNOTSUPP;
+
+	return ieee80211_request_scan(sdata, req);
+}
+
 struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -1304,4 +1328,5 @@
 	.set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie,
 	.suspend = ieee80211_suspend,
 	.resume = ieee80211_resume,
+	.scan = ieee80211_scan,
 };
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 7a38d2e..82ea0b6 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -17,8 +17,6 @@
 #include <net/wireless.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
-#include "sta_info.h"
-#include "wme.h"
 
 void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
 				       struct ieee80211_ht_cap *ht_cap_ie,
@@ -155,105 +153,20 @@
 	return changed;
 }
 
-static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
-					 const u8 *da, u16 tid,
-					 u8 dialog_token, u16 start_seq_num,
-					 u16 agg_size, u16 timeout)
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
 {
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-	u16 capab;
+	int i;
 
-	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
-	if (!skb) {
-		printk(KERN_ERR "%s: failed to allocate buffer "
-				"for addba request frame\n", sdata->dev->name);
-		return;
+	for (i = 0; i <  STA_TID_NUM; i++) {
+		__ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
+		__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
+					       WLAN_REASON_QSTA_LEAVE_QBSS);
 	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, da, ETH_ALEN);
-	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-	if (sdata->vif.type == NL80211_IFTYPE_AP)
-		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
-	else
-		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-
-	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-					  IEEE80211_STYPE_ACTION);
-
-	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
-
-	mgmt->u.action.category = WLAN_CATEGORY_BACK;
-	mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
-
-	mgmt->u.action.u.addba_req.dialog_token = dialog_token;
-	capab = (u16)(1 << 1);		/* bit 1 aggregation policy */
-	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
-	capab |= (u16)(agg_size << 6);	/* bit 15:6 max size of aggergation */
-
-	mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
-
-	mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
-	mgmt->u.action.u.addba_req.start_seq_num =
-					cpu_to_le16(start_seq_num << 4);
-
-	ieee80211_tx_skb(sdata, skb, 1);
 }
 
-static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
-				      u8 dialog_token, u16 status, u16 policy,
-				      u16 buf_size, u16 timeout)
-{
-	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	struct ieee80211_local *local = sdata->local;
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-	u16 capab;
-
-	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
-	if (!skb) {
-		printk(KERN_DEBUG "%s: failed to allocate buffer "
-		       "for addba resp frame\n", sdata->dev->name);
-		return;
-	}
-
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, da, ETH_ALEN);
-	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-	if (sdata->vif.type == NL80211_IFTYPE_AP)
-		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
-	else
-		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-					  IEEE80211_STYPE_ACTION);
-
-	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
-	mgmt->u.action.category = WLAN_CATEGORY_BACK;
-	mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
-	mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
-
-	capab = (u16)(policy << 1);	/* bit 1 aggregation policy */
-	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
-	capab |= (u16)(buf_size << 6);	/* bit 15:6 max size of aggregation */
-
-	mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
-	mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
-	mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
-
-	ieee80211_tx_skb(sdata, skb, 1);
-}
-
-static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
-				 const u8 *da, u16 tid,
-				 u16 initiator, u16 reason_code)
+void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
+			  const u8 *da, u16 tid,
+			  u16 initiator, u16 reason_code)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
@@ -274,7 +187,8 @@
 	memset(mgmt, 0, 24);
 	memcpy(mgmt->da, da, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-	if (sdata->vif.type == NL80211_IFTYPE_AP)
+	if (sdata->vif.type == NL80211_IFTYPE_AP ||
+	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
 	else
 		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -294,767 +208,6 @@
 	ieee80211_tx_skb(sdata, skb, 1);
 }
 
-void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct sk_buff *skb;
-	struct ieee80211_bar *bar;
-	u16 bar_control = 0;
-
-	skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
-	if (!skb) {
-		printk(KERN_ERR "%s: failed to allocate buffer for "
-			"bar frame\n", sdata->dev->name);
-		return;
-	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-	bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
-	memset(bar, 0, sizeof(*bar));
-	bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
-					 IEEE80211_STYPE_BACK_REQ);
-	memcpy(bar->ra, ra, ETH_ALEN);
-	memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
-	bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
-	bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
-	bar_control |= (u16)(tid << 12);
-	bar->control = cpu_to_le16(bar_control);
-	bar->start_seq_num = cpu_to_le16(ssn);
-
-	ieee80211_tx_skb(sdata, skb, 0);
-}
-
-void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
-					u16 initiator, u16 reason)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_hw *hw = &local->hw;
-	struct sta_info *sta;
-	int ret, i;
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-		rcu_read_unlock();
-		return;
-	}
-
-	/* check if TID is in operational state */
-	spin_lock_bh(&sta->lock);
-	if (sta->ampdu_mlme.tid_state_rx[tid]
-				!= HT_AGG_STATE_OPERATIONAL) {
-		spin_unlock_bh(&sta->lock);
-		rcu_read_unlock();
-		return;
-	}
-	sta->ampdu_mlme.tid_state_rx[tid] =
-		HT_AGG_STATE_REQ_STOP_BA_MSK |
-		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
-	spin_unlock_bh(&sta->lock);
-
-	/* stop HW Rx aggregation. ampdu_action existence
-	 * already verified in session init so we add the BUG_ON */
-	BUG_ON(!local->ops->ampdu_action);
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
-	       ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
-				       &sta->sta, tid, NULL);
-	if (ret)
-		printk(KERN_DEBUG "HW problem - can not stop rx "
-				"aggregation for tid %d\n", tid);
-
-	/* shutdown timer has not expired */
-	if (initiator != WLAN_BACK_TIMER)
-		del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
-	/* check if this is a self generated aggregation halt */
-	if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
-		ieee80211_send_delba(sdata, ra, tid, 0, reason);
-
-	/* free the reordering buffer */
-	for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
-		if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
-			/* release the reordered frames */
-			dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
-			sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
-			sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
-		}
-	}
-	/* free resources */
-	kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
-	kfree(sta->ampdu_mlme.tid_rx[tid]);
-	sta->ampdu_mlme.tid_rx[tid] = NULL;
-	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
-
-	rcu_read_unlock();
-}
-
-
-/*
- * After sending add Block Ack request we activated a timer until
- * add Block Ack response will arrive from the recipient.
- * If this timer expires sta_addba_resp_timer_expired will be executed.
- */
-static void sta_addba_resp_timer_expired(unsigned long data)
-{
-	/* not an elegant detour, but there is no choice as the timer passes
-	 * only one argument, and both sta_info and TID are needed, so init
-	 * flow in sta_info_create gives the TID as data, while the timer_to_id
-	 * array gives the sta through container_of */
-	u16 tid = *(u8 *)data;
-	struct sta_info *temp_sta = container_of((void *)data,
-		struct sta_info, timer_to_tid[tid]);
-
-	struct ieee80211_local *local = temp_sta->local;
-	struct ieee80211_hw *hw = &local->hw;
-	struct sta_info *sta;
-	u8 *state;
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, temp_sta->sta.addr);
-	if (!sta) {
-		rcu_read_unlock();
-		return;
-	}
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	/* check if the TID waits for addBA response */
-	spin_lock_bh(&sta->lock);
-	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-		spin_unlock_bh(&sta->lock);
-		*state = HT_AGG_STATE_IDLE;
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "timer expired on tid %d but we are not "
-				"expecting addBA response there", tid);
-#endif
-		goto timer_expired_exit;
-	}
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
-#endif
-
-	/* go through the state check in stop_BA_session */
-	*state = HT_AGG_STATE_OPERATIONAL;
-	spin_unlock_bh(&sta->lock);
-	ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
-				     WLAN_BACK_INITIATOR);
-
-timer_expired_exit:
-	rcu_read_unlock();
-}
-
-void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
-{
-	struct ieee80211_local *local = sdata->local;
-	int i;
-
-	for (i = 0; i <  STA_TID_NUM; i++) {
-		ieee80211_stop_tx_ba_session(&local->hw, addr, i,
-					     WLAN_BACK_INITIATOR);
-		ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
-						 WLAN_BACK_RECIPIENT,
-						 WLAN_REASON_QSTA_LEAVE_QBSS);
-	}
-}
-
-int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	struct ieee80211_sub_if_data *sdata;
-	u16 start_seq_num;
-	u8 *state;
-	int ret = 0;
-
-	if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
-		return -EINVAL;
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
-	       ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find the station\n");
-#endif
-		ret = -ENOENT;
-		goto exit;
-	}
-
-	spin_lock_bh(&sta->lock);
-
-	/* we have tried too many times, receiver does not want A-MPDU */
-	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
-		ret = -EBUSY;
-		goto err_unlock_sta;
-	}
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	/* check if the TID is not in aggregation flow already */
-	if (*state != HT_AGG_STATE_IDLE) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - session is not "
-				 "idle on tid %u\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		ret = -EAGAIN;
-		goto err_unlock_sta;
-	}
-
-	/* prepare A-MPDU MLME for Tx aggregation */
-	sta->ampdu_mlme.tid_tx[tid] =
-			kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
-	if (!sta->ampdu_mlme.tid_tx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
-					tid);
-#endif
-		ret = -ENOMEM;
-		goto err_unlock_sta;
-	}
-	/* Tx timer */
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
-			sta_addba_resp_timer_expired;
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
-			(unsigned long)&sta->timer_to_tid[tid];
-	init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-
-	if (hw->ampdu_queues) {
-		/* create a new queue for this aggregation */
-		ret = ieee80211_ht_agg_queue_add(local, sta, tid);
-
-		/* case no queue is available to aggregation
-		 * don't switch to aggregation */
-		if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-			printk(KERN_DEBUG "BA request denied - "
-			       "queue unavailable for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-			goto err_unlock_queue;
-		}
-	}
-	sdata = sta->sdata;
-
-	/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
-	 * call back right away, it must see that the flow has begun */
-	*state |= HT_ADDBA_REQUESTED_MSK;
-
-	/* This is slightly racy because the queue isn't stopped */
-	start_seq_num = sta->tid_seq[tid];
-
-	if (local->ops->ampdu_action)
-		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
-					       &sta->sta, tid, &start_seq_num);
-
-	if (ret) {
-		/* No need to requeue the packets in the agg queue, since we
-		 * held the tx lock: no packet could be enqueued to the newly
-		 * allocated queue */
-		if (hw->ampdu_queues)
-			ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - HW unavailable for"
-					" tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		*state = HT_AGG_STATE_IDLE;
-		goto err_unlock_queue;
-	}
-
-	/* Will put all the packets in the new SW queue */
-	if (hw->ampdu_queues)
-		ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
-	spin_unlock_bh(&sta->lock);
-
-	/* send an addBA request */
-	sta->ampdu_mlme.dialog_token_allocator++;
-	sta->ampdu_mlme.tid_tx[tid]->dialog_token =
-			sta->ampdu_mlme.dialog_token_allocator;
-	sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
-
-
-	ieee80211_send_addba_request(sta->sdata, ra, tid,
-			 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
-			 sta->ampdu_mlme.tid_tx[tid]->ssn,
-			 0x40, 5000);
-	/* activate the timer for the recipient's addBA response */
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
-				jiffies + ADDBA_RESP_INTERVAL;
-	add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-#endif
-	goto exit;
-
-err_unlock_queue:
-	kfree(sta->ampdu_mlme.tid_tx[tid]);
-	sta->ampdu_mlme.tid_tx[tid] = NULL;
-	ret = -EBUSY;
-err_unlock_sta:
-	spin_unlock_bh(&sta->lock);
-exit:
-	rcu_read_unlock();
-	return ret;
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
-
-int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
-				 u8 *ra, u16 tid,
-				 enum ieee80211_back_parties initiator)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	u8 *state;
-	int ret = 0;
-
-	if (tid >= STA_TID_NUM)
-		return -EINVAL;
-
-	rcu_read_lock();
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-		rcu_read_unlock();
-		return -ENOENT;
-	}
-
-	/* check if the TID is in aggregation */
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	spin_lock_bh(&sta->lock);
-
-	if (*state != HT_AGG_STATE_OPERATIONAL) {
-		ret = -ENOENT;
-		goto stop_BA_exit;
-	}
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
-	       ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	if (hw->ampdu_queues)
-		ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
-
-	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
-		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
-
-	if (local->ops->ampdu_action)
-		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
-					       &sta->sta, tid, NULL);
-
-	/* case HW denied going back to legacy */
-	if (ret) {
-		WARN_ON(ret != -EBUSY);
-		*state = HT_AGG_STATE_OPERATIONAL;
-		if (hw->ampdu_queues)
-			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-		goto stop_BA_exit;
-	}
-
-stop_BA_exit:
-	spin_unlock_bh(&sta->lock);
-	rcu_read_unlock();
-	return ret;
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
-
-void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	u8 *state;
-
-	if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-				tid, STA_TID_NUM);
-#endif
-		return;
-	}
-
-	rcu_read_lock();
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-		rcu_read_unlock();
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
-		return;
-	}
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	spin_lock_bh(&sta->lock);
-
-	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
-				*state);
-#endif
-		spin_unlock_bh(&sta->lock);
-		rcu_read_unlock();
-		return;
-	}
-
-	WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
-
-	*state |= HT_ADDBA_DRV_READY_MSK;
-
-	if (*state == HT_AGG_STATE_OPERATIONAL) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
-#endif
-		if (hw->ampdu_queues)
-			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-	}
-	spin_unlock_bh(&sta->lock);
-	rcu_read_unlock();
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
-
-void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	u8 *state;
-	int agg_queue;
-
-	if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-				tid, STA_TID_NUM);
-#endif
-		return;
-	}
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
-	       ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	rcu_read_lock();
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
-		rcu_read_unlock();
-		return;
-	}
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-
-	/* NOTE: no need to use sta->lock in this state check, as
-	 * ieee80211_stop_tx_ba_session will let only one stop call to
-	 * pass through per sta/tid
-	 */
-	if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
-#endif
-		rcu_read_unlock();
-		return;
-	}
-
-	if (*state & HT_AGG_STATE_INITIATOR_MSK)
-		ieee80211_send_delba(sta->sdata, ra, tid,
-			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
-
-	if (hw->ampdu_queues) {
-		agg_queue = sta->tid_to_tx_q[tid];
-		ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
-
-		/* We just requeued the all the frames that were in the
-		 * removed queue, and since we might miss a softirq we do
-		 * netif_schedule_queue.  ieee80211_wake_queue is not used
-		 * here as this queue is not necessarily stopped
-		 */
-		netif_schedule_queue(netdev_get_tx_queue(local->mdev,
-							 agg_queue));
-	}
-	spin_lock_bh(&sta->lock);
-	*state = HT_AGG_STATE_IDLE;
-	sta->ampdu_mlme.addba_req_num[tid] = 0;
-	kfree(sta->ampdu_mlme.tid_tx[tid]);
-	sta->ampdu_mlme.tid_tx[tid] = NULL;
-	spin_unlock_bh(&sta->lock);
-
-	rcu_read_unlock();
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
-
-void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
-				      const u8 *ra, u16 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_ra_tid *ra_tid;
-	struct sk_buff *skb = dev_alloc_skb(0);
-
-	if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_WARNING "%s: Not enough memory, "
-			       "dropping start BA session", skb->dev->name);
-#endif
-		return;
-	}
-	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-	memcpy(&ra_tid->ra, ra, ETH_ALEN);
-	ra_tid->tid = tid;
-
-	skb->pkt_type = IEEE80211_ADDBA_MSG;
-	skb_queue_tail(&local->skb_queue, skb);
-	tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
-
-void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
-				     const u8 *ra, u16 tid)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_ra_tid *ra_tid;
-	struct sk_buff *skb = dev_alloc_skb(0);
-
-	if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_WARNING "%s: Not enough memory, "
-			       "dropping stop BA session", skb->dev->name);
-#endif
-		return;
-	}
-	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-	memcpy(&ra_tid->ra, ra, ETH_ALEN);
-	ra_tid->tid = tid;
-
-	skb->pkt_type = IEEE80211_DELBA_MSG;
-	skb_queue_tail(&local->skb_queue, skb);
-	tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
-
-/*
- * After accepting the AddBA Request we activated a timer,
- * resetting it after each frame that arrives from the originator.
- * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
- */
-static void sta_rx_agg_session_timer_expired(unsigned long data)
-{
-	/* not an elegant detour, but there is no choice as the timer passes
-	 * only one argument, and various sta_info are needed here, so init
-	 * flow in sta_info_create gives the TID as data, while the timer_to_id
-	 * array gives the sta through container_of */
-	u8 *ptid = (u8 *)data;
-	u8 *timer_to_id = ptid - *ptid;
-	struct sta_info *sta = container_of(timer_to_id, struct sta_info,
-					 timer_to_tid[0]);
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
-#endif
-	ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
-					 (u16)*ptid, WLAN_BACK_TIMER,
-					 WLAN_REASON_QSTA_TIMEOUT);
-}
-
-void ieee80211_process_addba_request(struct ieee80211_local *local,
-				     struct sta_info *sta,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len)
-{
-	struct ieee80211_hw *hw = &local->hw;
-	struct ieee80211_conf *conf = &hw->conf;
-	struct tid_ampdu_rx *tid_agg_rx;
-	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
-	u8 dialog_token;
-	int ret = -EOPNOTSUPP;
-
-	/* extract session parameters from addba request frame */
-	dialog_token = mgmt->u.action.u.addba_req.dialog_token;
-	timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
-	start_seq_num =
-		le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
-
-	capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
-	ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
-	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-	buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
-
-	status = WLAN_STATUS_REQUEST_DECLINED;
-
-	/* sanity check for incoming parameters:
-	 * check if configuration can support the BA policy
-	 * and if buffer size does not exceeds max value */
-	/* XXX: check own ht delayed BA capability?? */
-	if (((ba_policy != 1)
-		&& (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
-		|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
-		status = WLAN_STATUS_INVALID_QOS_PARAM;
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_DEBUG "AddBA Req with bad params from "
-				"%pM on tid %u. policy %d, buffer size %d\n",
-				mgmt->sa, tid, ba_policy,
-				buf_size);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		goto end_no_lock;
-	}
-	/* determine default buffer size */
-	if (buf_size == 0) {
-		struct ieee80211_supported_band *sband;
-
-		sband = local->hw.wiphy->bands[conf->channel->band];
-		buf_size = IEEE80211_MIN_AMPDU_BUF;
-		buf_size = buf_size << sband->ht_cap.ampdu_factor;
-	}
-
-
-	/* examine state machine */
-	spin_lock_bh(&sta->lock);
-
-	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_DEBUG "unexpected AddBA Req from "
-				"%pM on tid %u\n",
-				mgmt->sa, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		goto end;
-	}
-
-	/* prepare A-MPDU MLME for Rx aggregation */
-	sta->ampdu_mlme.tid_rx[tid] =
-			kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
-	if (!sta->ampdu_mlme.tid_rx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
-					tid);
-#endif
-		goto end;
-	}
-	/* rx timer */
-	sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
-				sta_rx_agg_session_timer_expired;
-	sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
-				(unsigned long)&sta->timer_to_tid[tid];
-	init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
-	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
-
-	/* prepare reordering buffer */
-	tid_agg_rx->reorder_buf =
-		kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
-	if (!tid_agg_rx->reorder_buf) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		if (net_ratelimit())
-			printk(KERN_ERR "can not allocate reordering buffer "
-			       "to tid %d\n", tid);
-#endif
-		kfree(sta->ampdu_mlme.tid_rx[tid]);
-		goto end;
-	}
-
-	if (local->ops->ampdu_action)
-		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
-					       &sta->sta, tid, &start_seq_num);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
-	if (ret) {
-		kfree(tid_agg_rx->reorder_buf);
-		kfree(tid_agg_rx);
-		sta->ampdu_mlme.tid_rx[tid] = NULL;
-		goto end;
-	}
-
-	/* change state and send addba resp */
-	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
-	tid_agg_rx->dialog_token = dialog_token;
-	tid_agg_rx->ssn = start_seq_num;
-	tid_agg_rx->head_seq_num = start_seq_num;
-	tid_agg_rx->buf_size = buf_size;
-	tid_agg_rx->timeout = timeout;
-	tid_agg_rx->stored_mpdu_num = 0;
-	status = WLAN_STATUS_SUCCESS;
-end:
-	spin_unlock_bh(&sta->lock);
-
-end_no_lock:
-	ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
-				  dialog_token, status, 1, buf_size, timeout);
-}
-
-void ieee80211_process_addba_resp(struct ieee80211_local *local,
-				  struct sta_info *sta,
-				  struct ieee80211_mgmt *mgmt,
-				  size_t len)
-{
-	struct ieee80211_hw *hw = &local->hw;
-	u16 capab;
-	u16 tid, start_seq_num;
-	u8 *state;
-
-	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
-	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-
-	spin_lock_bh(&sta->lock);
-
-	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-		spin_unlock_bh(&sta->lock);
-		return;
-	}
-
-	if (mgmt->u.action.u.addba_resp.dialog_token !=
-		sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
-		spin_unlock_bh(&sta->lock);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		return;
-	}
-
-	del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
-			== WLAN_STATUS_SUCCESS) {
-		*state |= HT_ADDBA_RECEIVED_MSK;
-		sta->ampdu_mlme.addba_req_num[tid] = 0;
-
-		if (*state == HT_AGG_STATE_OPERATIONAL &&
-		    local->hw.ampdu_queues)
-			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-
-		if (local->ops->ampdu_action) {
-			(void)local->ops->ampdu_action(hw,
-					       IEEE80211_AMPDU_TX_RESUME,
-					       &sta->sta, tid, &start_seq_num);
-		}
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		spin_unlock_bh(&sta->lock);
-	} else {
-		sta->ampdu_mlme.addba_req_num[tid]++;
-		/* this will allow the state check in stop_BA_session */
-		*state = HT_AGG_STATE_OPERATIONAL;
-		spin_unlock_bh(&sta->lock);
-		ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
-					     WLAN_BACK_INITIATOR);
-	}
-}
-
 void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 			     struct sta_info *sta,
 			     struct ieee80211_mgmt *mgmt, size_t len)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index eaf3603..2cb743e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -57,6 +57,8 @@
  */
 #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
 
+#define TU_TO_EXP_TIME(x)	(jiffies + usecs_to_jiffies((x) * 1024))
+
 struct ieee80211_fragment_entry {
 	unsigned long first_frag_time;
 	unsigned int seq;
@@ -70,43 +72,36 @@
 
 
 struct ieee80211_bss {
-	struct list_head list;
-	struct ieee80211_bss *hnext;
+	/* Yes, this is a hack */
+	struct cfg80211_bss cbss;
+
+	/* don't want to look up all the time */
 	size_t ssid_len;
-
-	atomic_t users;
-
-	u8 bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
+
 	u8 dtim_period;
-	u16 capability; /* host byte order */
-	enum ieee80211_band band;
-	int freq;
-	int signal, noise, qual;
-	u8 *ies; /* all information elements from the last Beacon or Probe
-		  * Response frames; note Beacon frame is not allowed to
-		  * override values from Probe Response */
-	size_t ies_len;
+
 	bool wmm_used;
+
+	unsigned long last_probe_resp;
+
 #ifdef CONFIG_MAC80211_MESH
 	u8 *mesh_id;
 	size_t mesh_id_len;
 	u8 *mesh_cfg;
 #endif
+
 #define IEEE80211_MAX_SUPP_RATES 32
 	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 	size_t supp_rates_len;
-	u64 timestamp;
-	int beacon_int;
 
-	unsigned long last_probe_resp;
-	unsigned long last_update;
-
-	/* during assocation, we save an ERP value from a probe response so
+	/*
+	 * During assocation, we save an ERP value from a probe response so
 	 * that we can feed ERP info to the driver when handling the
 	 * association completes. these fields probably won't be up-to-date
-	 * otherwise, you probably don't want to use them. */
-	int has_erp_value;
+	 * otherwise, you probably don't want to use them.
+	 */
+	bool has_erp_value;
 	u8 erp_value;
 };
 
@@ -292,8 +287,6 @@
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	enum ieee80211_sta_mlme_state state;
 	size_t ssid_len;
-	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
-	size_t scan_ssid_len;
 	u16 aid;
 	u16 ap_capab, capab;
 	u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -599,7 +592,6 @@
 	int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
 	unsigned int filter_flags; /* FIF_* */
 	struct iw_statistics wstats;
-	u8 wstats_flags;
 	bool tim_in_locked_section; /* see ieee80211_beacon_get() */
 	int tx_headroom; /* required headroom for hardware/radiotap */
 
@@ -656,20 +648,18 @@
 
 	/* Scanning and BSS list */
 	bool sw_scanning, hw_scanning;
+	struct cfg80211_ssid scan_ssid;
+	struct cfg80211_scan_request int_scan_req;
+	struct cfg80211_scan_request *scan_req;
+	struct ieee80211_channel *scan_channel;
 	int scan_channel_idx;
-	enum ieee80211_band scan_band;
 
 	enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
 	unsigned long last_scan_completed;
 	struct delayed_work scan_work;
 	struct ieee80211_sub_if_data *scan_sdata;
-	struct ieee80211_channel *oper_channel, *scan_channel, *csa_channel;
 	enum nl80211_channel_type oper_channel_type;
-	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
-	size_t scan_ssid_len;
-	struct list_head bss_list;
-	struct ieee80211_bss *bss_hash[STA_HASH_SIZE];
-	spinlock_t bss_lock;
+	struct ieee80211_channel *oper_channel, *csa_channel;
 
 	/* SNMP counters */
 	/* dot11CountersTable */
@@ -728,6 +718,7 @@
 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
 	bool powersave;
+	bool pspolling;
 	struct work_struct dynamic_ps_enable_work;
 	struct work_struct dynamic_ps_disable_work;
 	struct timer_list dynamic_ps_timer;
@@ -921,10 +912,12 @@
 			    enum ieee80211_band band);
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
 			      u8 *ssid, size_t ssid_len);
+void ieee80211_send_pspoll(struct ieee80211_local *local,
+			   struct ieee80211_sub_if_data *sdata);
 
 /* scan/BSS handling */
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
-			   u8 *ssid, size_t ssid_len);
+			   struct cfg80211_scan_request *req);
 int ieee80211_scan_results(struct ieee80211_local *local,
 			   struct iw_request_info *info,
 			   char *buf, size_t len);
@@ -932,29 +925,27 @@
 ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
 		  struct sk_buff *skb,
 		  struct ieee80211_rx_status *rx_status);
-void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
-void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
 int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
 			       char *ie, size_t len);
 
 void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
 int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
-			 u8 *ssid, size_t ssid_len);
+			 struct cfg80211_scan_request *req);
 struct ieee80211_bss *
 ieee80211_bss_info_update(struct ieee80211_local *local,
 			  struct ieee80211_rx_status *rx_status,
 			  struct ieee80211_mgmt *mgmt,
 			  size_t len,
 			  struct ieee802_11_elems *elems,
-			  int freq, bool beacon);
-struct ieee80211_bss *
-ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
-		     u8 *ssid, u8 ssid_len);
+			  struct ieee80211_channel *channel,
+			  bool beacon);
 struct ieee80211_bss *
 ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
 		     u8 *ssid, u8 ssid_len);
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
 			  struct ieee80211_bss *bss);
+void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
+			     int freq, u8 *ssid, u8 ssid_len);
 
 /* interface handling */
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
@@ -980,10 +971,15 @@
 			struct ieee80211_ht_info *hti,
 			u16 ap_ht_cap_flags);
 void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
+void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
+			  const u8 *da, u16 tid,
+			  u16 initiator, u16 reason_code);
 
 void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
 				u16 tid, u16 initiator, u16 reason);
-void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr);
+void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+				    u16 initiator, u16 reason);
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
 void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 			     struct sta_info *sta,
 			     struct ieee80211_mgmt *mgmt, size_t len);
@@ -996,6 +992,9 @@
 				     struct ieee80211_mgmt *mgmt,
 				     size_t len);
 
+int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
+				   enum ieee80211_back_parties initiator);
+
 /* Spectrum management */
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
 				       struct ieee80211_mgmt *mgmt,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 915d043..df94b93 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -362,8 +362,7 @@
 
 	list_for_each_entry_rcu(sta, &local->sta_list, list) {
 		if (sta->sdata == sdata)
-			ieee80211_sta_tear_down_BA_sessions(sdata,
-							    sta->sta.addr);
+			ieee80211_sta_tear_down_BA_sessions(sta);
 	}
 
 	rcu_read_unlock();
@@ -523,7 +522,7 @@
 			 * scan event to userspace -- the scan is incomplete.
 			 */
 			if (local->sw_scanning)
-				ieee80211_scan_completed(&local->hw);
+				ieee80211_scan_completed(&local->hw, true);
 		}
 
 		conf.vif = &sdata->vif;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index caf9242..5667f4e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -210,6 +210,8 @@
 					!!rcu_dereference(sdata->u.ap.beacon);
 				break;
 			case NL80211_IFTYPE_ADHOC:
+				conf.enable_beacon = !!sdata->u.sta.probe_resp;
+				break;
 			case NL80211_IFTYPE_MESH_POINT:
 				conf.enable_beacon = true;
 				break;
@@ -731,6 +733,10 @@
 		return NULL;
 
 	wiphy->privid = mac80211_wiphy_privid;
+	wiphy->max_scan_ssids = 4;
+	/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
+	wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
+			       sizeof(struct cfg80211_bss);
 
 	local = wiphy_priv(wiphy);
 	local->hw.wiphy = wiphy;
@@ -815,25 +821,33 @@
 	enum ieee80211_band band;
 	struct net_device *mdev;
 	struct ieee80211_master_priv *mpriv;
+	int channels, i, j;
 
 	/*
 	 * generic code guarantees at least one band,
 	 * set this very early because much code assumes
 	 * that hw.conf.channel is assigned
 	 */
+	channels = 0;
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 		struct ieee80211_supported_band *sband;
 
 		sband = local->hw.wiphy->bands[band];
-		if (sband) {
+		if (sband && !local->oper_channel) {
 			/* init channel we're on */
 			local->hw.conf.channel =
 			local->oper_channel =
 			local->scan_channel = &sband->channels[0];
-			break;
 		}
+		if (sband)
+			channels += sband->n_channels;
 	}
 
+	local->int_scan_req.n_channels = channels;
+	local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL);
+	if (!local->int_scan_req.channels)
+		return -ENOMEM;
+
 	/* if low-level driver supports AP, we also support VLAN */
 	if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
 		local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
@@ -843,7 +857,7 @@
 
 	result = wiphy_register(local->hw.wiphy);
 	if (result < 0)
-		return result;
+		goto fail_wiphy_register;
 
 	/*
 	 * We use the number of queues for feature tests (QoS, HT) internally
@@ -866,8 +880,6 @@
 	mpriv->local = local;
 	local->mdev = mdev;
 
-	ieee80211_rx_bss_list_init(local);
-
 	local->hw.workqueue =
 		create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
 	if (!local->hw.workqueue) {
@@ -893,14 +905,6 @@
 
 	local->hw.conf.listen_interval = local->hw.max_listen_interval;
 
-	local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
-						  IEEE80211_HW_SIGNAL_DBM) ?
-			       IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
-	local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
-			       IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
-	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
-		local->wstats_flags |= IW_QUAL_DBM;
-
 	result = sta_info_start(local);
 	if (result < 0)
 		goto fail_sta_info;
@@ -946,6 +950,20 @@
 
 	ieee80211_led_init(local);
 
+	/* alloc internal scan request */
+	i = 0;
+	local->int_scan_req.ssids = &local->scan_ssid;
+	local->int_scan_req.n_ssids = 1;
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		if (!hw->wiphy->bands[band])
+			continue;
+		for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
+			local->int_scan_req.channels[i] =
+				&hw->wiphy->bands[band]->channels[j];
+			i++;
+		}
+	}
+
 	return 0;
 
 fail_wep:
@@ -964,6 +982,8 @@
 		free_netdev(local->mdev);
 fail_mdev_alloc:
 	wiphy_unregister(local->hw.wiphy);
+fail_wiphy_register:
+	kfree(local->int_scan_req.channels);
 	return result;
 }
 EXPORT_SYMBOL(ieee80211_register_hw);
@@ -991,7 +1011,6 @@
 
 	rtnl_unlock();
 
-	ieee80211_rx_bss_list_deinit(local);
 	ieee80211_clear_tx_pending(local);
 	sta_info_stop(local);
 	rate_control_deinitialize(local);
@@ -1009,6 +1028,7 @@
 	ieee80211_wep_free(local);
 	ieee80211_led_exit(local);
 	free_netdev(local->mdev);
+	kfree(local->int_scan_req.channels);
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 8a1fcae..9a3e5de 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -275,16 +275,6 @@
 		& tbl->hash_mask;
 }
 
-u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len)
-{
-	if (!mesh_id_len)
-		return 1;
-	else if (mesh_id_len == 1)
-		return (u8) mesh_id[0];
-	else
-		return (u8) (mesh_id[0] + 2 * mesh_id[1]);
-}
-
 struct mesh_table *mesh_table_alloc(int size_order)
 {
 	int i;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 9e064ee..d891d7d 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -196,7 +196,6 @@
 
 /* Public interfaces */
 /* Various */
-u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len);
 int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
 		struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 4f862b2..60b35ac 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -58,7 +58,6 @@
 #define PERR_IE_DST_ADDR(x)	(x + 2)
 #define PERR_IE_DST_DSN(x)	u32_field_get(x, 8, 0);
 
-#define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000))
 #define MSEC_TO_TU(x) (x*1000/1024)
 #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0)
 #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 57967d3..fbb766a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -55,10 +55,10 @@
 {
 	u8 *end, *pos;
 
-	pos = bss->ies;
+	pos = bss->cbss.information_elements;
 	if (pos == NULL)
 		return NULL;
-	end = pos + bss->ies_len;
+	end = pos + bss->cbss.len_information_elements;
 
 	while (pos + 1 < end) {
 		if (pos + 2 + pos[1] > end)
@@ -289,7 +289,7 @@
 				   local->hw.conf.channel->center_freq,
 				   ifsta->ssid, ifsta->ssid_len);
 	if (bss) {
-		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+		if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
 			capab |= WLAN_CAPABILITY_PRIVACY;
 		if (bss->wmm_used)
 			wmm = 1;
@@ -300,7 +300,7 @@
 		 * b-only mode) */
 		rates_len = ieee80211_compatible_rates(bss, sband, &rates);
 
-		if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+		if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
 		    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
 			capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
@@ -511,16 +511,50 @@
 	ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED);
 }
 
+void ieee80211_send_pspoll(struct ieee80211_local *local,
+			   struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_pspoll *pspoll;
+	struct sk_buff *skb;
+	u16 fc;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for "
+		       "pspoll frame\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
+	memset(pspoll, 0, sizeof(*pspoll));
+	fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;
+	pspoll->frame_control = cpu_to_le16(fc);
+	pspoll->aid = cpu_to_le16(ifsta->aid);
+
+	/* aid in PS-Poll has its two MSBs each set to 1 */
+	pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
+
+	memcpy(pspoll->bssid, ifsta->bssid, ETH_ALEN);
+	memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
+
+	ieee80211_tx_skb(sdata, skb, 0);
+
+	return;
+}
+
 /* MLME */
 static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
-					 struct ieee80211_bss *bss)
+					 const size_t supp_rates_len,
+					 const u8 *supp_rates)
 {
 	struct ieee80211_local *local = sdata->local;
 	int i, have_higher_than_11mbit = 0;
 
 	/* cf. IEEE 802.11 9.2.12 */
-	for (i = 0; i < bss->supp_rates_len; i++)
-		if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
+	for (i = 0; i < supp_rates_len; i++)
+		if ((supp_rates[i] & 0x7f) * 5 > 110)
 			have_higher_than_11mbit = 1;
 
 	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
@@ -611,7 +645,7 @@
 	}
 }
 
-static bool check_tim(struct ieee802_11_elems *elems, u16 aid, bool *is_mc)
+static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid)
 {
 	u8 mask;
 	u8 index, indexn1, indexn2;
@@ -621,9 +655,6 @@
 	index = aid / 8;
 	mask  = 1 << (aid & 7);
 
-	if (tim->bitmap_ctrl & 0x01)
-		*is_mc = true;
-
 	indexn1 = tim->bitmap_ctrl & 0xfe;
 	indexn2 = elems->tim_len + indexn1 - 4;
 
@@ -777,20 +808,17 @@
 	bss_info_changed |= BSS_CHANGED_ASSOC;
 	ifsta->flags |= IEEE80211_STA_ASSOCIATED;
 
-	if (sdata->vif.type != NL80211_IFTYPE_STATION)
-		return;
-
 	bss = ieee80211_rx_bss_get(local, ifsta->bssid,
 				   conf->channel->center_freq,
 				   ifsta->ssid, ifsta->ssid_len);
 	if (bss) {
 		/* set timing information */
-		sdata->vif.bss_conf.beacon_int = bss->beacon_int;
-		sdata->vif.bss_conf.timestamp = bss->timestamp;
+		sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
+		sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
 		sdata->vif.bss_conf.dtim_period = bss->dtim_period;
 
 		bss_info_changed |= ieee80211_handle_bss_capability(sdata,
-			bss->capability, bss->has_erp_value, bss->erp_value);
+			bss->cbss.capability, bss->has_erp_value, bss->erp_value);
 
 		ieee80211_rx_bss_put(local, bss);
 	}
@@ -840,6 +868,14 @@
 		       sdata->dev->name, ifsta->bssid);
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
 		ieee80211_sta_send_apinfo(sdata, ifsta);
+
+		/*
+		 * Most likely AP is not in the range so remove the
+		 * bss information associated to the AP
+		 */
+		ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+				sdata->local->hw.conf.channel->center_freq,
+				ifsta->ssid, ifsta->ssid_len);
 		return;
 	}
 
@@ -871,6 +907,9 @@
 		       sdata->dev->name, ifsta->bssid);
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
 		ieee80211_sta_send_apinfo(sdata, ifsta);
+		ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+				sdata->local->hw.conf.channel->center_freq,
+				ifsta->ssid, ifsta->ssid_len);
 		return;
 	}
 
@@ -913,7 +952,7 @@
 	netif_tx_stop_all_queues(sdata->dev);
 	netif_carrier_off(sdata->dev);
 
-	ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr);
+	ieee80211_sta_tear_down_BA_sessions(sta);
 
 	if (self_disconnected) {
 		if (deauth)
@@ -933,8 +972,12 @@
 
 	ieee80211_sta_send_apinfo(sdata, ifsta);
 
-	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT)
+	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
+		ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+				sdata->local->hw.conf.channel->center_freq,
+				ifsta->ssid, ifsta->ssid_len);
+	}
 
 	rcu_read_unlock();
 
@@ -995,7 +1038,7 @@
 	if (!bss)
 		return 0;
 
-	bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
+	bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY);
 	wep_privacy = !!ieee80211_sta_wep_configured(sdata);
 	privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
 
@@ -1017,6 +1060,9 @@
 		       sdata->dev->name, ifsta->bssid);
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
 		ieee80211_sta_send_apinfo(sdata, ifsta);
+		ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+				sdata->local->hw.conf.channel->center_freq,
+				ifsta->ssid, ifsta->ssid_len);
 		return;
 	}
 
@@ -1042,7 +1088,6 @@
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	int disassoc;
-	bool remove_bss = false;
 
 	/* TODO: start monitoring current AP signal quality and number of
 	 * missed beacons. Scan other channels every now and then and search
@@ -1068,7 +1113,6 @@
 				       "range\n",
 				       sdata->dev->name, ifsta->bssid);
 				disassoc = 1;
-				remove_bss = true;
 			} else
 				ieee80211_send_probe_req(sdata, ifsta->bssid,
 							 ifsta->ssid,
@@ -1088,24 +1132,12 @@
 
 	rcu_read_unlock();
 
-	if (disassoc) {
+	if (disassoc)
 		ieee80211_set_disassoc(sdata, ifsta, true, true,
 					WLAN_REASON_PREV_AUTH_NOT_VALID);
-		if (remove_bss) {
-			struct ieee80211_bss *bss;
-
-			bss = ieee80211_rx_bss_get(local, ifsta->bssid,
-					local->hw.conf.channel->center_freq,
-					ifsta->ssid, ifsta->ssid_len);
-			if (bss) {
-				atomic_dec(&bss->users);
-				ieee80211_rx_bss_put(local, bss);
-			}
-		}
-	} else {
+	else
 		mod_timer(&ifsta->timer, jiffies +
 				      IEEE80211_MONITORING_INTERVAL);
-	}
 }
 
 
@@ -1134,6 +1166,30 @@
 			    elems.challenge_len + 2, 1);
 }
 
+static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
+					struct ieee80211_if_sta *ifsta,
+					struct ieee80211_mgmt *mgmt,
+					size_t len)
+{
+	u16 auth_alg, auth_transaction, status_code;
+
+	if (len < 24 + 6)
+		return;
+
+	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+	status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+	/*
+	 * IEEE 802.11 standard does not require authentication in IBSS
+	 * networks and most implementations do not seem to use it.
+	 * However, try to reply to authentication attempts if someone
+	 * has actually implemented this.
+	 */
+	if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
+		ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
+}
+
 static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_if_sta *ifsta,
 				   struct ieee80211_mgmt *mgmt,
@@ -1141,37 +1197,22 @@
 {
 	u16 auth_alg, auth_transaction, status_code;
 
-	if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
-	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
+	if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE)
 		return;
 
 	if (len < 24 + 6)
 		return;
 
-	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-	    memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
+	if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
 		return;
 
-	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-	    memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
+	if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
 		return;
 
 	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
 	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
 	status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
-	if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-		/*
-		 * IEEE 802.11 standard does not require authentication in IBSS
-		 * networks and most implementations do not seem to use it.
-		 * However, try to reply to authentication attempts if someone
-		 * has actually implemented this.
-		 */
-		if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
-			return;
-		ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
-	}
-
 	if (auth_alg != ifsta->auth_alg ||
 	    auth_transaction != ifsta->auth_transaction)
 		return;
@@ -1381,8 +1422,6 @@
 	/* Add STA entry for the AP */
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
-		struct ieee80211_bss *bss;
-
 		newsta = true;
 
 		sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
@@ -1392,15 +1431,6 @@
 			rcu_read_unlock();
 			return;
 		}
-		bss = ieee80211_rx_bss_get(local, ifsta->bssid,
-					   local->hw.conf.channel->center_freq,
-					   ifsta->ssid, ifsta->ssid_len);
-		if (bss) {
-			sta->last_signal = bss->signal;
-			sta->last_qual = bss->qual;
-			sta->last_noise = bss->noise;
-			ieee80211_rx_bss_put(local, bss);
-		}
 
 		/* update new sta with its last rx activity */
 		sta->last_rx = jiffies;
@@ -1512,9 +1542,13 @@
 }
 
 
-static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
-				   struct ieee80211_if_sta *ifsta,
-				   struct ieee80211_bss *bss)
+static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_if_sta *ifsta,
+				     const u8 *bssid, const int beacon_int,
+				     const int freq,
+				     const size_t supp_rates_len,
+				     const u8 *supp_rates,
+				     const u16 capability)
 {
 	struct ieee80211_local *local = sdata->local;
 	int res = 0, rates, i, j;
@@ -1530,7 +1564,7 @@
 	}
 
 	if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) &&
-	   memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) == 0)
+	   memcmp(ifsta->bssid, bssid, ETH_ALEN) == 0)
 		return res;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
@@ -1541,28 +1575,28 @@
 		return -ENOMEM;
 	}
 
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
 	if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) {
 		/* Remove possible STA entries from other IBSS networks. */
 		sta_info_flush_delayed(sdata);
 	}
 
-	memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
+	memcpy(ifsta->bssid, bssid, ETH_ALEN);
 	res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
 	if (res)
 		return res;
 
-	local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
+	local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;
 
-	sdata->drop_unencrypted = bss->capability &
+	sdata->drop_unencrypted = capability &
 		WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-	res = ieee80211_set_freq(sdata, bss->freq);
+	res = ieee80211_set_freq(sdata, freq);
 
 	if (res)
 		return res;
 
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	/* Build IBSS probe response */
 
 	skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -1571,33 +1605,32 @@
 		skb_put(skb, 24 + sizeof(mgmt->u.beacon));
 	memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-						IEEE80211_STYPE_PROBE_RESP);
+					  IEEE80211_STYPE_PROBE_RESP);
 	memset(mgmt->da, 0xff, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
 	mgmt->u.beacon.beacon_int =
 		cpu_to_le16(local->hw.conf.beacon_int);
-	mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp);
-	mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
+	mgmt->u.beacon.capab_info = cpu_to_le16(capability);
 
 	pos = skb_put(skb, 2 + ifsta->ssid_len);
 	*pos++ = WLAN_EID_SSID;
 	*pos++ = ifsta->ssid_len;
 	memcpy(pos, ifsta->ssid, ifsta->ssid_len);
 
-	rates = bss->supp_rates_len;
+	rates = supp_rates_len;
 	if (rates > 8)
 		rates = 8;
 	pos = skb_put(skb, 2 + rates);
 	*pos++ = WLAN_EID_SUPP_RATES;
 	*pos++ = rates;
-	memcpy(pos, bss->supp_rates, rates);
+	memcpy(pos, supp_rates, rates);
 
-	if (bss->band == IEEE80211_BAND_2GHZ) {
+	if (sband->band == IEEE80211_BAND_2GHZ) {
 		pos = skb_put(skb, 2 + 1);
 		*pos++ = WLAN_EID_DS_PARAMS;
 		*pos++ = 1;
-		*pos++ = ieee80211_frequency_to_channel(bss->freq);
+		*pos++ = ieee80211_frequency_to_channel(freq);
 	}
 
 	pos = skb_put(skb, 2 + 2);
@@ -1607,12 +1640,12 @@
 	*pos++ = 0;
 	*pos++ = 0;
 
-	if (bss->supp_rates_len > 8) {
-		rates = bss->supp_rates_len - 8;
+	if (supp_rates_len > 8) {
+		rates = supp_rates_len - 8;
 		pos = skb_put(skb, 2 + rates);
 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
 		*pos++ = rates;
-		memcpy(pos, &bss->supp_rates[8], rates);
+		memcpy(pos, &supp_rates[8], rates);
 	}
 
 	add_extra_ies(skb, sdata->u.sta.ie_proberesp,
@@ -1625,16 +1658,15 @@
 
 
 	rates = 0;
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-	for (i = 0; i < bss->supp_rates_len; i++) {
-		int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+	for (i = 0; i < supp_rates_len; i++) {
+		int bitrate = (supp_rates[i] & 0x7f) * 5;
 		for (j = 0; j < sband->n_bitrates; j++)
 			if (sband->bitrates[j].bitrate == bitrate)
 				rates |= BIT(j);
 	}
 	ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
 
-	ieee80211_sta_def_wmm_params(sdata, bss);
+	ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);
 
 	ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
 	ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED;
@@ -1643,12 +1675,24 @@
 	ieee80211_led_assoc(local, true);
 
 	memset(&wrqu, 0, sizeof(wrqu));
-	memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+	memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
 	wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
 
 	return res;
 }
 
+static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+				   struct ieee80211_if_sta *ifsta,
+				   struct ieee80211_bss *bss)
+{
+	return __ieee80211_sta_join_ibss(sdata, ifsta,
+					 bss->cbss.bssid,
+					 bss->cbss.beacon_interval,
+					 bss->cbss.channel->center_freq,
+					 bss->supp_rates_len, bss->supp_rates,
+					 bss->cbss.capability);
+}
+
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 				  struct ieee80211_mgmt *mgmt,
 				  size_t len,
@@ -1709,7 +1753,7 @@
 	}
 
 	bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
-					freq, beacon);
+					channel, beacon);
 	if (!bss)
 		return;
 
@@ -1721,76 +1765,87 @@
 	}
 
 	/* was just updated in ieee80211_bss_info_update */
-	beacon_timestamp = bss->timestamp;
+	beacon_timestamp = bss->cbss.tsf;
 
-	/*
-	 * In STA mode, the remaining parameters should not be overridden
-	 * by beacons because they're not necessarily accurate there.
-	 */
-	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-	    bss->last_probe_resp && beacon) {
-		ieee80211_rx_bss_put(local, bss);
-		return;
-	}
+	if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
+		goto put_bss;
 
 	/* check if we need to merge IBSS */
-	if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon &&
-	    (!(sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)) &&
-	    bss->capability & WLAN_CAPABILITY_IBSS &&
-	    bss->freq == local->oper_channel->center_freq &&
-	    elems->ssid_len == sdata->u.sta.ssid_len &&
+
+	/* merge only on beacons (???) */
+	if (!beacon)
+		goto put_bss;
+
+	/* we use a fixed BSSID */
+	if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)
+		goto put_bss;
+
+	/* not an IBSS */
+	if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))
+		goto put_bss;
+
+	/* different channel */
+	if (bss->cbss.channel != local->oper_channel)
+		goto put_bss;
+
+	/* different SSID */
+	if (elems->ssid_len != sdata->u.sta.ssid_len ||
 	    memcmp(elems->ssid, sdata->u.sta.ssid,
-				sdata->u.sta.ssid_len) == 0) {
-		if (rx_status->flag & RX_FLAG_TSFT) {
-			/* in order for correct IBSS merging we need mactime
-			 *
-			 * since mactime is defined as the time the first data
-			 * symbol of the frame hits the PHY, and the timestamp
-			 * of the beacon is defined as "the time that the data
-			 * symbol containing the first bit of the timestamp is
-			 * transmitted to the PHY plus the transmitting STA’s
-			 * delays through its local PHY from the MAC-PHY
-			 * interface to its interface with the WM"
-			 * (802.11 11.1.2) - equals the time this bit arrives at
-			 * the receiver - we have to take into account the
-			 * offset between the two.
-			 * e.g: at 1 MBit that means mactime is 192 usec earlier
-			 * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
-			 */
-			int rate;
-			if (rx_status->flag & RX_FLAG_HT) {
-				rate = 65; /* TODO: HT rates */
-			} else {
-				rate = local->hw.wiphy->bands[band]->
-					bitrates[rx_status->rate_idx].bitrate;
-			}
-			rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
-		} else if (local && local->ops && local->ops->get_tsf)
-			/* second best option: get current TSF */
-			rx_timestamp = local->ops->get_tsf(local_to_hw(local));
+				sdata->u.sta.ssid_len))
+		goto put_bss;
+
+	if (rx_status->flag & RX_FLAG_TSFT) {
+		/*
+		 * For correct IBSS merging we need mactime; since mactime is
+		 * defined as the time the first data symbol of the frame hits
+		 * the PHY, and the timestamp of the beacon is defined as "the
+		 * time that the data symbol containing the first bit of the
+		 * timestamp is transmitted to the PHY plus the transmitting
+		 * STA's delays through its local PHY from the MAC-PHY
+		 * interface to its interface with the WM" (802.11 11.1.2)
+		 * - equals the time this bit arrives at the receiver - we have
+		 * to take into account the offset between the two.
+		 *
+		 * E.g. at 1 MBit that means mactime is 192 usec earlier
+		 * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
+		 */
+		int rate;
+
+		if (rx_status->flag & RX_FLAG_HT)
+			rate = 65; /* TODO: HT rates */
 		else
-			/* can't merge without knowing the TSF */
-			rx_timestamp = -1LLU;
+			rate = local->hw.wiphy->bands[band]->
+				bitrates[rx_status->rate_idx].bitrate;
+
+		rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
+	} else if (local && local->ops && local->ops->get_tsf)
+		/* second best option: get current TSF */
+		rx_timestamp = local->ops->get_tsf(local_to_hw(local));
+	else
+		/* can't merge without knowing the TSF */
+		rx_timestamp = -1LLU;
+
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
-		       "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
-		       mgmt->sa, mgmt->bssid,
-		       (unsigned long long)rx_timestamp,
-		       (unsigned long long)beacon_timestamp,
-		       (unsigned long long)(rx_timestamp - beacon_timestamp),
-		       jiffies);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-		if (beacon_timestamp > rx_timestamp) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-			printk(KERN_DEBUG "%s: beacon TSF higher than "
-			       "local TSF - IBSS merge with BSSID %pM\n",
-			       sdata->dev->name, mgmt->bssid);
+	printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
+	       "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+	       mgmt->sa, mgmt->bssid,
+	       (unsigned long long)rx_timestamp,
+	       (unsigned long long)beacon_timestamp,
+	       (unsigned long long)(rx_timestamp - beacon_timestamp),
+	       jiffies);
 #endif
-			ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
-			ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
-		}
+
+	if (beacon_timestamp > rx_timestamp) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+		printk(KERN_DEBUG "%s: beacon TSF higher than "
+		       "local TSF - IBSS merge with BSSID %pM\n",
+		       sdata->dev->name, mgmt->bssid);
+#endif
+		ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
+		ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
 	}
 
+ put_bss:
 	ieee80211_rx_bss_put(local, bss);
 }
 
@@ -1836,7 +1891,7 @@
 	struct ieee802_11_elems elems;
 	struct ieee80211_local *local = sdata->local;
 	u32 changed = 0;
-	bool erp_valid, directed_tim, is_mc = false;
+	bool erp_valid, directed_tim;
 	u8 erp_value = 0;
 
 	/* Process beacon from the current BSS */
@@ -1864,12 +1919,27 @@
 
 	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK &&
 	    local->hw.conf.flags & IEEE80211_CONF_PS) {
-		directed_tim = check_tim(&elems, ifsta->aid, &is_mc);
+		directed_tim = ieee80211_check_tim(&elems, ifsta->aid);
 
-		if (directed_tim || is_mc) {
-			local->hw.conf.flags &= ~IEEE80211_CONF_PS;
-			ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-			ieee80211_send_nullfunc(local, sdata, 0);
+		if (directed_tim) {
+			if (local->hw.conf.dynamic_ps_timeout > 0) {
+				local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+				ieee80211_hw_config(local,
+						    IEEE80211_CONF_CHANGE_PS);
+				ieee80211_send_nullfunc(local, sdata, 0);
+			} else {
+				local->pspolling = true;
+
+				/*
+				 * Here is assumed that the driver will be
+				 * able to send ps-poll frame and receive a
+				 * response even though power save mode is
+				 * enabled, but some drivers might require
+				 * to disable power save here. This needs
+				 * to be investigated.
+				 */
+				ieee80211_send_pspoll(local, sdata);
+			}
 		}
 	}
 
@@ -1939,8 +2009,7 @@
 	struct ieee80211_mgmt *resp;
 	u8 *pos, *end;
 
-	if (sdata->vif.type != NL80211_IFTYPE_ADHOC ||
-	    ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||
+	if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||
 	    len < 24 + 2 || !ifsta->probe_resp)
 		return;
 
@@ -2044,31 +2113,54 @@
 	mgmt = (struct ieee80211_mgmt *) skb->data;
 	fc = le16_to_cpu(mgmt->frame_control);
 
-	switch (fc & IEEE80211_FCTL_STYPE) {
-	case IEEE80211_STYPE_PROBE_REQ:
-		ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len);
-		break;
-	case IEEE80211_STYPE_PROBE_RESP:
-		ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status);
-		break;
-	case IEEE80211_STYPE_BEACON:
-		ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
-		break;
-	case IEEE80211_STYPE_AUTH:
-		ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);
-		break;
-	case IEEE80211_STYPE_ASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0);
-		break;
-	case IEEE80211_STYPE_REASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1);
-		break;
-	case IEEE80211_STYPE_DEAUTH:
-		ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);
-		break;
-	case IEEE80211_STYPE_DISASSOC:
-		ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len);
-		break;
+	if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_PROBE_REQ:
+			ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt,
+						    skb->len);
+			break;
+		case IEEE80211_STYPE_PROBE_RESP:
+			ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
+						     rx_status);
+			break;
+		case IEEE80211_STYPE_BEACON:
+			ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+						 rx_status);
+			break;
+		case IEEE80211_STYPE_AUTH:
+			ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt,
+						    skb->len);
+			break;
+		}
+	} else { /* NL80211_IFTYPE_STATION */
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_PROBE_RESP:
+			ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
+						     rx_status);
+			break;
+		case IEEE80211_STYPE_BEACON:
+			ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+						 rx_status);
+			break;
+		case IEEE80211_STYPE_AUTH:
+			ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);
+			break;
+		case IEEE80211_STYPE_ASSOC_RESP:
+			ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,
+						     skb->len, 0);
+			break;
+		case IEEE80211_STYPE_REASSOC_RESP:
+			ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,
+						     skb->len, 1);
+			break;
+		case IEEE80211_STYPE_DEAUTH:
+			ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);
+			break;
+		case IEEE80211_STYPE_DISASSOC:
+			ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt,
+						   skb->len);
+			break;
+		}
 	}
 
 	kfree_skb(skb);
@@ -2113,7 +2205,15 @@
 
 	printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
 	       "IBSS networks with same SSID (merge)\n", sdata->dev->name);
-	ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len);
+
+	/* XXX maybe racy? */
+	if (sdata->local->scan_req)
+		return;
+
+	memcpy(sdata->local->int_scan_req.ssids[0].ssid,
+	       ifsta->ssid, IEEE80211_MAX_SSID_LEN);
+	sdata->local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
+	ieee80211_request_scan(sdata, &sdata->local->int_scan_req);
 }
 
 
@@ -2159,46 +2259,16 @@
 	netif_carrier_off(sdata->dev);
 }
 
-
-static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
-				    const char *ssid, int ssid_len)
-{
-	int tmp, hidden_ssid;
-
-	if (ssid_len == ifsta->ssid_len &&
-	    !memcmp(ifsta->ssid, ssid, ssid_len))
-		return 1;
-
-	if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
-		return 0;
-
-	hidden_ssid = 1;
-	tmp = ssid_len;
-	while (tmp--) {
-		if (ssid[tmp] != '\0') {
-			hidden_ssid = 0;
-			break;
-		}
-	}
-
-	if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0))
-		return 1;
-
-	if (ssid_len == 1 && ssid[0] == ' ')
-		return 1;
-
-	return 0;
-}
-
 static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_if_sta *ifsta)
 {
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_bss *bss;
 	struct ieee80211_supported_band *sband;
-	u8 bssid[ETH_ALEN], *pos;
+	u8 *pos;
+	u8 bssid[ETH_ALEN];
+	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+	u16 capability;
 	int i;
-	int ret;
 
 	if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) {
 		memcpy(bssid, ifsta->bssid, ETH_ALEN);
@@ -2216,36 +2286,29 @@
 	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
 	       sdata->dev->name, bssid);
 
-	bss = ieee80211_rx_bss_add(local, bssid,
-				   local->hw.conf.channel->center_freq,
-				   sdata->u.sta.ssid, sdata->u.sta.ssid_len);
-	if (!bss)
-		return -ENOMEM;
-
-	bss->band = local->hw.conf.channel->band;
-	sband = local->hw.wiphy->bands[bss->band];
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 	if (local->hw.conf.beacon_int == 0)
 		local->hw.conf.beacon_int = 100;
-	bss->beacon_int = local->hw.conf.beacon_int;
-	bss->last_update = jiffies;
-	bss->capability = WLAN_CAPABILITY_IBSS;
+
+	capability = WLAN_CAPABILITY_IBSS;
 
 	if (sdata->default_key)
-		bss->capability |= WLAN_CAPABILITY_PRIVACY;
+		capability |= WLAN_CAPABILITY_PRIVACY;
 	else
 		sdata->drop_unencrypted = 0;
 
-	bss->supp_rates_len = sband->n_bitrates;
-	pos = bss->supp_rates;
+	pos = supp_rates;
 	for (i = 0; i < sband->n_bitrates; i++) {
 		int rate = sband->bitrates[i].bitrate;
 		*pos++ = (u8) (rate / 5);
 	}
 
-	ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);
-	ieee80211_rx_bss_put(local, bss);
-	return ret;
+	return __ieee80211_sta_join_ibss(sdata, ifsta,
+					 bssid, local->hw.conf.beacon_int,
+					 local->hw.conf.channel->center_freq,
+					 sband->n_bitrates, supp_rates,
+					 capability);
 }
 
 
@@ -2254,8 +2317,6 @@
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_bss *bss;
-	int found = 0;
-	u8 bssid[ETH_ALEN];
 	int active_ibss;
 
 	if (ifsta->ssid_len == 0)
@@ -2266,56 +2327,39 @@
 	printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
 	       sdata->dev->name, active_ibss);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
-	spin_lock_bh(&local->bss_lock);
-	list_for_each_entry(bss, &local->bss_list, list) {
-		if (ifsta->ssid_len != bss->ssid_len ||
-		    memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0
-		    || !(bss->capability & WLAN_CAPABILITY_IBSS))
-			continue;
-		if ((ifsta->flags & IEEE80211_STA_BSSID_SET) &&
-		    memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) != 0)
-			continue;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "   bssid=%pM found\n", bss->bssid);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-		memcpy(bssid, bss->bssid, ETH_ALEN);
-		found = 1;
-		if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0)
-			break;
-	}
-	spin_unlock_bh(&local->bss_lock);
 
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	if (found)
-		printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
-		       "%pM\n", bssid, ifsta->bssid);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	if (active_ibss)
+		return 0;
 
-	if (found &&
-	    ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) ||
-	     memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0)) {
-		int ret;
-		int search_freq;
-
-		if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
-			search_freq = bss->freq;
-		else
-			search_freq = local->hw.conf.channel->center_freq;
-
-		bss = ieee80211_rx_bss_get(local, bssid, search_freq,
+	if (ifsta->flags & IEEE80211_STA_BSSID_SET)
+		bss = ieee80211_rx_bss_get(local, ifsta->bssid, 0,
 					   ifsta->ssid, ifsta->ssid_len);
-		if (!bss)
-			goto dont_join;
+	else
+		bss = (void *)cfg80211_get_ibss(local->hw.wiphy,
+						NULL,
+						ifsta->ssid, ifsta->ssid_len);
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	if (bss)
+		printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
+		       "%pM\n", bss->cbss.bssid, ifsta->bssid);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+	if (bss &&
+	    (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) ||
+	     memcmp(ifsta->bssid, bss->cbss.bssid, ETH_ALEN))) {
+		int ret;
 
 		printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
 		       " based on configured SSID\n",
-		       sdata->dev->name, bssid);
+		       sdata->dev->name, bss->cbss.bssid);
+
 		ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);
 		ieee80211_rx_bss_put(local, bss);
 		return ret;
-	}
+	} else if (bss)
+		ieee80211_rx_bss_put(local, bss);
 
-dont_join:
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 	printk(KERN_DEBUG "   did not try to join ibss\n");
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
@@ -2329,8 +2373,15 @@
 			      IEEE80211_SCAN_INTERVAL)) {
 		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
 		       "join\n", sdata->dev->name);
-		return ieee80211_request_scan(sdata, ifsta->ssid,
-					      ifsta->ssid_len);
+
+		/* XXX maybe racy? */
+		if (local->scan_req)
+			return -EBUSY;
+
+		memcpy(local->int_scan_req.ssids[0].ssid,
+		       ifsta->ssid, IEEE80211_MAX_SSID_LEN);
+		local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
+		return ieee80211_request_scan(sdata, &local->int_scan_req);
 	} else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) {
 		int interval = IEEE80211_SCAN_INTERVAL;
 
@@ -2364,50 +2415,44 @@
 				     struct ieee80211_if_sta *ifsta)
 {
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_bss *bss, *selected = NULL;
-	int top_rssi = 0, freq;
+	struct ieee80211_bss *bss;
+	u8 *bssid = ifsta->bssid, *ssid = ifsta->ssid;
+	u8 ssid_len = ifsta->ssid_len;
+	u16 capa_mask = WLAN_CAPABILITY_ESS;
+	u16 capa_val = WLAN_CAPABILITY_ESS;
+	struct ieee80211_channel *chan = local->oper_channel;
 
-	spin_lock_bh(&local->bss_lock);
-	freq = local->oper_channel->center_freq;
-	list_for_each_entry(bss, &local->bss_list, list) {
-		if (!(bss->capability & WLAN_CAPABILITY_ESS))
-			continue;
-
-		if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
-			IEEE80211_STA_AUTO_BSSID_SEL |
-			IEEE80211_STA_AUTO_CHANNEL_SEL)) &&
-		    (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
-		     !!sdata->default_key))
-			continue;
-
-		if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) &&
-		    bss->freq != freq)
-			continue;
-
-		if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) &&
-		    memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
-			continue;
-
-		if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) &&
-		    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
-			continue;
-
-		if (!selected || top_rssi < bss->signal) {
-			selected = bss;
-			top_rssi = bss->signal;
-		}
+	if (ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
+			    IEEE80211_STA_AUTO_BSSID_SEL |
+			    IEEE80211_STA_AUTO_CHANNEL_SEL)) {
+		capa_mask |= WLAN_CAPABILITY_PRIVACY;
+		if (sdata->default_key)
+			capa_val |= WLAN_CAPABILITY_PRIVACY;
 	}
-	if (selected)
-		atomic_inc(&selected->users);
-	spin_unlock_bh(&local->bss_lock);
 
-	if (selected) {
-		ieee80211_set_freq(sdata, selected->freq);
+	if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
+		chan = NULL;
+
+	if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
+		bssid = NULL;
+
+	if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) {
+		ssid = NULL;
+		ssid_len = 0;
+	}
+
+	bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan,
+				       bssid, ssid, ssid_len,
+				       capa_mask, capa_val);
+
+	if (bss) {
+		ieee80211_set_freq(sdata, bss->cbss.channel->center_freq);
 		if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
-			ieee80211_sta_set_ssid(sdata, selected->ssid,
-					       selected->ssid_len);
-		ieee80211_sta_set_bssid(sdata, selected->bssid);
-		ieee80211_sta_def_wmm_params(sdata, selected);
+			ieee80211_sta_set_ssid(sdata, bss->ssid,
+					       bss->ssid_len);
+		ieee80211_sta_set_bssid(sdata, bss->cbss.bssid);
+		ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len,
+						    bss->supp_rates);
 		if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED)
 			sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED;
 		else
@@ -2416,24 +2461,29 @@
 		/* Send out direct probe if no probe resp was received or
 		 * the one we have is outdated
 		 */
-		if (!selected->last_probe_resp ||
-		    time_after(jiffies, selected->last_probe_resp
+		if (!bss->last_probe_resp ||
+		    time_after(jiffies, bss->last_probe_resp
 					+ IEEE80211_SCAN_RESULT_EXPIRE))
 			ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
 		else
 			ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
 
-		ieee80211_rx_bss_put(local, selected);
+		ieee80211_rx_bss_put(local, bss);
 		ieee80211_sta_reset_auth(sdata, ifsta);
 		return 0;
 	} else {
 		if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
 			ifsta->assoc_scan_tries++;
+			/* XXX maybe racy? */
+			if (local->scan_req)
+				return -1;
+			memcpy(local->int_scan_req.ssids[0].ssid,
+			       ifsta->ssid, IEEE80211_MAX_SSID_LEN);
 			if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)
-				ieee80211_start_scan(sdata, NULL, 0);
+				local->int_scan_req.ssids[0].ssid_len = 0;
 			else
-				ieee80211_start_scan(sdata, ifsta->ssid,
-							 ifsta->ssid_len);
+				local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
+			ieee80211_start_scan(sdata, &local->int_scan_req);
 			ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
 			set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
 		} else {
@@ -2471,8 +2521,7 @@
 	    ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
 	    ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
 	    test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
-		ieee80211_start_scan(sdata, ifsta->scan_ssid,
-				     ifsta->scan_ssid_len);
+		ieee80211_start_scan(sdata, local->scan_req);
 		return;
 	}
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 8e8ddbf..1327d42 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -731,6 +731,39 @@
 	return result;
 }
 
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
+{
+	struct ieee80211_local *local;
+	struct ieee80211_hdr *hdr;
+	struct sk_buff *skb;
+
+	local = rx->local;
+	skb = rx->skb;
+	hdr = (struct ieee80211_hdr *) skb->data;
+
+	if (!local->pspolling)
+		return RX_CONTINUE;
+
+	if (!ieee80211_has_fromds(hdr->frame_control))
+		/* this is not from AP */
+		return RX_CONTINUE;
+
+	if (!ieee80211_is_data(hdr->frame_control))
+		return RX_CONTINUE;
+
+	if (!ieee80211_has_moredata(hdr->frame_control)) {
+		/* AP has no more frames buffered for us */
+		local->pspolling = false;
+		return RX_CONTINUE;
+	}
+
+	/* more data bit is set, let's request a new frame from the AP */
+	ieee80211_send_pspoll(local, rx->sdata);
+
+	return RX_CONTINUE;
+}
+
 static void ap_sta_ps_start(struct sta_info *sta)
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -1640,11 +1673,9 @@
 		start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
 
 		/* reset session timer */
-		if (tid_agg_rx->timeout) {
-			unsigned long expires =
-				jiffies + (tid_agg_rx->timeout / 1000) * HZ;
-			mod_timer(&tid_agg_rx->session_timer, expires);
-		}
+		if (tid_agg_rx->timeout)
+			mod_timer(&tid_agg_rx->session_timer,
+				  TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
 		/* manage reordering buffer according to requested */
 		/* sequence number */
@@ -1737,6 +1768,17 @@
 
 	switch (mgmt->u.action.category) {
 	case WLAN_CATEGORY_BACK:
+		/*
+		 * The aggregation code is not prepared to handle
+		 * anything but STA/AP due to the BSSID handling;
+		 * IBSS could work in the code but isn't supported
+		 * by drivers or the standard.
+		 */
+		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+		    sdata->vif.type != NL80211_IFTYPE_AP)
+			return RX_DROP_MONITOR;
+
 		switch (mgmt->u.action.u.addba_req.action_code) {
 		case WLAN_ACTION_ADDBA_REQ:
 			if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1987,6 +2029,7 @@
 	CALL_RXH(ieee80211_rx_h_passive_scan)
 	CALL_RXH(ieee80211_rx_h_check)
 	CALL_RXH(ieee80211_rx_h_decrypt)
+	CALL_RXH(ieee80211_rx_h_check_more_data)
 	CALL_RXH(ieee80211_rx_h_sta_process)
 	CALL_RXH(ieee80211_rx_h_defragment)
 	CALL_RXH(ieee80211_rx_h_ps_poll)
@@ -2030,9 +2073,10 @@
 /* main receive path */
 
 static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
-				u8 *bssid, struct ieee80211_rx_data *rx,
+				struct ieee80211_rx_data *rx,
 				struct ieee80211_hdr *hdr)
 {
+	u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type);
 	int multicast = is_multicast_ether_addr(hdr->addr1);
 
 	switch (sdata->vif.type) {
@@ -2135,7 +2179,6 @@
 	int prepares;
 	struct ieee80211_sub_if_data *prev = NULL;
 	struct sk_buff *skb_new;
-	u8 *bssid;
 
 	hdr = (struct ieee80211_hdr *)skb->data;
 	memset(&rx, 0, sizeof(rx));
@@ -2174,9 +2217,8 @@
 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
 			continue;
 
-		bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
 		rx.flags |= IEEE80211_RX_RA_MATCH;
-		prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
+		prepares = prepare_for_handlers(sdata, &rx, hdr);
 
 		if (!prepares)
 			continue;
@@ -2381,11 +2423,9 @@
 	/* new un-ordered ampdu frame - process it */
 
 	/* reset session timer */
-	if (tid_agg_rx->timeout) {
-		unsigned long expires =
-			jiffies + (tid_agg_rx->timeout / 1000) * HZ;
-		mod_timer(&tid_agg_rx->session_timer, expires);
-	}
+	if (tid_agg_rx->timeout)
+		mod_timer(&tid_agg_rx->session_timer,
+			  TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
 	/* if this mpdu is fragmented - terminate rx aggregation session */
 	sc = le16_to_cpu(hdr->seq_ctrl);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 282e6a0..f883ab9 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -12,11 +12,7 @@
  * published by the Free Software Foundation.
  */
 
-/* TODO:
- * order BSS list by RSSI(?) ("quality of AP")
- * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
- *    SSID)
- */
+/* TODO: figure out how to avoid that the "current BSS" expires */
 
 #include <linux/wireless.h>
 #include <linux/if_arp.h>
@@ -31,192 +27,29 @@
 #define IEEE80211_CHANNEL_TIME (HZ / 33)
 #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
 
-void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
-{
-	spin_lock_init(&local->bss_lock);
-	INIT_LIST_HEAD(&local->bss_list);
-}
-
-void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
-{
-	struct ieee80211_bss *bss, *tmp;
-
-	list_for_each_entry_safe(bss, tmp, &local->bss_list, list)
-		ieee80211_rx_bss_put(local, bss);
-}
-
 struct ieee80211_bss *
 ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
 		     u8 *ssid, u8 ssid_len)
 {
-	struct ieee80211_bss *bss;
-
-	spin_lock_bh(&local->bss_lock);
-	bss = local->bss_hash[STA_HASH(bssid)];
-	while (bss) {
-		if (!bss_mesh_cfg(bss) &&
-		    !memcmp(bss->bssid, bssid, ETH_ALEN) &&
-		    bss->freq == freq &&
-		    bss->ssid_len == ssid_len &&
-		    (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
-			atomic_inc(&bss->users);
-			break;
-		}
-		bss = bss->hnext;
-	}
-	spin_unlock_bh(&local->bss_lock);
-	return bss;
+	return (void *)cfg80211_get_bss(local->hw.wiphy,
+					ieee80211_get_channel(local->hw.wiphy,
+							      freq),
+					bssid, ssid, ssid_len,
+					0, 0);
 }
 
-/* Caller must hold local->bss_lock */
-static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local,
-					struct ieee80211_bss *bss)
+static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
 {
-	u8 hash_idx;
+	struct ieee80211_bss *bss = (void *)cbss;
 
-	if (bss_mesh_cfg(bss))
-		hash_idx = mesh_id_hash(bss_mesh_id(bss),
-					bss_mesh_id_len(bss));
-	else
-		hash_idx = STA_HASH(bss->bssid);
-
-	bss->hnext = local->bss_hash[hash_idx];
-	local->bss_hash[hash_idx] = bss;
-}
-
-/* Caller must hold local->bss_lock */
-static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
-					struct ieee80211_bss *bss)
-{
-	struct ieee80211_bss *b, *prev = NULL;
-	b = local->bss_hash[STA_HASH(bss->bssid)];
-	while (b) {
-		if (b == bss) {
-			if (!prev)
-				local->bss_hash[STA_HASH(bss->bssid)] =
-					bss->hnext;
-			else
-				prev->hnext = bss->hnext;
-			break;
-		}
-		prev = b;
-		b = b->hnext;
-	}
-}
-
-struct ieee80211_bss *
-ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
-		     u8 *ssid, u8 ssid_len)
-{
-	struct ieee80211_bss *bss;
-
-	bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
-	if (!bss)
-		return NULL;
-	atomic_set(&bss->users, 2);
-	memcpy(bss->bssid, bssid, ETH_ALEN);
-	bss->freq = freq;
-	if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
-		memcpy(bss->ssid, ssid, ssid_len);
-		bss->ssid_len = ssid_len;
-	}
-
-	spin_lock_bh(&local->bss_lock);
-	/* TODO: order by RSSI? */
-	list_add_tail(&bss->list, &local->bss_list);
-	__ieee80211_rx_bss_hash_add(local, bss);
-	spin_unlock_bh(&local->bss_lock);
-	return bss;
-}
-
-#ifdef CONFIG_MAC80211_MESH
-static struct ieee80211_bss *
-ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
-			  u8 *mesh_cfg, int freq)
-{
-	struct ieee80211_bss *bss;
-
-	spin_lock_bh(&local->bss_lock);
-	bss = local->bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
-	while (bss) {
-		if (bss_mesh_cfg(bss) &&
-		    !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
-		    bss->freq == freq &&
-		    mesh_id_len == bss->mesh_id_len &&
-		    (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
-						 mesh_id_len))) {
-			atomic_inc(&bss->users);
-			break;
-		}
-		bss = bss->hnext;
-	}
-	spin_unlock_bh(&local->bss_lock);
-	return bss;
-}
-
-static struct ieee80211_bss *
-ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
-			  u8 *mesh_cfg, int mesh_config_len, int freq)
-{
-	struct ieee80211_bss *bss;
-
-	if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN)
-		return NULL;
-
-	bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
-	if (!bss)
-		return NULL;
-
-	bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC);
-	if (!bss->mesh_cfg) {
-		kfree(bss);
-		return NULL;
-	}
-
-	if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) {
-		bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC);
-		if (!bss->mesh_id) {
-			kfree(bss->mesh_cfg);
-			kfree(bss);
-			return NULL;
-		}
-		memcpy(bss->mesh_id, mesh_id, mesh_id_len);
-	}
-
-	atomic_set(&bss->users, 2);
-	memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN);
-	bss->mesh_id_len = mesh_id_len;
-	bss->freq = freq;
-	spin_lock_bh(&local->bss_lock);
-	/* TODO: order by RSSI? */
-	list_add_tail(&bss->list, &local->bss_list);
-	__ieee80211_rx_bss_hash_add(local, bss);
-	spin_unlock_bh(&local->bss_lock);
-	return bss;
-}
-#endif
-
-static void ieee80211_rx_bss_free(struct ieee80211_bss *bss)
-{
-	kfree(bss->ies);
 	kfree(bss_mesh_id(bss));
 	kfree(bss_mesh_cfg(bss));
-	kfree(bss);
 }
 
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
 			  struct ieee80211_bss *bss)
 {
-	local_bh_disable();
-	if (!atomic_dec_and_lock(&bss->users, &local->bss_lock)) {
-		local_bh_enable();
-		return;
-	}
-
-	__ieee80211_rx_bss_hash_del(local, bss);
-	list_del(&bss->list);
-	spin_unlock_bh(&local->bss_lock);
-	ieee80211_rx_bss_free(bss);
+	cfg80211_put_bss((struct cfg80211_bss *)bss);
 }
 
 struct ieee80211_bss *
@@ -225,49 +58,37 @@
 			  struct ieee80211_mgmt *mgmt,
 			  size_t len,
 			  struct ieee802_11_elems *elems,
-			  int freq, bool beacon)
+			  struct ieee80211_channel *channel,
+			  bool beacon)
 {
 	struct ieee80211_bss *bss;
 	int clen;
+	enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE;
+	s32 signal = 0;
 
-#ifdef CONFIG_MAC80211_MESH
-	if (elems->mesh_config)
-		bss = ieee80211_rx_mesh_bss_get(local, elems->mesh_id,
-				elems->mesh_id_len, elems->mesh_config, freq);
-	else
-#endif
-		bss = ieee80211_rx_bss_get(local, mgmt->bssid, freq,
-					   elems->ssid, elems->ssid_len);
-	if (!bss) {
-#ifdef CONFIG_MAC80211_MESH
-		if (elems->mesh_config)
-			bss = ieee80211_rx_mesh_bss_add(local, elems->mesh_id,
-				elems->mesh_id_len, elems->mesh_config,
-				elems->mesh_config_len, freq);
-		else
-#endif
-			bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq,
-						  elems->ssid, elems->ssid_len);
-		if (!bss)
-			return NULL;
-	} else {
-#if 0
-		/* TODO: order by RSSI? */
-		spin_lock_bh(&local->bss_lock);
-		list_move_tail(&bss->list, &local->bss_list);
-		spin_unlock_bh(&local->bss_lock);
-#endif
+	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+		sigtype = CFG80211_SIGNAL_TYPE_MBM;
+		signal = rx_status->signal * 100;
+	} else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
+		sigtype = CFG80211_SIGNAL_TYPE_UNSPEC;
+		signal = (rx_status->signal * 100) / local->hw.max_signal;
 	}
 
+	bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
+						mgmt, len, signal, sigtype,
+						GFP_ATOMIC);
+
+	if (!bss)
+		return NULL;
+
+	bss->cbss.free_priv = ieee80211_rx_bss_free;
+
 	/* save the ERP value so that it is available at association time */
 	if (elems->erp_info && elems->erp_info_len >= 1) {
 		bss->erp_value = elems->erp_info[0];
 		bss->has_erp_value = 1;
 	}
 
-	bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
-	bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
-
 	if (elems->tim) {
 		struct ieee80211_tim_ie *tim_ie =
 			(struct ieee80211_tim_ie *)elems->tim;
@@ -296,37 +117,27 @@
 		bss->supp_rates_len += clen;
 	}
 
-	bss->band = rx_status->band;
-
-	bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
-	bss->last_update = jiffies;
-	bss->signal = rx_status->signal;
-	bss->noise = rx_status->noise;
-	bss->qual = rx_status->qual;
 	bss->wmm_used = elems->wmm_param || elems->wmm_info;
 
 	if (!beacon)
 		bss->last_probe_resp = jiffies;
 
-	/*
-	 * For probe responses, or if we don't have any information yet,
-	 * use the IEs from the beacon.
-	 */
-	if (!bss->ies || !beacon) {
-		if (bss->ies == NULL || bss->ies_len < elems->total_len) {
-			kfree(bss->ies);
-			bss->ies = kmalloc(elems->total_len, GFP_ATOMIC);
-		}
-		if (bss->ies) {
-			memcpy(bss->ies, elems->ie_start, elems->total_len);
-			bss->ies_len = elems->total_len;
-		} else
-			bss->ies_len = 0;
-	}
-
 	return bss;
 }
 
+void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
+			     int freq, u8 *ssid, u8 ssid_len)
+{
+	struct ieee80211_bss *bss;
+	struct ieee80211_local *local = sdata->local;
+
+	bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len);
+	if (bss) {
+		cfg80211_unlink_bss(local->hw.wiphy, (void *)bss);
+		ieee80211_rx_bss_put(local, bss);
+	}
+}
+
 ieee80211_rx_result
 ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 		  struct ieee80211_rx_status *rx_status)
@@ -388,7 +199,7 @@
 
 	bss = ieee80211_bss_info_update(sdata->local, rx_status,
 					mgmt, skb->len, &elems,
-					freq, beacon);
+					channel, beacon);
 	if (bss)
 		ieee80211_rx_bss_put(sdata->local, bss);
 
@@ -426,26 +237,22 @@
 	ieee80211_tx_skb(sdata, skb, 0);
 }
 
-void ieee80211_scan_completed(struct ieee80211_hw *hw)
+void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata;
-	union iwreq_data wrqu;
 
 	if (WARN_ON(!local->hw_scanning && !local->sw_scanning))
 		return;
 
-	local->last_scan_completed = jiffies;
-	memset(&wrqu, 0, sizeof(wrqu));
+	if (WARN_ON(!local->scan_req))
+		return;
 
-	/*
-	 * local->scan_sdata could have been NULLed by the interface
-	 * down code in case we were scanning on an interface that is
-	 * being taken down.
-	 */
-	sdata = local->scan_sdata;
-	if (sdata)
-		wireless_send_event(sdata->dev, SIOCGIWSCAN, &wrqu, NULL);
+	if (local->scan_req != &local->int_scan_req)
+		cfg80211_scan_done(local->scan_req, aborted);
+	local->scan_req = NULL;
+
+	local->last_scan_completed = jiffies;
 
 	if (local->hw_scanning) {
 		local->hw_scanning = false;
@@ -487,7 +294,12 @@
 		} else
 			netif_tx_wake_all_queues(sdata->dev);
 
-		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
+		/* re-enable beaconing */
+		if (sdata->vif.type == NL80211_IFTYPE_AP ||
+		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+			ieee80211_if_config(sdata,
+					    IEEE80211_IFCC_BEACON_ENABLED);
 	}
 	mutex_unlock(&local->iflist_mtx);
 
@@ -502,9 +314,8 @@
 	struct ieee80211_local *local =
 		container_of(work, struct ieee80211_local, scan_work.work);
 	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
-	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *chan;
-	int skip;
+	int skip, i;
 	unsigned long next_delay = 0;
 
 	/*
@@ -515,33 +326,13 @@
 
 	switch (local->scan_state) {
 	case SCAN_SET_CHANNEL:
-		/*
-		 * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
-		 * after we successfully scanned the last channel of the last
-		 * band (and the last band is supported by the hw)
-		 */
-		if (local->scan_band < IEEE80211_NUM_BANDS)
-			sband = local->hw.wiphy->bands[local->scan_band];
-		else
-			sband = NULL;
-
-		/*
-		 * If we are at an unsupported band and have more bands
-		 * left to scan, advance to the next supported one.
-		 */
-		while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
-			local->scan_band++;
-			sband = local->hw.wiphy->bands[local->scan_band];
-			local->scan_channel_idx = 0;
-		}
-
 		/* if no more bands/channels left, complete scan */
-		if (!sband || local->scan_channel_idx >= sband->n_channels) {
-			ieee80211_scan_completed(local_to_hw(local));
+		if (local->scan_channel_idx >= local->scan_req->n_channels) {
+			ieee80211_scan_completed(local_to_hw(local), false);
 			return;
 		}
 		skip = 0;
-		chan = &sband->channels[local->scan_channel_idx];
+		chan = local->scan_req->channels[local->scan_channel_idx];
 
 		if (chan->flags & IEEE80211_CHAN_DISABLED ||
 		    (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
@@ -557,15 +348,6 @@
 
 		/* advance state machine to next channel/band */
 		local->scan_channel_idx++;
-		if (local->scan_channel_idx >= sband->n_channels) {
-			/*
-			 * scan_band may end up == IEEE80211_NUM_BANDS, but
-			 * we'll catch that case above and complete the scan
-			 * if that is the case.
-			 */
-			local->scan_band++;
-			local->scan_channel_idx = 0;
-		}
 
 		if (skip)
 			break;
@@ -578,10 +360,14 @@
 		next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
 		local->scan_state = SCAN_SET_CHANNEL;
 
-		if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+		if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
+		    !local->scan_req->n_ssids)
 			break;
-		ieee80211_send_probe_req(sdata, NULL, local->scan_ssid,
-					 local->scan_ssid_len);
+		for (i = 0; i < local->scan_req->n_ssids; i++)
+			ieee80211_send_probe_req(
+				sdata, NULL,
+				local->scan_req->ssids[i].ssid,
+				local->scan_req->ssids[i].ssid_len);
 		next_delay = IEEE80211_CHANNEL_TIME;
 		break;
 	}
@@ -592,14 +378,19 @@
 
 
 int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
-			 u8 *ssid, size_t ssid_len)
+			 struct cfg80211_scan_request *req)
 {
 	struct ieee80211_local *local = scan_sdata->local;
 	struct ieee80211_sub_if_data *sdata;
 
-	if (ssid_len > IEEE80211_MAX_SSID_LEN)
+	if (!req)
 		return -EINVAL;
 
+	if (local->scan_req && local->scan_req != req)
+		return -EBUSY;
+
+	local->scan_req = req;
+
 	/* MLME-SCAN.request (page 118)  page 144 (11.1.3.1)
 	 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
 	 * BSSID: MACAddress
@@ -627,7 +418,7 @@
 		int rc;
 
 		local->hw_scanning = true;
-		rc = local->ops->hw_scan(local_to_hw(local), ssid, ssid_len);
+		rc = local->ops->hw_scan(local_to_hw(local), req);
 		if (rc) {
 			local->hw_scanning = false;
 			return rc;
@@ -643,7 +434,12 @@
 		if (!netif_running(sdata->dev))
 			continue;
 
-		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
+		/* disable beaconing */
+		if (sdata->vif.type == NL80211_IFTYPE_AP ||
+		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+			ieee80211_if_config(sdata,
+					    IEEE80211_IFCC_BEACON_ENABLED);
 
 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 			if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
@@ -655,15 +451,10 @@
 	}
 	mutex_unlock(&local->iflist_mtx);
 
-	if (ssid) {
-		local->scan_ssid_len = ssid_len;
-		memcpy(local->scan_ssid, ssid, ssid_len);
-	} else
-		local->scan_ssid_len = 0;
 	local->scan_state = SCAN_SET_CHANNEL;
 	local->scan_channel_idx = 0;
-	local->scan_band = IEEE80211_BAND_2GHZ;
 	local->scan_sdata = scan_sdata;
+	local->scan_req = req;
 
 	netif_addr_lock_bh(local->mdev);
 	local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
@@ -683,13 +474,21 @@
 
 
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
-			   u8 *ssid, size_t ssid_len)
+			   struct cfg80211_scan_request *req)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_sta *ifsta;
 
+	if (!req)
+		return -EINVAL;
+
+	if (local->scan_req && local->scan_req != req)
+		return -EBUSY;
+
+	local->scan_req = req;
+
 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
-		return ieee80211_start_scan(sdata, ssid, ssid_len);
+		return ieee80211_start_scan(sdata, req);
 
 	/*
 	 * STA has a state machine that might need to defer scanning
@@ -704,241 +503,8 @@
 	}
 
 	ifsta = &sdata->u.sta;
-
-	ifsta->scan_ssid_len = ssid_len;
-	if (ssid_len)
-		memcpy(ifsta->scan_ssid, ssid, ssid_len);
 	set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
 	queue_work(local->hw.workqueue, &ifsta->work);
 
 	return 0;
 }
-
-
-static void ieee80211_scan_add_ies(struct iw_request_info *info,
-				   struct ieee80211_bss *bss,
-				   char **current_ev, char *end_buf)
-{
-	u8 *pos, *end, *next;
-	struct iw_event iwe;
-
-	if (bss == NULL || bss->ies == NULL)
-		return;
-
-	/*
-	 * If needed, fragment the IEs buffer (at IE boundaries) into short
-	 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
-	 */
-	pos = bss->ies;
-	end = pos + bss->ies_len;
-
-	while (end - pos > IW_GENERIC_IE_MAX) {
-		next = pos + 2 + pos[1];
-		while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
-			next = next + 2 + next[1];
-
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = next - pos;
-		*current_ev = iwe_stream_add_point(info, *current_ev,
-						   end_buf, &iwe, pos);
-
-		pos = next;
-	}
-
-	if (end > pos) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = end - pos;
-		*current_ev = iwe_stream_add_point(info, *current_ev,
-						   end_buf, &iwe, pos);
-	}
-}
-
-
-static char *
-ieee80211_scan_result(struct ieee80211_local *local,
-		      struct iw_request_info *info,
-		      struct ieee80211_bss *bss,
-		      char *current_ev, char *end_buf)
-{
-	struct iw_event iwe;
-	char *buf;
-
-	if (time_after(jiffies,
-		       bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
-		return current_ev;
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWAP;
-	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-					  IW_EV_ADDR_LEN);
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWESSID;
-	if (bss_mesh_cfg(bss)) {
-		iwe.u.data.length = bss_mesh_id_len(bss);
-		iwe.u.data.flags = 1;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, bss_mesh_id(bss));
-	} else {
-		iwe.u.data.length = bss->ssid_len;
-		iwe.u.data.flags = 1;
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, bss->ssid);
-	}
-
-	if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
-	    || bss_mesh_cfg(bss)) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = SIOCGIWMODE;
-		if (bss_mesh_cfg(bss))
-			iwe.u.mode = IW_MODE_MESH;
-		else if (bss->capability & WLAN_CAPABILITY_ESS)
-			iwe.u.mode = IW_MODE_MASTER;
-		else
-			iwe.u.mode = IW_MODE_ADHOC;
-		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-						  &iwe, IW_EV_UINT_LEN);
-	}
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWFREQ;
-	iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
-	iwe.u.freq.e = 0;
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-					  IW_EV_FREQ_LEN);
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWFREQ;
-	iwe.u.freq.m = bss->freq;
-	iwe.u.freq.e = 6;
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-					  IW_EV_FREQ_LEN);
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = IWEVQUAL;
-	iwe.u.qual.qual = bss->qual;
-	iwe.u.qual.level = bss->signal;
-	iwe.u.qual.noise = bss->noise;
-	iwe.u.qual.updated = local->wstats_flags;
-	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
-					  IW_EV_QUAL_LEN);
-
-	memset(&iwe, 0, sizeof(iwe));
-	iwe.cmd = SIOCGIWENCODE;
-	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-	else
-		iwe.u.data.flags = IW_ENCODE_DISABLED;
-	iwe.u.data.length = 0;
-	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-					  &iwe, "");
-
-	ieee80211_scan_add_ies(info, bss, &current_ev, end_buf);
-
-	if (bss->supp_rates_len > 0) {
-		/* display all supported rates in readable format */
-		char *p = current_ev + iwe_stream_lcp_len(info);
-		int i;
-
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = SIOCGIWRATE;
-		/* Those two flags are ignored... */
-		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
-		for (i = 0; i < bss->supp_rates_len; i++) {
-			iwe.u.bitrate.value = ((bss->supp_rates[i] &
-							0x7f) * 500000);
-			p = iwe_stream_add_value(info, current_ev, p,
-					end_buf, &iwe, IW_EV_PARAM_LEN);
-		}
-		current_ev = p;
-	}
-
-	buf = kmalloc(30, GFP_ATOMIC);
-	if (buf) {
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVCUSTOM;
-		sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
-		iwe.u.data.length = strlen(buf);
-		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-						  &iwe, buf);
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVCUSTOM;
-		sprintf(buf, " Last beacon: %dms ago",
-			jiffies_to_msecs(jiffies - bss->last_update));
-		iwe.u.data.length = strlen(buf);
-		current_ev = iwe_stream_add_point(info, current_ev,
-						  end_buf, &iwe, buf);
-		kfree(buf);
-	}
-
-	if (bss_mesh_cfg(bss)) {
-		u8 *cfg = bss_mesh_cfg(bss);
-		buf = kmalloc(50, GFP_ATOMIC);
-		if (buf) {
-			memset(&iwe, 0, sizeof(iwe));
-			iwe.cmd = IWEVCUSTOM;
-			sprintf(buf, "Mesh network (version %d)", cfg[0]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			sprintf(buf, "Path Selection Protocol ID: "
-				"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
-							cfg[4]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			sprintf(buf, "Path Selection Metric ID: "
-				"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
-							cfg[8]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			sprintf(buf, "Congestion Control Mode ID: "
-				"0x%02X%02X%02X%02X", cfg[9], cfg[10],
-							cfg[11], cfg[12]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			sprintf(buf, "Channel Precedence: "
-				"0x%02X%02X%02X%02X", cfg[13], cfg[14],
-							cfg[15], cfg[16]);
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(info, current_ev,
-							  end_buf,
-							  &iwe, buf);
-			kfree(buf);
-		}
-	}
-
-	return current_ev;
-}
-
-
-int ieee80211_scan_results(struct ieee80211_local *local,
-			   struct iw_request_info *info,
-			   char *buf, size_t len)
-{
-	char *current_ev = buf;
-	char *end_buf = buf + len;
-	struct ieee80211_bss *bss;
-
-	spin_lock_bh(&local->bss_lock);
-	list_for_each_entry(bss, &local->bss_list, list) {
-		if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
-			spin_unlock_bh(&local->bss_lock);
-			return -E2BIG;
-		}
-		current_ev = ieee80211_scan_result(local, info, bss,
-						       current_ev, end_buf);
-	}
-	spin_unlock_bh(&local->bss_lock);
-	return current_ev - buf;
-}
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 8d4ec29..47bb2ae 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -102,8 +102,9 @@
 		goto exit;
 
 	sdata->local->oper_channel = sdata->local->csa_channel;
+	/* XXX: shouldn't really modify cfg80211-owned data! */
 	if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
-		bss->freq = sdata->local->oper_channel->center_freq;
+		bss->cbss.channel = sdata->local->oper_channel;
 
 	ieee80211_rx_bss_put(sdata->local, bss);
 exit:
@@ -158,7 +159,9 @@
 						IEEE80211_QUEUE_STOP_REASON_CSA);
 		ifsta->flags |= IEEE80211_STA_CSA_RECEIVED;
 		mod_timer(&ifsta->chswitch_timer,
-			  jiffies + msecs_to_jiffies(sw_elem->count * bss->beacon_int));
+			  jiffies +
+			  msecs_to_jiffies(sw_elem->count *
+					   bss->cbss.beacon_interval));
 	}
 }
 
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 10c5539..634f65c 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -194,12 +194,41 @@
 		dev_kfree_skb_any(skb);
 
 	for (i = 0; i <  STA_TID_NUM; i++) {
+		struct tid_ampdu_rx *tid_rx;
+		struct tid_ampdu_tx *tid_tx;
+
 		spin_lock_bh(&sta->lock);
-		if (sta->ampdu_mlme.tid_rx[i])
-		  del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer);
-		if (sta->ampdu_mlme.tid_tx[i])
-		  del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer);
+		tid_rx = sta->ampdu_mlme.tid_rx[i];
+		/* Make sure timer won't free the tid_rx struct, see below */
+		if (tid_rx)
+			tid_rx->shutdown = true;
 		spin_unlock_bh(&sta->lock);
+
+		/*
+		 * Outside spinlock - shutdown is true now so that the timer
+		 * won't free tid_rx, we have to do that now. Can't let the
+		 * timer do it because we have to sync the timer outside the
+		 * lock that it takes itself.
+		 */
+		if (tid_rx) {
+			del_timer_sync(&tid_rx->session_timer);
+			kfree(tid_rx);
+		}
+
+		/*
+		 * No need to do such complications for TX agg sessions, the
+		 * path leading to freeing the tid_tx struct goes via a call
+		 * from the driver, and thus needs to look up the sta struct
+		 * again, which cannot be found when we get here. Hence, we
+		 * just need to delete the timer and free the aggregation
+		 * info; we won't be telling the peer about it then but that
+		 * doesn't matter if we're not talking to it again anyway.
+		 */
+		tid_tx = sta->ampdu_mlme.tid_tx[i];
+		if (tid_tx) {
+			del_timer_sync(&tid_tx->addba_resp_timer);
+			kfree(tid_tx);
+		}
 	}
 
 	__sta_info_free(local, sta);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index d13a44b..d965323 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -65,7 +65,6 @@
 #define HT_AGG_STATE_OPERATIONAL	(HT_ADDBA_REQUESTED_MSK |	\
 					 HT_ADDBA_DRV_READY_MSK |	\
 					 HT_ADDBA_RECEIVED_MSK)
-#define HT_AGG_STATE_DEBUGFS_CTL	BIT(7)
 
 /**
  * struct tid_ampdu_tx - TID aggregation information (Tx).
@@ -89,7 +88,7 @@
  * @stored_mpdu_num: number of MPDUs in reordering buffer
  * @ssn: Starting Sequence Number expected to be aggregated.
  * @buf_size: buffer size for incoming A-MPDUs
- * @timeout: reset timer value.
+ * @timeout: reset timer value (in TUs).
  * @dialog_token: dialog token for aggregation session
  */
 struct tid_ampdu_rx {
@@ -101,6 +100,7 @@
 	u16 buf_size;
 	u16 timeout;
 	u8 dialog_token;
+	bool shutdown;
 };
 
 /**
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index f1c726d..bf73f6d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -35,6 +35,7 @@
 #define IEEE80211_TX_OK		0
 #define IEEE80211_TX_AGAIN	1
 #define IEEE80211_TX_FRAG_AGAIN	2
+#define IEEE80211_TX_PENDING	3
 
 /* misc utils */
 
@@ -1085,7 +1086,7 @@
 
 	if (skb) {
 		if (netif_subqueue_stopped(local->mdev, skb))
-			return IEEE80211_TX_AGAIN;
+			return IEEE80211_TX_PENDING;
 
 		ret = local->ops->tx(local_to_hw(local), skb);
 		if (ret)
@@ -1211,8 +1212,9 @@
 		 * queues, there's no reason for a driver to reject
 		 * a frame there, warn and drop it.
 		 */
-		if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
-			goto drop;
+		if (ret != IEEE80211_TX_PENDING)
+			if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
+				goto drop;
 
 		store = &local->pending_packet[queue];
 
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index bad1cfb..2b023dc 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -145,6 +145,21 @@
 	return -EOPNOTSUPP;
 }
 
+static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local)
+{
+	u8 wstats_flags = 0;
+
+	wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+					   IEEE80211_HW_SIGNAL_DBM) ?
+				IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
+	wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
+				IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
+	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+		wstats_flags |= IW_QUAL_DBM;
+
+	return wstats_flags;
+}
+
 static int ieee80211_ioctl_giwrange(struct net_device *dev,
 				 struct iw_request_info *info,
 				 struct iw_point *data, char *extra)
@@ -173,8 +188,9 @@
 	range->num_encoding_sizes = 2;
 	range->max_encoding_tokens = NUM_DEFAULT_KEYS;
 
+	/* cfg80211 requires this, and enforces 0..100 */
 	if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
-		range->max_qual.level = local->hw.max_signal;
+		range->max_qual.level = 100;
 	else if  (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
 		range->max_qual.level = -110;
 	else
@@ -186,13 +202,13 @@
 		range->max_qual.noise = 0;
 
 	range->max_qual.qual = 100;
-	range->max_qual.updated = local->wstats_flags;
+	range->max_qual.updated = ieee80211_get_wstats_flags(local);
 
 	range->avg_qual.qual = 50;
 	/* not always true but better than nothing */
 	range->avg_qual.level = range->max_qual.level / 2;
 	range->avg_qual.noise = range->max_qual.noise / 2;
-	range->avg_qual.updated = local->wstats_flags;
+	range->avg_qual.updated = ieee80211_get_wstats_flags(local);
 
 	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
 			  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
@@ -415,58 +431,6 @@
 }
 
 
-static int ieee80211_ioctl_siwscan(struct net_device *dev,
-				   struct iw_request_info *info,
-				   union iwreq_data *wrqu, char *extra)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct iw_scan_req *req = NULL;
-	u8 *ssid = NULL;
-	size_t ssid_len = 0;
-
-	if (!netif_running(dev))
-		return -ENETDOWN;
-
-	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
-		return -EOPNOTSUPP;
-
-	/* if SSID was specified explicitly then use that */
-	if (wrqu->data.length == sizeof(struct iw_scan_req) &&
-	    wrqu->data.flags & IW_SCAN_THIS_ESSID) {
-		req = (struct iw_scan_req *)extra;
-		ssid = req->essid;
-		ssid_len = req->essid_len;
-	}
-
-	return ieee80211_request_scan(sdata, ssid, ssid_len);
-}
-
-
-static int ieee80211_ioctl_giwscan(struct net_device *dev,
-				   struct iw_request_info *info,
-				   struct iw_point *data, char *extra)
-{
-	int res;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	if (local->sw_scanning || local->hw_scanning)
-		return -EAGAIN;
-
-	res = ieee80211_scan_results(local, info, extra, data->length);
-	if (res >= 0) {
-		data->length = res;
-		return 0;
-	}
-	data->length = 0;
-	return res;
-}
-
-
 static int ieee80211_ioctl_siwrate(struct net_device *dev,
 				  struct iw_request_info *info,
 				  struct iw_param *rate, char *extra)
@@ -982,9 +946,21 @@
 			break;
 		}
 		if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-		    sdata->vif.type == NL80211_IFTYPE_ADHOC)
-			sdata->u.sta.mfp = data->value;
-		else
+		    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+			switch (data->value) {
+			case IW_AUTH_MFP_DISABLED:
+				sdata->u.sta.mfp = IEEE80211_MFP_DISABLED;
+				break;
+			case IW_AUTH_MFP_OPTIONAL:
+				sdata->u.sta.mfp = IEEE80211_MFP_OPTIONAL;
+				break;
+			case IW_AUTH_MFP_REQUIRED:
+				sdata->u.sta.mfp = IEEE80211_MFP_REQUIRED;
+				break;
+			default:
+				ret = -EINVAL;
+			}
+		} else
 			ret = -EOPNOTSUPP;
 		break;
 	default:
@@ -1018,7 +994,7 @@
 		wstats->qual.level = sta->last_signal;
 		wstats->qual.qual = sta->last_qual;
 		wstats->qual.noise = sta->last_noise;
-		wstats->qual.updated = local->wstats_flags;
+		wstats->qual.updated = ieee80211_get_wstats_flags(local);
 	}
 
 	rcu_read_unlock();
@@ -1153,8 +1129,8 @@
 	(iw_handler) ieee80211_ioctl_giwap,		/* SIOCGIWAP */
 	(iw_handler) ieee80211_ioctl_siwmlme,		/* SIOCSIWMLME */
 	(iw_handler) NULL,				/* SIOCGIWAPLIST */
-	(iw_handler) ieee80211_ioctl_siwscan,		/* SIOCSIWSCAN */
-	(iw_handler) ieee80211_ioctl_giwscan,		/* SIOCGIWSCAN */
+	(iw_handler) cfg80211_wext_siwscan,		/* SIOCSIWSCAN */
+	(iw_handler) cfg80211_wext_giwscan,		/* SIOCGIWSCAN */
 	(iw_handler) ieee80211_ioctl_siwessid,		/* SIOCSIWESSID */
 	(iw_handler) ieee80211_ioctl_giwessid,		/* SIOCGIWESSID */
 	(iw_handler) NULL,				/* SIOCSIWNICKN */
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 938a334..dad43c2 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -5,7 +5,7 @@
 obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
 obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
 
-cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o
 cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
 cfg80211-$(CONFIG_NL80211) += nl80211.o
 
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 1252264..0668b2bf 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -240,6 +240,8 @@
 	mutex_init(&drv->mtx);
 	mutex_init(&drv->devlist_mtx);
 	INIT_LIST_HEAD(&drv->netdev_list);
+	spin_lock_init(&drv->bss_lock);
+	INIT_LIST_HEAD(&drv->bss_list);
 
 	device_initialize(&drv->wiphy.dev);
 	drv->wiphy.dev.class = &ieee80211_class;
@@ -259,6 +261,9 @@
 	int i;
 	u16 ifmodes = wiphy->interface_modes;
 
+	if (WARN_ON(wiphy->max_scan_ssids < 1))
+		return -EINVAL;
+
 	/* sanity check ifmodes */
 	WARN_ON(!ifmodes);
 	ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
@@ -367,8 +372,11 @@
 
 void cfg80211_dev_free(struct cfg80211_registered_device *drv)
 {
+	struct cfg80211_internal_bss *scan, *tmp;
 	mutex_destroy(&drv->mtx);
 	mutex_destroy(&drv->devlist_mtx);
+	list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
+		cfg80211_put_bss(&scan->pub);
 	kfree(drv);
 }
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index f7fb9f4..e29ad4c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -8,6 +8,8 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/netdevice.h>
+#include <linux/kref.h>
+#include <linux/rbtree.h>
 #include <net/genetlink.h>
 #include <net/wireless.h>
 #include <net/cfg80211.h>
@@ -41,6 +43,13 @@
 	struct mutex devlist_mtx;
 	struct list_head netdev_list;
 
+	/* BSSes/scanning */
+	spinlock_t bss_lock;
+	struct list_head bss_list;
+	struct rb_root bss_tree;
+	u32 bss_generation;
+	struct cfg80211_scan_request *scan_req; /* protected by RTNL */
+
 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
 	struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -56,6 +65,15 @@
 extern struct mutex cfg80211_drv_mutex;
 extern struct list_head cfg80211_drv_list;
 
+struct cfg80211_internal_bss {
+	struct list_head list;
+	struct rb_node rbn;
+	unsigned long ts;
+	struct kref ref;
+	/* must be last because of priv member */
+	struct cfg80211_bss pub;
+};
+
 /*
  * This function returns a pointer to the driver
  * that the genl_info item that is passed refers to.
@@ -94,4 +112,6 @@
 void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
 void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby);
 
+void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
+
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d452396..298a4de 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -14,6 +14,7 @@
 #include <linux/nl80211.h>
 #include <linux/rtnetlink.h>
 #include <linux/netlink.h>
+#include <linux/etherdevice.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
 #include "core.h"
@@ -109,6 +110,8 @@
 	[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
 	[NL80211_ATTR_IE] = { .type = NLA_BINARY,
 			      .len = IEEE80211_MAX_DATA_LEN },
+	[NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
+	[NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
 };
 
 /* message building helper */
@@ -141,6 +144,8 @@
 
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
 	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+	NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+		   dev->wiphy.max_scan_ssids);
 
 	nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
 	if (!nl_modes)
@@ -2270,6 +2275,246 @@
 	return err;
 }
 
+static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	struct net_device *dev;
+	struct cfg80211_scan_request *request;
+	struct cfg80211_ssid *ssid;
+	struct ieee80211_channel *channel;
+	struct nlattr *attr;
+	struct wiphy *wiphy;
+	int err, tmp, n_ssids = 0, n_channels = 0, i;
+	enum ieee80211_band band;
+
+	err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+	if (err)
+		return err;
+
+	wiphy = &drv->wiphy;
+
+	if (!drv->ops->scan) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+
+	if (drv->scan_req) {
+		err = -EBUSY;
+		goto out_unlock;
+	}
+
+	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp)
+			n_channels++;
+		if (!n_channels) {
+			err = -EINVAL;
+			goto out_unlock;
+		}
+	} else {
+		for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+			if (wiphy->bands[band])
+				n_channels += wiphy->bands[band]->n_channels;
+	}
+
+	if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
+		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
+			n_ssids++;
+
+	if (n_ssids > wiphy->max_scan_ssids) {
+		err = -EINVAL;
+		goto out_unlock;
+	}
+
+	request = kzalloc(sizeof(*request)
+			+ sizeof(*ssid) * n_ssids
+			+ sizeof(channel) * n_channels, GFP_KERNEL);
+	if (!request) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+
+	request->channels = (void *)((char *)request + sizeof(*request));
+	request->n_channels = n_channels;
+	if (n_ssids)
+		request->ssids = (void *)(request->channels + n_channels);
+	request->n_ssids = n_ssids;
+
+	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+		/* user specified, bail out if channel not found */
+		request->n_channels = n_channels;
+		i = 0;
+		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
+			request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr));
+			if (!request->channels[i]) {
+				err = -EINVAL;
+				goto out_free;
+			}
+			i++;
+		}
+	} else {
+		/* all channels */
+		i = 0;
+		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+			int j;
+			if (!wiphy->bands[band])
+				continue;
+			for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+				request->channels[i] = &wiphy->bands[band]->channels[j];
+				i++;
+			}
+		}
+	}
+
+	i = 0;
+	if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
+		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
+			if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) {
+				err = -EINVAL;
+				goto out_free;
+			}
+			memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
+			request->ssids[i].ssid_len = nla_len(attr);
+			i++;
+		}
+	}
+
+	request->ifidx = dev->ifindex;
+	request->wiphy = &drv->wiphy;
+
+	drv->scan_req = request;
+	err = drv->ops->scan(&drv->wiphy, dev, request);
+
+ out_free:
+	if (err) {
+		drv->scan_req = NULL;
+		kfree(request);
+	}
+ out_unlock:
+	rtnl_unlock();
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+			    struct cfg80211_registered_device *rdev,
+			    struct net_device *dev,
+			    struct cfg80211_bss *res)
+{
+	void *hdr;
+	struct nlattr *bss;
+
+	hdr = nl80211hdr_put(msg, pid, seq, flags,
+			     NL80211_CMD_NEW_SCAN_RESULTS);
+	if (!hdr)
+		return -1;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION,
+		    rdev->bss_generation);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+
+	bss = nla_nest_start(msg, NL80211_ATTR_BSS);
+	if (!bss)
+		goto nla_put_failure;
+	if (!is_zero_ether_addr(res->bssid))
+		NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid);
+	if (res->information_elements && res->len_information_elements)
+		NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
+			res->len_information_elements,
+			res->information_elements);
+	if (res->tsf)
+		NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
+	if (res->beacon_interval)
+		NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
+	NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
+	NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
+
+	switch (res->signal_type) {
+	case CFG80211_SIGNAL_TYPE_MBM:
+		NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal);
+		break;
+	case CFG80211_SIGNAL_TYPE_UNSPEC:
+		NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal);
+		break;
+	default:
+		break;
+	}
+
+	nla_nest_end(msg, bss);
+
+	return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+static int nl80211_dump_scan(struct sk_buff *skb,
+			     struct netlink_callback *cb)
+{
+	struct cfg80211_registered_device *dev;
+	struct net_device *netdev;
+	struct cfg80211_internal_bss *scan;
+	int ifidx = cb->args[0];
+	int start = cb->args[1], idx = 0;
+	int err;
+
+	if (!ifidx) {
+		err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+				  nl80211_fam.attrbuf, nl80211_fam.maxattr,
+				  nl80211_policy);
+		if (err)
+			return err;
+
+		if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
+			return -EINVAL;
+
+		ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
+		if (!ifidx)
+			return -EINVAL;
+		cb->args[0] = ifidx;
+	}
+
+	netdev = dev_get_by_index(&init_net, ifidx);
+	if (!netdev)
+		return -ENODEV;
+
+	dev = cfg80211_get_dev_from_ifindex(ifidx);
+	if (IS_ERR(dev)) {
+		err = PTR_ERR(dev);
+		goto out_put_netdev;
+	}
+
+	spin_lock_bh(&dev->bss_lock);
+	cfg80211_bss_expire(dev);
+
+	list_for_each_entry(scan, &dev->bss_list, list) {
+		if (++idx <= start)
+			continue;
+		if (nl80211_send_bss(skb,
+				NETLINK_CB(cb->skb).pid,
+				cb->nlh->nlmsg_seq, NLM_F_MULTI,
+				dev, netdev, &scan->pub) < 0) {
+			idx--;
+			goto out;
+		}
+	}
+
+ out:
+	spin_unlock_bh(&dev->bss_lock);
+
+	cb->args[1] = idx;
+	err = skb->len;
+	cfg80211_put_dev(dev);
+ out_put_netdev:
+	dev_put(netdev);
+
+	return err;
+}
+
 static struct genl_ops nl80211_ops[] = {
 	{
 		.cmd = NL80211_CMD_GET_WIPHY,
@@ -2443,12 +2688,26 @@
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
+	{
+		.cmd = NL80211_CMD_TRIGGER_SCAN,
+		.doit = nl80211_trigger_scan,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_GET_SCAN,
+		.policy = nl80211_policy,
+		.dumpit = nl80211_dump_scan,
+	},
 };
 
 /* multicast groups */
 static struct genl_multicast_group nl80211_config_mcgrp = {
 	.name = "config",
 };
+static struct genl_multicast_group nl80211_scan_mcgrp = {
+	.name = "scan",
+};
 
 /* notification functions */
 
@@ -2468,6 +2727,66 @@
 	genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
 }
 
+static int nl80211_send_scan_donemsg(struct sk_buff *msg,
+				    struct cfg80211_registered_device *rdev,
+				    struct net_device *netdev,
+				    u32 pid, u32 seq, int flags,
+				    u32 cmd)
+{
+	void *hdr;
+
+	hdr = nl80211hdr_put(msg, pid, seq, flags, cmd);
+	if (!hdr)
+		return -1;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+
+	/* XXX: we should probably bounce back the request? */
+
+	return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+			    struct net_device *netdev)
+{
+	struct sk_buff *msg;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return;
+
+	if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
+				      NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
+void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
+			       struct net_device *netdev)
+{
+	struct sk_buff *msg;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return;
+
+	if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
+				      NL80211_CMD_SCAN_ABORTED) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
@@ -2488,6 +2807,10 @@
 	if (err)
 		goto err_out;
 
+	err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp);
+	if (err)
+		goto err_out;
+
 	return 0;
  err_out:
 	genl_unregister_family(&nl80211_fam);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index f3ea5c0..b565a5f 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -7,6 +7,10 @@
 extern int nl80211_init(void);
 extern void nl80211_exit(void);
 extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
+extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+				   struct net_device *netdev);
+extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
+				      struct net_device *netdev);
 #else
 static inline int nl80211_init(void)
 {
@@ -19,6 +23,10 @@
 	struct cfg80211_registered_device *rdev)
 {
 }
+static inline void
+nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+		       struct net_device *netdev)
+{}
 #endif /* CONFIG_NL80211 */
 
 #endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
new file mode 100644
index 0000000..b1893c8
--- /dev/null
+++ b/net/wireless/scan.c
@@ -0,0 +1,836 @@
+/*
+ * cfg80211 scan result handling
+ *
+ * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/nl80211.h>
+#include <linux/etherdevice.h>
+#include <net/arp.h>
+#include <net/cfg80211.h>
+#include <net/iw_handler.h>
+#include "core.h"
+#include "nl80211.h"
+
+#define IEEE80211_SCAN_RESULT_EXPIRE	(10 * HZ)
+
+void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
+{
+	struct net_device *dev;
+#ifdef CONFIG_WIRELESS_EXT
+	union iwreq_data wrqu;
+#endif
+
+	dev = dev_get_by_index(&init_net, request->ifidx);
+	if (!dev)
+		goto out;
+
+	WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
+	wiphy_to_dev(request->wiphy)->scan_req = NULL;
+
+	if (aborted)
+		nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
+	else
+		nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
+
+#ifdef CONFIG_WIRELESS_EXT
+	if (!aborted) {
+		memset(&wrqu, 0, sizeof(wrqu));
+
+		wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+	}
+#endif
+
+	dev_put(dev);
+
+ out:
+	kfree(request);
+}
+EXPORT_SYMBOL(cfg80211_scan_done);
+
+static void bss_release(struct kref *ref)
+{
+	struct cfg80211_internal_bss *bss;
+
+	bss = container_of(ref, struct cfg80211_internal_bss, ref);
+	if (bss->pub.free_priv)
+		bss->pub.free_priv(&bss->pub);
+	kfree(bss);
+}
+
+/* must hold dev->bss_lock! */
+void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
+{
+	struct cfg80211_internal_bss *bss, *tmp;
+	bool expired = false;
+
+	list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
+		if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+			continue;
+		list_del(&bss->list);
+		rb_erase(&bss->rbn, &dev->bss_tree);
+		kref_put(&bss->ref, bss_release);
+		expired = true;
+	}
+
+	if (expired)
+		dev->bss_generation++;
+}
+
+static u8 *find_ie(u8 num, u8 *ies, size_t len)
+{
+	while (len > 2 && ies[0] != num) {
+		len -= ies[1] + 2;
+		ies += ies[1] + 2;
+	}
+	if (len < 2)
+		return NULL;
+	if (len < 2 + ies[1])
+		return NULL;
+	return ies;
+}
+
+static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
+{
+	const u8 *ie1 = find_ie(num, ies1, len1);
+	const u8 *ie2 = find_ie(num, ies2, len2);
+	int r;
+
+	if (!ie1 && !ie2)
+		return 0;
+	if (!ie1)
+		return -1;
+
+	r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1]));
+	if (r == 0 && ie1[1] != ie2[1])
+		return ie2[1] - ie1[1];
+	return r;
+}
+
+static bool is_bss(struct cfg80211_bss *a,
+		   const u8 *bssid,
+		   const u8 *ssid, size_t ssid_len)
+{
+	const u8 *ssidie;
+
+	if (bssid && compare_ether_addr(a->bssid, bssid))
+		return false;
+
+	if (!ssid)
+		return true;
+
+	ssidie = find_ie(WLAN_EID_SSID,
+			 a->information_elements,
+			 a->len_information_elements);
+	if (!ssidie)
+		return false;
+	if (ssidie[1] != ssid_len)
+		return false;
+	return memcmp(ssidie + 2, ssid, ssid_len) == 0;
+}
+
+static bool is_mesh(struct cfg80211_bss *a,
+		    const u8 *meshid, size_t meshidlen,
+		    const u8 *meshcfg)
+{
+	const u8 *ie;
+
+	if (!is_zero_ether_addr(a->bssid))
+		return false;
+
+	ie = find_ie(WLAN_EID_MESH_ID,
+		     a->information_elements,
+		     a->len_information_elements);
+	if (!ie)
+		return false;
+	if (ie[1] != meshidlen)
+		return false;
+	if (memcmp(ie + 2, meshid, meshidlen))
+		return false;
+
+	ie = find_ie(WLAN_EID_MESH_CONFIG,
+		     a->information_elements,
+		     a->len_information_elements);
+	if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
+		return false;
+
+	/*
+	 * Ignore mesh capability (last two bytes of the IE) when
+	 * comparing since that may differ between stations taking
+	 * part in the same mesh.
+	 */
+	return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0;
+}
+
+static int cmp_bss(struct cfg80211_bss *a,
+		   struct cfg80211_bss *b)
+{
+	int r;
+
+	if (a->channel != b->channel)
+		return b->channel->center_freq - a->channel->center_freq;
+
+	r = memcmp(a->bssid, b->bssid, ETH_ALEN);
+	if (r)
+		return r;
+
+	if (is_zero_ether_addr(a->bssid)) {
+		r = cmp_ies(WLAN_EID_MESH_ID,
+			    a->information_elements,
+			    a->len_information_elements,
+			    b->information_elements,
+			    b->len_information_elements);
+		if (r)
+			return r;
+		return cmp_ies(WLAN_EID_MESH_CONFIG,
+			       a->information_elements,
+			       a->len_information_elements,
+			       b->information_elements,
+			       b->len_information_elements);
+	}
+
+	return cmp_ies(WLAN_EID_SSID,
+		       a->information_elements,
+		       a->len_information_elements,
+		       b->information_elements,
+		       b->len_information_elements);
+}
+
+struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
+				      struct ieee80211_channel *channel,
+				      const u8 *bssid,
+				      const u8 *ssid, size_t ssid_len,
+				      u16 capa_mask, u16 capa_val)
+{
+	struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+	struct cfg80211_internal_bss *bss, *res = NULL;
+
+	spin_lock_bh(&dev->bss_lock);
+
+	list_for_each_entry(bss, &dev->bss_list, list) {
+		if ((bss->pub.capability & capa_mask) != capa_val)
+			continue;
+		if (channel && bss->pub.channel != channel)
+			continue;
+		if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
+			res = bss;
+			kref_get(&res->ref);
+			break;
+		}
+	}
+
+	spin_unlock_bh(&dev->bss_lock);
+	if (!res)
+		return NULL;
+	return &res->pub;
+}
+EXPORT_SYMBOL(cfg80211_get_bss);
+
+struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
+				       struct ieee80211_channel *channel,
+				       const u8 *meshid, size_t meshidlen,
+				       const u8 *meshcfg)
+{
+	struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+	struct cfg80211_internal_bss *bss, *res = NULL;
+
+	spin_lock_bh(&dev->bss_lock);
+
+	list_for_each_entry(bss, &dev->bss_list, list) {
+		if (channel && bss->pub.channel != channel)
+			continue;
+		if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) {
+			res = bss;
+			kref_get(&res->ref);
+			break;
+		}
+	}
+
+	spin_unlock_bh(&dev->bss_lock);
+	if (!res)
+		return NULL;
+	return &res->pub;
+}
+EXPORT_SYMBOL(cfg80211_get_mesh);
+
+
+static void rb_insert_bss(struct cfg80211_registered_device *dev,
+			  struct cfg80211_internal_bss *bss)
+{
+	struct rb_node **p = &dev->bss_tree.rb_node;
+	struct rb_node *parent = NULL;
+	struct cfg80211_internal_bss *tbss;
+	int cmp;
+
+	while (*p) {
+		parent = *p;
+		tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
+
+		cmp = cmp_bss(&bss->pub, &tbss->pub);
+
+		if (WARN_ON(!cmp)) {
+			/* will sort of leak this BSS */
+			return;
+		}
+
+		if (cmp < 0)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+
+	rb_link_node(&bss->rbn, parent, p);
+	rb_insert_color(&bss->rbn, &dev->bss_tree);
+}
+
+static struct cfg80211_internal_bss *
+rb_find_bss(struct cfg80211_registered_device *dev,
+	    struct cfg80211_internal_bss *res)
+{
+	struct rb_node *n = dev->bss_tree.rb_node;
+	struct cfg80211_internal_bss *bss;
+	int r;
+
+	while (n) {
+		bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
+		r = cmp_bss(&res->pub, &bss->pub);
+
+		if (r == 0)
+			return bss;
+		else if (r < 0)
+			n = n->rb_left;
+		else
+			n = n->rb_right;
+	}
+
+	return NULL;
+}
+
+static struct cfg80211_internal_bss *
+cfg80211_bss_update(struct cfg80211_registered_device *dev,
+		    struct cfg80211_internal_bss *res,
+		    bool overwrite)
+{
+	struct cfg80211_internal_bss *found = NULL;
+	const u8 *meshid, *meshcfg;
+
+	/*
+	 * The reference to "res" is donated to this function.
+	 */
+
+	if (WARN_ON(!res->pub.channel)) {
+		kref_put(&res->ref, bss_release);
+		return NULL;
+	}
+
+	res->ts = jiffies;
+
+	if (is_zero_ether_addr(res->pub.bssid)) {
+		/* must be mesh, verify */
+		meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements,
+				 res->pub.len_information_elements);
+		meshcfg = find_ie(WLAN_EID_MESH_CONFIG,
+				  res->pub.information_elements,
+				  res->pub.len_information_elements);
+		if (!meshid || !meshcfg ||
+		    meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) {
+			/* bogus mesh */
+			kref_put(&res->ref, bss_release);
+			return NULL;
+		}
+	}
+
+	spin_lock_bh(&dev->bss_lock);
+
+	found = rb_find_bss(dev, res);
+
+	if (found && overwrite) {
+		list_replace(&found->list, &res->list);
+		rb_replace_node(&found->rbn, &res->rbn,
+				&dev->bss_tree);
+		kref_put(&found->ref, bss_release);
+		found = res;
+	} else if (found) {
+		kref_get(&found->ref);
+		found->pub.beacon_interval = res->pub.beacon_interval;
+		found->pub.tsf = res->pub.tsf;
+		found->pub.signal = res->pub.signal;
+		found->pub.signal_type = res->pub.signal_type;
+		found->pub.capability = res->pub.capability;
+		found->ts = res->ts;
+		kref_put(&res->ref, bss_release);
+	} else {
+		/* this "consumes" the reference */
+		list_add_tail(&res->list, &dev->bss_list);
+		rb_insert_bss(dev, res);
+		found = res;
+	}
+
+	dev->bss_generation++;
+	spin_unlock_bh(&dev->bss_lock);
+
+	kref_get(&found->ref);
+	return found;
+}
+
+struct cfg80211_bss *
+cfg80211_inform_bss_frame(struct wiphy *wiphy,
+			  struct ieee80211_channel *channel,
+			  struct ieee80211_mgmt *mgmt, size_t len,
+			  s32 signal, enum cfg80211_signal_type sigtype,
+			  gfp_t gfp)
+{
+	struct cfg80211_internal_bss *res;
+	size_t ielen = len - offsetof(struct ieee80211_mgmt,
+				      u.probe_resp.variable);
+	bool overwrite;
+	size_t privsz = wiphy->bss_priv_size;
+
+	if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC &&
+	            (signal < 0 || signal > 100)))
+		return NULL;
+
+	if (WARN_ON(!mgmt || !wiphy ||
+		    len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
+		return NULL;
+
+	res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
+	if (!res)
+		return NULL;
+
+	memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
+	res->pub.channel = channel;
+	res->pub.signal_type = sigtype;
+	res->pub.signal = signal;
+	res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
+	res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
+	res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
+	/* point to after the private area */
+	res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
+	memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen);
+	res->pub.len_information_elements = ielen;
+
+	kref_init(&res->ref);
+
+	overwrite = ieee80211_is_probe_resp(mgmt->frame_control);
+
+	res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);
+	if (!res)
+		return NULL;
+
+	/* cfg80211_bss_update gives us a referenced result */
+	return &res->pub;
+}
+EXPORT_SYMBOL(cfg80211_inform_bss_frame);
+
+void cfg80211_put_bss(struct cfg80211_bss *pub)
+{
+	struct cfg80211_internal_bss *bss;
+
+	if (!pub)
+		return;
+
+	bss = container_of(pub, struct cfg80211_internal_bss, pub);
+	kref_put(&bss->ref, bss_release);
+}
+EXPORT_SYMBOL(cfg80211_put_bss);
+
+void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
+{
+	struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+	struct cfg80211_internal_bss *bss;
+
+	if (WARN_ON(!pub))
+		return;
+
+	bss = container_of(pub, struct cfg80211_internal_bss, pub);
+
+	spin_lock_bh(&dev->bss_lock);
+
+	list_del(&bss->list);
+	rb_erase(&bss->rbn, &dev->bss_tree);
+
+	spin_unlock_bh(&dev->bss_lock);
+
+	kref_put(&bss->ref, bss_release);
+}
+EXPORT_SYMBOL(cfg80211_unlink_bss);
+
+#ifdef CONFIG_WIRELESS_EXT
+int cfg80211_wext_siwscan(struct net_device *dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *wrqu, char *extra)
+{
+	struct cfg80211_registered_device *rdev;
+	struct wiphy *wiphy;
+	struct iw_scan_req *wreq = NULL;
+	struct cfg80211_scan_request *creq;
+	int i, err, n_channels = 0;
+	enum ieee80211_band band;
+
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	rdev = cfg80211_get_dev_from_ifindex(dev->ifindex);
+
+	if (IS_ERR(rdev))
+		return PTR_ERR(rdev);
+
+	if (rdev->scan_req) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	wiphy = &rdev->wiphy;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+		if (wiphy->bands[band])
+			n_channels += wiphy->bands[band]->n_channels;
+
+	creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
+		       n_channels * sizeof(void *),
+		       GFP_ATOMIC);
+	if (!creq) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	creq->wiphy = wiphy;
+	creq->ifidx = dev->ifindex;
+	creq->ssids = (void *)(creq + 1);
+	creq->channels = (void *)(creq->ssids + 1);
+	creq->n_channels = n_channels;
+	creq->n_ssids = 1;
+
+	/* all channels */
+	i = 0;
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		int j;
+		if (!wiphy->bands[band])
+			continue;
+		for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+			creq->channels[i] = &wiphy->bands[band]->channels[j];
+			i++;
+		}
+	}
+
+	/* translate scan request */
+	if (wrqu->data.length == sizeof(struct iw_scan_req)) {
+		wreq = (struct iw_scan_req *)extra;
+
+		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+			if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
+				return -EINVAL;
+			memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
+			creq->ssids[0].ssid_len = wreq->essid_len;
+		}
+		if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
+			creq->n_ssids = 0;
+	}
+
+	rdev->scan_req = creq;
+	err = rdev->ops->scan(wiphy, dev, creq);
+	if (err) {
+		rdev->scan_req = NULL;
+		kfree(creq);
+	}
+ out:
+	cfg80211_put_dev(rdev);
+	return err;
+}
+EXPORT_SYMBOL(cfg80211_wext_siwscan);
+
+static void ieee80211_scan_add_ies(struct iw_request_info *info,
+				   struct cfg80211_bss *bss,
+				   char **current_ev, char *end_buf)
+{
+	u8 *pos, *end, *next;
+	struct iw_event iwe;
+
+	if (!bss->information_elements ||
+	    !bss->len_information_elements)
+		return;
+
+	/*
+	 * If needed, fragment the IEs buffer (at IE boundaries) into short
+	 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
+	 */
+	pos = bss->information_elements;
+	end = pos + bss->len_information_elements;
+
+	while (end - pos > IW_GENERIC_IE_MAX) {
+		next = pos + 2 + pos[1];
+		while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
+			next = next + 2 + next[1];
+
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = next - pos;
+		*current_ev = iwe_stream_add_point(info, *current_ev,
+						   end_buf, &iwe, pos);
+
+		pos = next;
+	}
+
+	if (end > pos) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = end - pos;
+		*current_ev = iwe_stream_add_point(info, *current_ev,
+						   end_buf, &iwe, pos);
+	}
+}
+
+
+static char *
+ieee80211_bss(struct iw_request_info *info,
+		      struct cfg80211_internal_bss *bss,
+		      char *current_ev, char *end_buf)
+{
+	struct iw_event iwe;
+	u8 *buf, *cfg, *p;
+	u8 *ie = bss->pub.information_elements;
+	int rem = bss->pub.len_information_elements, i;
+	bool ismesh = false;
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+					  IW_EV_ADDR_LEN);
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
+	iwe.u.freq.e = 0;
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+					  IW_EV_FREQ_LEN);
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = bss->pub.channel->center_freq;
+	iwe.u.freq.e = 6;
+	current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+					  IW_EV_FREQ_LEN);
+
+	if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVQUAL;
+		iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
+				     IW_QUAL_NOISE_INVALID |
+				     IW_QUAL_QUAL_INVALID;
+		switch (bss->pub.signal_type) {
+		case CFG80211_SIGNAL_TYPE_MBM:
+			iwe.u.qual.level = bss->pub.signal / 100;
+			iwe.u.qual.updated |= IW_QUAL_DBM;
+			break;
+		case CFG80211_SIGNAL_TYPE_UNSPEC:
+			iwe.u.qual.level = bss->pub.signal;
+			break;
+		default:
+			/* not reached */
+			break;
+		}
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_QUAL_LEN);
+	}
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWENCODE;
+	if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+					  &iwe, "");
+
+	while (rem >= 2) {
+		/* invalid data */
+		if (ie[1] > rem - 2)
+			break;
+
+		switch (ie[0]) {
+		case WLAN_EID_SSID:
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWESSID;
+			iwe.u.data.length = ie[1];
+			iwe.u.data.flags = 1;
+			current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+							  &iwe, ie + 2);
+			break;
+		case WLAN_EID_MESH_ID:
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWESSID;
+			iwe.u.data.length = ie[1];
+			iwe.u.data.flags = 1;
+			current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+							  &iwe, ie + 2);
+			break;
+		case WLAN_EID_MESH_CONFIG:
+			ismesh = true;
+			if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
+				break;
+			buf = kmalloc(50, GFP_ATOMIC);
+			if (!buf)
+				break;
+			cfg = ie + 2;
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVCUSTOM;
+			sprintf(buf, "Mesh network (version %d)", cfg[0]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Path Selection Protocol ID: "
+				"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
+							cfg[4]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Path Selection Metric ID: "
+				"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
+							cfg[8]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Congestion Control Mode ID: "
+				"0x%02X%02X%02X%02X", cfg[9], cfg[10],
+							cfg[11], cfg[12]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Channel Precedence: "
+				"0x%02X%02X%02X%02X", cfg[13], cfg[14],
+							cfg[15], cfg[16]);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(info, current_ev,
+							  end_buf,
+							  &iwe, buf);
+			kfree(buf);
+			break;
+		case WLAN_EID_SUPP_RATES:
+		case WLAN_EID_EXT_SUPP_RATES:
+			/* display all supported rates in readable format */
+			p = current_ev + iwe_stream_lcp_len(info);
+
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = SIOCGIWRATE;
+			/* Those two flags are ignored... */
+			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+			for (i = 0; i < ie[1]; i++) {
+				iwe.u.bitrate.value =
+					((ie[i + 2] & 0x7f) * 500000);
+				p = iwe_stream_add_value(info, current_ev, p,
+						end_buf, &iwe, IW_EV_PARAM_LEN);
+			}
+			current_ev = p;
+			break;
+		}
+		rem -= ie[1] + 2;
+		ie += ie[1] + 2;
+	}
+
+	if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
+	    || ismesh) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = SIOCGIWMODE;
+		if (ismesh)
+			iwe.u.mode = IW_MODE_MESH;
+		else if (bss->pub.capability & WLAN_CAPABILITY_ESS)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+						  &iwe, IW_EV_UINT_LEN);
+	}
+
+	buf = kmalloc(30, GFP_ATOMIC);
+	if (buf) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVCUSTOM;
+		sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf));
+		iwe.u.data.length = strlen(buf);
+		current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+						  &iwe, buf);
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVCUSTOM;
+		sprintf(buf, " Last beacon: %dms ago",
+			jiffies_to_msecs(jiffies - bss->ts));
+		iwe.u.data.length = strlen(buf);
+		current_ev = iwe_stream_add_point(info, current_ev,
+						  end_buf, &iwe, buf);
+		kfree(buf);
+	}
+
+	ieee80211_scan_add_ies(info, &bss->pub, &current_ev, end_buf);
+
+	return current_ev;
+}
+
+
+static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
+				  struct iw_request_info *info,
+				  char *buf, size_t len)
+{
+	char *current_ev = buf;
+	char *end_buf = buf + len;
+	struct cfg80211_internal_bss *bss;
+
+	spin_lock_bh(&dev->bss_lock);
+	cfg80211_bss_expire(dev);
+
+	list_for_each_entry(bss, &dev->bss_list, list) {
+		if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
+			spin_unlock_bh(&dev->bss_lock);
+			return -E2BIG;
+		}
+		current_ev = ieee80211_bss(info, bss,
+						   current_ev, end_buf);
+	}
+	spin_unlock_bh(&dev->bss_lock);
+	return current_ev - buf;
+}
+
+
+int cfg80211_wext_giwscan(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_point *data, char *extra)
+{
+	struct cfg80211_registered_device *rdev;
+	int res;
+
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	rdev = cfg80211_get_dev_from_ifindex(dev->ifindex);
+
+	if (IS_ERR(rdev))
+		return PTR_ERR(rdev);
+
+	if (rdev->scan_req) {
+		res = -EAGAIN;
+		goto out;
+	}
+
+	res = ieee80211_scan_results(rdev, info, extra, data->length);
+	data->length = 0;
+	if (res >= 0) {
+		data->length = res;
+		res = 0;
+	}
+
+ out:
+	cfg80211_put_dev(rdev);
+	return res;
+}
+EXPORT_SYMBOL(cfg80211_wext_giwscan);
+#endif