From e617fcefcd55b1184a1626ce34ab898832208862 Mon Sep 17 00:00:00 2001
From: nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Wed, 16 Jul 2008 16:30:03 +0000
Subject: add some madwifi fixes and enhancements by Sven-Ola, refresh patches

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11848 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 package/madwifi/Makefile                           |    2 +-
 package/madwifi/patches/202-debug_variables.patch  |  204 ++
 package/madwifi/patches/300-napi_polling.patch     |   38 +-
 package/madwifi/patches/305-pureg_fix.patch        |    2 +-
 package/madwifi/patches/309-micfail_detect.patch   |   10 +-
 package/madwifi/patches/310-noise_get.patch        |    8 +-
 package/madwifi/patches/317-bmask.patch            |    2 +-
 package/madwifi/patches/323-dfs_optional.patch     |    4 +-
 package/madwifi/patches/325-channel_spam.patch     |    6 +-
 package/madwifi/patches/327-queue.patch            |    6 +-
 package/madwifi/patches/330-beaconcal.patch        |   22 +-
 package/madwifi/patches/331-memory_alloc.patch     |    4 +-
 package/madwifi/patches/332-reset_beacons.patch    |    2 +-
 package/madwifi/patches/333-apscan_mode.patch      |    2 +-
 package/madwifi/patches/342-performance.patch      |    6 +-
 package/madwifi/patches/343-txqueue_races.patch    |    2 +-
 .../madwifi/patches/345-minstrel_sampling.patch    |    2 +-
 package/madwifi/patches/347-tuning.patch           |    2 +-
 package/madwifi/patches/348-ackcts.patch           |    4 +-
 package/madwifi/patches/349-reset.patch            |    2 +-
 package/madwifi/patches/351-scanlist.patch         |    2 +-
 package/madwifi/patches/352-ani_fix.patch          |   24 +-
 .../madwifi/patches/355-eap_auth_disassoc.patch    |    2 +-
 package/madwifi/patches/363-fix_turbo.patch        |   11 +
 package/madwifi/patches/364-memory_alloc.patch     |   13 +
 .../madwifi/patches/365-turbo_channelsearch.patch  |   10 +
 package/madwifi/patches/366-bstuck_thresh.patch    |   52 +
 package/madwifi/patches/406-monitor_r3711.patch    |   20 +
 package/madwifi/patches/407-new_athinfo.patch      | 2352 ++++++++++++++++++++
 29 files changed, 2739 insertions(+), 77 deletions(-)
 create mode 100644 package/madwifi/patches/202-debug_variables.patch
 create mode 100644 package/madwifi/patches/363-fix_turbo.patch
 create mode 100644 package/madwifi/patches/364-memory_alloc.patch
 create mode 100644 package/madwifi/patches/365-turbo_channelsearch.patch
 create mode 100644 package/madwifi/patches/366-bstuck_thresh.patch
 create mode 100644 package/madwifi/patches/406-monitor_r3711.patch
 create mode 100644 package/madwifi/patches/407-new_athinfo.patch

(limited to 'package/madwifi')

diff --git a/package/madwifi/Makefile b/package/madwifi/Makefile
index 874438b29..ac15b2c67 100644
--- a/package/madwifi/Makefile
+++ b/package/madwifi/Makefile
@@ -118,7 +118,7 @@ ifeq ($(findstring PCI,$(BUS)),PCI)
   MADWIFI_AUTOLOAD+= ath_pci
 endif
 
-MADWIFI_APPLETS:=80211stats,athchans,athctrl,athkey,athstats,wlanconfig
+MADWIFI_APPLETS:=80211stats,athchans,athctrl,athkey,athstats,wlanconfig,ath_info
 ifdef CONFIG_MADWIFI_DEBUG
   MADWIFI_APPLETS:=$(strip $(MADWIFI_APPLETS)),athdebug,80211debug
 endif
diff --git a/package/madwifi/patches/202-debug_variables.patch b/package/madwifi/patches/202-debug_variables.patch
new file mode 100644
index 000000000..83556ee7d
--- /dev/null
+++ b/package/madwifi/patches/202-debug_variables.patch
@@ -0,0 +1,204 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -453,8 +453,8 @@
+ MODULE_PARM_DESC(ratectl, "Rate control algorithm [amrr|minstrel|onoe|sample], "
+ 		"defaults to '" DEF_RATE_CTL "'");
+ 
+-static int	ath_debug = 0;
+ #ifdef AR_DEBUG
++static int	ath_debug = 0;
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(ath_debug, "i");
+ #else
+@@ -465,8 +465,8 @@
+ static void ath_printtxbuf(const struct ath_buf *, int);
+ #endif /* defined(AR_DEBUG) */
+ 
+-static int	ieee80211_debug = 0;
+ #ifdef AR_DEBUG
++static int	ieee80211_debug = 0;
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(ieee80211_debug, "i");
+ #else
+@@ -1565,7 +1565,9 @@
+ void
+ ath_suspend(struct net_device *dev)
+ {
++#ifdef AR_DEBUG
+ 	struct ath_softc *sc = dev->priv;
++#endif
+ 
+ 	DPRINTF(sc, ATH_DEBUG_ANY, "flags=%x\n", dev->flags);
+ 	ath_stop(dev);
+@@ -1574,7 +1576,9 @@
+ void
+ ath_resume(struct net_device *dev)
+ {
++#ifdef AR_DEBUG
+ 	struct ath_softc *sc = dev->priv;
++#endif
+ 
+ 	DPRINTF(sc, ATH_DEBUG_ANY, "flags=%x\n", dev->flags);
+ 	ath_init(dev);
+@@ -4019,7 +4023,9 @@
+ ath_key_update_begin(struct ieee80211vap *vap)
+ {
+ 	struct net_device *dev = vap->iv_ic->ic_dev;
++#ifdef AR_DEBUG
+ 	struct ath_softc *sc = dev->priv;
++#endif
+ 
+ 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "Begin\n");
+ 	/*
+@@ -4040,7 +4046,9 @@
+ ath_key_update_end(struct ieee80211vap *vap)
+ {
+ 	struct net_device *dev = vap->iv_ic->ic_dev;
++#ifdef AR_DEBUG
+ 	struct ath_softc *sc = dev->priv;
++#endif
+ 
+ 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n");
+ 	netif_wake_queue(dev);
+@@ -6218,7 +6226,9 @@
+ 	struct sk_buff *skb, int subtype, int rssi, u_int64_t rtsf)
+ {
+ 	struct ath_softc *sc = vap->iv_ic->ic_dev->priv;
++#ifdef AR_DEBUG
+         struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
++#endif
+ 	struct ieee80211_node * ni = ni_or_null;
+ 	u_int64_t hw_tsf, beacon_tsf;
+ 	u_int32_t hw_tu, beacon_tu, intval;
+@@ -8382,7 +8392,9 @@
+ static void
+ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
+ {
++#ifdef AR_DEBUG
+ 	struct ath_hal *ah = sc->sc_ah;
++#endif
+ 	struct ath_buf *bf;
+ 	/*
+ 	 * NB: this assumes output has been stopped and
+@@ -11002,6 +11014,7 @@
+ 		strncat(m, b, MLEN);
+ 	}
+ 	strncat(m, "\n", MLEN);
++#ifdef AR_DEBUG
+ 	if (1 /* bootverbose */) {
+ 		unsigned int i;
+ 		for (i = 0; i <= WME_AC_VO; i++) {
+@@ -11014,6 +11027,7 @@
+ 			sc->sc_cabq->axq_qnum);
+ 		IPRINTF(sc, "Use hw queue %u for beacons\n", sc->sc_bhalq);
+ 	}
++#endif
+ #undef HAL_MODE_DUALBAND
+ }
+  
+--- a/ath/if_ath_radar.c
++++ b/ath/if_ath_radar.c
+@@ -156,7 +156,9 @@
+ #endif
+ };
+ 
++#ifdef AR_DEBUG
+ static u_int32_t interval_to_frequency(u_int32_t pri);
++#endif
+ 
+ /* Returns true if radar detection is enabled. */
+ int ath_radar_is_enabled(struct ath_softc *sc)
+@@ -229,7 +231,9 @@
+ {
+ 
+ 	struct ath_hal *ah = sc->sc_ah;
++#ifdef AR_DEBUG
+ 	struct net_device *dev = sc->sc_dev;
++#endif
+ 	struct ieee80211com *ic = &sc->sc_ic;
+ 	int required = 0;
+ 
+@@ -366,6 +370,7 @@
+ #define MR_FAIL_MIN_PERIOD	4
+ #define MR_FAIL_MAX_PERIOD	5
+ 
++#ifdef AR_DEBUG
+ static const char* get_match_result_desc(u_int32_t code) {
+ 	switch (code) {
+ 	case MR_MATCH:
+@@ -384,6 +389,7 @@
+ 		return "unknown";
+ 	}
+ }
++#endif
+ 
+ static int32_t match_radar(
+ 	u_int32_t matched, 
+@@ -775,7 +781,10 @@
+ 	struct ath_softc *sc, struct ath_rp *last_pulse, 
+ 	u_int32_t *index, u_int32_t *pri, u_int32_t *matching_pulses, 
+ 	u_int32_t *missed_pulses, u_int32_t *noise_pulses)
+-{ struct net_device *dev = sc->sc_dev;
++{
++#ifdef AR_DEBUG
++	struct net_device *dev = sc->sc_dev;
++#endif
+ 	int i;
+ 	int best_index = -1;
+ 	unsigned int best_matched = 0;
+@@ -1217,6 +1226,7 @@
+ 	return (-1 != best_index) ? AH_TRUE : AH_FALSE;
+ }
+ 
++#ifdef AR_DEBUG
+ static u_int32_t interval_to_frequency(u_int32_t interval)
+ {
+ 	/* Calculate BRI from PRI */
+@@ -1224,6 +1234,7 @@
+ 	/* Round to nearest multiple of 50 */
+ 	return frequency + ((frequency % 50) >= 25 ? 50 : 0) - (frequency % 50);
+ }
++#endif
+ 
+ #ifdef ATH_RADAR_LONG_PULSE
+ static const char* get_longpulse_desc(int lp) {
+@@ -1580,7 +1591,9 @@
+ void ath_rp_record(struct ath_softc *sc, u_int64_t tsf, u_int8_t rssi, 
+ 			    u_int8_t width, HAL_BOOL is_simulated)
+ {
++#ifdef AR_DEBUG
+ 	struct net_device *dev = sc->sc_dev;
++#endif
+ 	struct ath_rp *pulse;
+ 
+ 	DPRINTF(sc, ATH_DEBUG_DOTHPULSES, "%s: ath_rp_record: "
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -931,7 +931,9 @@
+ 			    (struct ieee80211_node_table *) &vap->iv_ic->ic_sta;
+ 		unsigned int x = 0;
+ 		unsigned int this_tp, this_prob, this_eprob;
++#ifdef AR_DEBUG
+ 			struct ath_softc *sc = vap->iv_ic->ic_dev->priv;;
++#endif
+ 
+ 		IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+ 		TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -731,6 +731,7 @@
+ 
+ 	sort(chans, ss_last, sizeof(*chans), pc_cmp, pc_swap);
+ 
++#ifdef IEEE80211_DEBUG
+ 	for (i = 0; i < ss_last; i++) {
+ 		int chan = ieee80211_chan2ieee(ic, chans[i].chan);
+ 
+@@ -742,6 +743,7 @@
+ 				!!IEEE80211_ARE_CHANS_SAME_MODE(chans[i].chan, 
+ 					ic->ic_bsschan));
+ 	}
++#endif
+ 
+ 	best = NULL;
+ 	best_rssi = 0xff; /* If signal is bigger than 0xff, we'd be melting. */
diff --git a/package/madwifi/patches/300-napi_polling.patch b/package/madwifi/patches/300-napi_polling.patch
index ba72329f6..6b472caac 100644
--- a/package/madwifi/patches/300-napi_polling.patch
+++ b/package/madwifi/patches/300-napi_polling.patch
@@ -44,7 +44,7 @@
  #ifdef USE_HEADERLEN_RESV
  	dev->hard_header_len += sizeof(struct ieee80211_qosframe) +
  				sizeof(struct llc) +
-@@ -2216,6 +2228,7 @@
+@@ -2220,6 +2232,7 @@
  		(status & HAL_INT_GLOBAL)	? " HAL_INT_GLOBAL"	: ""
  		);
  
@@ -52,7 +52,7 @@
  	status &= sc->sc_imask;			/* discard unasked for bits */
  	/* As soon as we know we have a real interrupt we intend to service, 
  	 * we will check to see if we need an initial hardware TSF reading. 
-@@ -2273,7 +2286,23 @@
+@@ -2277,7 +2290,23 @@
  		}
  		if (status & (HAL_INT_RX | HAL_INT_RXPHY)) {
  			ath_uapsd_processtriggers(sc, hw_tsf);
@@ -77,7 +77,7 @@
  		}
  		if (status & HAL_INT_TX) {
  #ifdef ATH_SUPERG_DYNTURBO
-@@ -2299,6 +2328,11 @@
+@@ -2303,6 +2332,11 @@
  				}
  			}
  #endif
@@ -89,7 +89,7 @@
  			ATH_SCHEDULE_TQUEUE(&sc->sc_txtq, &needmark);
  		}
  		if (status & HAL_INT_BMISS) {
-@@ -2511,6 +2545,7 @@
+@@ -2515,6 +2549,7 @@
  	if (sc->sc_tx99 != NULL)
  		sc->sc_tx99->start(sc->sc_tx99);
  #endif
@@ -97,7 +97,7 @@
  
  done:
  	ATH_UNLOCK(sc);
-@@ -2551,6 +2586,9 @@
+@@ -2555,6 +2590,9 @@
  		if (sc->sc_tx99 != NULL)
  			sc->sc_tx99->stop(sc->sc_tx99);
  #endif
@@ -107,7 +107,7 @@
  		netif_stop_queue(dev);	/* XXX re-enabled by ath_newstate */
  		dev->flags &= ~IFF_RUNNING;	/* NB: avoid recursion */
  		ieee80211_stop_running(ic);	/* stop all VAPs */
-@@ -4009,6 +4047,39 @@
+@@ -4013,6 +4051,39 @@
  	return ath_keyset(sc, k, mac, vap->iv_bss);
  }
  
@@ -147,7 +147,7 @@
  /*
   * Block/unblock tx+rx processing while a key change is done.
   * We assume the caller serializes key management operations
-@@ -4026,13 +4097,7 @@
+@@ -4032,13 +4103,7 @@
  	 * When called from the rx tasklet we cannot use
  	 * tasklet_disable because it will block waiting
  	 * for us to complete execution.
@@ -161,8 +161,8 @@
  	netif_stop_queue(dev);
  }
  
-@@ -4043,9 +4108,9 @@
- 	struct ath_softc *sc = dev->priv;
+@@ -4051,9 +4116,9 @@
+ #endif
  
  	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n");
 -	netif_wake_queue(dev);
@@ -174,7 +174,7 @@
  }
  
  /*
-@@ -6350,15 +6415,25 @@
+@@ -6360,15 +6425,25 @@
  	sc->sc_rxotherant = 0;
  }
  
@@ -204,7 +204,7 @@
  	struct ieee80211com *ic = &sc->sc_ic;
  	struct ath_hal *ah = sc ? sc->sc_ah : NULL;
  	struct ath_desc *ds;
-@@ -6368,8 +6443,10 @@
+@@ -6378,8 +6453,10 @@
  	unsigned int len;
  	int type;
  	u_int phyerr;
@@ -215,7 +215,7 @@
  	do {
  		bf = STAILQ_FIRST(&sc->sc_rxbuf);
  		if (bf == NULL) {		/* XXX ??? can this happen */
-@@ -6393,6 +6470,15 @@
+@@ -6403,6 +6480,15 @@
  			/* NB: never process the self-linked entry at the end */
  			break;
  		}
@@ -231,7 +231,7 @@
  		skb = bf->bf_skb;
  		if (skb == NULL) {
  			EPRINTF(sc, "Dropping; buffer contains NULL skbuff.\n");
-@@ -6440,6 +6526,7 @@
+@@ -6450,6 +6536,7 @@
  				sc->sc_stats.ast_rx_phyerr++;
  				phyerr = rs->rs_phyerr & 0x1f;
  				sc->sc_stats.ast_rx_phy[phyerr]++;
@@ -239,7 +239,7 @@
  			}
  			if (rs->rs_status & HAL_RXERR_DECRYPT) {
  				/*
-@@ -6635,9 +6722,43 @@
+@@ -6645,9 +6732,43 @@
  		STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
  		ATH_RXBUF_UNLOCK_IRQ(sc);
  	} while (ath_rxbuf_init(sc, bf) == 0);
@@ -283,7 +283,7 @@
  #undef PA2DESC
  }
  
-@@ -8288,12 +8409,24 @@
+@@ -8298,12 +8419,24 @@
  {
  	struct net_device *dev = (struct net_device *)data;
  	struct ath_softc *sc = dev->priv;
@@ -308,7 +308,7 @@
  	netif_wake_queue(dev);
  
  	if (sc->sc_softled)
-@@ -8309,7 +8442,9 @@
+@@ -8319,7 +8452,9 @@
  {
  	struct net_device *dev = (struct net_device *)data;
  	struct ath_softc *sc = dev->priv;
@@ -318,7 +318,7 @@
  	/*
  	 * Process each active queue.
  	 */
-@@ -8330,6 +8465,16 @@
+@@ -8340,6 +8475,16 @@
  	if (sc->sc_uapsdq && txqactive(sc->sc_ah, sc->sc_uapsdq->axq_qnum))
  		ath_tx_processq(sc, sc->sc_uapsdq);
  
@@ -335,7 +335,7 @@
  	netif_wake_queue(dev);
  
  	if (sc->sc_softled)
-@@ -8345,13 +8490,25 @@
+@@ -8355,13 +8500,25 @@
  	struct net_device *dev = (struct net_device *)data;
  	struct ath_softc *sc = dev->priv;
  	unsigned int i;
@@ -361,7 +361,7 @@
  	netif_wake_queue(dev);
  
  	if (sc->sc_softled)
-@@ -10284,9 +10441,9 @@
+@@ -10296,9 +10453,9 @@
  	dev->mtu = mtu;
  	if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) {
  		/* NB: the rx buffers may need to be reallocated */
diff --git a/package/madwifi/patches/305-pureg_fix.patch b/package/madwifi/patches/305-pureg_fix.patch
index 196ac743c..ba7e62ed8 100644
--- a/package/madwifi/patches/305-pureg_fix.patch
+++ b/package/madwifi/patches/305-pureg_fix.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -4149,7 +4149,9 @@
+@@ -4157,7 +4157,9 @@
  		rfilt |= HAL_RX_FILTER_PROM;
  	if (ic->ic_opmode == IEEE80211_M_STA ||
  	    sc->sc_opmode == HAL_M_IBSS ||	/* NB: AHDEMO too */
diff --git a/package/madwifi/patches/309-micfail_detect.patch b/package/madwifi/patches/309-micfail_detect.patch
index 91986cd62..23da33378 100644
--- a/package/madwifi/patches/309-micfail_detect.patch
+++ b/package/madwifi/patches/309-micfail_detect.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -6446,6 +6446,7 @@
+@@ -6456,6 +6456,7 @@
  	int type;
  	u_int phyerr;
  	u_int processed = 0, early_stop = 0;
@@ -8,7 +8,7 @@
  
  	DPRINTF(sc, ATH_DEBUG_RX_PROC, "invoked\n");
  process_rx_again:
-@@ -6547,24 +6548,8 @@
+@@ -6557,24 +6558,8 @@
  			}
  			if (rs->rs_status & HAL_RXERR_MIC) {
  				sc->sc_stats.ast_rx_badmic++;
@@ -35,7 +35,7 @@
  			}
  			/*
  			 * Reject error frames if we have no vaps that
-@@ -6603,8 +6588,9 @@
+@@ -6613,8 +6598,9 @@
  		/*
  		 * Finished monitor mode handling, now reject
  		 * error frames before passing to other vaps
@@ -46,7 +46,7 @@
  			ieee80211_dev_kfree_skb(&skb);
  			goto rx_next;
  		}
-@@ -6612,6 +6598,26 @@
+@@ -6622,6 +6608,26 @@
  		/* remove the CRC */
  		skb_trim(skb, skb->len - IEEE80211_CRC_LEN);
  
@@ -73,7 +73,7 @@
  		/*
  		 * From this point on we assume the frame is at least
  		 * as large as ieee80211_frame_min; verify that.
-@@ -6624,6 +6630,7 @@
+@@ -6634,6 +6640,7 @@
  			goto rx_next;
  		}
  
diff --git a/package/madwifi/patches/310-noise_get.patch b/package/madwifi/patches/310-noise_get.patch
index b37ff5292..8b24b2110 100644
--- a/package/madwifi/patches/310-noise_get.patch
+++ b/package/madwifi/patches/310-noise_get.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -1695,8 +1695,6 @@
+@@ -1699,8 +1699,6 @@
  	 * get to reality.  This value is used in monitor mode and by tools like
  	 * Wireshark and Kismet.
  	 */
@@ -9,7 +9,7 @@
  	ATH_RXBUF_LOCK_IRQ(sc);
  	if (sc->sc_rxbufcur == NULL)
  		sc->sc_rxbufcur = STAILQ_FIRST(&sc->sc_rxbuf);
-@@ -8966,6 +8964,7 @@
+@@ -8978,6 +8976,7 @@
  			sc->sc_curchan.channel);
  		sc->sc_stats.ast_per_calfail++;
  	}
@@ -17,7 +17,7 @@
  
  	ath_hal_process_noisefloor(ah);
  	if (isIQdone == AH_TRUE) {
-@@ -9034,6 +9033,7 @@
+@@ -9046,6 +9045,7 @@
  	struct ath_softc *sc = dev->priv;
  
  	(void) ath_chan_set(sc, ic->ic_curchan);
@@ -25,7 +25,7 @@
  	/*
  	 * If we are returning to our bss channel then mark state
  	 * so the next recv'd beacon's TSF will be used to sync the
-@@ -9302,6 +9302,7 @@
+@@ -9314,6 +9314,7 @@
  		}
  
  		ath_hal_process_noisefloor(ah);
diff --git a/package/madwifi/patches/317-bmask.patch b/package/madwifi/patches/317-bmask.patch
index 4654b818c..24d2f9f22 100644
--- a/package/madwifi/patches/317-bmask.patch
+++ b/package/madwifi/patches/317-bmask.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8680,6 +8680,10 @@
+@@ -8692,6 +8692,10 @@
  
  	sc->sc_rxbufcur = NULL;
  
diff --git a/package/madwifi/patches/323-dfs_optional.patch b/package/madwifi/patches/323-dfs_optional.patch
index 46c480aac..d1f3b6258 100644
--- a/package/madwifi/patches/323-dfs_optional.patch
+++ b/package/madwifi/patches/323-dfs_optional.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -1774,17 +1774,14 @@
+@@ -1778,17 +1778,14 @@
  			 * may have occurred in the intervening timeframe. */
  			bf->bf_channoise = ic->ic_channoise;
  
@@ -27,7 +27,7 @@
  			bus_dma_sync_single(sc->sc_bdev, bf->bf_skbaddr,
 --- a/ath/if_ath_radar.c
 +++ b/ath/if_ath_radar.c
-@@ -261,7 +261,7 @@
+@@ -265,7 +265,7 @@
  		unsigned int new_rxfilt = old_rxfilt;
  
  		ath_hal_intrset(ah, old_ier & ~HAL_INT_GLOBAL);
diff --git a/package/madwifi/patches/325-channel_spam.patch b/package/madwifi/patches/325-channel_spam.patch
index 0059ba654..5c18c1184 100644
--- a/package/madwifi/patches/325-channel_spam.patch
+++ b/package/madwifi/patches/325-channel_spam.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -9783,7 +9783,9 @@
+@@ -9795,7 +9795,9 @@
  	/*
  	 * Convert HAL channels to ieee80211 ones.
  	 */
@@ -10,7 +10,7 @@
  	for (i = 0; i < nchan; i++) {
  		HAL_CHANNEL *c = &chans[i];
  		struct ieee80211_channel *ichan = &ic->ic_channels[i];
-@@ -9810,6 +9812,7 @@
+@@ -9822,6 +9824,7 @@
  		ic->ic_chan_non_occupy[i].tv_sec  = 0;
  		ic->ic_chan_non_occupy[i].tv_usec = 0;
  
@@ -18,7 +18,7 @@
  		IPRINTF(sc, "Channel %3d (%4d MHz) Max Tx Power %d dBm%s "
  				"[%d hw %d reg] Flags%s%s%s%s%s%s%s%s%s%s%s%s%"
  				"s%s%s%s%s%s%s%s%s%s%s%s\n",
-@@ -9898,6 +9901,7 @@
+@@ -9910,6 +9913,7 @@
  				(c->privFlags & 0x0080 ? 
  				 " PF & (1 << 7)" : "")
  				);
diff --git a/package/madwifi/patches/327-queue.patch b/package/madwifi/patches/327-queue.patch
index 53a80f6e6..ca42da386 100644
--- a/package/madwifi/patches/327-queue.patch
+++ b/package/madwifi/patches/327-queue.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8431,8 +8431,6 @@
+@@ -8441,8 +8441,6 @@
  	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
  	local_irq_restore(flags);
  
@@ -9,7 +9,7 @@
  	if (sc->sc_softled)
  		ath_led_event(sc, ATH_LED_TX);
  }
-@@ -8479,8 +8477,6 @@
+@@ -8489,8 +8487,6 @@
  	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
  	local_irq_restore(flags);
  
@@ -18,7 +18,7 @@
  	if (sc->sc_softled)
  		ath_led_event(sc, ATH_LED_TX);
  }
-@@ -8513,8 +8509,6 @@
+@@ -8523,8 +8519,6 @@
  	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
  	local_irq_restore(flags);
  
diff --git a/package/madwifi/patches/330-beaconcal.patch b/package/madwifi/patches/330-beaconcal.patch
index 46b8b76a0..174e566bf 100644
--- a/package/madwifi/patches/330-beaconcal.patch
+++ b/package/madwifi/patches/330-beaconcal.patch
@@ -24,7 +24,7 @@
  module_param(countrycode, int, 0600);
  module_param(maxvaps, int, 0600);
  module_param(outdoor, int, 0600);
-@@ -2598,7 +2601,8 @@
+@@ -2602,7 +2605,8 @@
  		}
  		if (!sc->sc_invalid) {
  			del_timer_sync(&sc->sc_dfs_cac_timer);
@@ -34,7 +34,7 @@
  		}
  		ath_draintxq(sc);
  		if (!sc->sc_invalid) {
-@@ -2615,6 +2619,20 @@
+@@ -2619,6 +2623,20 @@
  	return 0;
  }
  
@@ -55,7 +55,7 @@
  /*
   * Stop the device, grabbing the top-level lock to protect
   * against concurrent entry through ath_init (which can happen
-@@ -2740,6 +2758,12 @@
+@@ -2744,6 +2762,12 @@
  	HAL_STATUS status;
  
  	/*
@@ -68,7 +68,7 @@
  	 * Convert to a HAL channel description with the flags
  	 * constrained to reflect the current operating mode.
  	 */
-@@ -5145,6 +5169,8 @@
+@@ -5153,6 +5177,8 @@
  			"Invoking ath_hal_txstart with sc_bhalq: %d\n",
  			sc->sc_bhalq);
  		ath_hal_txstart(ah, sc->sc_bhalq);
@@ -77,7 +77,7 @@
  
  		sc->sc_stats.ast_be_xmit++;		/* XXX per-VAP? */
  	}
-@@ -5394,6 +5420,7 @@
+@@ -5402,6 +5428,7 @@
  		ath_hal_beacontimers(ah, &bs);
  		sc->sc_imask |= HAL_INT_BMISS;
  		ath_hal_intrset(ah, sc->sc_imask);
@@ -85,7 +85,7 @@
  	} else {
  		ath_hal_intrset(ah, 0);
  		if (reset_tsf)
-@@ -5405,8 +5432,11 @@
+@@ -5413,8 +5440,11 @@
  			 */
  			intval |= HAL_BEACON_ENA;
  			sc->sc_imask |= HAL_INT_SWBA;
@@ -98,7 +98,7 @@
  #ifdef ATH_SUPERG_DYNTURBO
  		ath_beacon_dturbo_config(vap, intval &
  				~(HAL_BEACON_RESET_TSF | HAL_BEACON_ENA));
-@@ -8870,6 +8900,9 @@
+@@ -8882,6 +8912,9 @@
  			/* Enter DFS wait period */
  			mod_timer(&sc->sc_dfs_cac_timer,
  				jiffies + (sc->sc_dfs_cac_period * HZ));
@@ -108,7 +108,7 @@
  		}
  		/*
  		 * re configure beacons when it is a turbo mode switch.
-@@ -8979,8 +9012,11 @@
+@@ -8991,8 +9024,11 @@
  		sc->sc_curchan.channel, sc->sc_curchan.channelFlags,
  		isIQdone ? "done" : "not done");
  
@@ -122,7 +122,7 @@
  }
  
  static void
-@@ -9087,7 +9123,8 @@
+@@ -9099,7 +9135,8 @@
  		ieee80211_state_name[vap->iv_state],
  		ieee80211_state_name[nstate]);
  
@@ -132,7 +132,7 @@
  
  	ath_hal_setledstate(ah, leds[nstate]);	/* set LED */
  	netif_stop_queue(dev);			/* before we do anything else */
-@@ -9312,7 +9349,8 @@
+@@ -9324,7 +9361,8 @@
  				"VAP -> DFSWAIT_PENDING \n");
  			/* start calibration timer with a really small value 
  			 * 1/10 sec */
@@ -142,7 +142,7 @@
  			/* wake the receiver */
  			netif_wake_queue(dev);
  			/* don't do the other usual stuff... */
-@@ -9355,7 +9393,7 @@
+@@ -9367,7 +9405,7 @@
  	error = avp->av_newstate(vap, nstate, arg);
  
  	/* Finally, start any timers. */
diff --git a/package/madwifi/patches/331-memory_alloc.patch b/package/madwifi/patches/331-memory_alloc.patch
index eae4a5536..c18f6b4fd 100644
--- a/package/madwifi/patches/331-memory_alloc.patch
+++ b/package/madwifi/patches/331-memory_alloc.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -3318,17 +3318,18 @@
+@@ -3322,17 +3322,18 @@
  	 * without affecting any other bridge ports. */
  	if (skb_cloned(skb)) {
  		/* Remember the original SKB so we can free up our references */
@@ -25,7 +25,7 @@
  	eh = (struct ether_header *)skb->data;
  
  #ifdef ATH_SUPERG_FF
-@@ -3599,6 +3600,8 @@
+@@ -3603,6 +3604,8 @@
  	sc->sc_stats.ast_tx_mgmt++;
  	return 0;
  bad:
diff --git a/package/madwifi/patches/332-reset_beacons.patch b/package/madwifi/patches/332-reset_beacons.patch
index 8d4cdabcf..b01ea7cba 100644
--- a/package/madwifi/patches/332-reset_beacons.patch
+++ b/package/madwifi/patches/332-reset_beacons.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8911,7 +8911,7 @@
+@@ -8923,7 +8923,7 @@
  		 * re configure beacons when it is a turbo mode switch.
  		 * HW seems to turn off beacons during turbo mode switch.
  		 */
diff --git a/package/madwifi/patches/333-apscan_mode.patch b/package/madwifi/patches/333-apscan_mode.patch
index d869440de..d8497a6d8 100644
--- a/package/madwifi/patches/333-apscan_mode.patch
+++ b/package/madwifi/patches/333-apscan_mode.patch
@@ -1,6 +1,6 @@
 --- a/net80211/ieee80211_scan_ap.c
 +++ b/net80211/ieee80211_scan_ap.c
-@@ -781,12 +781,6 @@
+@@ -783,12 +783,6 @@
  				/* break the loop as the subsequent chans won't be 
  				 * better */
  				break;
diff --git a/package/madwifi/patches/342-performance.patch b/package/madwifi/patches/342-performance.patch
index d79349dce..c9316c653 100644
--- a/package/madwifi/patches/342-performance.patch
+++ b/package/madwifi/patches/342-performance.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -3237,7 +3237,6 @@
+@@ -3241,7 +3241,6 @@
  	struct ath_softc *sc = dev->priv;
  	struct ieee80211_node *ni = NULL;
  	struct ath_buf *bf = NULL;
@@ -8,7 +8,7 @@
  	ath_bufhead bf_head;
  	struct ath_buf *tbf, *tempbf;
  	struct sk_buff *tskb;
-@@ -3249,6 +3248,7 @@
+@@ -3253,6 +3252,7 @@
  	*/
  	int requeue = 0;
  #ifdef ATH_SUPERG_FF
@@ -16,7 +16,7 @@
  	unsigned int pktlen;
  	struct ieee80211com *ic = &sc->sc_ic;
  	struct ath_node *an;
-@@ -3314,27 +3314,9 @@
+@@ -3318,27 +3318,9 @@
  		requeue = 1;
  		goto hardstart_fail;
  	}
diff --git a/package/madwifi/patches/343-txqueue_races.patch b/package/madwifi/patches/343-txqueue_races.patch
index 74fd9be21..20b6f527c 100644
--- a/package/madwifi/patches/343-txqueue_races.patch
+++ b/package/madwifi/patches/343-txqueue_races.patch
@@ -2,7 +2,7 @@ Merged from madwifi trunk r3551, r3552
 
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8244,6 +8244,17 @@
+@@ -8254,6 +8254,17 @@
  			goto bf_fail;
  		}
  
diff --git a/package/madwifi/patches/345-minstrel_sampling.patch b/package/madwifi/patches/345-minstrel_sampling.patch
index 51416e5bf..0e68422f7 100644
--- a/package/madwifi/patches/345-minstrel_sampling.patch
+++ b/package/madwifi/patches/345-minstrel_sampling.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8094,6 +8094,7 @@
+@@ -8104,6 +8104,7 @@
  		ath_hal_setupxtxdesc(sc->sc_ah, ds, mrr.rate1, mrr.retries1,
  				     mrr.rate2, mrr.retries2,
  				     mrr.rate3, mrr.retries3);
diff --git a/package/madwifi/patches/347-tuning.patch b/package/madwifi/patches/347-tuning.patch
index deddd0de6..4c8379a7c 100644
--- a/package/madwifi/patches/347-tuning.patch
+++ b/package/madwifi/patches/347-tuning.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -10265,11 +10265,11 @@
+@@ -10277,11 +10277,11 @@
  	sc->sc_currates = rt;
  	sc->sc_curmode = mode;
  	/*
diff --git a/package/madwifi/patches/348-ackcts.patch b/package/madwifi/patches/348-ackcts.patch
index a505ef86d..55acf74c0 100644
--- a/package/madwifi/patches/348-ackcts.patch
+++ b/package/madwifi/patches/348-ackcts.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -2721,6 +2721,9 @@
+@@ -2725,6 +2725,9 @@
  static int
  ath_set_ack_bitrate(struct ath_softc *sc, int high)
  {
@@ -10,7 +10,7 @@
  	if (ar_device(sc->devid) == 5212 || ar_device(sc->devid) == 5213) {
  		/* set ack to be sent at low bit-rate */
  		/* registers taken from the OpenBSD 5212 HAL */
-@@ -10780,8 +10783,13 @@
+@@ -10792,8 +10795,13 @@
  				break;
  #endif
  			case ATH_ACKRATE:
diff --git a/package/madwifi/patches/349-reset.patch b/package/madwifi/patches/349-reset.patch
index 1047dd23d..570193d25 100644
--- a/package/madwifi/patches/349-reset.patch
+++ b/package/madwifi/patches/349-reset.patch
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8853,8 +8853,7 @@
+@@ -8865,8 +8865,7 @@
  		 * needed to do the reset with chanchange = AH_FALSE in order
  		 * to receive traffic when peforming high velocity channel
  		 * changes. */
diff --git a/package/madwifi/patches/351-scanlist.patch b/package/madwifi/patches/351-scanlist.patch
index 6a4ae8b2f..376526496 100644
--- a/package/madwifi/patches/351-scanlist.patch
+++ b/package/madwifi/patches/351-scanlist.patch
@@ -640,7 +640,7 @@
  	ss->ss_next = 0;
  	/* XXX tunables */
  	ss->ss_mindwell = msecs_to_jiffies(200);	/* 200ms */
-@@ -759,13 +538,6 @@
+@@ -761,13 +540,6 @@
  		if (IEEE80211_IS_CHAN_RADAR(c->chan))
  			continue;
  
diff --git a/package/madwifi/patches/352-ani_fix.patch b/package/madwifi/patches/352-ani_fix.patch
index 012966523..aff0d4a42 100644
--- a/package/madwifi/patches/352-ani_fix.patch
+++ b/package/madwifi/patches/352-ani_fix.patch
@@ -23,7 +23,7 @@
  	return 0;
  bad3:
  	ieee80211_ifdetach(ic);
-@@ -2347,16 +2350,6 @@
+@@ -2351,16 +2354,6 @@
  		}
  		if (status & HAL_INT_MIB) {
  			sc->sc_stats.ast_mib++;
@@ -40,7 +40,7 @@
  			/* Let the HAL handle the event. */
  			ath_hal_mibevent(ah, &sc->sc_halstats);
  		}
-@@ -2426,6 +2419,43 @@
+@@ -2430,6 +2423,43 @@
  	return flags;
  }
  
@@ -84,7 +84,7 @@
  /*
   * Context: process context
   */
-@@ -2491,8 +2521,7 @@
+@@ -2495,8 +2525,7 @@
  	if (sc->sc_softled)
  		ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
  
@@ -94,7 +94,7 @@
  
  	/*
  	 * This is needed only to setup initial state
-@@ -2528,7 +2557,7 @@
+@@ -2532,7 +2561,7 @@
  	 * Enable MIB interrupts when there are hardware phy counters.
  	 * Note we only do this (at the moment) for station mode.
  	 */
@@ -103,7 +103,7 @@
  		sc->sc_imask |= HAL_INT_MIB;
  	ath_hal_intrset(ah, sc->sc_imask);
  
-@@ -2785,9 +2814,7 @@
+@@ -2789,9 +2818,7 @@
  		EPRINTF(sc, "Unable to reset hardware: '%s' (HAL status %u)\n",
  			ath_get_hal_status_desc(status), status);
  
@@ -114,7 +114,7 @@
  	ath_update_txpow(sc);		/* update tx power state */
  	ath_radar_update(sc);
  	ath_setdefantenna(sc, sc->sc_defant);
-@@ -4165,6 +4192,8 @@
+@@ -4173,6 +4200,8 @@
  	if (sc->sc_nmonvaps > 0)
  		rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
  			  HAL_RX_FILTER_PROBEREQ | HAL_RX_FILTER_PROM);
@@ -123,7 +123,7 @@
  	if (sc->sc_curchan.privFlags & CHANNEL_DFS)
  		rfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR);
  	return rfilt;
-@@ -6513,9 +6542,6 @@
+@@ -6523,9 +6552,6 @@
  			rs->rs_rssi = 0;
  
  		len = rs->rs_datalen;
@@ -133,7 +133,7 @@
  
  		if (rs->rs_more) {
  			/*
-@@ -8865,9 +8891,7 @@
+@@ -8877,9 +8903,7 @@
  		if (sc->sc_softled)
  			ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
  
@@ -144,7 +144,7 @@
  		sc->sc_curchan = hchan;
  		ath_update_txpow(sc);		/* update tx power state */
  		ath_radar_update(sc);
-@@ -10644,9 +10668,54 @@
+@@ -10656,9 +10680,54 @@
  	ATH_RP_IGNORED 		= 24,
  	ATH_RADAR_IGNORED       = 25,
  	ATH_MAXVAPS  		= 26,
@@ -199,7 +199,7 @@
  ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
  {
  	struct ath_softc *sc = ctl->extra1;
-@@ -10832,6 +10901,11 @@
+@@ -10844,6 +10913,11 @@
  			case ATH_RADAR_IGNORED:
  				sc->sc_radar_ignored = val;
  				break;
@@ -211,7 +211,7 @@
  			default:
  				ret = -EINVAL;
  				break;
-@@ -10898,6 +10972,11 @@
+@@ -10910,6 +10984,11 @@
  		case ATH_RADAR_IGNORED:
  			val = sc->sc_radar_ignored;
  			break;
@@ -223,7 +223,7 @@
  		default:
  			ret = -EINVAL;
  			break;
-@@ -11075,6 +11154,24 @@
+@@ -11087,6 +11166,24 @@
  	  .proc_handler = ath_sysctl_halparam,
  	  .extra2	= (void *)ATH_RADAR_IGNORED,
  	},
diff --git a/package/madwifi/patches/355-eap_auth_disassoc.patch b/package/madwifi/patches/355-eap_auth_disassoc.patch
index e85d93a78..303370dd0 100644
--- a/package/madwifi/patches/355-eap_auth_disassoc.patch
+++ b/package/madwifi/patches/355-eap_auth_disassoc.patch
@@ -5,7 +5,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8315,6 +8315,18 @@
+@@ -8325,6 +8325,18 @@
  #endif
  				if (ts->ts_status & HAL_TXERR_XRETRY) {
  					sc->sc_stats.ast_tx_xretries++;
diff --git a/package/madwifi/patches/363-fix_turbo.patch b/package/madwifi/patches/363-fix_turbo.patch
new file mode 100644
index 000000000..174e6953c
--- /dev/null
+++ b/package/madwifi/patches/363-fix_turbo.patch
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -4914,7 +4914,7 @@
+ 	 * capability info and arrange for a mode change
+ 	 * if needed.
+ 	 */
+-	if (sc->sc_dturbo) {
++	if (sc->sc_dturbo && NULL != avp->av_boff.bo_tim) {
+ 		u_int8_t dtim;
+ 		dtim = ((avp->av_boff.bo_tim[2] == 1) ||
+ 			(avp->av_boff.bo_tim[3] == 1));
diff --git a/package/madwifi/patches/364-memory_alloc.patch b/package/madwifi/patches/364-memory_alloc.patch
new file mode 100644
index 000000000..d0d76a179
--- /dev/null
+++ b/package/madwifi/patches/364-memory_alloc.patch
@@ -0,0 +1,13 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -539,8 +539,8 @@
+ 
+ 	/* Allocate space for dynamically determined maximum VAP count */
+ 	sc->sc_bslot = 
+-		kmalloc(ath_maxvaps * sizeof(struct ieee80211vap), GFP_KERNEL);
+-	memset(sc->sc_bslot, 0, ath_maxvaps * sizeof(struct ieee80211vap));
++		kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL);
++	memset(sc->sc_bslot, 0, ath_maxvaps * sizeof(struct ieee80211vap*));
+ 
+ 	/*
+ 	 * Cache line size is used to size and align various
diff --git a/package/madwifi/patches/365-turbo_channelsearch.patch b/package/madwifi/patches/365-turbo_channelsearch.patch
new file mode 100644
index 000000000..31caa1bfe
--- /dev/null
+++ b/package/madwifi/patches/365-turbo_channelsearch.patch
@@ -0,0 +1,10 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -684,6 +684,7 @@
+ 	int i;
+ 
+ 	/* Brute force search */
++	flags &= IEEE80211_CHAN_ALLTURBO;
+ 	for (i = 0; i < ic->ic_nchans; i++) {
+ 		c = &ic->ic_channels[i];
+ 		if (c->ic_freq == freq &&
diff --git a/package/madwifi/patches/366-bstuck_thresh.patch b/package/madwifi/patches/366-bstuck_thresh.patch
new file mode 100644
index 000000000..d04756e2f
--- /dev/null
+++ b/package/madwifi/patches/366-bstuck_thresh.patch
@@ -0,0 +1,52 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -389,6 +389,7 @@
+ static int ath_outdoor = AH_FALSE;		/* enable outdoor use */
+ static int ath_xchanmode = AH_TRUE;		/* enable extended channels */
+ static int ath_maxvaps = ATH_MAXVAPS_DEFAULT;   /* set default maximum vaps */
++static int bstuck_thresh = BSTUCK_THRESH;       /* Stuck beacon count required for reset */
+ static char *autocreate = NULL;
+ static char *ratectl = DEF_RATE_CTL;
+ static int rfkill = 0;
+@@ -432,6 +433,7 @@
+ #ifdef ATH_CAP_TPC
+ MODULE_PARM(tpc, "i");
+ #endif
++MODULE_PARM(bstuck_thresh, "i");
+ MODULE_PARM(autocreate, "s");
+ MODULE_PARM(ratectl, "s");
+ #else
+@@ -445,6 +447,7 @@
+ #ifdef ATH_CAP_TPC
+ module_param(tpc, int, 0600);
+ #endif
++module_param(bstuck_thresh, int, 0600);
+ module_param(autocreate, charp, 0600);
+ module_param(ratectl, charp, 0600);
+ #endif
+@@ -457,6 +460,7 @@
+ MODULE_PARM_DESC(tpc, "Enable/disable per-packet transmit power control (TPC) "
+ 		"capability");
+ #endif
++MODULE_PARM_DESC(bstuck_thresh, "Override default stuck beacon threshold");
+ MODULE_PARM_DESC(autocreate, "Create ath device in "
+ 		"[sta|ap|wds|adhoc|ahdemo|monitor] mode. defaults to sta, use "
+ 		"'none' to disable");
+@@ -5061,7 +5065,7 @@
+ 		DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
+ 			"Missed %u consecutive beacons (n_beacon=%u)\n",
+ 			sc->sc_bmisscount, n_beacon);
+-		if (sc->sc_bmisscount > BSTUCK_THRESH)
++		if (sc->sc_bmisscount > bstuck_thresh)
+ 			ATH_SCHEDULE_TQUEUE(&sc->sc_bstucktq, needmark);
+ 		return;
+ 	}
+@@ -5217,7 +5221,7 @@
+ 	 *     check will be true, in which case return
+ 	 *     without resetting the driver.
+ 	 */
+-	if (sc->sc_bmisscount <= BSTUCK_THRESH)
++	if (sc->sc_bmisscount <= bstuck_thresh)
+ 		return;
+ 	EPRINTF(sc, "Stuck beacon; resetting (beacon miss count: %u)\n",
+ 		sc->sc_bmisscount);
diff --git a/package/madwifi/patches/406-monitor_r3711.patch b/package/madwifi/patches/406-monitor_r3711.patch
new file mode 100644
index 000000000..e1a56c01b
--- /dev/null
+++ b/package/madwifi/patches/406-monitor_r3711.patch
@@ -0,0 +1,20 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6321,7 +6321,7 @@
+ 
+ 	/* Never copy the SKB, as it is ours on the RX side, and this is the 
+ 	 * last process on the TX side and we only modify our own headers. */
+-	tskb = ath_skb_removepad(skb, 0 /* Copy SKB */);
++	tskb = ath_skb_removepad(skb, !tx /* Copy SKB */);
+ 	if (tskb == NULL) {
+ 		DPRINTF(sc, ATH_DEBUG_ANY,
+ 			"Dropping; ath_skb_removepad failed!\n");
+@@ -6329,6 +6329,8 @@
+ 	}
+ 	
+ 	ieee80211_input_monitor(ic, tskb, bf, tx, tsf, sc);
++	if (tskb != skb)
++		ieee80211_dev_kfree_skb(&tskb);
+ }
+ 
+ /*
diff --git a/package/madwifi/patches/407-new_athinfo.patch b/package/madwifi/patches/407-new_athinfo.patch
new file mode 100644
index 000000000..157794975
--- /dev/null
+++ b/package/madwifi/patches/407-new_athinfo.patch
@@ -0,0 +1,2352 @@
+--- a/tools/ath_info.c
++++ b/tools/ath_info.c
+@@ -16,78 +16,8 @@
+  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-/* So here is how it works:
+- *
+- * First compile...
+- *
+- * gcc ath_info.c -o ath_info
+- *
+- * then find card's physical address
+- *
+- * lspci -v
+- *
+- * 02:02.0 Ethernet controller: Atheros Communications, Inc. AR5212 802.11abg NIC (rev 01)
+- *         Subsystem: Fujitsu Limited. Unknown device 1234
+- *         Flags: bus master, medium devsel, latency 168, IRQ 23
+- *         Memory at c2000000 (32-bit, non-prefetchable) [size=64K]
+- *         Capabilities: [44] Power Management version 2
+- *
+- * address here is 0xc2000000
+- *
+- * load madwifi-ng or madwifi-old if not already loaded (be sure the
+- * interface is down!)
+- *
+- * modprobe ath_pci
+- *
+- * OR
+- *
+- * call:
+- * setpci -s 02:02.0 command=0x41f cache_line_size=0x10
+- *
+- * to enable access to the PCI device.
+- *
+- * and we run the thing...
+- *
+- * ./ath_info 0xc2000000
+- *
+- * In order to change the regdomain to 0, call:
+- *
+- * ./ath_info -w 0xc2000000 regdomain 0
+- *
+- * to change any PCI ID value, say:
+- *
+- * ./ath_info -w 0xc2000000 <name> X
+- *
+- * with <name> ::= pci_dev_id | pci_vendor_id | pci_class |
+- *                 pci_subsys_dev_id | pci_subsys_vendor_id
+- *
+- * With newer chipsets (>= AR5004x, i.e. MAC >= AR5213), Atheros introduced
+- * write protection on the EEPROM. On a GIGABYTE GN-WI01HT you can set GPIO 4
+- * to low to be able to write the EEPROM. This depends highly on the PCB layout,
+- * so there may be different GPIO used.
+- * This program currently sets GPIO 4 to low for a MAC >= AR5213, but you can
+- * override this with the -g option:
+- *
+- * ./ath_info -g 5:0 -w 0xc2000000 regdomain X
+- *
+- * would set GPIO 5 to low (and wouldn't touch GPIO 4). -g can be given several times.
+- *
+- * The write function is currently not tested with 5210 devices.
+- *
+- * Use at your own risk, entering a false device address will have really
+- * nasty results!
+- *
+- * Writing wrong values to the PCI id fields may prevent the driver from
+- * detecting the card!
+- *
+- * Transmitting on illegal frequencies may violate state laws. Stick to the local
+- * regulations!
+- *
+- * DISCLAIMER:
+- * The authors are in no case responsible for damaged hardware or violation of
+- * local laws by operating modified hardware.
+- *
+- */
++/* Try accepting 64-bit device address even with 32-bit userspace */
++#define _FILE_OFFSET_BITS 64
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -130,109 +60,103 @@
+  */
+ #define AR5K_GPIODI	0x401c
+ 
+-/*
+- * Common silicon revision/version values
+- */
+-enum ath5k_srev_type {
+-	AR5K_VERSION_VER,
+-	AR5K_VERSION_REV,
+-	AR5K_VERSION_RAD,
+-};
+-
+ struct ath5k_srev_name {
+ 	const char *sr_name;
+-	enum ath5k_srev_type sr_type;
+-	u_int sr_val;
++	u_int8_t sr_val;
+ };
+ 
+-#define AR5K_SREV_UNKNOWN	0xffff
+-
+ /* Known MAC revision numbers */
+-#define AR5K_SREV_VER_AR5210	0x00
+-#define AR5K_SREV_VER_AR5311	0x10
+-#define AR5K_SREV_VER_AR5311A	0x20
+-#define AR5K_SREV_VER_AR5311B	0x30
+-#define AR5K_SREV_VER_AR5211	0x40
+-#define AR5K_SREV_VER_AR5212	0x50
+-#define AR5K_SREV_VER_AR5213	0x55
+-#define AR5K_SREV_VER_AR5213A	0x59
+-#define	AR5K_SREV_VER_AR2424	0xa0
+-#define	AR5K_SREV_VER_AR5424	0xa3
+-#define	AR5K_SREV_VER_AR5413	0xa4
+-#define AR5K_SREV_VER_AR5414	0xa5
+-#define	AR5K_SREV_VER_AR5416	0xc0
+-#define	AR5K_SREV_VER_AR5418	0xca
+-#define	AR5K_SREV_VER_AR2425	0xe0
+-
+-/* Known PHY revision nymbers */
+-#define AR5K_SREV_RAD_5110	0x00
+-#define AR5K_SREV_RAD_5111	0x10
+-#define AR5K_SREV_RAD_5111A	0x15
+-#define AR5K_SREV_RAD_2111	0x20
+-#define AR5K_SREV_RAD_5112	0x30
+-#define AR5K_SREV_RAD_5112A	0x35
+-#define AR5K_SREV_RAD_2112	0x40
+-#define AR5K_SREV_RAD_2112A	0x45
+-#define AR5K_SREV_RAD_SC1	0x63	/* Found on 5413/5414 */
+-#define	AR5K_SREV_RAD_SC2	0xa2	/* Found on 2424/5424 */
+-#define	AR5K_SREV_RAD_5133	0xc0	/* MIMO found on 5418 */
+-
+-static const struct ath5k_srev_name ath5k_srev_names[] = {
+-	{"5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210},
+-	{"5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311},
+-	{"5311A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A},
+-	{"5311B", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B},
+-	{"5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211},
+-	{"5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212},
+-	{"5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213},
+-	{"5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A},
+-	{"2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424},
+-	{"5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424},
+-	{"5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413},
+-	{"5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414},
+-	{"5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416},
+-	{"5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418},
+-	{"2425", AR5K_VERSION_VER, AR5K_SREV_VER_AR2425},
+-	{"xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN},
+-	{"5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110},
+-	{"5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111},
+-	{"2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111},
+-	{"5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112},
+-	{"5112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A},
+-	{"2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112},
+-	{"2112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A},
+-	{"SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1},
+-	{"SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2},
+-	{"5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133},
+-	{"xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN},
++#define AR5K_SREV_MAC_AR5210	0x00
++#define AR5K_SREV_MAC_AR5311	0x10
++#define AR5K_SREV_MAC_AR5311A	0x20
++#define AR5K_SREV_MAC_AR5311B	0x30
++#define AR5K_SREV_MAC_AR5211	0x40
++#define AR5K_SREV_MAC_AR5212	0x50
++#define AR5K_SREV_MAC_AR5213	0x55
++#define AR5K_SREV_MAC_AR5213A	0x59
++#define AR5K_SREV_MAC_AR5513	0x61
++#define AR5K_SREV_MAC_AR2413	0x78
++#define AR5K_SREV_MAC_AR2414	0x79
++#define AR5K_SREV_MAC_AR2424	0xa0
++#define AR5K_SREV_MAC_AR5424	0xa3
++#define AR5K_SREV_MAC_AR5413	0xa4
++#define AR5K_SREV_MAC_AR5414	0xa5
++#define AR5K_SREV_MAC_AR5416	0xc0
++#define AR5K_SREV_MAC_AR5418	0xca
++#define AR5K_SREV_MAC_AR2425	0xe2
++
++/* Known PHY revision numbers */
++#define AR5K_SREV_PHY_5110	0x00
++#define AR5K_SREV_PHY_5111	0x10
++#define AR5K_SREV_PHY_5111A	0x15
++#define AR5K_SREV_PHY_2111	0x20
++#define AR5K_SREV_PHY_5112	0x30
++#define AR5K_SREV_PHY_5112A	0x35
++#define AR5K_SREV_PHY_2112	0x40
++#define AR5K_SREV_PHY_2112A	0x45
++#define AR5K_SREV_PHY_SC0	0x56	/* Found on 2413/2414 */
++#define AR5K_SREV_PHY_SC1	0x63	/* Found on 5413/5414 */
++#define AR5K_SREV_PHY_SC2	0xa2	/* Found on 2424/5424 */
++#define AR5K_SREV_PHY_5133	0xc0	/* MIMO found on 5418 */
++
++static const struct ath5k_srev_name ath5k_mac_names[] = {
++	{"5210", AR5K_SREV_MAC_AR5210},
++	{"5311", AR5K_SREV_MAC_AR5311},
++	{"5311A", AR5K_SREV_MAC_AR5311A},
++	{"5311B", AR5K_SREV_MAC_AR5311B},
++	{"5211", AR5K_SREV_MAC_AR5211},
++	{"5212", AR5K_SREV_MAC_AR5212},
++	{"5213", AR5K_SREV_MAC_AR5213},
++	{"5213A", AR5K_SREV_MAC_AR5213A},
++	{"2413", AR5K_SREV_MAC_AR2413},
++	{"2414", AR5K_SREV_MAC_AR2414},
++	{"2424", AR5K_SREV_MAC_AR2424},
++	{"5424", AR5K_SREV_MAC_AR5424},
++	{"5413", AR5K_SREV_MAC_AR5413},
++	{"5414", AR5K_SREV_MAC_AR5414},
++	{"5416", AR5K_SREV_MAC_AR5416},
++	{"5418", AR5K_SREV_MAC_AR5418},
++	{"2425", AR5K_SREV_MAC_AR2425},
++};
++
++static const struct ath5k_srev_name ath5k_phy_names[] = {
++	{"5110", AR5K_SREV_PHY_5110},
++	{"5111", AR5K_SREV_PHY_5111},
++	{"2111", AR5K_SREV_PHY_2111},
++	{"5112", AR5K_SREV_PHY_5112},
++	{"5112A", AR5K_SREV_PHY_5112A},
++	{"2112", AR5K_SREV_PHY_2112},
++	{"2112A", AR5K_SREV_PHY_2112A},
++	{"SChip", AR5K_SREV_PHY_SC0},
++	{"SChip", AR5K_SREV_PHY_SC1},
++	{"SChip", AR5K_SREV_PHY_SC2},
++	{"5133", AR5K_SREV_PHY_5133},
+ };
+ 
+ /*
+  * Silicon revision register
+  */
+ #define AR5K_SREV		0x4020	/* Register Address */
+-#define AR5K_SREV_REV		0x0000000f	/* Mask for revision */
+-#define AR5K_SREV_REV_S		0
+-#define AR5K_SREV_VER		0x000000ff	/* Mask for version */
+-#define AR5K_SREV_VER_S		4
++#define AR5K_SREV_VER		0x000000f0	/* Mask for version */
++#define AR5K_SREV_REV		0x000000ff	/* Mask for revision */
+ 
+ /*
+  * PHY chip revision register
+  */
+-#define	AR5K_PHY_CHIP_ID		0x9818
++#define AR5K_PHY_CHIP_ID		0x9818
+ 
+ /*
+  * PHY register
+  */
+-#define	AR5K_PHY_BASE			0x9800
+-#define	AR5K_PHY(_n)			(AR5K_PHY_BASE + ((_n) << 2))
++#define AR5K_PHY_BASE			0x9800
++#define AR5K_PHY(_n)			(AR5K_PHY_BASE + ((_n) << 2))
+ #define AR5K_PHY_SHIFT_2GHZ		0x00004007
+ #define AR5K_PHY_SHIFT_5GHZ		0x00000007
+ 
+ #define AR5K_RESET_CTL		0x4000	/* Register Address */
+ #define AR5K_RESET_CTL_PCU	0x00000001	/* Protocol Control Unit reset */
+ #define AR5K_RESET_CTL_DMA	0x00000002	/* DMA (Rx/Tx) reset -5210 only */
+-#define	AR5K_RESET_CTL_BASEBAND	0x00000002	/* Baseband reset (5211/5212) */
++#define AR5K_RESET_CTL_BASEBAND	0x00000002	/* Baseband reset (5211/5212) */
+ #define AR5K_RESET_CTL_MAC	0x00000004	/* MAC reset (PCU+Baseband?) -5210 only */
+ #define AR5K_RESET_CTL_PHY	0x00000008	/* PHY reset -5210 only */
+ #define AR5K_RESET_CTL_PCI	0x00000010	/* PCI Core reset (interrupts etc) */
+@@ -253,7 +177,7 @@
+ #define AR5K_SLEEP_CTL_SLE_UNITS	0x00000008	/* not on 5210 */
+ 
+ #define AR5K_PCICFG			0x4010	/* Register Address */
+-#define AR5K_PCICFG_EEAE		0x00000001	/* Eeprom access enable [5210] */
++#define AR5K_PCICFG_EEAE		0x00000001	/* EEPROM access enable [5210] */
+ #define AR5K_PCICFG_CLKRUNEN		0x00000004	/* CLKRUN enable [5211+] */
+ #define AR5K_PCICFG_EESIZE		0x00000018	/* Mask for EEPROM size [5211+] */
+ #define AR5K_PCICFG_EESIZE_S		3
+@@ -264,26 +188,118 @@
+ 
+ #define AR5K_PCICFG_SPWR_DN		0x00010000	/* Mask for power status (5210) */
+ 
+-#define AR5K_EEPROM_BASE		0x6000
++#define AR5K_EEPROM_BASE	0x6000
+ 
+-#define AR5K_EEPROM_MAGIC		0x003d	/* Offset for EEPROM Magic number */
++/*
++ * Common AR5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
++ */
++#define AR5K_EEPROM_MAGIC		0x003d	/* EEPROM Magic number */
+ #define AR5K_EEPROM_MAGIC_VALUE		0x5aa5	/* Default - found on EEPROM */
+ #define AR5K_EEPROM_MAGIC_5212		0x0000145c	/* 5212 */
+ #define AR5K_EEPROM_MAGIC_5211		0x0000145b	/* 5211 */
+ #define AR5K_EEPROM_MAGIC_5210		0x0000145a	/* 5210 */
+ 
++#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
++#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
++#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
++#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
++#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
++#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
++#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
++#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
++#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
++#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
++#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
++#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
++#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
++#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
++#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
++#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
++#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
++#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
++#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
++#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
++#define AR5K_EEPROM_INFO_CKSUM		0xffff
++#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
++
++#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
++#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
++#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2GHz (AR5211_rfregs) */
++#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
++#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
++#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
++#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_3		0x4003
++#define AR5K_EEPROM_VERSION_4_4		0x4004
++#define AR5K_EEPROM_VERSION_4_5		0x4005
++#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
++#define AR5K_EEPROM_VERSION_4_7		0x3007
++
++#define AR5K_EEPROM_MODE_11A		0
++#define AR5K_EEPROM_MODE_11B		1
++#define AR5K_EEPROM_MODE_11G		2
++
++#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
++#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
++#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
++#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
++#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2GHz (?) */
++#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
++#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
++#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5GHz (?) */
++#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
++
++/* Misc values available since EEPROM 4.0 */
++#define AR5K_EEPROM_MISC0		AR5K_EEPROM_INFO(4)
++#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
++#define AR5K_EEPROM_HDR_XR2_DIS(_v)	(((_v) >> 12) & 0x1)
++#define AR5K_EEPROM_HDR_XR5_DIS(_v)	(((_v) >> 13) & 0x1)
++#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
++#define AR5K_EEPROM_MISC1		AR5K_EEPROM_INFO(5)
++#define AR5K_EEPROM_TARGET_PWRSTART(_v)	((_v) & 0xfff)
++#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)	(((_v) >> 14) & 0x1)
++
++#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
++#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
++#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
++#define AR5K_EEPROM_RFKILL_POLARITY_S	1
++
++/* Newer EEPROMs are using a different offset */
++#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
++	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
++
++#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
++#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((int8_t)(((_v) >> 8) & 0xff))
++#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((int8_t)((_v) & 0xff))
++
++/* calibration settings */
++#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
++#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
++#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
++#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
++#define AR5K_EEPROM_CHANNELS_5GHZ(_v)	AR5K_EEPROM_OFF(_v, 0x0100, 0x0150)	/* List of calibrated 5GHz chans */
++#define	AR5K_EEPROM_TARGET_PWR_OFF_11A(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0055, 0x0000)
++#define	AR5K_EEPROM_TARGET_PWR_OFF_11B(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0065, 0x0010)
++#define	AR5K_EEPROM_TARGET_PWR_OFF_11G(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_CHANNELS_5GHZ(_v) + 0x0069, 0x0014)
++
++/* [3.1 - 3.3] */
++#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
++#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
++
+ /*
+  * EEPROM data register
+  */
+ #define AR5K_EEPROM_DATA_5211	0x6004
+ #define AR5K_EEPROM_DATA_5210	0x6800
+-#define	AR5K_EEPROM_DATA	(mac_version == AR5K_SREV_VER_AR5210 ? \
++#define AR5K_EEPROM_DATA	(mac_version == AR5K_SREV_MAC_AR5210 ? \
+ 				AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
+ 
+ /*
+  * EEPROM command register
+  */
+-#define AR5K_EEPROM_CMD		0x6008	/* Register Addres */
++#define AR5K_EEPROM_CMD		0x6008			/* Register Address */
+ #define AR5K_EEPROM_CMD_READ	0x00000001	/* EEPROM read */
+ #define AR5K_EEPROM_CMD_WRITE	0x00000002	/* EEPROM write */
+ #define AR5K_EEPROM_CMD_RESET	0x00000004	/* EEPROM reset */
+@@ -291,43 +307,163 @@
+ /*
+  * EEPROM status register
+  */
+-#define AR5K_EEPROM_STAT_5210	0x6c00	/* Register Address [5210] */
+-#define AR5K_EEPROM_STAT_5211	0x600c	/* Register Address [5211+] */
+-#define	AR5K_EEPROM_STATUS	(mac_version == AR5K_SREV_VER_AR5210 ? \
++#define AR5K_EEPROM_STAT_5210	0x6c00			/* Register Address [5210] */
++#define AR5K_EEPROM_STAT_5211	0x600c			/* Register Address [5211+] */
++#define AR5K_EEPROM_STATUS	(mac_version == AR5K_SREV_MAC_AR5210 ? \
+ 				AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
+ #define AR5K_EEPROM_STAT_RDERR	0x00000001	/* EEPROM read failed */
+ #define AR5K_EEPROM_STAT_RDDONE	0x00000002	/* EEPROM read successful */
+ #define AR5K_EEPROM_STAT_WRERR	0x00000004	/* EEPROM write failed */
+ #define AR5K_EEPROM_STAT_WRDONE	0x00000008	/* EEPROM write successful */
+ 
+-#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* Offset for EEPROM regulatory domain */
+-#define AR5K_EEPROM_INFO_BASE		0x00c0	/* Offset for EEPROM header */
+-#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
+-#define AR5K_EEPROM_INFO_CKSUM		0xffff
+-#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
+-#define AR5K_EEPROM_MODE_11A		0
+-#define AR5K_EEPROM_MODE_11B		1
+-#define AR5K_EEPROM_MODE_11G		2
++/*
++ * EEPROM config register (?)
++ */
++#define AR5K_EEPROM_CFG	0x6010
+ 
+-#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)
++/* Some EEPROM defines */
++#define AR5K_EEPROM_EEP_SCALE		100
++#define AR5K_EEPROM_EEP_DELTA		10
++#define AR5K_EEPROM_N_MODES		3
++#define AR5K_EEPROM_N_5GHZ_CHAN		10
++#define AR5K_EEPROM_N_2GHZ_CHAN		3
++#define AR5K_EEPROM_MAX_CHAN		10
++#define AR5K_EEPROM_N_PCDAC		11
++#define AR5K_EEPROM_N_TEST_FREQ		8
++#define AR5K_EEPROM_N_EDGES		8
++#define AR5K_EEPROM_N_INTERCEPTS	11
++#define AR5K_EEPROM_FREQ_M(_v)		AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
++#define AR5K_EEPROM_PCDAC_M		0x3f
++#define AR5K_EEPROM_PCDAC_START		1
++#define AR5K_EEPROM_PCDAC_STOP		63
++#define AR5K_EEPROM_PCDAC_STEP		1
++#define AR5K_EEPROM_NON_EDGE_M		0x40
++#define AR5K_EEPROM_CHANNEL_POWER	8
++#define AR5K_EEPROM_N_OBDB		4
++#define AR5K_EEPROM_OBDB_DIS		0xffff
++#define AR5K_EEPROM_CHANNEL_DIS		0xff
++#define AR5K_EEPROM_SCALE_OC_DELTA(_x)	(((_x) * 2) / 10)
++#define AR5K_EEPROM_N_CTLS(_v)		AR5K_EEPROM_OFF(_v, 16, 32)
++#define AR5K_EEPROM_MAX_CTLS		32
++#define AR5K_EEPROM_N_XPD_PER_CHANNEL	4
++#define AR5K_EEPROM_N_XPD0_POINTS	4
++#define AR5K_EEPROM_N_XPD3_POINTS	3
++#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
++#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
++#define AR5K_EEPROM_POWER_M		0x3f
++#define AR5K_EEPROM_POWER_MIN		0
++#define AR5K_EEPROM_POWER_MAX		3150
++#define AR5K_EEPROM_POWER_STEP		50
++#define AR5K_EEPROM_POWER_TABLE_SIZE	64
++#define AR5K_EEPROM_N_POWER_LOC_11B	4
++#define AR5K_EEPROM_N_POWER_LOC_11G	6
++#define AR5K_EEPROM_I_GAIN		10
++#define AR5K_EEPROM_CCK_OFDM_DELTA	15
++#define AR5K_EEPROM_N_IQ_CAL		2
++
++enum ath5k_ant_setting {
++	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
++	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
++	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
++	AR5K_ANT_MAX		= 3,
++};
+ 
+-#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
+-#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)	/* Device has a support */
+-#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)	/* Device has b support */
+-#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)	/* Device has g support */
+-#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
+-#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
+-#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
+-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz (?) */
+-#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
++/* Per channel calibration data, used for power table setup */
++struct ath5k_chan_pcal_info {
++	u_int16_t	freq; /* Frequency */
++	/* Power levels in dBm * 4 units */
++	int16_t		pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
++	int16_t		pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
++	/* PCDAC tables in dBm * 2 units */
++	u_int16_t	pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
++	u_int16_t	pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
++	/* Max available power */
++	u_int16_t	max_pwr;
++};
+ 
+-/* Misc values available since EEPROM 4.0 */
+-#define AR5K_EEPROM_MISC0		0x00c4
+-#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
+-#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
+-#define AR5K_EEPROM_MISC1		0x00c5
+-#define AR5K_EEPROM_TARGET_PWRSTART(_v)	((_v) & 0xfff)
+-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)	(((_v) >> 14) & 0x1)
++/* Per rate calibration data for each mode, used for power table setup */
++struct ath5k_rate_pcal_info {
++	u_int16_t	freq; /* Frequency */
++	/* Power level for 6-24Mbit/s rates */
++	u_int16_t	target_power_6to24;
++	/* Power level for 36Mbit rate */
++	u_int16_t	target_power_36;
++	/* Power level for 48Mbit rate */
++	u_int16_t	target_power_48;
++	/* Power level for 54Mbit rate */
++	u_int16_t	target_power_54;
++};
++
++/* EEPROM calibration data */
++struct ath5k_eeprom_info {
++
++	/* Header information */
++	u_int16_t	ee_magic;
++	u_int16_t	ee_protect;
++	u_int16_t	ee_regdomain;
++	u_int16_t	ee_version;
++	u_int16_t	ee_header;
++	u_int16_t	ee_ant_gain;
++	u_int16_t	ee_misc0;
++	u_int16_t	ee_misc1;
++	u_int16_t	ee_cck_ofdm_gain_delta;
++	u_int16_t	ee_cck_ofdm_power_delta;
++	u_int16_t	ee_scaled_cck_delta;
++
++	/* Used for tx thermal adjustment (eeprom_init, rfregs) */
++	u_int16_t	ee_tx_clip;
++	u_int16_t	ee_pwd_84;
++	u_int16_t	ee_pwd_90;
++	u_int16_t	ee_gain_select;
++
++	/* RF Calibration settings (reset, rfregs) */
++	u_int16_t	ee_i_cal[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_q_cal[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_fixed_bias[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_xr_power[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_switch_settling[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
++	u_int16_t	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
++	u_int16_t	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
++	u_int16_t	ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_thr_62[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_xlna_gain[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_xpd[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_x_gain[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_i_gain[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
++
++	/* Power calibration data */
++	u_int16_t	ee_false_detect[AR5K_EEPROM_N_MODES];
++	u_int16_t	ee_cal_piers_a;
++	struct ath5k_chan_pcal_info	ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
++	u_int16_t	ee_cal_piers_b;
++	struct ath5k_chan_pcal_info	ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN];
++	u_int16_t	ee_cal_piers_g;
++	struct ath5k_chan_pcal_info	ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN];
++	/* Per rate target power levels */
++	u_int16_t	ee_rate_target_pwr_num_a;
++	struct ath5k_rate_pcal_info	ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
++	u_int16_t	ee_rate_target_pwr_num_b;
++	struct ath5k_rate_pcal_info	ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN];
++	u_int16_t	ee_rate_target_pwr_num_g;
++	struct ath5k_rate_pcal_info	ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN];
++
++	/* Conformance test limits (Unused) */
++	u_int16_t	ee_ctls;
++	u_int16_t	ee_ctl[AR5K_EEPROM_MAX_CTLS];
++
++	/* Noise Floor Calibration settings */
++	int16_t		ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
++	int8_t		ee_adc_desired_size[AR5K_EEPROM_N_MODES];
++	int8_t		ee_pga_desired_size[AR5K_EEPROM_N_MODES];
++
++	u_int32_t	ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
++};
+ 
+ /*
+  * Read data by masking
+@@ -350,7 +486,6 @@
+ 	(*((volatile u_int32_t *)(mem + (_reg))) = (_val))
+ #endif
+ 
+-
+ #define AR5K_REG_ENABLE_BITS(_reg, _flags)	\
+ 	AR5K_REG_WRITE(_reg, AR5K_REG_READ(_reg) | (_flags))
+ 
+@@ -359,7 +494,12 @@
+ 
+ #define AR5K_TUNE_REGISTER_TIMEOUT		20000
+ 
+-/* names for eeprom fields */
++#define AR5K_EEPROM_READ(_o, _v) do {					\
++	if ((ret = ath5k_hw_eeprom_read(mem, (_o), &(_v), mac_version)) != 0)	\
++		return (ret);						\
++} while (0)
++
++/* Names for EEPROM fields */
+ struct eeprom_entry {
+ 	const char *name;
+ 	int addr;
+@@ -375,8 +515,6 @@
+ 	{"regdomain", AR5K_EEPROM_REG_DOMAIN},
+ };
+ 
+-static const int eeprom_addr_len = sizeof(eeprom_addr) / sizeof(eeprom_addr[0]);
+-
+ static int force_write = 0;
+ static int verbose = 0;
+ 
+@@ -398,8 +536,8 @@
+ /*
+  * Get the PHY Chip revision
+  */
+-static u_int16_t
+-ath5k_hw_radio_revision(u_int16_t mac_version, void *mem, u_int8_t chip)
++static u_int16_t ath5k_hw_radio_revision(u_int16_t mac_version, void *mem,
++					 u_int8_t chip)
+ {
+ 	int i;
+ 	u_int32_t srev;
+@@ -427,7 +565,7 @@
+ 	for (i = 0; i < 8; i++)
+ 		AR5K_REG_WRITE(AR5K_PHY(0x20), 0x00010000);
+ 
+-	if (mac_version == AR5K_SREV_VER_AR5210) {
++	if (mac_version == AR5K_SREV_MAC_AR5210) {
+ 		srev = AR5K_REG_READ(AR5K_PHY(256) >> 28) & 0xf;
+ 
+ 		ret = (u_int16_t)ath5k_hw_bitswap(srev, 4) + 1;
+@@ -447,9 +585,8 @@
+ /*
+  * Write to EEPROM
+  */
+-static int
+-ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data,
+-		      u_int8_t mac_version)
++static int ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data,
++				 u_int8_t mac_version)
+ {
+ 	u_int32_t status, timeout;
+ 
+@@ -457,7 +594,7 @@
+ 	 * Initialize EEPROM access
+ 	 */
+ 
+-	if (mac_version == AR5K_SREV_VER_AR5210) {
++	if (mac_version == AR5K_SREV_MAC_AR5210) {
+ 
+ 		AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE);
+ 
+@@ -466,7 +603,7 @@
+ 
+ 	} else {
+ 		/* not 5210 */
+-		/* reset eeprom access */
++		/* reset EEPROM access */
+ 		AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_RESET);
+ 		usleep(5);
+ 
+@@ -484,7 +621,7 @@
+ 		status = AR5K_REG_READ(AR5K_EEPROM_STATUS);
+ 		if (status & AR5K_EEPROM_STAT_WRDONE) {
+ 			if (status & AR5K_EEPROM_STAT_WRERR) {
+-				err("eeprom write access to 0x%04x failed",
++				err("EEPROM write access to 0x%04x failed",
+ 				    offset);
+ 				return 1;
+ 			}
+@@ -499,16 +636,15 @@
+ /*
+  * Read from EEPROM
+  */
+-static int
+-ath5k_hw_eeprom_read(void *mem, u_int32_t offset, u_int16_t *data,
+-		     u_int8_t mac_version)
++static int ath5k_hw_eeprom_read(void *mem, u_int32_t offset, u_int16_t *data,
++				u_int8_t mac_version)
+ {
+ 	u_int32_t status, timeout;
+ 
+ 	/*
+ 	 * Initialize EEPROM access
+ 	 */
+-	if (mac_version == AR5K_SREV_VER_AR5210) {
++	if (mac_version == AR5K_SREV_MAC_AR5210) {
+ 		AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE);
+ 		(void)AR5K_REG_READ(AR5K_EEPROM_BASE + (4 * offset));
+ 	} else {
+@@ -531,50 +667,701 @@
+ 	return 1;
+ }
+ 
+-static const char *ath5k_hw_get_part_name(enum ath5k_srev_type type,
+-					  u_int32_t val)
++/*
++ * Translate binary channel representation in EEPROM to frequency
++ */
++static u_int16_t ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee,
++				       u_int16_t bin, unsigned int mode)
+ {
+-	const char *name = "xxxxx";
+-	int i;
++	u_int16_t val;
+ 
+-	for (i = 0; i < ARRAY_SIZE(ath5k_srev_names); i++) {
+-		if (ath5k_srev_names[i].sr_type != type ||
+-		    ath5k_srev_names[i].sr_val == AR5K_SREV_UNKNOWN)
+-			continue;
+-		if ((val & 0xff) < ath5k_srev_names[i + 1].sr_val) {
+-			name = ath5k_srev_names[i].sr_name;
++	if (bin == AR5K_EEPROM_CHANNEL_DIS)
++		return bin;
++
++	if (mode == AR5K_EEPROM_MODE_11A) {
++		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
++			val = (5 * bin) + 4800;
++		else
++			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
++			    (bin * 10) + 5100;
++	} else {
++		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
++			val = bin + 2300;
++		else
++			val = bin + 2400;
++	}
++
++	return val;
++}
++
++/*
++ * Read antenna info from EEPROM
++ */
++static int ath5k_eeprom_read_ants(void *mem, u_int8_t mac_version,
++				  struct ath5k_eeprom_info *ee,
++				  u_int32_t *offset, unsigned int mode)
++{
++	u_int32_t o = *offset;
++	u_int16_t val;
++	int ret, i = 0;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
++	ee->ee_ant_tx_rx[mode]		= (val >> 2) & 0x3f;
++	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
++	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
++	ee->ee_ant_control[mode][i++]	= val & 0x3f;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
++	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
++	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
++	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
++	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
++	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
++	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
++	ee->ee_ant_control[mode][i++]	= val & 0x3f;
++
++	/* Get antenna modes */
++	ee->ee_antenna[mode][0] =
++	    (ee->ee_ant_control[mode][0] << 4) | 0x1;
++	ee->ee_antenna[mode][AR5K_ANT_FIXED_A] =
++	     ee->ee_ant_control[mode][1]	|
++	    (ee->ee_ant_control[mode][2] << 6)	|
++	    (ee->ee_ant_control[mode][3] << 12) |
++	    (ee->ee_ant_control[mode][4] << 18) |
++	    (ee->ee_ant_control[mode][5] << 24);
++	ee->ee_antenna[mode][AR5K_ANT_FIXED_B] =
++	     ee->ee_ant_control[mode][6]	|
++	    (ee->ee_ant_control[mode][7] << 6)	|
++	    (ee->ee_ant_control[mode][8] << 12) |
++	    (ee->ee_ant_control[mode][9] << 18) |
++	    (ee->ee_ant_control[mode][10] << 24);
++
++	/* return new offset */
++	*offset = o;
++
++	return 0;
++}
++
++/*
++ * Read supported modes from EEPROM
++ */
++static int ath5k_eeprom_read_modes(void *mem, u_int8_t mac_version,
++				   struct ath5k_eeprom_info *ee,
++				   u_int32_t *offset, unsigned int mode)
++{
++	u_int32_t o = *offset;
++	u_int16_t val;
++	int ret;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
++	ee->ee_thr_62[mode]		= val & 0xff;
++
++	if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2)
++		ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
++	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
++
++	if ((val & 0xff) & 0x80)
++		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
++	else
++		ee->ee_noise_floor_thr[mode] = val & 0xff;
++
++	if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2)
++		ee->ee_noise_floor_thr[mode] =
++		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
++	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
++	ee->ee_xpd[mode]		= val & 0x1;
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
++		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
++		AR5K_EEPROM_READ(o++, val);
++		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
++
++		if (mode == AR5K_EEPROM_MODE_11A)
++			ee->ee_xr_power[mode] = val & 0x3f;
++		else {
++			ee->ee_ob[mode][0] = val & 0x7;
++			ee->ee_db[mode][0] = (val >> 3) & 0x7;
++		}
++	}
++
++	if (ee->ee_version < AR5K_EEPROM_VERSION_3_4) {
++		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
++		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
++	} else {
++		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
++
++		AR5K_EEPROM_READ(o++, val);
++		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
++
++		if (mode == AR5K_EEPROM_MODE_11G)
++			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
++	}
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0 &&
++	    mode == AR5K_EEPROM_MODE_11A) {
++		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
++		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
++	}
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_6 &&
++	    mode == AR5K_EEPROM_MODE_11G)
++		ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
++
++	/* return new offset */
++	*offset = o;
++
++	return 0;
++}
++
++/*
++ * Read per channel calibration info from EEPROM
++ * This doesn't work on 2112+ chips (EEPROM versions >= 4.6),
++ * I only tested it on 5213 + 5112. This is still work in progress...
++ *
++ * This info is used to calibrate the baseband power table. Imagine
++ * that for each channel there is a power curve that's hw specific
++ * (depends on amplifier) and we try to "correct" this curve using offests
++ * we pass on to phy chip (baseband -> before amplifier) so that it can
++ * use acurate power values when setting tx power (takes amplifier's performance
++ * on each channel into account).
++ *
++ * EEPROM provides us with the offsets for some pre-calibrated channels
++ * and we have to scale (to create the full table for these channels) and
++ * interpolate (in order to create the table for any channel).
++ */
++static int ath5k_eeprom_read_pcal_info(void *mem, u_int8_t mac_version,
++				       struct ath5k_eeprom_info *ee,
++				       u_int32_t *offset, unsigned int mode)
++{
++	u_int32_t o = *offset;
++	unsigned int i, c;
++	int ret;
++	u_int16_t val;
++	struct ath5k_chan_pcal_info *chan_pcal_info;
++	u_int16_t cal_piers;
++
++	switch (mode) {
++	case AR5K_EEPROM_MODE_11A:
++		chan_pcal_info = ee->ee_pwr_cal_a;
++		cal_piers = ee->ee_cal_piers_a;
++		break;
++	case AR5K_EEPROM_MODE_11B:
++		chan_pcal_info = ee->ee_pwr_cal_b;
++		cal_piers = ee->ee_cal_piers_b;
++		break;
++	case AR5K_EEPROM_MODE_11G:
++		chan_pcal_info = ee->ee_pwr_cal_g;
++		cal_piers = ee->ee_cal_piers_g;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	for (i = 0; i < cal_piers; i++) {
++		/* Power values in dBm * 4 */
++		for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++			AR5K_EEPROM_READ(o++, val);
++			chan_pcal_info[i].pwr_x0[c] = (val & 0xff);
++			chan_pcal_info[i].pwr_x0[++c] = ((val >> 8) & 0xff);
++		}
++
++		/* PCDAC steps (dBm * 2) */
++		AR5K_EEPROM_READ(o++, val);
++		chan_pcal_info[i].pcdac_x0[1] = (val & 0x1f);
++		chan_pcal_info[i].pcdac_x0[2] = ((val >> 5) & 0x1f);
++		chan_pcal_info[i].pcdac_x0[3] = ((val >> 10) & 0x1f);
++
++		/* No idea what these power levels are for (4 xpds ?)
++		   I got zeroes on my card and the EEPROM info
++		   dumps we found on the net also have weird values */
++		AR5K_EEPROM_READ(o++, val);
++		chan_pcal_info[i].pwr_x3[0] = (val & 0xff);
++		chan_pcal_info[i].pwr_x3[1] = ((val >> 8) & 0xff);
++
++		AR5K_EEPROM_READ(o++, val);
++		chan_pcal_info[i].pwr_x3[2] = (val & 0xff);
++		/* It's weird but they put it here, that's the
++		   PCDAC starting step */
++		chan_pcal_info[i].pcdac_x0[0] = ((val >> 8) & 0xff);
++
++		/* Static values seen on EEPROM info dumps */
++		chan_pcal_info[i].pcdac_x3[0] = 20;
++		chan_pcal_info[i].pcdac_x3[1] = 35;
++		chan_pcal_info[i].pcdac_x3[2] = 63;
++
++		/* Last xpd0 power level is also channel maximum */
++		chan_pcal_info[i].max_pwr = chan_pcal_info[i].pwr_x0[3];
++
++		/* Recreate pcdac_x0 table for this channel using pcdac steps */
++		chan_pcal_info[i].pcdac_x0[1] += chan_pcal_info[i].pcdac_x0[0];
++		chan_pcal_info[i].pcdac_x0[2] += chan_pcal_info[i].pcdac_x0[1];
++		chan_pcal_info[i].pcdac_x0[3] += chan_pcal_info[i].pcdac_x0[2];
++	}
++
++	/* return new offset */
++	(*offset) = o;
++
++	return 0;
++}
++
++/*
++ * Read per rate target power (this is the maximum tx power
++ * supported by the card). This info is used when setting
++ * tx power, no matter the channel.
++ *
++ * This also works for v5 EEPROMs.
++ */
++static int ath5k_eeprom_read_target_rate_pwr_info(void *mem,
++						  u_int8_t mac_version,
++						  struct ath5k_eeprom_info *ee,
++						  u_int32_t *offset,
++						  unsigned int mode)
++{
++	u_int32_t o = *offset;
++	u_int16_t val;
++	struct ath5k_rate_pcal_info *rate_pcal_info;
++	u_int16_t *rate_target_pwr_num;
++	int ret, i;
++
++	switch (mode) {
++	case AR5K_EEPROM_MODE_11A:
++		rate_pcal_info = ee->ee_rate_tpwr_a;
++		ee->ee_rate_target_pwr_num_a = AR5K_EEPROM_N_5GHZ_CHAN;
++		rate_target_pwr_num = &ee->ee_rate_target_pwr_num_a;
++		break;
++	case AR5K_EEPROM_MODE_11B:
++		rate_pcal_info = ee->ee_rate_tpwr_b;
++		ee->ee_rate_target_pwr_num_b = 2; /* 3rd is g mode'ss 1st */
++		rate_target_pwr_num = &ee->ee_rate_target_pwr_num_b;
++		break;
++	case AR5K_EEPROM_MODE_11G:
++		rate_pcal_info = ee->ee_rate_tpwr_g;
++		ee->ee_rate_target_pwr_num_g = AR5K_EEPROM_N_2GHZ_CHAN;
++		rate_target_pwr_num = &ee->ee_rate_target_pwr_num_g;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* Different freq mask for older eeproms (<= v3.2) */
++	if(ee->ee_version <= 0x3002){
++		for (i = 0; i < (*rate_target_pwr_num); i++) {
++			AR5K_EEPROM_READ(o++, val);
++			rate_pcal_info[i].freq =
++			    ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
++	
++			rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
++			rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
++	
++			AR5K_EEPROM_READ(o++, val);
++	
++			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
++			    val == 0) {
++				(*rate_target_pwr_num) = i;
++				break;
++			}
++
++			rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
++			rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
++			rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
++		}
++	} else {
++		for (i = 0; i < (*rate_target_pwr_num); i++) {
++			AR5K_EEPROM_READ(o++, val);
++			rate_pcal_info[i].freq =
++			    ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++	
++			rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
++			rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
++	
++			AR5K_EEPROM_READ(o++, val);
++	
++			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
++			    val == 0) {
++				(*rate_target_pwr_num) = i;
++				break;
++			}
++
++			rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
++			rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
++			rate_pcal_info[i].target_power_54 = (val & 0x3f);
++		}
++	}
++	/* return new offset */
++	(*offset) = o;
++
++	return 0;
++}
++
++/*
++ * Initialize EEPROM & capabilities data
++ */
++static int ath5k_eeprom_init(void *mem, u_int8_t mac_version,
++			     struct ath5k_eeprom_info *ee)
++{
++	unsigned int mode, i;
++	int ret;
++	u_int32_t offset;
++	u_int16_t val;
++
++	/* Initial TX thermal adjustment values */
++	ee->ee_tx_clip = 4;
++	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
++	ee->ee_gain_select = 1;
++
++	/*
++	 * Read values from EEPROM and store them in the capability structure
++	 */
++	AR5K_EEPROM_READ(AR5K_EEPROM_MAGIC, ee->ee_magic);
++	AR5K_EEPROM_READ(AR5K_EEPROM_PROTECT, ee->ee_protect);
++	AR5K_EEPROM_READ(AR5K_EEPROM_REG_DOMAIN, ee->ee_regdomain);
++	AR5K_EEPROM_READ(AR5K_EEPROM_VERSION, ee->ee_version);
++	AR5K_EEPROM_READ(AR5K_EEPROM_HDR, ee->ee_header);
++
++	/* Return if we have an old EEPROM */
++	if (ee->ee_version < AR5K_EEPROM_VERSION_3_0)
++		return 0;
++
++#ifdef notyet
++	/*
++	 * Validate the checksum of the EEPROM date. There are some
++	 * devices with invalid EEPROMs.
++	 */
++	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
++		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
++		cksum ^= val;
++	}
++	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
++		AR5K_PRINTF("Invalid EEPROM checksum 0x%04x\n", cksum);
++		return -EIO;
++	}
++#endif
++
++	AR5K_EEPROM_READ(AR5K_EEPROM_ANT_GAIN(ee->ee_version), ee->ee_ant_gain);
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++		AR5K_EEPROM_READ(AR5K_EEPROM_MISC0, ee->ee_misc0);
++		AR5K_EEPROM_READ(AR5K_EEPROM_MISC1, ee->ee_misc1);
++	}
++
++	if (ee->ee_version < AR5K_EEPROM_VERSION_3_3) {
++		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
++		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
++		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
++
++		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
++		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
++		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
++	}
++
++	/*
++	 * Get conformance test limit values
++	 */
++	offset = AR5K_EEPROM_CTL(ee->ee_version);
++	ee->ee_ctls = 0;
++
++	for (i = 0; i < AR5K_EEPROM_N_CTLS(ee->ee_version); i++) {
++		AR5K_EEPROM_READ(offset++, val);
++
++		if (((val >> 8) & 0xff) == 0)
++			break;
++
++		ee->ee_ctl[i] = (val >> 8) & 0xff;
++		ee->ee_ctls++;
++
++		if ((val & 0xff) == 0)
+ 			break;
++
++		ee->ee_ctl[i + 1] = val & 0xff;
++		ee->ee_ctls++;
++	}
++
++	/*
++	 * Get values for 802.11a (5GHz)
++	 */
++	mode = AR5K_EEPROM_MODE_11A;
++
++	ee->ee_turbo_max_power[mode] =
++	    AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
++
++	offset = AR5K_EEPROM_MODES_11A(ee->ee_version);
++
++	ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	AR5K_EEPROM_READ(offset++, val);
++	ee->ee_adc_desired_size[mode]	= (int8_t)((val >> 8) & 0xff);
++	ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
++	ee->ee_db[mode][3]		= (val >> 2) & 0x7;
++	ee->ee_ob[mode][2]		= (val << 1) & 0x7;
++
++	AR5K_EEPROM_READ(offset++, val);
++	ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
++	ee->ee_db[mode][2]		= (val >> 12) & 0x7;
++	ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
++	ee->ee_db[mode][1]		= (val >> 6) & 0x7;
++	ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
++	ee->ee_db[mode][0]		= val & 0x7;
++
++	ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1) {
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_margin_tx_rx[mode] = val & 0x3f;
++	}
++
++	/*
++	 * Get values for 802.11b (2.4GHz)
++	 */
++	mode = AR5K_EEPROM_MODE_11B;
++	offset = AR5K_EEPROM_MODES_11B(ee->ee_version);
++
++	ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	AR5K_EEPROM_READ(offset++, val);
++	ee->ee_adc_desired_size[mode]	= (int8_t)((val >> 8) & 0xff);
++	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
++	ee->ee_db[mode][1]		= val & 0x7;
++
++	ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++		AR5K_EEPROM_READ(offset++, val);
++
++		ee->ee_cal_piers_b = 0;
++
++		ee->ee_pwr_cal_b[0].freq =
++			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++		if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
++			ee->ee_cal_piers_b++;
++
++		ee->ee_pwr_cal_b[1].freq =
++			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++		if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
++			ee->ee_cal_piers_b++;
++
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_pwr_cal_b[2].freq =
++			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++		if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
++			ee->ee_cal_piers_b++;
++	}
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1)
++		ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
++
++	/*
++	 * Get values for 802.11g (2.4GHz)
++	 */
++	mode = AR5K_EEPROM_MODE_11G;
++	offset = AR5K_EEPROM_MODES_11G(ee->ee_version);
++
++	ret = ath5k_eeprom_read_ants(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	AR5K_EEPROM_READ(offset++, val);
++	ee->ee_adc_desired_size[mode]	= (signed short int)((val >> 8) & 0xff);
++	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
++	ee->ee_db[mode][1]		= val & 0x7;
++
++	ret = ath5k_eeprom_read_modes(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) {
++		AR5K_EEPROM_READ(offset++, val);
++
++		ee->ee_cal_piers_g = 0;
++
++		ee->ee_pwr_cal_g[0].freq =
++			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++		if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
++			ee->ee_cal_piers_g++;
++
++		ee->ee_pwr_cal_g[1].freq =
++			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
++		if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
++			ee->ee_cal_piers_g++;
++
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_turbo_max_power[mode] = val & 0x7f;
++		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
++
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_pwr_cal_g[2].freq =
++			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
++		if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
++			ee->ee_cal_piers_g++;
++
++		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_1)
++			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
++
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
++		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
++
++		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_2) {
++			AR5K_EEPROM_READ(offset++, val);
++			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+ 		}
+ 	}
+ 
+-	return (name);
++	/*
++	 * Read 5GHz EEPROM channels
++	 */
++	offset = AR5K_EEPROM_CHANNELS_5GHZ(ee->ee_version);
++	ee->ee_cal_piers_a = 0;
++	for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {
++		AR5K_EEPROM_READ(offset++, val);
++
++		if ((val & 0xff) == 0)
++			break;
++
++		ee->ee_pwr_cal_a[i].freq =
++			ath5k_eeprom_bin2freq(ee, val & 0xff, AR5K_EEPROM_MODE_11A);
++		ee->ee_cal_piers_a++;
++
++		if (((val >> 8) & 0xff) == 0)
++			break;
++
++		ee->ee_pwr_cal_a[++i].freq =
++			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, AR5K_EEPROM_MODE_11A);
++		ee->ee_cal_piers_a++;
++
++	}
++
++	/*
++	 * Read power calibration info
++	 */
++	mode = AR5K_EEPROM_MODE_11A;
++	ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	mode = AR5K_EEPROM_MODE_11B;
++	ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	mode = AR5K_EEPROM_MODE_11G;
++	ret = ath5k_eeprom_read_pcal_info(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++
++	/*
++	 * Read per rate target power info
++	 */
++	offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
++	mode = AR5K_EEPROM_MODE_11A;
++	ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
++	mode = AR5K_EEPROM_MODE_11B;
++	ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) + AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
++	mode = AR5K_EEPROM_MODE_11G;
++	ret = ath5k_eeprom_read_target_rate_pwr_info(mem, mac_version, ee, &offset, mode);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static const char *ath5k_hw_get_mac_name(u_int8_t val)
++{
++	static char name[16];
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(ath5k_mac_names); i++) {
++		if (val <= ath5k_mac_names[i].sr_val)
++			break;
++	}
++
++	if (val == ath5k_mac_names[i].sr_val)
++		return ath5k_mac_names[i].sr_name;
++
++	snprintf(name, sizeof(name), "%s+", ath5k_mac_names[i - 1].sr_name);
++	return name;
++}
++
++static const char *ath5k_hw_get_phy_name(u_int8_t val)
++{
++	const char *name = "?????";
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(ath5k_phy_names); i++) {
++		if (val < ath5k_phy_names[i + 1].sr_val) {
++			name = ath5k_phy_names[i].sr_name;
++			break;
++		}
++	}
++
++	return name;
+ }
+ 
+ /* returns -1 on unknown name */
+ static int eeprom_name2addr(const char *name)
+ {
+-	int i;
++	unsigned int i;
++
+ 	if (!name || !name[0])
+ 		return -1;
+-	for (i = 0; i < eeprom_addr_len; i++)
++	for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+ 		if (!strcmp(name, eeprom_addr[i].name))
+ 			return eeprom_addr[i].addr;
+ 	return -1;
+-}				/* eeprom_name2addr */
++}
+ 
+ /* returns "<unknown>" on unknown address */
+ static const char *eeprom_addr2name(int addr)
+ {
+-	int i;
+-	for (i = 0; i < eeprom_addr_len; i++)
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+ 		if (eeprom_addr[i].addr == addr)
+ 			return eeprom_addr[i].name;
+ 	return "<unknown>";
+-}				/* eeprom_addr2name */
++}
+ 
+-static int
+-do_write_pairs(int anr, int argc, char **argv, unsigned char *mem,
+-	       int mac_version)
++static int do_write_pairs(int anr, int argc, char **argv, unsigned char *mem,
++			  int mac_version)
+ {
+ #define MAX_NR_WRITES 16
+ 	struct {
+@@ -635,7 +1422,7 @@
+ 		}
+ 		anr++;
+ 		i++;
+-	}			/* while (anr < (argc-1)) */
++	}
+ 
+ 	if (!(wr_ops_len = i)) {
+ 		err("no (addr,val) pairs given");
+@@ -702,20 +1489,22 @@
+ 	}
+ 
+ 	return errors ? 11 : 0;
+-}				/* do_write_pairs */
++}
+ 
+ static void usage(const char *n)
+ {
+-	int i;
++	unsigned int i;
+ 
+-	fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] <base_address> "
++	fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] [-d] [-R addr] [-W addr val] <base_address> "
+ 		"[<name1> <val1> [<name2> <val2> ...]]\n\n", n);
+ 	fprintf(stderr,
+ 		"-w      write values into EEPROM\n"
+ 		"-g N:M  set GPIO N to level M (only used with -w)\n"
+ 		"-v      verbose output\n"
+ 		"-f      force; suppress question before writing\n"
+-		"-d      dump eeprom (file 'ath-eeprom-dump.bin' and screen)\n"
++		"-d      dump EEPROM (file 'ath-eeprom-dump.bin' and screen)\n"
++		"-R <addr>       read register at <addr> (hex)\n"
++		"-W <addr> <val> write <val> (hex) into register at <addr> (hex)\n"
+ 		"<base_address>  device base address (see lspci output)\n\n");
+ 
+ 	fprintf(stderr,
+@@ -725,8 +1514,8 @@
+ 		"  %s -w <base_address> regdomain N\n\n"
+ 		"- set a PCI id field to value N:\n"
+ 		"  %s -w <base_address> <field> N\n"
+-		"  where <field> is on of:\n    ", n, n, n);
+-	for (i = 0; i < eeprom_addr_len; i++)
++		"  where <field> is one of:\n    ", n, n, n);
++	for (i = 0; i < ARRAY_SIZE(eeprom_addr); i++)
+ 		fprintf(stderr, " %s", eeprom_addr[i].name);
+ 	fprintf(stderr, "\n\n");
+ 	fprintf(stderr,
+@@ -739,19 +1528,457 @@
+ 		"unlawful radio transmissions!\n\n");
+ }
+ 
++static void dump_capabilities(struct ath5k_eeprom_info *ee)
++{
++	u_int8_t has_a, has_b, has_g, has_rfkill, turbog_dis, turboa_dis;
++	u_int8_t xr2_dis, xr5_dis, has_crystal;
++
++	has_a = AR5K_EEPROM_HDR_11A(ee->ee_header);
++	has_b = AR5K_EEPROM_HDR_11B(ee->ee_header);
++	has_g = AR5K_EEPROM_HDR_11G(ee->ee_header);
++	has_rfkill = AR5K_EEPROM_HDR_RFKILL(ee->ee_header);
++	has_crystal = AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1);
++	turbog_dis = AR5K_EEPROM_HDR_T_2GHZ_DIS(ee->ee_header);
++	turboa_dis = AR5K_EEPROM_HDR_T_5GHZ_DIS(ee->ee_header);
++	xr2_dis = AR5K_EEPROM_HDR_XR2_DIS(ee->ee_misc0);
++	xr5_dis = AR5K_EEPROM_HDR_XR5_DIS(ee->ee_misc0);
++
++	printf("|================= Capabilities ================|\n");
++
++	printf("| 802.11a Support: ");
++	if (has_a)
++		printf(" yes |");
++	else
++		printf(" no  |");
++
++	printf(" Turbo-A disabled:");
++	if (turboa_dis)
++		printf(" yes |\n");
++	else
++		printf(" no  |\n");
++
++	printf("| 802.11b Support: ");
++	if (has_b)
++		printf(" yes |");
++	else
++		printf(" no  |");
++
++	printf(" Turbo-G disabled:");
++	if (turbog_dis)
++		printf(" yes |\n");
++	else
++		printf(" no  |\n");
++
++	printf("| 802.11g Support: ");
++	if (has_g)
++		printf(" yes |");
++	else
++		printf(" no  |");
++
++	printf(" 2GHz XR disabled:");
++	if (xr2_dis)
++		printf(" yes |\n");
++	else
++		printf(" no  |\n");
++
++	printf("| RFKill  Support: ");
++	if (has_rfkill)
++		printf(" yes |");
++	else
++		printf(" no  |");
++
++	printf(" 5GHz XR disabled:");
++	if (xr5_dis)
++		printf(" yes |\n");
++	else
++		printf(" no  |\n");
++
++	if (has_crystal != 2) {
++		printf("| 32kHz   Crystal: ");
++		if (has_crystal)
++			printf(" yes |");
++		else
++			printf(" no  |");
++
++		printf("                       |\n");
++	}
++
++	printf("\\===============================================/\n");
++}
++
++static void dump_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++	int i;
++
++	printf("|=========================================================|\n");
++	printf("| I power:              0x%02x |", ee->ee_i_cal[mode]);
++	printf(" Q power:              0x%02x |\n", ee->ee_q_cal[mode]);
++	printf("| Use fixed bias:       0x%02x |", ee->ee_fixed_bias[mode]);
++	printf(" Max turbo power:      0x%02x |\n", ee->ee_turbo_max_power[mode]);
++	printf("| Max XR power:         0x%02x |", ee->ee_xr_power[mode]);
++	printf(" Switch Settling Time: 0x%02x |\n", ee->ee_switch_settling[mode]);
++	printf("| Tx/Rx attenuation:    0x%02x |", ee->ee_ant_tx_rx[mode]);
++	printf(" TX end to XLNA On:    0x%02x |\n", ee->ee_tx_end2xlna_enable[mode]);
++	printf("| TX end to XPA Off:    0x%02x |", ee->ee_tx_end2xpa_disable[mode]);
++	printf(" TX end to XPA On:     0x%02x |\n", ee->ee_tx_frm2xpa_enable[mode]);
++	printf("| 62db Threshold:       0x%02x |", ee->ee_thr_62[mode]);
++	printf(" XLNA gain:            0x%02x |\n", ee->ee_xlna_gain[mode]);
++	printf("| XPD:                  0x%02x |", ee->ee_xpd[mode]);
++	printf(" XPD gain:             0x%02x |\n", ee->ee_x_gain[mode]);
++	printf("| I gain:               0x%02x |", ee->ee_i_gain[mode]);
++	printf(" Tx/Rx margin:         0x%02x |\n", ee->ee_margin_tx_rx[mode]);
++	printf("| False detect backoff: 0x%02x |", ee->ee_false_detect[mode]);
++	printf(" Noise Floor Threshold: %3d |\n", ee->ee_noise_floor_thr[mode]);
++	printf("| ADC desired size:      %3d |", ee->ee_adc_desired_size[mode]);
++	printf(" PGA desired size:      %3d |\n", ee->ee_pga_desired_size[mode]);
++	printf("|=========================================================|\n");
++	for (i = 0; i < AR5K_EEPROM_N_PCDAC; i++) {
++		printf("| Antenna control  %2i:  0x%02x |", i, ee->ee_ant_control[mode][i]);
++		i++;
++		printf(" Antenna control  %2i:  0x%02x |\n", i, ee->ee_ant_control[mode][i]);
++	}
++	printf("|=========================================================|\n");
++	for (i = 0; i < AR5K_EEPROM_N_OBDB; i++) {
++		printf("| Octave Band %i:          %2i |", i, ee->ee_ob[mode][i]);
++		printf(" db %i:                   %2i |\n", i, ee->ee_db[mode][i]);
++	}
++	printf("\\=========================================================/\n");
++}
++
++static void dump_power_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++	struct ath5k_chan_pcal_info *chan_pcal_info;
++	u_int16_t cal_piers;
++	int i, c;
++
++	switch (mode) {
++	case AR5K_EEPROM_MODE_11A:
++		chan_pcal_info = ee->ee_pwr_cal_a;
++		cal_piers = ee->ee_cal_piers_a;
++		break;
++	case AR5K_EEPROM_MODE_11B:
++		chan_pcal_info = ee->ee_pwr_cal_b;
++		cal_piers = ee->ee_cal_piers_b;
++		break;
++	case AR5K_EEPROM_MODE_11G:
++		chan_pcal_info = ee->ee_pwr_cal_g;
++		cal_piers = ee->ee_cal_piers_g;
++		break;
++	default:
++		return;
++	}
++
++	printf("/=================== Per channel power calibration ====================\\\n");
++	printf("| Freq | pwr_0 | pwr_1 | pwr_2 | pwr_3 |pwrx3_0|pwrx3_1|pwrx3_2|max_pwr|\n");
++	printf("|      | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac | pcdac |       |\n");
++
++	for (i = 0; i < cal_piers; i++) {
++		char buf[16];
++
++		printf("|======|=======|=======|=======|=======|=======|=======|=======|=======|\n");
++		printf("| %4i |", chan_pcal_info[i].freq);
++		for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++			printf(" %2i.%02i |", chan_pcal_info[i].pwr_x0[c] / 4,
++			       chan_pcal_info[i].pwr_x0[c] % 4);
++		}
++		for (c = 0; c < AR5K_EEPROM_N_XPD3_POINTS; c++) {
++			printf(" %2i.%02i |", chan_pcal_info[i].pwr_x3[c] / 4,
++			       chan_pcal_info[i].pwr_x3[c] % 4);
++		}
++		printf(" %2i.%02i |\n", chan_pcal_info[i].max_pwr / 4,
++		       chan_pcal_info[i].max_pwr % 4);
++
++		printf("|      |");
++		for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
++			snprintf(buf, sizeof(buf), "[%i]",
++				 chan_pcal_info[i].pcdac_x0[c]);
++			printf("%6s |", buf);
++		}
++		for (c = 0; c < AR5K_EEPROM_N_XPD3_POINTS; c++) {
++			snprintf(buf, sizeof(buf), "[%i]",
++				 chan_pcal_info[i].pcdac_x3[c]);
++			printf("%6s |", buf);
++		}
++		printf("       |\n");
++
++	}
++	printf("\\======================================================================/\n");
++}
++
++static void dump_rate_calinfo_for_mode(int mode, struct ath5k_eeprom_info *ee)
++{
++	int i;
++	struct ath5k_rate_pcal_info *rate_pcal_info;
++	u_int16_t rate_target_pwr_num;
++
++	switch (mode) {
++	case AR5K_EEPROM_MODE_11A:
++		rate_pcal_info = ee->ee_rate_tpwr_a;
++		rate_target_pwr_num = ee->ee_rate_target_pwr_num_a;
++		break;
++	case AR5K_EEPROM_MODE_11B:
++		rate_pcal_info = ee->ee_rate_tpwr_b;
++		rate_target_pwr_num = ee->ee_rate_target_pwr_num_b;
++		break;
++	case AR5K_EEPROM_MODE_11G:
++		rate_pcal_info = ee->ee_rate_tpwr_g;
++		rate_target_pwr_num = ee->ee_rate_target_pwr_num_g;
++		break;
++	default:
++		return;
++	}
++
++	printf("/============== Per rate power calibration ===========\\\n");
++	if (mode == AR5K_EEPROM_MODE_11B)
++		printf("| Freq |   1Mbit/s  | 2Mbit/s  | 5.5Mbit/s | 11Mbit/s |\n");
++	else
++		printf("| Freq | 6-24Mbit/s | 36Mbit/s |  48Mbit/s | 54Mbit/s |\n");
++
++	for (i = 0; i < rate_target_pwr_num; i++) {
++
++		printf("|======|============|==========|===========|==========|\n");
++		printf("| %4i |", rate_pcal_info[i].freq);
++		printf("    %2i.%02i   |",rate_pcal_info[i].target_power_6to24 /2,
++					rate_pcal_info[i].target_power_6to24 % 2);
++		printf("  %2i.%02i   |",rate_pcal_info[i].target_power_36 /2,
++					rate_pcal_info[i].target_power_36 % 2);
++		printf("   %2i.%02i   |",rate_pcal_info[i].target_power_48 /2,
++					rate_pcal_info[i].target_power_48 % 2);
++		printf("  %2i.%02i   |\n",rate_pcal_info[i].target_power_54 /2,
++					rate_pcal_info[i].target_power_54 % 2);
++	}
++	printf("\\=====================================================/\n");
++}
++
++static u_int32_t extend_tu(u_int32_t base_tu, u_int32_t val, u_int32_t mask)
++{
++	u_int32_t result;
++
++	result = (base_tu & ~mask) | (val & mask);
++	if ((base_tu & mask) > (val & mask))
++		result += mask + 1;
++	return result;
++}
++
++static void dump_timers_register(void *mem, u_int16_t mac_version)
++{
++#define AR5K_TIMER0_5210		0x802c	/* next TBTT */
++#define AR5K_TIMER0_5211		0x8028
++#define AR5K_TIMER0			(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
++
++#define AR5K_TIMER1_5210		0x8030	/* next DMA beacon */
++#define AR5K_TIMER1_5211		0x802c
++#define AR5K_TIMER1			(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
++
++#define AR5K_TIMER2_5210		0x8034	/* next SWBA interrupt */
++#define AR5K_TIMER2_5211		0x8030
++#define AR5K_TIMER2			(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
++
++#define AR5K_TIMER3_5210		0x8038	/* next ATIM window */
++#define AR5K_TIMER3_5211		0x8034
++#define AR5K_TIMER3			(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
++
++#define AR5K_TSF_L32_5210		0x806c	/* TSF (lower 32 bits) */
++#define AR5K_TSF_L32_5211		0x804c
++#define AR5K_TSF_L32			(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
++
++#define AR5K_TSF_U32_5210		0x8070
++#define AR5K_TSF_U32_5211		0x8050
++#define AR5K_TSF_U32			(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
++
++#define AR5K_BEACON_5210		0x8024
++#define AR5K_BEACON_5211		0x8020
++#define AR5K_BEACON			(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_BEACON_5210 : AR5K_BEACON_5211)
++
++#define AR5K_LAST_TSTP			0x8080
++
++	const int timer_mask = 0xffff;
++
++	u_int32_t timer0, timer1, timer2, timer3, now_tu;
++	u_int32_t timer0_tu, timer1_tu, timer2_tu, timer3_tu;
++	u_int64_t now_tsf;
++
++	timer0 = AR5K_REG_READ(AR5K_TIMER0);		/* 0x0000ffff */
++	timer1 = AR5K_REG_READ(AR5K_TIMER1_5211);	/* 0x0007ffff */
++	timer2 = AR5K_REG_READ(AR5K_TIMER2_5211);	/* 0x?1ffffff */
++	timer3 = AR5K_REG_READ(AR5K_TIMER3_5211);	/* 0x0000ffff */
++
++	now_tsf = ((u_int64_t)AR5K_REG_READ(AR5K_TSF_U32_5211) << 32)
++		| (u_int64_t)AR5K_REG_READ(AR5K_TSF_L32_5211);
++
++	now_tu = now_tsf >> 10;
++
++	timer0_tu = extend_tu(now_tu, timer0, 0xffff);
++	printf("TIMER0: 0x%08x, TBTT: %5u, TU: 0x%08x\n", timer0,
++	       timer0 & timer_mask, timer0_tu);
++	timer1_tu = extend_tu(now_tu, timer1 >> 3, 0x7ffff >> 3);
++	printf("TIMER1: 0x%08x, DMAb: %5u, TU: 0x%08x (%+d)\n", timer1,
++	       (timer1 >> 3) & timer_mask, timer1_tu, timer1_tu - timer0_tu);
++	timer2_tu = extend_tu(now_tu, timer2 >> 3, 0x1ffffff >> 3);
++	printf("TIMER2: 0x%08x, SWBA: %5u, TU: 0x%08x (%+d)\n", timer2,
++	       (timer2 >> 3) & timer_mask, timer2_tu, timer2_tu - timer0_tu);
++	timer3_tu = extend_tu(now_tu, timer3, 0xffff);
++	printf("TIMER3: 0x%08x, ATIM: %5u, TU: 0x%08x (%+d)\n", timer3,
++	       timer3 & timer_mask, timer3_tu, timer3_tu - timer0_tu);
++	printf("TSF: 0x%016llx, TSFTU: %5u, TU: 0x%08x\n",
++	       (unsigned long long)now_tsf, now_tu & timer_mask, now_tu);
++
++	printf("BEACON: 0x%08x\n", AR5K_REG_READ(AR5K_BEACON));
++	printf("LAST_TSTP: 0x%08x\n", AR5K_REG_READ(AR5K_LAST_TSTP));
++}
++
++#define AR5K_KEYTABLE_0_5210		0x9000
++#define AR5K_KEYTABLE_0_5211		0x8800
++#define AR5K_KEYTABLE_0			(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_KEYTABLE_0_5210 : \
++					AR5K_KEYTABLE_0_5211)
++
++#define AR5K_KEYTABLE(_n)		(AR5K_KEYTABLE_0_5211 + ((_n) << 5))
++#define AR5K_KEYTABLE_OFF(_n, x)	(AR5K_KEYTABLE(_n) + ((x) << 2))
++#define AR5K_KEYTABLE_VALID		0x00008000
++
++#define AR5K_KEYTABLE_SIZE_5210		64
++#define AR5K_KEYTABLE_SIZE_5211		128
++#define AR5K_KEYTABLE_SIZE		(mac_version == AR5K_SREV_MAC_AR5210 ? \
++					AR5K_KEYTABLE_SIZE_5210 : \
++					AR5K_KEYTABLE_SIZE_5211)
++
++static void keycache_dump(void *mem, u_int16_t mac_version)
++{
++	int i, keylen;
++	u_int32_t val0, val1, val2, val3, val4, keytype, ant, mac0, mac1;
++
++	/* dump all 128 entries */
++	printf("Dumping keycache entries...\n");
++	for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) {
++		mac1 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 7));
++		if (mac1 & AR5K_KEYTABLE_VALID) {
++			val0    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 0));
++			val1    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 1));
++			val2    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 2));
++			val3    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 3));
++			val4    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 4));
++			keytype = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 5));
++			ant = keytype & 8;
++			keytype &= ~8;
++			switch (keytype) {
++			case 0: /* WEP40  */ keylen =  40 / 8; break;
++			case 1: /* WEP104 */ keylen = 104 / 8; break;
++			case 3: /* WEP128 */ keylen = 128 / 8; break;
++			case 4: /* TKIP   */ keylen = 128 / 8; break;
++			case 5: /* AES    */ keylen = 128 / 8; break;
++			case 6: /* CCM    */ keylen = 128 / 8; break;
++			default:             keylen = 0;       break;
++			}
++			mac0 = AR5K_REG_READ(AR5K_KEYTABLE_OFF(i, 6));
++
++			printf("[%3u] keytype %d [%s%s%s%s%s%s%s%s] mac %02x:%02x:%02x:%02x:%02x:%02x key:%08x-%08x-%08x-%08x-%08x\n",
++			       i,
++			       keytype,
++			       keytype == 0 ? "WEP40 " : "",
++			       keytype == 1 ? "WEP104" : "",
++			       keytype == 3 ? "WEP128" : "",
++			       keytype == 4 ? "TKIP  " : "",
++			       keytype == 5 ? "AES   " : "",
++			       keytype == 6 ? "CCM   " : "",
++			       keytype == 7 ? "NULL  " : "",
++			       ant     == 8 ? "+ANT"   : "",
++			       ((mac0 <<  1) & 0xff),
++			       ((mac0 >>  7) & 0xff),
++			       ((mac0 >> 15) & 0xff),
++			       ((mac0 >> 23) & 0xff),
++			       ((mac1 <<  1) & 0xff) | (mac0 >> 31),
++			       ((mac1 >>  7) & 0xff),
++			       val0, val1, val2, val3, val4);
++		}
++	}
++}
++
++/* copy key index (0) to key index (idx) */
++
++static void keycache_copy(void *mem, u_int16_t mac_version, int idx)
++{
++	u_int32_t val0, val1, val2, val3, val4, keytype, mac0, mac1;
++
++	printf("Copying keycache entry 0 to %d\n", idx);
++	if (idx < 0 || idx >= AR5K_KEYTABLE_SIZE) {
++		printf("invalid keycache index\n");
++		return;
++	}
++
++	val0    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 0));
++	val1    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 1));
++	val2    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 2));
++	val3    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 3));
++	val4    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 4));
++	keytype = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 5));
++	mac0    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 6));
++	mac1    = AR5K_REG_READ(AR5K_KEYTABLE_OFF(0, 7));
++
++	AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 0), val0);
++	AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 1), val1);
++	AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 2), val2);
++	AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 3), val3);
++	AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 4), val4);
++	AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 5), keytype);
++	AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 6), mac0);
++	AR5K_REG_WRITE(AR5K_KEYTABLE_OFF(idx, 7), mac1);
++}
++
++static void sta_id0_id1_dump(void *mem)
++{
++#define AR5K_STA_ID0			0x8000
++#define AR5K_STA_ID1			0x8004
++#define AR5K_STA_ID1_AP                 0x00010000
++#define AR5K_STA_ID1_ADHOC              0x00020000
++#define AR5K_STA_ID1_NO_KEYSRCH		0x00080000
++
++	u_int32_t sta_id0, sta_id1;
++
++	sta_id0 = AR5K_REG_READ(AR5K_STA_ID0);
++	sta_id1 = AR5K_REG_READ(AR5K_STA_ID1);
++	printf("STA_ID0: %02x:%02x:%02x:%02x:%02x:%02x\n",
++	       (sta_id0 >>  0) & 0xff,
++	       (sta_id0 >>  8) & 0xff,
++	       (sta_id0 >> 16) & 0xff,
++	       (sta_id0 >> 24) & 0xff,
++	       (sta_id1 >>  0) & 0xff,
++	       (sta_id1 >>  8) & 0xff);
++	printf("STA_ID1: 0x%08x, AP: %d, IBSS: %d, KeyCache Disable: %d\n",
++	       sta_id1,
++	       sta_id1 & AR5K_STA_ID1_AP ? 1 : 0,
++	       sta_id1 & AR5K_STA_ID1_ADHOC ? 1 : 0,
++	       sta_id1 & AR5K_STA_ID1_NO_KEYSRCH ? 1 : 0);
++}
++
+ int
+ CMD(athinfo)(int argc, char *argv[])
+ {
+-	u_int32_t dev_addr;
+-	u_int16_t eeprom_header, srev, phy_rev_5ghz, phy_rev_2ghz;
+-	u_int16_t eeprom_version, mac_version, regdomain, has_crystal, ee_magic;
+-	u_int8_t error, has_a, has_b, has_g, has_rfkill, eeprom_size;
+-	int byte_size = 0;
++	unsigned long long dev_addr;
++	u_int16_t srev, phy_rev_5ghz, phy_rev_2ghz, ee_magic;
++	u_int8_t mac_version, mac_revision;
++	u_int8_t error, eeprom_size, dev_type, eemap;
++	struct ath5k_eeprom_info *ee;
++	unsigned int byte_size = 0;
+ 	void *mem;
+ 	int fd;
+-	int i, anr = 1;
++	unsigned int i;
++	int anr = 1;
+ 	int do_write = 0;	/* default: read only */
+ 	int do_dump = 0;
++	int reg_read = 0;
++	int reg_write = 0;
++	unsigned int reg_write_val = 0;
++	unsigned int timer_count = 1;
++	int do_keycache_dump = 0;
++	int keycache_copy_idx = 0;
+ 
+ 	struct {
+ 		int valid;
+@@ -759,7 +1986,7 @@
+ 	} gpio_set[AR5K_NUM_GPIO];
+ 	int nr_gpio_set = 0;
+ 
+-	for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++)
++	for (i = 0; i < ARRAY_SIZE(gpio_set); i++)
+ 		gpio_set[i].valid = 0;
+ 
+ 	if (argc < 2) {
+@@ -769,6 +1996,15 @@
+ 
+ 	while (anr < argc && argv[anr][0] == '-') {
+ 		switch (argv[anr][1]) {
++		case 't':
++			if (++anr < argc) {
++				timer_count = atoi(argv[anr]);
++				printf("timer_count:%d\n", timer_count);
++			} else {
++				usage(argv[0]);
++				return 0;
++			}
++			break;
+ 		case 'w':
+ 			do_write = 1;
+ 			break;
+@@ -777,7 +2013,7 @@
+ 			if (strlen(argv[anr]) != 3 || argv[anr][1] != ':' ||
+ 			    argv[anr][0] < '0' || argv[anr][0] > '5' ||
+ 			    (argv[anr][2] != '0' && argv[anr][2] != '1')) {
+-				err("invalid gpio spec. %s", argv[anr]);
++				err("invalid GPIO spec. %s", argv[anr]);
+ 				return 2;
+ 			}
+ 			gpio_set[argv[anr][0] - '0'].valid = 1;
+@@ -797,6 +2033,25 @@
+ 			do_dump = 1;
+ 			break;
+ 
++		case 'R':
++			anr++;
++			reg_read = strtoul(argv[anr], NULL, 16);
++			break;
++
++		case 'W':
++			anr++;
++			reg_write = strtoul(argv[anr++], NULL, 16);
++			reg_write_val = strtoul(argv[anr], NULL, 16);
++			break;
++
++		case 'k':
++			do_keycache_dump = 1;
++			break;
++
++		case 'K':
++			keycache_copy_idx = atoi(argv[++anr]);
++			break;
++
+ 		case 'h':
+ 			usage(argv[0]);
+ 			return 0;
+@@ -805,10 +2060,10 @@
+ 		default:
+ 			err("unknown option %s", argv[anr]);
+ 			return 2;
+-		}		/* switch (argv[anr][1]) */
++		}
+ 
+ 		anr++;
+-	}			/* while (anr < argc && ...) */
++	}
+ 
+ 	if (anr >= argc) {
+ 		err("missing device address");
+@@ -816,7 +2071,7 @@
+ 		return 3;
+ 	}
+ 
+-	dev_addr = strtoul(argv[anr], NULL, 16);
++	dev_addr = strtoull(argv[anr], NULL, 16);
+ 
+ 	fd = open("/dev/mem", O_RDWR);
+ 	if (fd < 0) {
+@@ -828,7 +2083,7 @@
+ 		   MAP_SHARED | MAP_FILE, fd, dev_addr);
+ 
+ 	if (mem == MAP_FAILED) {
+-		printf("Mmap of device at 0x%08X for 0x%X bytes failed - "
++		printf("mmap of device at 0x%08llX for 0x%X bytes failed - "
+ 		       "%s\n", dev_addr, AR5K_PCI_MEM_SIZE, strerror(errno));
+ 		return -3;
+ 	}
+@@ -856,10 +2111,31 @@
+ 	AR5K_REG_DISABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_SPWR_DN);
+ 	usleep(500);
+ 
++	if (reg_read) {
++		printf("READ %04x = %08x\n", reg_read, AR5K_REG_READ(reg_read));
++		return 0;
++	}
++
++	if (reg_write) {
++		printf("WRITE %04x = %08x\n", reg_write, reg_write_val);
++		AR5K_REG_WRITE(reg_write, reg_write_val);
++		return 0;
++	}
++
+ 	srev = AR5K_REG_READ(AR5K_SREV);
+-	mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER) << 4;
++	if (srev >= 0x0100) {
++		printf("MAC revision 0x%04x is not supported!\n", srev);
++		return -1;
++	}
++	mac_version = srev & AR5K_SREV_VER;
++	mac_revision = srev & AR5K_SREV_REV;
+ 
+-	/* Verify eeprom magic value first */
++	printf(" -==Device Information==-\n");
++
++	printf("MAC Revision: %-5s (0x%02x)\n",
++	       ath5k_hw_get_mac_name(mac_revision), mac_revision);
++
++	/* Verify EEPROM magic value first */
+ 	error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MAGIC, &ee_magic,
+ 				     mac_version);
+ 
+@@ -872,157 +2148,114 @@
+ 		printf("Warning: Invalid EEPROM Magic number!\n");
+ 	}
+ 
+-	error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_HDR, &eeprom_header,
+-				     mac_version);
+-
+-	if (error) {
+-		printf("Unable to read EEPROM Header!\n");
+-		return -1;
+-	}
+-
+-	error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_VERSION, &eeprom_version,
+-				     mac_version);
+-
+-	if (error) {
+-		printf("Unable to read EEPROM version!\n");
++	ee = calloc(sizeof(struct ath5k_eeprom_info), 1);
++	if (!ee) {
++		printf("Cannot allocate memory for EEPROM information\n");
+ 		return -1;
+ 	}
+ 
+-	error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_REG_DOMAIN, &regdomain,
+-				     mac_version);
+-
+-	if (error) {
+-		printf("Unable to read Regdomain!\n");
++	if (ath5k_eeprom_init(mem, mac_version, ee)) {
++		printf("EEPROM init failed\n");
+ 		return -1;
+ 	}
+ 
+-	if (eeprom_version >= 0x4000) {
+-		error = ath5k_hw_eeprom_read(mem, AR5K_EEPROM_MISC0,
+-					     &has_crystal, mac_version);
+-
+-		if (error) {
+-			printf("Unable to read EEPROM Misc data!\n");
+-			return -1;
+-		}
+-
+-		has_crystal = AR5K_EEPROM_HAS32KHZCRYSTAL(has_crystal);
+-	} else {
+-		has_crystal = 2;
+-	}
+-
+ 	eeprom_size = AR5K_REG_MS(AR5K_REG_READ(AR5K_PCICFG),
+ 				  AR5K_PCICFG_EESIZE);
+ 
+-	has_a = AR5K_EEPROM_HDR_11A(eeprom_header);
+-	has_b = AR5K_EEPROM_HDR_11B(eeprom_header);
+-	has_g = AR5K_EEPROM_HDR_11G(eeprom_header);
+-	has_rfkill = AR5K_EEPROM_HDR_RFKILL(eeprom_header);
++	dev_type = AR5K_EEPROM_HDR_DEVICE(ee->ee_header);
++	eemap = AR5K_EEPROM_EEMAP(ee->ee_misc0);
+ 
+-	if (has_a)
++	/* 1 = ?? 2 = ?? 3 = card 4 = wmac */
++	printf("Device type:  %1i\n", dev_type);
++
++	if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+ 		phy_rev_5ghz = ath5k_hw_radio_revision(mac_version, mem, 1);
+ 	else
+ 		phy_rev_5ghz = 0;
+ 
+-	if (has_b)
++	if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+ 		phy_rev_2ghz = ath5k_hw_radio_revision(mac_version, mem, 0);
+ 	else
+ 		phy_rev_2ghz = 0;
+ 
+-	printf(" -==Device Information==-\n");
+-
+-	printf("MAC Version:  %-5s (0x%02x)\n",
+-	       ath5k_hw_get_part_name(AR5K_VERSION_VER, mac_version),
+-	       mac_version);
+-
+-	printf("MAC Revision: %-5s (0x%02x)\n",
+-	       ath5k_hw_get_part_name(AR5K_VERSION_VER, srev), srev);
+-
+-	/* Single-chip PHY with a/b/g support */
+-	if (has_b && !phy_rev_2ghz) {
+-		printf("PHY Revision: %-5s (0x%02x)\n",
+-		       ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_5ghz),
+-		       phy_rev_5ghz);
+-		phy_rev_5ghz = 0;
+-	}
+-
+-	/* Single-chip PHY with b/g support */
+-	if (!has_a) {
+-		printf("PHY Revision: %-5s (0x%02x)\n",
+-		       ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_2ghz),
+-		       phy_rev_2ghz);
+-		phy_rev_2ghz = 0;
+-	}
+-
+-	/* Different chip for 5Ghz and 2Ghz */
+ 	if (phy_rev_5ghz) {
+-		printf("5Ghz PHY Revision: %-5s (0x%2x)\n",
+-		       ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_5ghz),
+-		       phy_rev_5ghz);
++		printf("5GHz PHY Revision: %-5s (0x%02x)\n",
++		       ath5k_hw_get_phy_name(phy_rev_5ghz), phy_rev_5ghz);
+ 	}
+ 	if (phy_rev_2ghz) {
+-		printf("2Ghz PHY Revision: %-5s (0x%2x)\n",
+-		       ath5k_hw_get_part_name(AR5K_VERSION_RAD, phy_rev_2ghz),
+-		       phy_rev_2ghz);
++		printf("2GHz PHY Revision: %-5s (0x%02x)\n",
++		       ath5k_hw_get_phy_name(phy_rev_2ghz), phy_rev_2ghz);
+ 	}
+ 
+-	printf(" -==EEPROM Information==-\n");
+-
+-	printf("EEPROM Version:     %x.%x\n",
+-	       (eeprom_version & 0xF000) >> 12, eeprom_version & 0xFFF);
++	printf("\n");
++	printf("/============== EEPROM Information =============\\\n");
++	printf("| EEPROM Version:   %1x.%1x |",
++	       (ee->ee_version & 0xF000) >> 12, ee->ee_version & 0xFFF);
+ 
+-	printf("EEPROM Size: ");
++	printf(" EEPROM Size: ");
+ 
+ 	if (eeprom_size == 0) {
+-		printf("       4K\n");
+-		byte_size = 4096;
++		printf("  4 kbit |\n");
++		byte_size = 4096 / 8;
+ 	} else if (eeprom_size == 1) {
+-		printf("       8K\n");
+-		byte_size = 8192;
++		printf("  8 kbit |\n");
++		byte_size = 8192 / 8;
+ 	} else if (eeprom_size == 2) {
+-		printf("       16K\n");
+-		byte_size = 16384;
++		printf(" 16 kbit |\n");
++		byte_size = 16384 / 8;
+ 	} else
+-		printf("       ??\n");
++		printf(" unknown |\n");
+ 
+-	printf("Regulatory Domain:  0x%X\n", regdomain);
+-
+-	printf(" -==== Capabilities ====-\n");
+-
+-	printf("|  802.11a Support: ");
+-	if (has_a)
+-		printf("yes  |\n");
+-	else
+-		printf("no   |\n");
+-
+-	printf("|  802.11b Support: ");
+-	if (has_b)
+-		printf("yes  |\n");
+-	else
+-		printf("no   |\n");
++	printf("| EEMAP:              %i |", eemap);
+ 
+-	printf("|  802.11g Support: ");
+-	if (has_g)
+-		printf("yes  |\n");
+-	else
+-		printf("no   |\n");
++	printf(" Reg. Domain:     0x%02X |\n", ee->ee_regdomain);
+ 
+-	printf("|  RFKill  Support: ");
+-	if (has_rfkill)
+-		printf("yes  |\n");
+-	else
+-		printf("no   |\n");
++	dump_capabilities(ee);
++	printf("\n");
+ 
+-	if (has_crystal != 2) {
+-		printf("|  32KHz   Crystal: ");
+-		if (has_crystal)
+-			printf("yes  |\n");
+-		else
+-			printf("no   |\n");
++	printf("/=========================================================\\\n");
++	printf("|          Calibration data common for all modes          |\n");
++	printf("|=========================================================|\n");
++	printf("|          CCK/OFDM gain delta:            %2i             |\n", ee->ee_cck_ofdm_gain_delta);
++	printf("|          CCK/OFDM power delta:           %2i             |\n", ee->ee_cck_ofdm_power_delta);
++	printf("|          Scaled CCK delta:               %2i             |\n", ee->ee_scaled_cck_delta);
++	printf("|          2GHz Antenna gain:              %2i             |\n", AR5K_EEPROM_ANT_GAIN_2GHZ(ee->ee_ant_gain));
++	printf("|          5GHz Antenna gain:              %2i             |\n", AR5K_EEPROM_ANT_GAIN_5GHZ(ee->ee_ant_gain));
++	printf("|          Turbo 2W maximum dBm:           %2i             |\n", AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header));
++	printf("|          Target power start:          0x%03x             |\n", AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1));
++	printf("|          EAR Start:                   0x%03x             |\n", AR5K_EEPROM_EARSTART(ee->ee_misc0));
++	printf("\\=========================================================/\n");
++
++	printf("\n");
++	if (AR5K_EEPROM_HDR_11A(ee->ee_header)) {
++		printf("/=========================================================\\\n");
++		printf("|          Calibration data for 802.11a operation         |\n");
++		dump_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++		dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++		dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11A, ee);
++		printf("\n");
++	}
++
++	if (AR5K_EEPROM_HDR_11B(ee->ee_header)) {
++		printf("/=========================================================\\\n");
++		printf("|          Calibration data for 802.11b operation         |\n");
++		dump_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++		dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++		dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11B, ee);
++		printf("\n");
++	}
++
++	if (AR5K_EEPROM_HDR_11G(ee->ee_header)) {
++		printf("/=========================================================\\\n");
++		printf("|          Calibration data for 802.11g operation         |\n");
++		dump_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++		dump_rate_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++		dump_power_calinfo_for_mode(AR5K_EEPROM_MODE_11G, ee);
++		printf("\n");
+ 	}
+-	printf(" ========================\n");
+ 
+ 	/* print current GPIO settings */
+-	printf("GPIO registers: CR %08x DO %08x DI %08x\n",
++	printf("GPIO registers: CR 0x%08x, DO 0x%08x, DI 0x%08x\n",
+ 	       AR5K_REG_READ(AR5K_GPIOCR), AR5K_REG_READ(AR5K_GPIODO),
+ 	       AR5K_REG_READ(AR5K_GPIODI));
+ 
+@@ -1030,18 +2263,18 @@
+ 		u_int16_t data;
+ 		FILE *dumpfile = fopen("ath-eeprom-dump.bin", "w");
+ 
+-		printf("\nEEPROM dump (%d byte)\n", byte_size);
++		printf("\nEEPROM dump (%d bytes)\n", byte_size);
+ 		printf("==============================================");
+-		for (i = 1; i <= (byte_size / 2); i++) {
++		for (i = 0; i < byte_size / 2; i++) {
+ 			error =
+ 			    ath5k_hw_eeprom_read(mem, i, &data, mac_version);
+ 			if (error) {
+ 				printf("\nUnable to read at %04x\n", i);
+ 				continue;
+ 			}
+-			if (!((i - 1) % 8))
+-				printf("\n%04x:  ", i);
+-			printf("%04x ", data);
++			if (!(i % 8))
++				printf("\n%04x: ", i);
++			printf(" %04x", data);
+ 			fwrite(&data, 2, 1, dumpfile);
+ 		}
+ 		printf("\n==============================================\n");
+@@ -1054,18 +2287,18 @@
+ 		u_int32_t old_cr = rcr, old_do = rdo;
+ 		int rc;
+ 
+-		if (mac_version >= AR5K_SREV_VER_AR5213 && !nr_gpio_set) {
+-			dbg("new MAC %x (>= AR5213) set gpio4 to low",
++		if (mac_version >= AR5K_SREV_MAC_AR5213 && !nr_gpio_set) {
++			dbg("new MAC %x (>= AR5213) set GPIO4 to low",
+ 			    mac_version);
+ 			gpio_set[4].valid = 1;
+ 			gpio_set[4].value = 0;
+ 		}
+ 
+-		/* set gpios */
++		/* set GPIOs */
+ 		dbg("old GPIO CR %08x DO %08x DI %08x",
+ 		    rcr, rdo, AR5K_REG_READ(AR5K_GPIODI));
+ 
+-		for (i = 0; i < sizeof(gpio_set) / sizeof(gpio_set[0]); i++) {
++		for (i = 0; i < ARRAY_SIZE(gpio_set); i++) {
+ 			if (gpio_set[i].valid) {
+ 				rcr |= AR5K_GPIOCR_OUT(i);	/* we use mode 3 */
+ 				rcr &= ~AR5K_GPIOCR_INT_SEL(i);
+@@ -1111,5 +2344,17 @@
+ 
+ 		return rc;
+ 	}
++
++	sta_id0_id1_dump(mem);
++
++	for (i = 0; i < timer_count; i++)
++		dump_timers_register(mem, mac_version);
++
++	if (do_keycache_dump)
++		keycache_dump(mem, mac_version);
++
++	if (keycache_copy_idx > 0)
++		keycache_copy(mem, mac_version, keycache_copy_idx);
++
+ 	return 0;
+ }
-- 
cgit v1.2.3