[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree

zrouter-src-freebsd at zrouter.org zrouter-src-freebsd at zrouter.org
Mon Mar 12 23:21:48 UTC 2012


details:   http://zrouter.org/hg/FreeBSD/head//rev/ac5b1ebb1990
changeset: 426:ac5b1ebb1990
user:      ray at terran.dlink.ua
date:      Tue Mar 13 01:18:04 2012 +0200
description:
Insert rt2860 driver under ral(4).

diffstat:

 head/sys/dev/ral/if_ral_pci.c  |    30 +-
 head/sys/dev/ral/rt2860.c      |  9511 ++++++++++++++++++++++++++++++++++++++++
 head/sys/dev/ral/rt2860reg.h   |   560 ++
 head/sys/dev/ral/rt2860ucode.h |  2104 ++++++++
 head/sys/dev/ral/rt2860var.h   |   762 +++
 5 files changed, 12964 insertions(+), 3 deletions(-)

diffs (13032 lines):

diff -r 5624b06c8184 -r ac5b1ebb1990 head/sys/dev/ral/if_ral_pci.c
--- a/head/sys/dev/ral/if_ral_pci.c	Sat Mar 10 21:54:25 2012 +0200
+++ b/head/sys/dev/ral/if_ral_pci.c	Tue Mar 13 01:18:04 2012 +0200
@@ -21,7 +21,7 @@
 __FBSDID("$FreeBSD$");
 
 /*
- * PCI/Cardbus front-end for the Ralink RT2560/RT2561/RT2561S/RT2661 driver.
+ * PCI/Cardbus front-end for the Ralink RT2xxx wireless driver.
  */
 
 #include <sys/param.h>
@@ -57,6 +57,7 @@
 
 #include <dev/ral/rt2560var.h>
 #include <dev/ral/rt2661var.h>
+#include <dev/ral/rt2860var.h>
 
 MODULE_DEPEND(ral, pci, 1, 1, 1);
 MODULE_DEPEND(ral, firmware, 1, 1, 1);
@@ -78,6 +79,7 @@
 	{ 0x1814, 0x0681, "Ralink Technology RT2860 PCIe" },
 	{ 0x1814, 0x0701, "Ralink Technology RT2870 PCI" },
 	{ 0x1814, 0x0781, "Ralink Technology RT2870 PCIe" },
+	{ 0x1814, 0x3090, "Ralink Technology RT3090 PCIe" },
 
 	{ 0, 0, NULL }
 };
@@ -105,19 +107,20 @@
 	rt2661_suspend,
 	rt2661_resume,
 	rt2661_intr
-}/*, ral_rt2860_opns = {
+}, ral_rt2860_opns = {
 	rt2860_attach,
 	rt2860_detach,
 	rt2860_shutdown,
 	rt2860_suspend,
 	rt2860_resume,
 	rt2860_intr
-}*/;
+};
 
 struct ral_pci_softc {
 	union {
 		struct rt2560_softc sc_rt2560;
 		struct rt2661_softc sc_rt2661;
+		struct rt2860_softc sc_rt2860;
 	} u;
 
 	struct ral_opns		*sc_opns;
@@ -193,6 +196,27 @@
 
 	psc->sc_opns = (pci_get_device(dev) == 0x0201) ? &ral_rt2560_opns :
 	    &ral_rt2661_opns;
+	switch (pci_get_device(dev)) {
+	case 0x0201:
+		psc->sc_opns = &ral_rt2560_opns;
+		break;
+	case 0x0301:
+	case 0x0302:
+	case 0x0401:
+		psc->sc_opns = &ral_rt2661_opns;
+		break;
+	case 0x0601:
+	case 0x0681:
+	case 0x0701:
+	case 0x0781:
+	case 0x3090:
+		psc->sc_opns = &ral_rt2860_opns;
+		break;
+	default:
+		device_printf(dev, "ERROR: Unknown card 0x%04x\n",
+		    pci_get_device(dev));
+		return (ENXIO);
+	}
 
 	psc->mem_rid = RAL_PCI_BAR0;
 	psc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &psc->mem_rid,
diff -r 5624b06c8184 -r ac5b1ebb1990 head/sys/dev/ral/rt2860.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ral/rt2860.c	Tue Mar 13 01:18:04 2012 +0200
@@ -0,0 +1,9511 @@
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar at gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini at free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <dev/ral/rt2860var.h>
+#include <dev/ral/rt2860reg.h>
+#include <dev/ral/rt2860ucode.h>
+
+/*
+ * Defines and macros
+ */
+#define RT2860_MAX_AGG_SIZE						3840
+
+#define RT2860_TX_DATA_SEG0_SIZE				\
+	(sizeof(struct rt2860_txwi) + sizeof(struct ieee80211_qosframe_addr4))
+
+#define RT2860_NOISE_FLOOR						-95
+
+#define IEEE80211_HAS_ADDR4(wh)					\
+	(((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
+
+#define	RT2860_MS(_v, _f)			(((_v) & _f) >> _f##_S)
+#define	RT2860_SM(_v, _f)			(((_v) << _f##_S) & _f)
+
+#define RT2860_TX_WATCHDOG_TIMEOUT				5
+
+#define RUN_AID2WCID(aid)					((aid) & 0xff)
+#define RT2860_WCID_RESERVED					0xff
+#define RT2860_WCID_MCAST						0xf7
+
+#define LED_CFG_LED_POLARITY	(1<<30)
+#define LED_CFG_Y_LED_MODE_ONTX	(1<<28)
+#define LED_CFG_G_LED_MODE_ONTX	(1<<26)
+#define LED_CFG_R_LED_MODE_ONTX	(1<<24)
+#define LED_CFG_SLOW_BLK_TIME 	(0x03<<16) /* sec */
+#define LED_CFG_LED_OFF_TIME 	(0x1e<<8) /* msec */
+#define LED_CFG_LED_ON_TIME 	(0x46) /* msec */
+
+static void rt2872_rf_set_chan(struct rt2860_softc *sc,
+			       struct ieee80211_channel *c);
+
+/*
+ * Static variables
+ */
+
+static const struct rt2860_rf_prog
+{
+	uint8_t chan;
+	uint32_t r1, r2, r3, r4;
+} rt2860_rf_2850[] =
+{
+	{   1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b },
+	{   2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f },
+	{   3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b },
+	{   4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f },
+	{   5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b },
+	{   6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f },
+	{   7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b },
+	{   8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f },
+	{   9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b },
+	{  10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f },
+	{  11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b },
+	{  12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f },
+	{  13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b },
+	{  14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193 },
+	{  36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3 },
+	{  38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193 },
+	{  40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183 },
+	{  44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3 },
+	{  46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b },
+	{  48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b },
+	{  52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193 },
+	{  54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3 },
+	{  56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b },
+	{  60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183 },
+	{  62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193 },
+	{  64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3 },
+	{ 100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783 },
+	{ 102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793 },
+	{ 104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3 },
+	{ 108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193 },
+	{ 110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183 },
+	{ 112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b },
+	{ 116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3 },
+	{ 118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193 },
+	{ 120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183 },
+	{ 124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193 },
+	{ 126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b },
+	{ 128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3 },
+	{ 132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b },
+	{ 134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193 },
+	{ 136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b },
+	{ 140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183 },
+	{ 149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7 },
+	{ 151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187 },
+	{ 153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f },
+	{ 157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f },
+	{ 159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7 },
+	{ 161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187 },
+	{ 165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197 },
+	{ 184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b },
+	{ 188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13 },
+	{ 192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b },
+	{ 196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23 },
+	{ 208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13 },
+	{ 212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b },
+	{ 216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23 },
+};
+
+static const struct rfprog {
+	uint8_t		chan;
+	uint32_t	r1, r2, r3, r4;
+} rt2860_rf2850[] = {
+	{   1, 0x100bb3, 0x1301e1, 0x05a014, 0x001402 },
+	{   2, 0x100bb3, 0x1301e1, 0x05a014, 0x001407 },
+	{   3, 0x100bb3, 0x1301e2, 0x05a014, 0x001402 },
+	{   4, 0x100bb3, 0x1301e2, 0x05a014, 0x001407 },
+	{   5, 0x100bb3, 0x1301e3, 0x05a014, 0x001402 },
+	{   6, 0x100bb3, 0x1301e3, 0x05a014, 0x001407 },
+	{   7, 0x100bb3, 0x1301e4, 0x05a014, 0x001402 },
+	{   8, 0x100bb3, 0x1301e4, 0x05a014, 0x001407 },
+	{   9, 0x100bb3, 0x1301e5, 0x05a014, 0x001402 },
+	{  10, 0x100bb3, 0x1301e5, 0x05a014, 0x001407 },
+	{  11, 0x100bb3, 0x1301e6, 0x05a014, 0x001402 },
+	{  12, 0x100bb3, 0x1301e6, 0x05a014, 0x001407 },
+	{  13, 0x100bb3, 0x1301e7, 0x05a014, 0x001402 },
+	{  14, 0x100bb3, 0x1301e8, 0x05a014, 0x001404 },
+	{  36, 0x100bb3, 0x130266, 0x056014, 0x001408 },
+	{  38, 0x100bb3, 0x130267, 0x056014, 0x001404 },
+	{  40, 0x100bb2, 0x1301a0, 0x056014, 0x001400 },
+	{  44, 0x100bb2, 0x1301a0, 0x056014, 0x001408 },
+	{  46, 0x100bb2, 0x1301a1, 0x056014, 0x001402 },
+	{  48, 0x100bb2, 0x1301a1, 0x056014, 0x001406 },
+	{  52, 0x100bb2, 0x1301a2, 0x056014, 0x001404 },
+	{  54, 0x100bb2, 0x1301a2, 0x056014, 0x001408 },
+	{  56, 0x100bb2, 0x1301a3, 0x056014, 0x001402 },
+	{  60, 0x100bb2, 0x1301a4, 0x056014, 0x001400 },
+	{  62, 0x100bb2, 0x1301a4, 0x056014, 0x001404 },
+	{  64, 0x100bb2, 0x1301a4, 0x056014, 0x001408 },
+	{ 100, 0x100bb2, 0x1301ac, 0x05e014, 0x001400 },
+	{ 102, 0x100bb2, 0x1701ac, 0x15e014, 0x001404 },
+	{ 104, 0x100bb2, 0x1701ac, 0x15e014, 0x001408 },
+	{ 108, 0x100bb3, 0x17028c, 0x15e014, 0x001404 },
+	{ 110, 0x100bb3, 0x13028d, 0x05e014, 0x001400 },
+	{ 112, 0x100bb3, 0x13028d, 0x05e014, 0x001406 },
+	{ 116, 0x100bb3, 0x13028e, 0x05e014, 0x001408 },
+	{ 118, 0x100bb3, 0x13028f, 0x05e014, 0x001404 },
+	{ 120, 0x100bb1, 0x1300e0, 0x05e014, 0x001400 },
+	{ 124, 0x100bb1, 0x1300e0, 0x05e014, 0x001404 },
+	{ 126, 0x100bb1, 0x1300e0, 0x05e014, 0x001406 },
+	{ 128, 0x100bb1, 0x1300e0, 0x05e014, 0x001408 },
+	{ 132, 0x100bb1, 0x1300e1, 0x05e014, 0x001402 },
+	{ 134, 0x100bb1, 0x1300e1, 0x05e014, 0x001404 },
+	{ 136, 0x100bb1, 0x1300e1, 0x05e014, 0x001406 },
+	{ 140, 0x100bb1, 0x1300e2, 0x05e014, 0x001400 },
+	{ 149, 0x100bb1, 0x1300e2, 0x05e014, 0x001409 },
+	{ 151, 0x100bb1, 0x1300e3, 0x05e014, 0x001401 },
+	{ 153, 0x100bb1, 0x1300e3, 0x05e014, 0x001403 },
+	{ 157, 0x100bb1, 0x1300e3, 0x05e014, 0x001407 },
+	{ 159, 0x100bb1, 0x1300e3, 0x05e014, 0x001409 },
+	{ 161, 0x100bb1, 0x1300e4, 0x05e014, 0x001401 },
+	{ 165, 0x100bb1, 0x1300e4, 0x05e014, 0x001405 },
+	{ 167, 0x100bb1, 0x1300f4, 0x05e014, 0x001407 },
+	{ 169, 0x100bb1, 0x1300f4, 0x05e014, 0x001409 },
+	{ 171, 0x100bb1, 0x1300f5, 0x05e014, 0x001401 },
+	{ 173, 0x100bb1, 0x1300f5, 0x05e014, 0x001403 }
+};
+
+static const struct rt2860_rf_fi3020
+{
+	uint8_t channel, n, r, k;
+} rt2860_rf_fi3020[] =
+{
+	/* 802.11g  */
+	{1,	241,	2,	2},
+	{2,	241,	2,	7},
+	{3,	242,	2,	2},
+	{4,	242,	2,	7},
+	{5,	243,	2,	2},
+	{6,	243,	2,	7},
+	{7,	244,	2,	2},
+	{8,	244,	2,	7},
+	{9,	245,	2,	2},
+	{10,	245,	2,	7},
+	{11,	246,	2,	2},
+	{12,	246,	2,	7},
+	{13,	247,	2,	2},
+	{14,	248,	2,	4},
+
+	/* 802.11 UNI / HyperLan 2 */
+	{36,	0x56,	0,	4},
+	{38,	0x56,	0,	6},
+	{40,	0x56,	0,	8},
+	{44,	0x57,	0,	0},
+	{46,	0x57,	0,	2},
+	{48,	0x57,	0,	4},
+	{52,	0x57,	0,	8},
+	{54,	0x57,	0,	10},
+	{56,	0x58,	0,	0},
+	{60,	0x58,	0,	4},
+	{62,	0x58,	0,	6},
+	{64,	0x58,	0,	8},
+
+	/* 802.11 HyperLan 2 */
+	{100,	0x5b,	0,	8},
+	{102,	0x5b,	0,	10},
+	{104,	0x5c,	0,	0},
+	{108,	0x5c,	0,	4},
+	{110,	0x5c,	0,	6},
+	{112,	0x5c,	0,	8},
+	{116,	0x5d,	0,	0},
+	{118,	0x5d,	0,	2},
+	{120,	0x5d,	0,	4},
+	{124,	0x5d,	0,	8},
+	{126,	0x5d,	0,	10},
+	{128,	0x5e,	0,	0},
+	{132,	0x5e,	0,	4},
+	{134,	0x5e,	0,	6},
+	{136,	0x5e,	0,	8},
+	{140,	0x5f,	0,	0},
+
+	/* 802.11 UNII */
+	{149,	0x5f,	0,	9},
+	{151,	0x5f,	0,	11},
+	{153,	0x60,	0,	1},
+	{157,	0x60,	0,	5},
+	{159,	0x60,	0,	7},
+	{161,	0x60,	0,	9},
+	{165,	0x61,	0,	1},
+	{167,	0x61,	0,	3},
+	{169,	0x61,	0,	5},
+	{171,	0x61,	0,	7},
+	{173,	0x61,	0,	9},
+};
+
+static const struct {
+	uint8_t	reg;
+	uint8_t	val;
+}  rt3090_def_rf[] = {
+	{  4, 0x40 },
+	{  5, 0x03 },
+	{  6, 0x02 },
+	{  7, 0x70 },
+	{  9, 0x0f },
+	{ 10, 0x41 },
+	{ 11, 0x21 },
+	{ 12, 0x7b },
+	{ 14, 0x90 },
+	{ 15, 0x58 },
+	{ 16, 0xb3 },
+	{ 17, 0x92 },
+	{ 18, 0x2c },
+	{ 19, 0x02 },
+	{ 20, 0xba },
+	{ 21, 0xdb },
+	{ 24, 0x16 },
+	{ 25, 0x01 },
+	{ 29, 0x1f }
+};
+
+struct {
+	uint8_t	n, r, k;
+} rt3090_freqs[] = {
+	{ 0xf1, 2,  2 },
+	{ 0xf1, 2,  7 },
+	{ 0xf2, 2,  2 },
+	{ 0xf2, 2,  7 },
+	{ 0xf3, 2,  2 },
+	{ 0xf3, 2,  7 },
+	{ 0xf4, 2,  2 },
+	{ 0xf4, 2,  7 },
+	{ 0xf5, 2,  2 },
+	{ 0xf5, 2,  7 },
+	{ 0xf6, 2,  2 },
+	{ 0xf6, 2,  7 },
+	{ 0xf7, 2,  2 },
+	{ 0xf8, 2,  4 },
+	{ 0x56, 0,  4 },
+	{ 0x56, 0,  6 },
+	{ 0x56, 0,  8 },
+	{ 0x57, 0,  0 },
+	{ 0x57, 0,  2 },
+	{ 0x57, 0,  4 },
+	{ 0x57, 0,  8 },
+	{ 0x57, 0, 10 },
+	{ 0x58, 0,  0 },
+	{ 0x58, 0,  4 },
+	{ 0x58, 0,  6 },
+	{ 0x58, 0,  8 },
+	{ 0x5b, 0,  8 },
+	{ 0x5b, 0, 10 },
+	{ 0x5c, 0,  0 },
+	{ 0x5c, 0,  4 },
+	{ 0x5c, 0,  6 },
+	{ 0x5c, 0,  8 },
+	{ 0x5d, 0,  0 },
+	{ 0x5d, 0,  2 },
+	{ 0x5d, 0,  4 },
+	{ 0x5d, 0,  8 },
+	{ 0x5d, 0, 10 },
+	{ 0x5e, 0,  0 },
+	{ 0x5e, 0,  4 },
+	{ 0x5e, 0,  6 },
+	{ 0x5e, 0,  8 },
+	{ 0x5f, 0,  0 },
+	{ 0x5f, 0,  9 },
+	{ 0x5f, 0, 11 },
+	{ 0x60, 0,  1 },
+	{ 0x60, 0,  5 },
+	{ 0x60, 0,  7 },
+	{ 0x60, 0,  9 },
+	{ 0x61, 0,  1 },
+	{ 0x61, 0,  3 },
+	{ 0x61, 0,  5 },
+	{ 0x61, 0,  7 },
+	{ 0x61, 0,  9 }
+};
+
+static const struct {
+	uint32_t reg;
+	uint32_t val;
+} rt2860_def_mac[] = {
+	{ RT2860_REG_PBF_BCN_OFFSET0, 		0xf8f0e8e0 },
+	{ RT2860_REG_PBF_BCN_OFFSET1, 		0x6f77d0c8 },
+	{ RT2860_REG_LEGACY_BASIC_RATE, 	0x0000013f },
+	{ RT2860_REG_HT_BASIC_RATE, 		0x00008003 },
+	{ RT2860_REG_SYS_CTRL, 			0x00000000 },
+	{ RT2860_REG_RX_FILTER_CFG, 		0x00017f97 },
+	{ RT2860_REG_BKOFF_SLOT_CFG, 		0x00000209 },
+	{ RT2860_REG_TX_SW_CFG0, 		0x00000000 },
+	{ RT2860_REG_TX_SW_CFG1, 		0x00080606 },
+	{ RT2860_REG_TX_LINK_CFG, 		0x00001020 },
+	{ RT2860_REG_TX_TIMEOUT_CFG, 		0x000a2090 },
+	{ RT2860_REG_MAX_LEN_CFG, 	(1 << 12) | RT2860_MAX_AGG_SIZE },
+	{ RT2860_REG_LED_CFG, 			0x7f031e46 },
+	{ RT2860_REG_PBF_MAX_PCNT, 		0x1f3fbf9f },
+	{ RT2860_REG_TX_RTY_CFG, 		0x47d01f0f },
+	{ RT2860_REG_AUTO_RSP_CFG, 		0x00000013 },
+	{ RT2860_REG_TX_CCK_PROT_CFG, 		0x05740003 },
+	{ RT2860_REG_TX_OFDM_PROT_CFG, 		0x05740003 },
+	{ RT2860_REG_TX_GF20_PROT_CFG, 		0x01744004 },
+	{ RT2860_REG_TX_GF40_PROT_CFG, 		0x03f44084 },
+	{ RT2860_REG_TX_MM20_PROT_CFG, 		0x01744004 },
+	{ RT2860_REG_TX_MM40_PROT_CFG,		0x03f54084 },
+	{ RT2860_REG_TX_TXOP_CTRL_CFG, 		0x0000583f },
+	{ RT2860_REG_TX_RTS_CFG, 		0x00092b20 },
+	{ RT2860_REG_TX_EXP_ACK_TIME, 		0x002400ca },
+	{ RT2860_REG_HCCAPSMP_TXOP_HLDR_ET, 	0x00000002 },
+	{ RT2860_REG_XIFS_TIME_CFG, 		0x33a41010 },
+	{ RT2860_REG_PWR_PIN_CFG, 		0x00000003 },
+	{ RT2860_REG_SCHDMA_WMM_AIFSN_CFG,	0x00002273 },
+	{ RT2860_REG_SCHDMA_WMM_CWMIN_CFG,	0x00002344 },
+	{ RT2860_REG_SCHDMA_WMM_CWMAX_CFG,	0x000034aa },
+};
+
+#define	RT2860_DEF_MAC_SIZE				\
+    (sizeof(rt2860_def_mac) / sizeof(rt2860_def_mac[0]))
+
+static const struct {
+	uint8_t	reg;
+	uint8_t	val;
+} rt2860_def_bbp[] = {
+	{ 65,	0x2c },
+	{ 66,	0x38 },
+	{ 69,	0x12 },
+	{ 70,	0x0a },
+	{ 73,	0x10 },
+	{ 81,	0x37 },
+	{ 82,	0x62 },
+	{ 83,	0x6a },
+	{ 84,	0x99 },
+	{ 86,	0x00 },
+	{ 91,	0x04 },
+	{ 92,	0x00 },
+	{ 103,	0x00 },
+	{ 105,	0x05 },
+	{ 106,	0x35 },
+};
+
+#define RT2860_DEF_BBP_SIZE			\
+    (sizeof(rt2860_def_bbp) / sizeof(rt2860_def_bbp[0]))
+
+/*
+ * Static function prototypes
+ */
+static void rt2860_init_channels(struct rt2860_softc *sc);
+static void rt2860_init_channels_ht40(struct rt2860_softc *sc);
+static void rt2860_init_locked(void *priv);
+static void rt2860_init(void *priv);
+static int rt2860_init_bbp(struct rt2860_softc *sc);
+static void rt2860_stop_locked(void *priv);
+static void rt2860_stop(void *priv);
+static void rt2860_start(struct ifnet *ifp);
+static int rt2860_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
+static struct ieee80211vap *rt2860_vap_create(struct ieee80211com *ic,
+	const char name[IFNAMSIZ], int unit, enum ieee80211_opmode, int flags,
+	const uint8_t bssid[IEEE80211_ADDR_LEN],
+	const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void rt2860_vap_delete(struct ieee80211vap *vap);
+static int rt2860_vap_reset(struct ieee80211vap *vap, u_long cmd);
+static int rt2860_vap_newstate(struct ieee80211vap *vap,
+	enum ieee80211_state nstate, int arg);
+
+#ifndef RT2860_NO_HW_CRYPTO
+static void rt2860_vap_key_update_begin(struct ieee80211vap *vap);
+static void rt2860_vap_key_update_end(struct ieee80211vap *vap);
+static int rt2860_vap_key_set(struct ieee80211vap *vap,
+	const struct ieee80211_key *k, const uint8_t mac[IEEE80211_ADDR_LEN]);
+static int rt2860_vap_key_delete(struct ieee80211vap *vap,
+	const struct ieee80211_key *k);
+#endif
+
+static void rt2860_vap_update_beacon(struct ieee80211vap *vap, int what);
+static int rt2860_media_change(struct ifnet *ifp);
+static struct ieee80211_node *rt2860_node_alloc(struct ieee80211vap *vap,
+	const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void rt2860_node_cleanup(struct ieee80211_node *ni);
+static void rt2860_node_getmimoinfo(const struct ieee80211_node *ni,
+	struct ieee80211_mimo_info *mi);
+static int rt2860_setregdomain(struct ieee80211com *ic,
+	struct ieee80211_regdomain *reg,
+	int nchans, struct ieee80211_channel chans[]);
+static void rt2860_getradiocaps(struct ieee80211com *ic,
+	int maxchans, int *nchans, struct ieee80211_channel chans[]);
+static void rt2860_scan_start(struct ieee80211com *ic);
+static void rt2860_scan_end(struct ieee80211com *ic);
+static void rt2860_set_channel(struct ieee80211com *ic);
+static void rt2860_newassoc(struct ieee80211_node *ni, int isnew);
+static void rt2860_updateslot(struct ifnet *ifp);
+static void rt2860_update_promisc(struct ifnet *ifp);
+static void rt2860_update_mcast(struct ifnet *ifp);
+static int rt2860_wme_update(struct ieee80211com *ic);
+static int rt2860_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+	const struct ieee80211_bpf_params *params);
+static int rt2860_recv_action(struct ieee80211_node *ni,
+	const struct ieee80211_frame *wh,
+	const uint8_t *frm, const uint8_t *efrm);
+static int rt2860_send_action(struct ieee80211_node *ni,
+	int cat, int act, void *sa);
+static int rt2860_addba_response(struct ieee80211_node *ni,
+	struct ieee80211_tx_ampdu *tap,
+	int status, int baparamset, int batimeout);
+static void rt2860_addba_stop(struct ieee80211_node *ni,
+	struct ieee80211_tx_ampdu *tap);
+static int rt2860_ampdu_rx_start(struct ieee80211_node *ni,
+	struct ieee80211_rx_ampdu *rap,
+	int baparamset, int batimeout, int baseqctl);
+static void rt2860_ampdu_rx_stop(struct ieee80211_node *ni,
+	struct ieee80211_rx_ampdu *rap);
+static int rt2860_send_bar(struct ieee80211_node *ni,
+	struct ieee80211_tx_ampdu *tap, ieee80211_seq seqno);
+static void rt2860_amrr_update_iter_func(void *arg, struct ieee80211_node *ni);
+static void rt2860_periodic(void *arg);
+static void rt2860_tx_watchdog(void *arg);
+static int rt2860_staid_alloc(struct rt2860_softc *sc, int aid);
+static void rt2860_staid_delete(struct rt2860_softc *sc, int staid);
+void rt2860_amrr_init(struct rt2860_amrr *amrr, struct ieee80211vap *vap,
+		      int ntxpath, int min_success_threshold,
+		      int max_success_threshold, int msecs);
+void rt2860_amrr_cleanup(struct rt2860_amrr *amrr);
+void rt2860_amrr_node_init(struct rt2860_amrr *amrr,
+    struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni);
+int rt2860_amrr_choose(struct ieee80211_node *ni,
+	struct rt2860_amrr_node *amrr_node);
+
+static __inline void
+rt2860_amrr_tx_complete(struct rt2860_amrr_node *amrr_node, int ok, int retries)
+{
+
+	amrr_node->txcnt++;
+
+	if (ok)
+		amrr_node->success++;
+
+	amrr_node->retrycnt += retries;
+}
+
+static __inline void
+rt2860_amrr_tx_update(struct rt2860_amrr_node *amrr_node, int txcnt,
+		      int success, int retrycnt)
+{
+
+	amrr_node->txcnt = txcnt;
+	amrr_node->success = success;
+	amrr_node->retrycnt = retrycnt;
+}
+
+static void rt2860_asic_set_bssid(struct rt2860_softc *sc,
+				  const uint8_t *bssid);
+static void rt2860_asic_set_macaddr(struct rt2860_softc *sc,
+				    const uint8_t *addr);
+static void rt2860_asic_enable_tsf_sync(struct rt2860_softc *sc);
+static void rt2860_asic_disable_tsf_sync(struct rt2860_softc *sc);
+static void rt2860_asic_enable_mrr(struct rt2860_softc *sc);
+static void rt2860_asic_set_txpreamble(struct rt2860_softc *sc);
+static void rt2860_asic_set_basicrates(struct rt2860_softc *sc);
+static void rt2860_asic_update_rtsthreshold(struct rt2860_softc *sc);
+static void rt2860_asic_update_txpower(struct rt2860_softc *sc);
+static void rt2860_asic_update_promisc(struct rt2860_softc *sc);
+static void rt2860_asic_updateprot(struct rt2860_softc *sc);
+static void rt2860_asic_updateslot(struct rt2860_softc *sc);
+static void rt2860_asic_wme_update(struct rt2860_softc *sc);
+static void rt2860_asic_update_beacon(struct rt2860_softc *sc,
+				      struct ieee80211vap *vap);
+static void rt2860_asic_clear_keytables(struct rt2860_softc *sc);
+static void rt2860_asic_add_ba_session(struct rt2860_softc *sc,
+				       uint8_t wcid, int tid);
+static void rt2860_asic_del_ba_session(struct rt2860_softc *sc,
+				       uint8_t wcid, int tid);
+void rt2860_led_brightness(struct rt2860_softc *sc, uint8_t brightness);
+void rt2860_led_cmd(struct rt2860_softc *sc, uint8_t cmd);
+const char *rt2860_rf_name(int rf_rev);
+void rt2860_rf_select_chan_group(struct rt2860_softc *sc,
+	struct ieee80211_channel *c);
+void rt2860_rf_set_chan(struct rt2860_softc *sc,
+	struct ieee80211_channel *c);
+uint8_t rt3090_rf_read(struct rt2860_softc *sc, uint8_t reg);
+void rt3090_rf_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val);
+void rt3090_set_chan(struct rt2860_softc *sc, u_int chan);
+int rt3090_rf_init(struct rt2860_softc *sc);
+void rt3090_set_rx_antenna(struct rt2860_softc *, int);
+void rt3090_rf_wakeup(struct rt2860_softc *sc);
+int rt3090_filter_calib(struct rt2860_softc *sc, uint8_t init, uint8_t target,
+			uint8_t *val);
+void rt3090_rf_setup(struct rt2860_softc *sc);
+void rt2860_read_eeprom(struct rt2860_softc *sc);
+uint32_t rt2860_read_eeprom_txpow_rate_add_delta(uint32_t txpow_rate,
+						 int8_t delta);
+void rt2860_io_rf_load_defaults(struct rt2860_softc *sc);
+uint32_t rt2860_io_mac_read(struct rt2860_softc *sc, uint16_t reg);
+void rt2860_io_mac_read_multi(struct rt2860_softc *sc,
+			      uint16_t reg, void *buf, size_t len);
+void rt2860_io_mac_write(struct rt2860_softc *sc,
+			 uint16_t reg, uint32_t val);
+void rt2860_io_mac_write_multi(struct rt2860_softc *sc,
+			       uint16_t reg, const void *buf, size_t len);
+void rt2860_io_mac_set_region_4(struct rt2860_softc *sc,
+				uint16_t reg, uint32_t val, size_t len);
+uint16_t rt2860_io_eeprom_read(struct rt2860_softc *sc, uint16_t addr);
+void rt2860_io_eeprom_read_multi(struct rt2860_softc *sc,
+				 uint16_t addr, void *buf, size_t len);
+uint8_t rt2860_io_bbp_read(struct rt2860_softc *sc, uint8_t reg);
+void rt2860_io_bbp_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val);
+void rt2860_io_rf_write(struct rt2860_softc *sc, uint8_t reg, uint32_t val);
+int32_t rt2860_io_rf_read(struct rt2860_softc *sc, uint8_t reg);
+void rt2860_io_mcu_cmd(struct rt2860_softc *sc, uint8_t cmd,
+		       uint8_t token, uint16_t arg);
+int rt2860_io_mcu_cmd_check(struct rt2860_softc *sc, uint8_t cid);
+int rt2860_io_mcu_load_ucode(struct rt2860_softc *sc,
+			     const uint8_t *ucode, size_t len);
+static int rt2860_beacon_alloc(struct rt2860_softc *sc,
+			       struct ieee80211vap *vap);
+static uint8_t rt2860_rxrate(struct rt2860_rxwi *rxwi);
+static uint8_t rt2860_maxrssi_rxpath(struct rt2860_softc *sc,
+				     const struct rt2860_rxwi *rxwi);
+static int8_t rt2860_rssi2dbm(struct rt2860_softc *sc,
+			      uint8_t rssi, uint8_t rxpath);
+static uint8_t rt2860_rate2mcs(uint8_t rate);
+static int rt2860_tx_mgmt(struct rt2860_softc *sc,
+			  struct mbuf *m, struct ieee80211_node *ni, int qid);
+static int rt2860_tx_data(struct rt2860_softc *sc,
+			  struct mbuf *m, struct ieee80211_node *ni, int qid);
+
+static void rt2860_tx_coherent_intr(struct rt2860_softc *sc);
+static void rt2860_rx_coherent_intr(struct rt2860_softc *sc);
+static void rt2860_txrx_coherent_intr(struct rt2860_softc *sc);
+static void rt2860_fifo_sta_full_intr(struct rt2860_softc *sc);
+static void rt2860_rx_intr(struct rt2860_softc *sc);
+static void rt2860_rx_delay_intr(struct rt2860_softc *sc);
+static void rt2860_tx_intr(struct rt2860_softc *sc, int qid);
+static void rt2860_tx_delay_intr(struct rt2860_softc *sc);
+static void rt2860_pre_tbtt_intr(struct rt2860_softc *sc);
+static void rt2860_tbtt_intr(struct rt2860_softc *sc);
+static void rt2860_mcu_cmd_intr(struct rt2860_softc *sc);
+static void rt2860_auto_wakeup_intr(struct rt2860_softc *sc);
+static void rt2860_gp_timer_intr(struct rt2860_softc *sc);
+static void rt2860_rx_done_task(void *context, int pending);
+static void rt2860_tx_done_task(void *context, int pending);
+static void rt2860_fifo_sta_full_task(void *context, int pending);
+static void rt2860_periodic_task(void *context, int pending);
+static int rt2860_rx_eof(struct rt2860_softc *sc, int limit);
+static void rt2860_tx_eof(struct rt2860_softc *sc,
+	struct rt2860_softc_tx_ring *ring);
+static void rt2860_update_stats(struct rt2860_softc *sc);
+static void rt2860_bbp_tuning(struct rt2860_softc *sc);
+static void rt2860_watchdog(struct rt2860_softc *sc);
+static void rt2860_drain_fifo_stats(struct rt2860_softc *sc);
+static void rt2860_update_raw_counters(struct rt2860_softc *sc);
+static void rt2860_intr_enable(struct rt2860_softc *sc, uint32_t intr_mask);
+static void rt2860_intr_disable(struct rt2860_softc *sc, uint32_t intr_mask);
+static int rt2860_txrx_enable(struct rt2860_softc *sc);
+static int rt2860_alloc_rx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_rx_ring *ring);
+static void rt2860_reset_rx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_rx_ring *ring);
+static void rt2860_free_rx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_rx_ring *ring);
+static int rt2860_alloc_tx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_tx_ring *ring, int qid);
+static void rt2860_reset_tx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_tx_ring *ring);
+static void rt2860_free_tx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_tx_ring *ring);
+static void rt2860_dma_map_addr(void *arg, bus_dma_segment_t *segs,
+	int nseg, int error);
+static void rt2860_sysctl_attach(struct rt2860_softc *sc);
+
+/*
+ * Static variables
+ */
+
+SYSCTL_NODE(_hw, OID_AUTO, rt2860, CTLFLAG_RD, 0, "RT2860 driver parameters");
+
+static int rt2860_tx_stbc = 1;
+SYSCTL_INT(_hw_rt2860, OID_AUTO, tx_stbc, CTLFLAG_RW, &rt2860_tx_stbc, 0,
+	   "RT2860 Tx STBC");
+TUNABLE_INT("hw.rt2860.tx_stbc", &rt2860_tx_stbc);
+
+#ifdef RT2860_DEBUG
+static int rt2860_debug = 0;
+SYSCTL_INT(_hw_rt2860, OID_AUTO, debug, CTLFLAG_RW, &rt2860_debug, 0,
+	   "RT2860 debug level");
+TUNABLE_INT("hw.rt2860.debug", &rt2860_debug);
+#endif
+
+/*
+ * rt2860_attach
+ */
+int rt2860_attach(device_t dev, int id)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	int error, ntries, i;
+
+	sc = device_get_softc(dev);
+
+	sc->sc_dev = dev;
+	sc->id = id;
+
+	mtx_init(&sc->sc_mtx, device_get_nameunit(dev),
+		MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE);
+
+	sc->tx_stbc = rt2860_tx_stbc;
+
+#ifdef RT2860_DEBUG
+	sc->debug = rt2860_debug;
+
+	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+		"debug", CTLFLAG_RW, &sc->debug, 0, "rt2860 debug level");
+#endif
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+		"%s: attaching\n",
+		device_get_nameunit(sc->sc_dev));
+
+	/* wait for NIC to initialize */
+	for (ntries = 0; ntries < 100; ntries++) {
+		sc->mac_rev = rt2860_io_mac_read(sc, RT2860_REG_MAC_CSR0);
+		if (sc->mac_rev != 0x00000000 && sc->mac_rev != 0xffffffff)
+			break;
+
+		DELAY(10);
+	}
+
+	if (ntries == 100) {
+		printf("%s: timeout waiting for NIC to initialize\n",
+			device_get_nameunit(dev));
+		error = EIO;
+		goto fail;
+	}
+
+	rt2860_read_eeprom(sc);
+
+	printf("%s: MAC/BBP RT2860 (rev 0x%08x), RF %s\n",
+	    device_get_nameunit(sc->sc_dev), sc->mac_rev,
+		rt2860_rf_name(sc->rf_rev));
+
+	RT2860_SOFTC_LOCK(sc);
+	/* clear key tables */
+	rt2860_asic_clear_keytables(sc);
+	RT2860_SOFTC_UNLOCK(sc);
+
+	/* allocate Tx and Rx rings */
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++) {
+		error = rt2860_alloc_tx_ring(sc, &sc->tx_ring[i], i);
+		if (error != 0) {
+			printf("%s: could not allocate Tx ring #%d\n",
+				device_get_nameunit(sc->sc_dev), i);
+			goto fail;
+		}
+	}
+
+	sc->tx_ring_mgtqid = 5;
+
+	error = rt2860_alloc_rx_ring(sc, &sc->rx_ring);
+	if (error != 0) {
+		printf("%s: could not allocate Rx ring\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+
+	callout_init(&sc->periodic_ch, 0);
+	callout_init_mtx(&sc->tx_watchdog_ch, &sc->sc_mtx, 0);
+
+	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
+	if (ifp == NULL) {
+		printf("%s: could not if_alloc()\n",
+			device_get_nameunit(sc->sc_dev));
+		error = ENOMEM;
+		goto fail;
+	}
+
+	ifp->if_softc = sc;
+
+	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+
+	ifp->if_init = rt2860_init;
+	ifp->if_ioctl = rt2860_ioctl;
+	ifp->if_start = rt2860_start;
+
+	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+	IFQ_SET_READY(&ifp->if_snd);
+
+	ic = ifp->if_l2com;
+
+	ic->ic_ifp = ifp;
+
+	ic->ic_phytype = IEEE80211_T_HT;
+	ic->ic_opmode = IEEE80211_M_STA;
+
+	ic->ic_caps = IEEE80211_C_MONITOR |
+		IEEE80211_C_IBSS |
+		IEEE80211_C_STA |
+		IEEE80211_C_AHDEMO |
+		IEEE80211_C_HOSTAP |
+		IEEE80211_C_WDS |
+		IEEE80211_C_MBSS |
+		IEEE80211_C_BGSCAN |
+		IEEE80211_C_TXPMGT |
+		IEEE80211_C_SHPREAMBLE |
+		IEEE80211_C_SHSLOT |
+		IEEE80211_C_TXFRAG |
+		IEEE80211_C_BURST |
+		IEEE80211_C_WME |
+		IEEE80211_C_WPA;
+
+#ifndef RT2860_NO_HW_CRYPTO
+	ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP |
+		IEEE80211_CRYPTO_TKIP |
+		IEEE80211_CRYPTO_TKIPMIC |
+		IEEE80211_CRYPTO_AES_CCM;
+#endif
+	ic->ic_htcaps = IEEE80211_HTC_HT |
+		IEEE80211_HTC_AMSDU |		/* A-MSDU Tx */
+		IEEE80211_HTC_AMPDU |		/* A-MPDU Tx */
+		IEEE80211_HTC_SMPS |		/* MIMO power save */
+		IEEE80211_HTCAP_MAXAMSDU_3839 |	/* max. A-MSDU Rx length */
+		IEEE80211_HTCAP_CHWIDTH40 |	/* HT 40MHz channel width */
+		IEEE80211_HTCAP_GREENFIELD |	/* HT greenfield */
+		IEEE80211_HTCAP_SHORTGI20 |	/* HT 20MHz short GI */
+		IEEE80211_HTCAP_SHORTGI40 |	/* HT 40MHz short GI */
+		IEEE80211_HTCAP_SMPS_OFF;	/* MIMO power save disabled */
+
+	/* spatial streams */
+	if (sc->nrxpath == 2)
+		ic->ic_htcaps |= IEEE80211_HTCAP_RXSTBC_2STREAM;
+	else if (sc->nrxpath == 3)
+		ic->ic_htcaps |= IEEE80211_HTCAP_RXSTBC_3STREAM;
+	else
+		ic->ic_htcaps |= IEEE80211_HTCAP_RXSTBC_1STREAM;
+
+	if (sc->ntxpath > 1)
+		ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC;
+
+	/* delayed BA */
+	if (sc->mac_rev != 0x28600100)
+		ic->ic_htcaps |= IEEE80211_HTCAP_DELBA;
+
+	/* init channels */
+	ic->ic_nchans = 0;
+
+	rt2860_init_channels(sc);
+	rt2860_init_channels_ht40(sc);
+
+	ieee80211_ifattach(ic, sc->mac_addr);
+
+	ic->ic_vap_create = rt2860_vap_create;
+	ic->ic_vap_delete = rt2860_vap_delete;
+
+	ic->ic_node_alloc = rt2860_node_alloc;
+	sc->node_cleanup = ic->ic_node_cleanup;
+	ic->ic_node_cleanup = rt2860_node_cleanup;
+
+	ic->ic_node_getmimoinfo = rt2860_node_getmimoinfo;
+	ic->ic_setregdomain = rt2860_setregdomain;
+	ic->ic_getradiocaps = rt2860_getradiocaps;
+	ic->ic_scan_start = rt2860_scan_start;
+	ic->ic_scan_end = rt2860_scan_end;
+	ic->ic_set_channel = rt2860_set_channel;
+	ic->ic_newassoc = rt2860_newassoc;
+	ic->ic_updateslot = rt2860_updateslot;
+	ic->ic_update_promisc = rt2860_update_promisc;
+	ic->ic_update_mcast = rt2860_update_mcast;
+	ic->ic_wme.wme_update = rt2860_wme_update;
+	ic->ic_raw_xmit = rt2860_raw_xmit;
+
+	sc->recv_action = ic->ic_recv_action;
+	ic->ic_recv_action = rt2860_recv_action;
+
+	sc->send_action = ic->ic_send_action;
+	ic->ic_send_action = rt2860_send_action;
+
+	sc->addba_response = ic->ic_addba_response;
+	ic->ic_addba_response = rt2860_addba_response;
+
+	sc->addba_stop = ic->ic_addba_stop;
+	ic->ic_addba_stop = rt2860_addba_stop;
+
+	sc->ampdu_rx_start = ic->ic_ampdu_rx_start;
+	ic->ic_ampdu_rx_start = rt2860_ampdu_rx_start;
+
+	sc->ampdu_rx_stop = ic->ic_ampdu_rx_stop;
+	ic->ic_ampdu_rx_stop = rt2860_ampdu_rx_stop;
+
+	/* hardware requires padding between 802.11 frame header and body */
+	ic->ic_flags |= IEEE80211_F_DATAPAD | IEEE80211_F_DOTH;
+	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
+
+	ieee80211_radiotap_attach(ic,
+	    &sc->txtap.ihdr, sizeof(sc->txtap),
+		RT2860_SOFTC_TX_RADIOTAP_PRESENT,
+	    &sc->rxtap.ihdr, sizeof(sc->rxtap),
+		RT2860_SOFTC_RX_RADIOTAP_PRESENT);
+
+	/* init task queue */
+	TASK_INIT(&sc->rx_done_task, 0, rt2860_rx_done_task, sc);
+	TASK_INIT(&sc->tx_done_task, 0, rt2860_tx_done_task, sc);
+	TASK_INIT(&sc->fifo_sta_full_task, 0, rt2860_fifo_sta_full_task, sc);
+	TASK_INIT(&sc->periodic_task, 0, rt2860_periodic_task, sc);
+
+	sc->rx_process_limit = 100;
+
+	sc->taskqueue = taskqueue_create("rt2860_taskq", M_NOWAIT,
+	    taskqueue_thread_enqueue, &sc->taskqueue);
+
+	taskqueue_start_threads(&sc->taskqueue, 1, PI_NET, "%s taskq",
+	    device_get_nameunit(sc->sc_dev));
+
+	rt2860_sysctl_attach(sc);
+
+	if (bootverbose)
+		ieee80211_announce(ic);
+
+	return 0;
+
+fail:
+
+	/* free Tx and Rx rings */
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+		rt2860_free_tx_ring(sc, &sc->tx_ring[i]);
+
+	rt2860_free_rx_ring(sc, &sc->rx_ring);
+
+	mtx_destroy(&sc->sc_mtx);
+
+	if (sc->mem != NULL)
+		bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
+
+	if (sc->irq != NULL)
+		bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
+
+	return error;
+}
+
+/*
+ * rt2860_detach
+ */
+int rt2860_detach(void *xsc)
+{
+	struct rt2860_softc *sc = xsc;
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	int i;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+		"%s: detaching\n",
+		device_get_nameunit(sc->sc_dev));
+
+	RT2860_SOFTC_LOCK(sc);
+
+	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+	callout_stop(&sc->periodic_ch);
+	callout_stop(&sc->tx_watchdog_ch);
+
+	taskqueue_drain(sc->taskqueue, &sc->rx_done_task);
+	taskqueue_drain(sc->taskqueue, &sc->tx_done_task);
+	taskqueue_drain(sc->taskqueue, &sc->fifo_sta_full_task);
+	taskqueue_drain(sc->taskqueue, &sc->periodic_task);
+
+	/* free Tx and Rx rings */
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+		rt2860_free_tx_ring(sc, &sc->tx_ring[i]);
+
+	rt2860_free_rx_ring(sc, &sc->rx_ring);
+
+	RT2860_SOFTC_UNLOCK(sc);
+
+	ieee80211_ifdetach(ic);
+
+	if_free(ifp);
+
+	taskqueue_free(sc->taskqueue);
+
+	mtx_destroy(&sc->sc_mtx);
+
+	bus_generic_detach(sc->sc_dev);
+
+	bus_teardown_intr(sc->sc_dev, sc->irq, sc->irqh);
+
+	bus_release_resource(sc->sc_dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
+
+	bus_release_resource(sc->sc_dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
+
+	return 0;
+}
+
+/*
+ * rt2860_shutdown
+ */
+void
+rt2860_shutdown(void *xsc)
+{
+	struct rt2860_softc *sc = xsc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+		"%s: shutting down\n",
+		device_get_nameunit(sc->sc_dev));
+
+	rt2860_stop(sc);
+
+	sc->flags &= ~RT2860_SOFTC_FLAGS_UCODE_LOADED;
+
+	return;
+}
+
+/*
+ * rt2860_suspend
+ */
+void
+rt2860_suspend(void *xsc)
+{
+	struct rt2860_softc *sc = xsc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+		"%s: suspending\n",
+		device_get_nameunit(sc->sc_dev));
+
+	rt2860_stop(sc);
+
+	sc->flags &= ~RT2860_SOFTC_FLAGS_UCODE_LOADED;
+
+	return;
+}
+
+/*
+ * rt2860_resume
+ */
+void
+rt2860_resume(void *xsc)
+{
+	struct rt2860_softc *sc = xsc;
+	struct ifnet *ifp;
+
+	ifp = sc->sc_ifp;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+		"%s: resuming\n",
+		device_get_nameunit(sc->sc_dev));
+
+	if (ifp->if_flags & IFF_UP)
+		rt2860_init(sc);
+
+	return;
+}
+
+/*
+ * rt2860_init_channels
+ */
+static void
+rt2860_init_channels(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211_channel *c;
+	int i, flags;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	/* set supported channels for 2GHz band */
+	for (i = 1; i <= 14; i++) {
+		c = &ic->ic_channels[ic->ic_nchans++];
+		flags = IEEE80211_CHAN_B;
+
+		c->ic_freq = ieee80211_ieee2mhz(i, flags);
+		c->ic_ieee = i;
+		c->ic_flags = flags;
+
+		c = &ic->ic_channels[ic->ic_nchans++];
+		flags = IEEE80211_CHAN_B | IEEE80211_CHAN_HT20;
+
+		c->ic_freq = ieee80211_ieee2mhz(i, flags);
+		c->ic_ieee = i;
+		c->ic_flags = flags;
+
+		c = &ic->ic_channels[ic->ic_nchans++];
+		flags = IEEE80211_CHAN_G;
+
+		c->ic_freq = ieee80211_ieee2mhz(i, flags);
+		c->ic_ieee = i;
+		c->ic_flags = flags;
+
+		c = &ic->ic_channels[ic->ic_nchans++];
+		flags = IEEE80211_CHAN_G | IEEE80211_CHAN_HT20;
+
+		c->ic_freq = ieee80211_ieee2mhz(i, flags);
+		c->ic_ieee = i;
+		c->ic_flags = flags;
+	}
+
+	/* set supported channels for 5GHz band */
+	if (sc->rf_rev == RT2860_EEPROM_RF_2850 ||
+		sc->rf_rev == RT2860_EEPROM_RF_2750 ||
+		sc->rf_rev == RT2860_EEPROM_RF_3052) {
+		for (i = 36; i <= 64; i += 4) {
+			c = &ic->ic_channels[ic->ic_nchans++];
+			flags = IEEE80211_CHAN_A;
+
+			c->ic_freq = ieee80211_ieee2mhz(i, flags);
+			c->ic_ieee = i;
+			c->ic_flags = flags;
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+			flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20;
+
+			c->ic_freq = ieee80211_ieee2mhz(i, flags);
+			c->ic_ieee = i;
+			c->ic_flags = flags;
+		}
+
+		for (i = 100; i <= 140; i += 4) {
+			c = &ic->ic_channels[ic->ic_nchans++];
+			flags = IEEE80211_CHAN_A;
+
+			c->ic_freq = ieee80211_ieee2mhz(i, flags);
+			c->ic_ieee = i;
+			c->ic_flags = flags;
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+			flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20;
+
+			c->ic_freq = ieee80211_ieee2mhz(i, flags);
+			c->ic_ieee = i;
+			c->ic_flags = flags;
+		}
+
+		for (i = 149; i <= 165; i += 4) {
+			c = &ic->ic_channels[ic->ic_nchans++];
+			flags = IEEE80211_CHAN_A;
+
+			c->ic_freq = ieee80211_ieee2mhz(i, flags);
+			c->ic_ieee = i;
+			c->ic_flags = flags;
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+			flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20;
+
+			c->ic_freq = ieee80211_ieee2mhz(i, flags);
+			c->ic_ieee = i;
+			c->ic_flags = flags;
+		}
+	}
+}
+
+/*
+ * rt2860_init_channels_ht40
+ */
+static void rt2860_init_channels_ht40(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211_channel *c, *cent, *ext;
+	int i, flags;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	/* set supported channels for 2GHz band */
+	for (i = 1; i <= 14; i++) {
+		flags = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40;
+
+		/* find the center channel */
+		cent = ieee80211_find_channel_byieee(ic, i,
+			flags & ~IEEE80211_CHAN_HT);
+		if (cent == NULL) {
+			device_printf(sc->sc_dev, "skip channel %d, "
+				      "could not find center channel\n", i);
+			continue;
+		}
+
+		/* find the extension channel */
+		ext = ieee80211_find_channel(ic, cent->ic_freq + 20,
+			flags & ~IEEE80211_CHAN_HT);
+		if (ext == NULL) {
+			device_printf(sc->sc_dev, "skip channel %d, "
+				      "could not find extension channel\n", i);
+			continue;
+		}
+
+		c = &ic->ic_channels[ic->ic_nchans++];
+
+		*c = *cent;
+		c->ic_extieee = ext->ic_ieee;
+		c->ic_flags &= ~IEEE80211_CHAN_HT;
+		c->ic_flags |= IEEE80211_CHAN_HT40U;
+
+		c = &ic->ic_channels[ic->ic_nchans++];
+
+		*c = *ext;
+		c->ic_extieee = cent->ic_ieee;
+		c->ic_flags &= ~IEEE80211_CHAN_HT;
+		c->ic_flags |= IEEE80211_CHAN_HT40D;
+	}
+
+	/* set supported channels for 5GHz band */
+	if (sc->rf_rev == RT2860_EEPROM_RF_2850 ||
+		sc->rf_rev == RT2860_EEPROM_RF_2750 ||
+		sc->rf_rev == RT2860_EEPROM_RF_3052) {
+		for (i = 36; i <= 64; i += 4) {
+			flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40;
+
+			/* find the center channel */
+			cent = ieee80211_find_channel_byieee(ic, i,
+				flags & ~IEEE80211_CHAN_HT);
+			if (cent == NULL) {
+				printf("%s: skip channel %d, could not find center channel\n",
+					device_get_nameunit(sc->sc_dev), i);
+				continue;
+			}
+
+			/* find the extension channel */
+
+			ext = ieee80211_find_channel(ic, cent->ic_freq + 20,
+				flags & ~IEEE80211_CHAN_HT);
+			if (ext == NULL) {
+				printf("%s: skip channel %d, could not find extension channel\n",
+					device_get_nameunit(sc->sc_dev), i);
+				continue;
+			}
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+
+			*c = *cent;
+			c->ic_extieee = ext->ic_ieee;
+			c->ic_flags &= ~IEEE80211_CHAN_HT;
+			c->ic_flags |= IEEE80211_CHAN_HT40U;
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+
+			*c = *ext;
+			c->ic_extieee = cent->ic_ieee;
+			c->ic_flags &= ~IEEE80211_CHAN_HT;
+			c->ic_flags |= IEEE80211_CHAN_HT40D;
+		}
+
+		for (i = 100; i <= 140; i += 4) {
+			flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40;
+
+			/* find the center channel */
+			cent = ieee80211_find_channel_byieee(ic, i,
+				flags & ~IEEE80211_CHAN_HT);
+			if (cent == NULL) {
+				printf("%s: skip channel %d, could not find center channel\n",
+					device_get_nameunit(sc->sc_dev), i);
+				continue;
+			}
+
+			/* find the extension channel */
+			ext = ieee80211_find_channel(ic, cent->ic_freq + 20,
+				flags & ~IEEE80211_CHAN_HT);
+			if (ext == NULL) {
+				printf("%s: skip channel %d, could not find extension channel\n",
+					device_get_nameunit(sc->sc_dev), i);
+				continue;
+			}
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+
+			*c = *cent;
+			c->ic_extieee = ext->ic_ieee;
+			c->ic_flags &= ~IEEE80211_CHAN_HT;
+			c->ic_flags |= IEEE80211_CHAN_HT40U;
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+
+			*c = *ext;
+			c->ic_extieee = cent->ic_ieee;
+			c->ic_flags &= ~IEEE80211_CHAN_HT;
+			c->ic_flags |= IEEE80211_CHAN_HT40D;
+		}
+
+		for (i = 149; i <= 165; i += 4) {
+			flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40;
+
+			/* find the center channel */
+
+			cent = ieee80211_find_channel_byieee(ic, i,
+				flags & ~IEEE80211_CHAN_HT);
+			if (cent == NULL) {
+				printf("%s: skip channel %d, could not find center channel\n",
+					device_get_nameunit(sc->sc_dev), i);
+				continue;
+			}
+
+			/* find the extension channel */
+
+			ext = ieee80211_find_channel(ic, cent->ic_freq + 20,
+				flags & ~IEEE80211_CHAN_HT);
+			if (ext == NULL) {
+				printf("%s: skip channel %d, could not find extension channel\n",
+					device_get_nameunit(sc->sc_dev), i);
+				continue;
+			}
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+
+			*c = *cent;
+			c->ic_extieee = ext->ic_ieee;
+			c->ic_flags &= ~IEEE80211_CHAN_HT;
+			c->ic_flags |= IEEE80211_CHAN_HT40U;
+
+			c = &ic->ic_channels[ic->ic_nchans++];
+
+			*c = *ext;
+			c->ic_extieee = cent->ic_ieee;
+			c->ic_flags &= ~IEEE80211_CHAN_HT;
+			c->ic_flags |= IEEE80211_CHAN_HT40D;
+		}
+	}
+}
+
+/*
+ * rt2860_init_locked
+ */
+static void rt2860_init_locked(void *priv)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	int error, i, ntries;
+	uint32_t tmp, stacnt[6];
+
+	sc = priv;
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+		"%s: initializing\n",
+		device_get_nameunit(sc->sc_dev));
+
+	RT2860_SOFTC_ASSERT_LOCKED(sc);
+
+	if (sc->mac_rev != 0x28720200) {
+	    if (!(sc->flags & RT2860_SOFTC_FLAGS_UCODE_LOADED)) {
+		RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+			"%s: loading 8051 microcode\n",
+			device_get_nameunit(sc->sc_dev));
+
+		error = rt2860_io_mcu_load_ucode(sc, rt2860_ucode, sizeof(rt2860_ucode));
+		if (error != 0) {
+			printf("%s: could not load 8051 microcode\n",
+				device_get_nameunit(sc->sc_dev));
+			goto fail;
+		}
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+			"%s: 8051 microcode was successfully loaded\n",
+			device_get_nameunit(sc->sc_dev));
+
+		sc->flags |= RT2860_SOFTC_FLAGS_UCODE_LOADED;
+	    }
+	} else {
+		sc->flags |= RT2860_SOFTC_FLAGS_UCODE_LOADED;
+
+		/* Blink every TX */
+		rt2860_io_mac_write(sc, RT2860_REG_LED_CFG, 
+		    LED_CFG_LED_POLARITY |
+		    LED_CFG_Y_LED_MODE_ONTX |
+		    LED_CFG_G_LED_MODE_ONTX |
+		    LED_CFG_R_LED_MODE_ONTX |
+		    LED_CFG_SLOW_BLK_TIME |
+		    LED_CFG_LED_OFF_TIME |
+		    LED_CFG_LED_ON_TIME);
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_PWR_PIN_CFG, 0x2);
+
+	/* disable DMA engine */
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+
+	tmp &= 0xff0;
+	tmp |= RT2860_REG_TX_WB_DDONE;
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_RST_IDX, 0xffffffff);
+
+	/* PBF hardware reset */
+
+	rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0xe1f);
+	rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0xe00);
+
+	/* wait while DMA engine is busy */
+
+	for (ntries = 0; ntries < 100; ntries++) {
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+		if (!(tmp & (RT2860_REG_TX_DMA_BUSY | RT2860_REG_RX_DMA_BUSY)))
+			break;
+
+		DELAY(1000);
+	}
+
+	if (ntries == 100) {
+		printf("%s: timeout waiting for DMA engine\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+
+	tmp &= 0xff0;
+	tmp |= RT2860_REG_TX_WB_DDONE;
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+	/* reset Rx and Tx rings */
+
+	tmp = RT2860_REG_RST_IDX_RX |
+		RT2860_REG_RST_IDX_TX_MGMT |
+		RT2860_REG_RST_IDX_TX_HCCA |
+		RT2860_REG_RST_IDX_TX_AC3 |
+		RT2860_REG_RST_IDX_TX_AC2 |
+		RT2860_REG_RST_IDX_TX_AC1 |
+		RT2860_REG_RST_IDX_TX_AC0;
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_RST_IDX, tmp);
+
+	/* PBF hardware reset */
+
+	rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0xe1f);
+	rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0xe00);
+
+	rt2860_io_mac_write(sc, RT2860_REG_PWR_PIN_CFG, 0x3);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL,
+		RT2860_REG_MAC_SRST | RT2860_REG_BBP_HRST);
+	rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL, 0);
+
+	/* init Tx power per rate */
+
+	for (i = 0; i < RT2860_SOFTC_TXPOW_RATE_COUNT; i++) {
+		if (sc->txpow_rate_20mhz[i] == 0xffffffff)
+			continue;
+
+		rt2860_io_mac_write(sc, RT2860_REG_TX_PWR_CFG(i),
+			sc->txpow_rate_20mhz[i]);
+	}
+
+	for (i = 0; i < RT2860_DEF_MAC_SIZE; i++)
+		rt2860_io_mac_write(sc, rt2860_def_mac[i].reg,
+			rt2860_def_mac[i].val);
+
+	/* wait while MAC is busy */
+
+	for (ntries = 0; ntries < 100; ntries++) {
+		if (!(rt2860_io_mac_read(sc, RT2860_REG_STATUS_CFG) &
+			(RT2860_REG_STATUS_TX_BUSY | RT2860_REG_STATUS_RX_BUSY)))
+			break;
+
+		DELAY(1000);
+	}
+
+	if (ntries == 100) {
+		printf("%s: timeout waiting for MAC\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+	
+	/* clear Host to MCU mailbox */
+
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT, 0);
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX, 0);
+
+	rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_BOOT,
+		RT2860_REG_H2M_TOKEN_NO_INTR, 0);
+
+	DELAY(1000);
+
+	error = rt2860_init_bbp(sc);
+	if (error != 0)
+		goto fail;
+
+	/* set up maximum buffer sizes */
+
+	tmp = (1 << 12) | RT2860_MAX_AGG_SIZE;
+
+	rt2860_io_mac_write(sc, RT2860_REG_MAX_LEN_CFG, tmp);
+
+	if (sc->mac_rev == 0x28720200) {
+		/* set max. PSDU length from 16K to 32K bytes */
+
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_MAX_LEN_CFG);
+
+		tmp &= ~(3 << 12);
+		tmp |= (2 << 12);
+
+		rt2860_io_mac_write(sc, RT2860_REG_MAX_LEN_CFG, tmp);
+	}
+
+	if (sc->mac_rev >= 0x28720200 && sc->mac_rev < 0x30700200) {
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_MAX_LEN_CFG);
+
+		tmp &= 0xfff;
+		tmp |= 0x2000;
+
+		rt2860_io_mac_write(sc, RT2860_REG_MAX_LEN_CFG, tmp);
+	}
+
+	/* set mac address */
+
+	rt2860_asic_set_macaddr(sc, IF_LLADDR(ifp));
+
+	/* clear statistic registers */
+
+	rt2860_io_mac_read_multi(sc, RT2860_REG_RX_STA_CNT0,
+		stacnt, sizeof(stacnt));
+
+	/* set RTS threshold */
+
+	rt2860_asic_update_rtsthreshold(sc);
+
+	/* set Tx power */
+
+	rt2860_asic_update_txpower(sc);
+
+	/* set up protection mode */
+
+	sc->tx_ampdu_sessions = 0;
+
+	rt2860_asic_updateprot(sc);
+
+	/* clear beacon frame space (entries = 8, entry size = 512) */
+
+	rt2860_io_mac_set_region_4(sc, RT2860_REG_BEACON_BASE(0), 0, 1024);
+
+	taskqueue_unblock(sc->taskqueue);
+
+	/* init Tx rings (4 EDCAs + HCCA + MGMT) */
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+		rt2860_reset_tx_ring(sc, &sc->tx_ring[i]);
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++) {
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_BASE_PTR(i),
+			sc->tx_ring[i].desc_phys_addr);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_MAX_CNT(i),
+			RT2860_SOFTC_TX_RING_DESC_COUNT);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(i), 0);
+	}
+
+	/* init Rx ring */
+
+	rt2860_reset_rx_ring(sc, &sc->rx_ring);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_BASE_PTR,
+		sc->rx_ring.desc_phys_addr);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_MAX_CNT,
+		RT2860_SOFTC_RX_RING_DATA_COUNT);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+		RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+
+	/* wait while DMA engine is busy */
+
+	for (ntries = 0; ntries < 100; ntries++) {
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+		if (!(tmp & (RT2860_REG_TX_DMA_BUSY | RT2860_REG_RX_DMA_BUSY)))
+			break;
+
+		DELAY(1000);
+	}
+
+	if (ntries == 100) {
+		printf("%s: timeout waiting for DMA engine\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+
+	tmp &= 0xff0;
+	tmp |= RT2860_REG_TX_WB_DDONE;
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+	/* disable interrupts mitigation */
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_DELAY_INT_CFG, 0);
+
+	/* select Main antenna for 1T1R devices */
+	if (sc->rf_rev == RT2860_EEPROM_RF_2020 ||
+	    sc->rf_rev == RT2860_EEPROM_RF_3020 ||
+	    sc->rf_rev == RT2860_EEPROM_RF_3320)
+		rt3090_set_rx_antenna(sc, 0);
+
+	/* send LEDs operating mode to microcontroller */
+	rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LED1,
+		RT2860_REG_H2M_TOKEN_NO_INTR, sc->led_off[0]);
+	rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LED2,
+		RT2860_REG_H2M_TOKEN_NO_INTR, sc->led_off[1]);
+	rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LED3,
+		RT2860_REG_H2M_TOKEN_NO_INTR, sc->led_off[2]);
+
+	/* turn radio LED on */
+
+	rt2860_led_cmd(sc, RT2860_LED_CMD_RADIO_ON);
+
+	/* write vendor-specific BBP values (from EEPROM) */
+	for (i = 0; i < RT2860_SOFTC_BBP_EEPROM_COUNT; i++) {
+		if (sc->bbp_eeprom[i].reg == 0x00 ||
+			sc->bbp_eeprom[i].reg == 0xff)
+			continue;
+
+		rt2860_io_bbp_write(sc, sc->bbp_eeprom[i].reg,
+			sc->bbp_eeprom[i].val);
+	}
+
+	if ((sc->mac_rev & 0xffff0000) >= 0x30710000)
+		rt3090_rf_init(sc);
+
+	if (sc->mac_rev != 0x28720200) {
+		/* 0x28720200 don`t have RT2860_REG_SCHDMA_GPIO_CTRL_CFG */
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG);
+	        if (tmp & (1 << 2)) {
+			rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_SLEEP,
+				RT2860_REG_H2M_TOKEN_RADIOOFF, 0x02ff);
+			rt2860_io_mcu_cmd_check(sc, RT2860_REG_H2M_TOKEN_RADIOOFF);
+
+			rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_WAKEUP,
+				RT2860_REG_H2M_TOKEN_WAKEUP, 0);
+			rt2860_io_mcu_cmd_check(sc, RT2860_REG_H2M_TOKEN_WAKEUP);
+		}
+	}
+
+	if ((sc->mac_rev & 0xffff0000) >= 0x30710000)
+		rt3090_rf_wakeup(sc);
+
+	/* disable non-existing Rx chains */
+
+	tmp = rt2860_io_bbp_read(sc, 3);
+
+	tmp &= ~((1 << 4) | (1 << 3));
+
+	if (sc->nrxpath == 3)
+		tmp |= (1 << 4);
+	else if (sc->nrxpath == 2)
+		tmp |= (1 << 3);
+
+	rt2860_io_bbp_write(sc, 3, tmp);
+
+	/* disable non-existing Tx chains */
+
+	tmp = rt2860_io_bbp_read(sc, 1);
+
+	tmp &= ~((1 << 4) | (1 << 3));
+
+	if (sc->ntxpath == 2)
+		tmp |= (1 << 4);
+
+	rt2860_io_bbp_write(sc, 1, tmp);
+
+	if ((sc->mac_rev & 0xffff0000) >= 0x30710000)
+		rt3090_rf_setup(sc);
+
+	if (sc->rf_rev == RT2860_EEPROM_RF_3022) {
+		/* calibrate RF */
+                tmp = rt2860_io_rf_read(sc, 30);
+                tmp |= 0x80;
+                rt2860_io_rf_write(sc, 30, tmp);
+                DELAY(1000);
+                tmp &= 0x7F;
+                rt2860_io_rf_write(sc, 30, tmp);
+
+                /* Initialize RF register to default value */
+		rt2860_io_rf_load_defaults(sc);
+	}
+
+	/* set current channel */
+	rt2860_rf_set_chan(sc, ic->ic_curchan);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_TXOP0_CFG, 0);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_TXOP1_CFG,
+		(48 << 16) | 96);
+
+	if ((sc->mac_rev & 0xffff) != 0x0101)
+		rt2860_io_mac_write(sc, RT2860_REG_TX_TXOP_CTRL_CFG, 0x583f);
+
+	/* clear pending interrupts */
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_STATUS, 0xffffffff);
+
+	/* enable interrupts */
+
+	tmp = RT2860_REG_INT_TX_COHERENT |
+		RT2860_REG_INT_RX_COHERENT |
+		RT2860_REG_INT_GP_TIMER |
+		RT2860_REG_INT_AUTO_WAKEUP |
+		RT2860_REG_INT_FIFO_STA_FULL |
+		RT2860_REG_INT_PRE_TBTT |
+		RT2860_REG_INT_TBTT |
+		RT2860_REG_INT_TXRX_COHERENT |
+		RT2860_REG_INT_MCU_CMD |
+		RT2860_REG_INT_TX_MGMT_DONE |
+		RT2860_REG_INT_TX_HCCA_DONE |
+		RT2860_REG_INT_TX_AC3_DONE |
+		RT2860_REG_INT_TX_AC2_DONE |
+		RT2860_REG_INT_TX_AC1_DONE |
+		RT2860_REG_INT_TX_AC0_DONE |
+		RT2860_REG_INT_RX_DONE;
+
+	sc->intr_enable_mask = tmp;
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_MASK, tmp);
+
+	if (rt2860_txrx_enable(sc) != 0)
+		goto fail;
+
+	/* clear garbage interrupts */
+
+	tmp = rt2860_io_mac_read(sc, 0x1300);
+
+	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+	ifp->if_drv_flags |= IFF_DRV_RUNNING;
+
+	sc->periodic_round = 0;
+
+	callout_reset(&sc->periodic_ch, hz / 10, rt2860_periodic, sc);
+
+	return;
+
+fail:
+
+	rt2860_stop_locked(sc);
+}
+
+/*
+ * rt2860_init
+ */
+static void rt2860_init(void *priv)
+{
+	struct rt2860_softc *sc;
+
+	sc = priv;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	rt2860_init_locked(sc);
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_init_bbp
+ */
+static int rt2860_init_bbp(struct rt2860_softc *sc)
+{
+	int ntries, i;
+	uint8_t tmp;
+
+	for (ntries = 0; ntries < 20; ntries++) {
+		tmp = rt2860_io_bbp_read(sc, 0);
+		if (tmp != 0x00 && tmp != 0xff)
+			break;
+	}
+
+	if (tmp == 0x00 || tmp == 0xff) {
+		printf("%s: timeout waiting for BBP to wakeup\n",
+			device_get_nameunit(sc->sc_dev));
+		return ETIMEDOUT;
+	}
+
+	for (i = 0; i < RT2860_DEF_BBP_SIZE; i++)
+		rt2860_io_bbp_write(sc, rt2860_def_bbp[i].reg,
+			rt2860_def_bbp[i].val);
+
+	if ((sc->mac_rev & 0xffff) != 0x0101)
+		rt2860_io_bbp_write(sc, 84, 0x19);
+
+	if (sc->mac_rev == 0x28600100) {
+		rt2860_io_bbp_write(sc, 69, 0x16);
+		rt2860_io_bbp_write(sc, 73, 0x12);
+	}
+
+	return 0;
+}
+
+/*
+ * rt2860_stop_locked
+ */
+static void rt2860_stop_locked(void *priv)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	uint32_t tmp;
+
+	sc = priv;
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+		"%s: stopping\n",
+		device_get_nameunit(sc->sc_dev));
+
+	RT2860_SOFTC_ASSERT_LOCKED(sc);
+
+	sc->tx_timer = 0;
+
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+		rt2860_led_cmd(sc, RT2860_LED_CMD_RADIO_OFF);
+
+	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+	callout_stop(&sc->periodic_ch);
+	callout_stop(&sc->tx_watchdog_ch);
+
+	RT2860_SOFTC_UNLOCK(sc);
+
+	taskqueue_block(sc->taskqueue);
+
+	taskqueue_drain(sc->taskqueue, &sc->rx_done_task);
+	taskqueue_drain(sc->taskqueue, &sc->tx_done_task);
+	taskqueue_drain(sc->taskqueue, &sc->fifo_sta_full_task);
+	taskqueue_drain(sc->taskqueue, &sc->periodic_task);
+
+	RT2860_SOFTC_LOCK(sc);
+
+	/* clear key tables */
+
+	rt2860_asic_clear_keytables(sc);
+
+	/* disable interrupts */
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_MASK, 0);
+
+	/* disable Tx/Rx */
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_SYS_CTRL);
+
+	tmp &= ~(RT2860_REG_RX_ENABLE | RT2860_REG_TX_ENABLE);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL, tmp);
+
+	/* reset adapter */
+
+	rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL,
+		RT2860_REG_MAC_SRST | RT2860_REG_BBP_HRST);
+	rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL, 0);
+}
+
+/*
+ * rt2860_stop
+ */
+static void rt2860_stop(void *priv)
+{
+	struct rt2860_softc *sc;
+
+	sc = priv;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	rt2860_stop_locked(sc);
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_start
+ */
+static void rt2860_start(struct ifnet *ifp)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211_frame *wh;
+	struct ieee80211_node *ni;
+	struct ieee80211_key *k;
+	struct mbuf *m;
+	int qid;
+
+	sc = ifp->if_softc;
+
+	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING) || sc->sc_invalid)
+		return;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	for (;;) {
+		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+		if (m == NULL)
+			break;
+
+		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+
+		KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
+		wh = mtod(m, struct ieee80211_frame *);
+		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+			k = ieee80211_crypto_encap(ni, m);
+			if (k == NULL) {
+				ieee80211_free_node(ni);
+				m_freem(m);
+				ifp->if_oerrors++;
+				continue;
+			}
+		}
+		wh = NULL;	/* Catch any invalid use */
+
+		m->m_pkthdr.rcvif = NULL;
+
+		qid = M_WME_GETAC(m);
+
+		RT2860_SOFTC_TX_RING_LOCK(&sc->tx_ring[qid]);
+
+		if (sc->tx_ring[qid].data_queued >= RT2860_SOFTC_TX_RING_DATA_COUNT) {
+			RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]);
+
+			RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+				"%s: if_start: Tx ring with qid=%d is full\n",
+				device_get_nameunit(sc->sc_dev), qid);
+
+			m_freem(m);
+			ieee80211_free_node(ni);
+
+			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+			ifp->if_oerrors++;
+
+			sc->tx_data_queue_full[qid]++;
+
+			break;
+		}
+
+		if (rt2860_tx_data(sc, m, ni, qid) != 0) {
+			RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]);
+
+			ieee80211_free_node(ni);
+
+			ifp->if_oerrors++;
+
+			break;
+		}
+
+		RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]);
+
+		rt2860_drain_fifo_stats(sc);
+
+		sc->tx_timer = RT2860_TX_WATCHDOG_TIMEOUT;
+
+		callout_reset(&sc->tx_watchdog_ch, hz, rt2860_tx_watchdog, sc);
+	}
+	RT2860_SOFTC_UNLOCK(sc);
+
+}
+
+/*
+ * rt2860_ioctl
+ */
+static int rt2860_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifreq *ifr;
+	int error, startall;
+
+	sc = ifp->if_softc;
+	ic = ifp->if_l2com;
+	ifr = (struct ifreq *) data;
+
+	error = 0;
+
+	switch (cmd) {
+	case SIOCSIFFLAGS:
+		startall = 0;
+
+		RT2860_SOFTC_LOCK(sc);
+
+		if (ifp->if_flags & IFF_UP) {
+			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+				if ((ifp->if_flags ^ sc->if_flags) & IFF_PROMISC)
+					rt2860_asic_update_promisc(sc);
+			} else {
+				rt2860_init_locked(sc);
+				startall = 1;
+			}
+		} else {
+			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+				rt2860_stop_locked(sc);
+		}
+
+		sc->if_flags = ifp->if_flags;
+
+		RT2860_SOFTC_UNLOCK(sc);
+
+		if (startall)
+			ieee80211_start_all(ic);
+		break;
+
+	case SIOCGIFMEDIA:
+	case SIOCSIFMEDIA:
+		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
+		break;
+
+	case SIOCGIFADDR:
+		error = ether_ioctl(ifp, cmd, data);
+		break;
+
+	default:
+		error = EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+/*
+ * rt2860_vap_create
+ */
+static struct ieee80211vap *rt2860_vap_create(struct ieee80211com *ic,
+	const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode,
+	int flags, const uint8_t bssid[IEEE80211_ADDR_LEN],
+	const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+	struct rt2860_softc_vap *rvap;
+	struct ieee80211vap *vap;
+
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: VAP create: opmode=%s\n",
+		device_get_nameunit(sc->sc_dev),
+		ieee80211_opmode_name[opmode]);
+
+	switch (opmode) {
+	case IEEE80211_M_IBSS:
+	case IEEE80211_M_STA:
+	case IEEE80211_M_AHDEMO:
+	case IEEE80211_M_HOSTAP:
+	case IEEE80211_M_MBSS:
+		if ((sc->napvaps + sc->nadhocvaps + sc->nstavaps) != 0) {
+			if_printf(ifp, "only 1 VAP supported\n");
+			return NULL;
+		}
+
+		if (opmode == IEEE80211_M_STA)
+			flags |= IEEE80211_CLONE_NOBEACONS;
+		break;
+
+	case IEEE80211_M_WDS:
+		if (sc->napvaps == 0) {
+			if_printf(ifp, "WDS only supported in AP mode\n");
+			return NULL;
+		}
+		break;
+
+	case IEEE80211_M_MONITOR:
+		break;
+
+	default:
+		if_printf(ifp, "unknown opmode %d\n", opmode);
+		return NULL;
+	}
+
+	rvap = (struct rt2860_softc_vap *) malloc(sizeof(struct rt2860_softc_vap),
+		M_80211_VAP, M_NOWAIT | M_ZERO);
+	if (rvap == NULL)
+		return NULL;
+
+	vap = &rvap->vap;
+
+	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
+
+	rvap->newstate = vap->iv_newstate;
+	vap->iv_newstate = rt2860_vap_newstate;
+
+	vap->iv_reset = rt2860_vap_reset;
+#ifndef RT2860_NO_HW_CRYPTO
+	vap->iv_key_update_begin = rt2860_vap_key_update_begin;
+	vap->iv_key_update_end = rt2860_vap_key_update_end;
+	vap->iv_key_set = rt2860_vap_key_set;
+	vap->iv_key_delete = rt2860_vap_key_delete;
+#endif
+	vap->iv_update_beacon = rt2860_vap_update_beacon;
+
+	rt2860_amrr_init(&rvap->amrr, vap,
+		sc->ntxpath,
+		RT2860_AMRR_MIN_SUCCESS_THRESHOLD,
+		RT2860_AMRR_MAX_SUCCESS_THRESHOLD,
+		500);
+
+	vap->iv_max_aid = RT2860_SOFTC_STAID_COUNT;
+
+	/* overwrite default Rx A-MPDU factor */
+
+	vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_32K;
+	vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
+	vap->iv_ampdu_limit = vap->iv_ampdu_rxmax;
+
+	ieee80211_vap_attach(vap, rt2860_media_change, ieee80211_media_status);
+
+	switch (vap->iv_opmode) {
+	case IEEE80211_M_HOSTAP:
+	case IEEE80211_M_MBSS:
+	case IEEE80211_M_AHDEMO:
+		sc->napvaps++;
+		break;
+
+	case IEEE80211_M_IBSS:
+		sc->nadhocvaps++;
+		break;
+
+	case IEEE80211_M_STA:
+		sc->nstavaps++;
+		break;
+
+	case IEEE80211_M_WDS:
+		sc->nwdsvaps++;
+		break;
+
+	default:
+		break;
+	}
+
+	sc->nvaps++;
+
+	if (sc->napvaps > 0)
+		ic->ic_opmode = IEEE80211_M_HOSTAP;
+	else if (sc->nadhocvaps > 0)
+		ic->ic_opmode = IEEE80211_M_IBSS;
+	else if (sc->nstavaps > 0)
+		ic->ic_opmode = IEEE80211_M_STA;
+	else
+		ic->ic_opmode = opmode;
+
+	return vap;
+}
+
+/*
+ * rt2860_vap_delete
+ */
+static void rt2860_vap_delete(struct ieee80211vap *vap)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_vap *rvap;
+	enum ieee80211_opmode opmode;
+
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rvap = (struct rt2860_softc_vap *) vap;
+	opmode = vap->iv_opmode;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: VAP delete: opmode=%s\n",
+		device_get_nameunit(sc->sc_dev), ieee80211_opmode_name[opmode]);
+
+	rt2860_amrr_cleanup(&rvap->amrr);
+
+	ieee80211_vap_detach(vap);
+
+	if (rvap->beacon_mbuf != NULL) {
+		m_free(rvap->beacon_mbuf);
+		rvap->beacon_mbuf = NULL;
+	}
+
+	switch (opmode) {
+	case IEEE80211_M_HOSTAP:
+	case IEEE80211_M_MBSS:
+	case IEEE80211_M_AHDEMO:
+		sc->napvaps--;
+		break;
+	case IEEE80211_M_IBSS:
+		sc->nadhocvaps--;
+		break;
+	case IEEE80211_M_STA:
+		sc->nstavaps--;
+		break;
+	case IEEE80211_M_WDS:
+		sc->nwdsvaps--;
+		break;
+	default:
+		break;
+	}
+
+	sc->nvaps--;
+
+	if (sc->napvaps > 0)
+		ic->ic_opmode = IEEE80211_M_HOSTAP;
+	else if (sc->nadhocvaps > 0)
+		ic->ic_opmode = IEEE80211_M_IBSS;
+	else if (sc->nstavaps > 0)
+		ic->ic_opmode = IEEE80211_M_STA;
+
+	free(rvap, M_80211_VAP);
+}
+
+/*
+ * rt2860_reset_vap
+ */
+static int rt2860_vap_reset(struct ieee80211vap *vap, u_long cmd)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_vap *rvap;
+	int error;
+
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rvap = (struct rt2860_softc_vap *) vap;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: VAP reset: cmd=%lu\n",
+		device_get_nameunit(sc->sc_dev), cmd);
+
+	error = 0;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	switch (cmd){
+	case IEEE80211_IOC_RTSTHRESHOLD:
+	case IEEE80211_IOC_AMSDU:
+		rt2860_asic_update_rtsthreshold(sc);
+		break;
+	case IEEE80211_IOC_PROTMODE:
+	case IEEE80211_IOC_HTPROTMODE:
+		rt2860_asic_updateprot(sc);
+		break;
+	case IEEE80211_IOC_TXPOWER:
+		rt2860_asic_update_txpower(sc);
+		break;
+	case IEEE80211_IOC_BURST:
+		rt2860_asic_updateslot(sc);
+		break;
+	case IEEE80211_IOC_SHORTGI:
+	case IEEE80211_IOC_AMPDU_DENSITY:
+	case IEEE80211_IOC_SMPS:
+		break;
+	default:
+		error = ENETRESET;
+		break;
+	}
+
+	RT2860_SOFTC_UNLOCK(sc);
+
+	return error;
+}
+
+/*
+ * rt2860_vap_newstate
+ */
+static int rt2860_vap_newstate(struct ieee80211vap *vap,
+	enum ieee80211_state nstate, int arg)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_vap *rvap;
+	struct ieee80211_node *ni;
+	enum ieee80211_state ostate;
+	int error;
+
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rvap = (struct rt2860_softc_vap *) vap;
+
+	ostate = vap->iv_state;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: VAP newstate: %s -> %s\n",
+		device_get_nameunit(sc->sc_dev),
+		ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
+
+	error = rvap->newstate(vap, nstate, arg);
+	if (error != 0)
+		return error;
+
+	IEEE80211_UNLOCK(ic);
+
+	RT2860_SOFTC_LOCK(sc);
+
+	/* turn link LED off */
+
+	if (nstate != IEEE80211_S_RUN)
+		rt2860_led_cmd(sc, RT2860_LED_CMD_RADIO_OFF);
+
+	switch (nstate) {
+	case IEEE80211_S_INIT:
+		rt2860_asic_disable_tsf_sync(sc);
+		break;
+	case IEEE80211_S_RUN:
+		ni = vap->iv_bss;
+
+		rt2860_rf_set_chan(sc, ni->ni_chan);
+
+		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
+			rt2860_asic_enable_mrr(sc);
+			rt2860_asic_set_txpreamble(sc);
+			rt2860_asic_set_basicrates(sc);
+			rt2860_asic_update_txpower(sc);
+			rt2860_asic_set_bssid(sc, ni->ni_bssid);
+		}
+
+		if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
+	    	    vap->iv_opmode == IEEE80211_M_IBSS ||
+	    	    vap->iv_opmode == IEEE80211_M_MBSS) {
+			error = rt2860_beacon_alloc(sc, vap);
+			if (error != 0)
+				break;
+
+			rt2860_asic_update_beacon(sc, vap);
+		}
+
+		if (vap->iv_opmode != IEEE80211_M_MONITOR)
+			rt2860_asic_enable_tsf_sync(sc);
+
+		/* turn link LED on */
+		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
+			rt2860_led_cmd(sc, RT2860_LED_CMD_RADIO_ON |
+	    		(IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ?
+	     			RT2860_LED_CMD_LINK_2GHZ : RT2860_LED_CMD_LINK_5GHZ));
+		}
+		break;
+	case IEEE80211_S_SLEEP:
+		break;
+	default:
+		break;
+	}
+
+	RT2860_SOFTC_UNLOCK(sc);
+
+	IEEE80211_LOCK(ic);
+
+	return error;
+}
+
+#ifndef RT2860_NO_HW_CRYPTO
+/*
+ * rt2860_vap_key_update_begin
+ */
+static void rt2860_vap_key_update_begin(struct ieee80211vap *vap)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+		"%s: VAP key update begin\n",
+		device_get_nameunit(sc->sc_dev));
+
+	taskqueue_block(sc->taskqueue);
+
+	IF_LOCK(&ifp->if_snd);
+}
+
+/*
+ * rt2860_vap_key_update_end
+ */
+static void rt2860_vap_key_update_end(struct ieee80211vap *vap)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+		"%s: VAP key update end\n",
+		device_get_nameunit(sc->sc_dev));
+
+	IF_UNLOCK(&ifp->if_snd);
+
+	taskqueue_unblock(sc->taskqueue);
+}
+
+/*
+ * rt2860_vap_key_set
+ */
+static int rt2860_vap_key_set(struct ieee80211vap *vap,
+	const struct ieee80211_key *k, const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct ieee80211_node *ni;
+	struct rt2860_softc_node *rni;
+	uint16_t key_base, keymode_base;
+	uint8_t mode, vapid, wcid, iv[8];
+	uint32_t tmp;
+
+	switch (k->wk_cipher->ic_cipher) {
+	case IEEE80211_CIPHER_WEP:
+		if(k->wk_keylen < 8)
+			mode = RT2860_REG_CIPHER_MODE_WEP40;
+		else
+			mode = RT2860_REG_CIPHER_MODE_WEP104;
+		break;
+	case IEEE80211_CIPHER_TKIP:
+		mode = RT2860_REG_CIPHER_MODE_TKIP;
+		break;
+	case IEEE80211_CIPHER_AES_CCM:
+		mode = RT2860_REG_CIPHER_MODE_AES_CCMP;
+		break;
+	default:
+		printf("Wrong key CIPHER (%d)\n", k->wk_cipher->ic_cipher);
+		return 0;
+	}
+
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+		"%s: VAP key set: keyix=%d, keylen=%d, macaddr=%s, mode=%d, group=%d\n",
+		device_get_nameunit(sc->sc_dev), k->wk_keyix, k->wk_keylen, ether_sprintf(k->wk_macaddr),
+		mode, (k->wk_flags & IEEE80211_KEY_GROUP) ? 1 : 0);
+
+	if (!(k->wk_flags & IEEE80211_KEY_GROUP)) {
+		/* install pairwise key */
+
+		if (vap->iv_opmode == IEEE80211_M_HOSTAP)
+			ni = ieee80211_find_vap_node(&ic->ic_sta, vap, mac);
+		else
+			ni = vap->iv_bss;
+
+		rni = (struct rt2860_softc_node *) ni;
+
+		vapid = 0;
+		wcid = (ni != NULL) ? rni->staid : 0;
+		key_base = RT2860_REG_PKEY(wcid);
+
+		if (ni != NULL)
+			ieee80211_free_node(ni);
+
+		if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP) {
+			memset(iv, 0, 8);
+
+			iv[3] = (k->wk_keyix << 6);
+		} else {
+			if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
+				iv[0] = (k->wk_keytsc >> 8);
+				iv[1] = ((iv[0] | 0x20) & 0x7f);
+				iv[2] = k->wk_keytsc;
+			} else {
+				/* AES CCMP */
+				iv[0] = k->wk_keytsc;
+				iv[1] = k->wk_keytsc >> 8;
+				iv[2] = 0;
+			}
+
+			iv[3] = ((k->wk_keyix << 6) | IEEE80211_WEP_EXTIV);
+			iv[4] = (k->wk_keytsc >> 16);
+			iv[5] = (k->wk_keytsc >> 24);
+			iv[6] = (k->wk_keytsc >> 32);
+			iv[7] = (k->wk_keytsc >> 40);
+
+			RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+				"%s: VAP key set: iv=%02x %02x %02x %02x %02x %02x %02x %02x\n",
+				device_get_nameunit(sc->sc_dev),
+				iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);
+		}
+
+		rt2860_io_mac_write_multi(sc, RT2860_REG_IVEIV(wcid), iv, 8);
+
+		if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
+			rt2860_io_mac_write_multi(sc, key_base, k->wk_key, 16);
+
+			if (vap->iv_opmode != IEEE80211_M_HOSTAP) {
+				rt2860_io_mac_write_multi(sc, key_base + 16, &k->wk_key[16], 8);
+				rt2860_io_mac_write_multi(sc, key_base + 24, &k->wk_key[24], 8);
+			} else {
+				rt2860_io_mac_write_multi(sc, key_base + 16, &k->wk_key[24], 8);
+				rt2860_io_mac_write_multi(sc, key_base + 24, &k->wk_key[16], 8);
+			}
+		} else {
+			rt2860_io_mac_write_multi(sc, key_base, k->wk_key, k->wk_keylen);
+		}
+		tmp = ((vapid & RT2860_REG_VAP_MASK) << RT2860_REG_VAP_SHIFT) |
+			(mode << RT2860_REG_CIPHER_MODE_SHIFT) | RT2860_REG_PKEY_ENABLE;
+
+		rt2860_io_mac_write(sc, RT2860_REG_WCID_ATTR(wcid), tmp);
+	}
+
+	if ((k->wk_flags & IEEE80211_KEY_GROUP) ||
+		(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP)) {
+		/* install group key */
+
+		vapid = 0;
+		wcid = RT2860_WCID_MCAST;
+		key_base = RT2860_REG_SKEY(vapid, k->wk_keyix);
+		keymode_base = RT2860_REG_SKEY_MODE(vapid);
+
+		if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
+			rt2860_io_mac_write_multi(sc, key_base, k->wk_key, 16);
+
+			if (vap->iv_opmode != IEEE80211_M_HOSTAP) {
+				rt2860_io_mac_write_multi(sc, key_base + 16, &k->wk_key[16], 8);
+				rt2860_io_mac_write_multi(sc, key_base + 24, &k->wk_key[24], 8);
+			} else {
+				rt2860_io_mac_write_multi(sc, key_base + 16, &k->wk_key[24], 8);
+				rt2860_io_mac_write_multi(sc, key_base + 24, &k->wk_key[16], 8);
+			}
+		} else {
+			rt2860_io_mac_write_multi(sc, key_base, k->wk_key, k->wk_keylen);
+		}
+
+		tmp = rt2860_io_mac_read(sc, keymode_base);
+
+		tmp &= ~(0xf << (k->wk_keyix * 4 + 16 * (vapid % 2)));
+		tmp |= (mode << (k->wk_keyix * 4 + 16 * (vapid % 2)));
+
+		rt2860_io_mac_write(sc, keymode_base, tmp);
+
+		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+			if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP) {
+				memset(iv, 0, 8);
+
+				iv[3] = (k->wk_keyix << 6);
+			} else {
+				if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
+					iv[0] = (k->wk_keytsc >> 8);
+					iv[1] = ((iv[0] | 0x20) & 0x7f);
+					iv[2] = k->wk_keytsc;
+				} else {
+					/* AES CCMP */
+
+					iv[0] = k->wk_keytsc;
+					iv[1] = k->wk_keytsc >> 8;
+					iv[2] = 0;
+				}
+
+				iv[3] = ((k->wk_keyix << 6) | IEEE80211_WEP_EXTIV);
+				iv[4] = (k->wk_keytsc >> 16);
+				iv[5] = (k->wk_keytsc >> 24);
+				iv[6] = (k->wk_keytsc >> 32);
+				iv[7] = (k->wk_keytsc >> 40);
+
+				RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+					"%s: VAP key set: iv=%02x %02x %02x %02x %02x %02x %02x %02x\n",
+					device_get_nameunit(sc->sc_dev),
+					iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);
+			}
+
+			rt2860_io_mac_write_multi(sc, RT2860_REG_IVEIV(wcid), iv, 8);
+
+			tmp = ((vapid & RT2860_REG_VAP_MASK) << RT2860_REG_VAP_SHIFT) |
+				(mode << RT2860_REG_CIPHER_MODE_SHIFT);
+
+			rt2860_io_mac_write(sc, RT2860_REG_WCID_ATTR(wcid), tmp);
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * rt2860_vap_key_delete
+ */
+static int rt2860_vap_key_delete(struct ieee80211vap *vap,
+	const struct ieee80211_key *k)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	uint8_t vapid, wcid;
+	uint32_t tmp;
+
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+		"%s: VAP key delete: keyix=%d, keylen=%d, macaddr=%s, group=%d\n",
+		device_get_nameunit(sc->sc_dev), k->wk_keyix, k->wk_keylen, ether_sprintf(k->wk_macaddr),
+		(k->wk_flags & IEEE80211_KEY_GROUP) ? 1 : 0);
+
+	if (k->wk_flags & IEEE80211_KEY_GROUP) {
+		/* remove group key */
+
+		vapid = 0;
+		wcid = RT2860_WCID_MCAST;
+
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_SKEY_MODE(vapid));
+
+		tmp &= ~(0xf << (k->wk_keyix * 4 + 16 * (vapid % 2)));
+		tmp |= (RT2860_REG_CIPHER_MODE_NONE << (k->wk_keyix * 4 + 16 * (vapid % 2)));
+
+		rt2860_io_mac_write(sc, RT2860_REG_SKEY_MODE(vapid), tmp);
+
+		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+			tmp = ((vapid & RT2860_REG_VAP_MASK) << RT2860_REG_VAP_SHIFT) |
+				(RT2860_REG_CIPHER_MODE_NONE << RT2860_REG_CIPHER_MODE_SHIFT) | RT2860_REG_PKEY_ENABLE;
+
+			rt2860_io_mac_write(sc, RT2860_REG_WCID_ATTR(wcid), tmp);
+		}
+	}
+
+	return 1;
+}
+#endif
+
+/*
+ * rt2860_vap_update_beacon
+ */
+static void rt2860_vap_update_beacon(struct ieee80211vap *vap, int what)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_vap *rvap;
+	struct mbuf *m;
+	struct ieee80211_beacon_offsets *bo;
+	int error;
+
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rvap = (struct rt2860_softc_vap *) vap;
+	m = rvap->beacon_mbuf;
+	bo = &rvap->beacon_offsets;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BEACON,
+		"%s: VAP update beacon: what=%d\n",
+		device_get_nameunit(sc->sc_dev), what);
+
+	setbit(bo->bo_flags, what);
+
+	if (m == NULL) {
+		error = rt2860_beacon_alloc(sc, vap);
+		if (error != 0)
+			return;
+
+		m = rvap->beacon_mbuf;
+	}
+
+	ieee80211_beacon_update(vap->iv_bss, bo, m, 0);
+
+	rt2860_asic_update_beacon(sc, vap);
+}
+
+/*
+ * rt2860_media_change
+ */
+static int rt2860_media_change(struct ifnet *ifp)
+{
+	int error;
+
+	error = ieee80211_media_change(ifp);
+
+	return (error == ENETRESET ? 0 : error);
+}
+
+/*
+ * rt2860_node_alloc
+ */
+static struct ieee80211_node *rt2860_node_alloc(struct ieee80211vap *vap,
+	const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	return malloc(sizeof(struct rt2860_softc_node),
+		M_80211_NODE, M_NOWAIT | M_ZERO);
+}
+
+/*
+ * rt2860_node_cleanup
+ */
+static void rt2860_node_cleanup(struct ieee80211_node *ni)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_node *rni;
+	uint8_t vapid, wcid;
+	uint32_t tmp;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rni = (struct rt2860_softc_node *) ni;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_NODE,
+		"%s: node cleanup: macaddr=%s, associd=0x%04x, staid=0x%02x\n",
+		device_get_nameunit(sc->sc_dev), ether_sprintf(ni->ni_macaddr),
+		ni->ni_associd, rni->staid);
+
+	if (rni->staid != 0) {
+		vapid = 0;
+		wcid = rni->staid;
+
+		tmp = ((vapid & RT2860_REG_VAP_MASK) << RT2860_REG_VAP_SHIFT) |
+			(RT2860_REG_CIPHER_MODE_NONE << RT2860_REG_CIPHER_MODE_SHIFT) | RT2860_REG_PKEY_ENABLE;
+
+		rt2860_io_mac_write(sc, RT2860_REG_WCID_ATTR(wcid), tmp);
+
+		rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid), 0x00000000);
+		rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid) + 4, 0x00000000);
+
+		rt2860_staid_delete(sc, rni->staid);
+
+		rni->staid = 0;
+	}
+
+	sc->node_cleanup(ni);
+}
+
+/*
+ * rt2860_node_getmimoinfo
+ */
+static void rt2860_node_getmimoinfo(const struct ieee80211_node *ni,
+	struct ieee80211_mimo_info *mi)
+{
+	const struct rt2860_softc_node *rni;
+	int i;
+
+	rni = (const struct rt2860_softc_node *) ni;
+
+	for (i = 0; i < RT2860_SOFTC_RSSI_COUNT; i++) {
+		mi->rssi[i] = rni->last_rssi_dbm[i];
+		mi->noise[i] = RT2860_NOISE_FLOOR;
+	}
+}
+
+/*
+ * rt2860_setregdomain
+ */
+static int rt2860_setregdomain(struct ieee80211com *ic,
+	struct ieee80211_regdomain *reg,
+	int nchans, struct ieee80211_channel chans[])
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: set regulatory domain: country=%d, country code string=%c%c, location=%c\n",
+		device_get_nameunit(sc->sc_dev),
+		reg->country, reg->isocc[0], reg->isocc[1], reg->location);
+
+	return 0;
+}
+
+/*
+ * rt2860_getradiocaps
+ */
+static void rt2860_getradiocaps(struct ieee80211com *ic,
+	int maxchans, int *nchans, struct ieee80211_channel chans[])
+{
+	*nchans = (ic->ic_nchans >= maxchans) ? maxchans : ic->ic_nchans;
+
+	memcpy(chans, ic->ic_channels, (*nchans) * sizeof(struct ieee80211_channel));
+}
+
+/*
+ * rt2860_scan_start
+ */
+static void rt2860_scan_start(struct ieee80211com *ic)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	rt2860_asic_disable_tsf_sync(sc);
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_scan_end
+ */
+static void rt2860_scan_end(struct ieee80211com *ic)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	rt2860_asic_enable_tsf_sync(sc);
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_set_channel
+ */
+static void rt2860_set_channel(struct ieee80211com *ic)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_CHAN,
+		"%s: set channel: channel=%u, HT%s%s\n",
+		device_get_nameunit(sc->sc_dev),
+		ieee80211_chan2ieee(ic, ic->ic_curchan),
+		!IEEE80211_IS_CHAN_HT(ic->ic_curchan) ? " disabled" :
+			IEEE80211_IS_CHAN_HT20(ic->ic_curchan) ? "20":
+				IEEE80211_IS_CHAN_HT40U(ic->ic_curchan) ? "40U" : "40D",
+		(ic->ic_flags & IEEE80211_F_SCAN) ? ", scanning" : "");
+
+	RT2860_SOFTC_LOCK(sc);
+
+	rt2860_rf_set_chan(sc, ic->ic_curchan);
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_newassoc
+ */
+static void rt2860_newassoc(struct ieee80211_node *ni, int isnew)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct ieee80211vap *vap;
+	struct rt2860_softc_vap *rvap;
+	struct rt2860_softc_node *rni;
+	uint16_t aid;
+	uint8_t wcid;
+	uint32_t tmp;
+
+	vap = ni->ni_vap;
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rvap = (struct rt2860_softc_vap *) vap;
+	rni = (struct rt2860_softc_node *) ni;
+
+	if (isnew) {
+		aid = IEEE80211_AID(ni->ni_associd);
+		rni->staid = rt2860_staid_alloc(sc, aid);
+		wcid = rni->staid;
+
+		tmp = (ni->ni_macaddr[3] << 24) |
+			(ni->ni_macaddr[2] << 16) |
+			(ni->ni_macaddr[1] << 8) |
+			ni->ni_macaddr[0];
+
+		rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid), tmp);
+
+		tmp = (ni->ni_macaddr[5] << 8) |
+			ni->ni_macaddr[4];
+
+		rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid) + 4, tmp);
+
+		rt2860_amrr_node_init(&rvap->amrr, &sc->amrr_node[wcid], ni);
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_RATE,
+			"%s: initial%s node Tx rate: associd=0x%04x, rate=0x%02x, max rate=0x%02x\n",
+			device_get_nameunit(sc->sc_dev),
+			(ni->ni_flags & IEEE80211_NODE_HT) ? " HT" : "",
+			ni->ni_associd, ni->ni_txrate,
+			(ni->ni_flags & IEEE80211_NODE_HT) ?
+				(ni->ni_htrates.rs_rates[ni->ni_htrates.rs_nrates - 1] | IEEE80211_RATE_MCS) :
+				(ni->ni_rates.rs_rates[ni->ni_rates.rs_nrates - 1] & IEEE80211_RATE_VAL));
+
+		rt2860_asic_updateprot(sc);
+		rt2860_asic_updateslot(sc);
+		rt2860_asic_set_txpreamble(sc);
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_NODE,
+		"%s: new association: isnew=%d, macaddr=%s, associd=0x%04x, staid=0x%02x, QoS %s, ERP %s, HT %s\n",
+		device_get_nameunit(sc->sc_dev), isnew, ether_sprintf(ni->ni_macaddr),
+		ni->ni_associd, rni->staid,
+		(ni->ni_flags & IEEE80211_NODE_QOS) ? "enabled" : "disabled",
+		(ni->ni_flags & IEEE80211_NODE_ERP) ? "enabled" : "disabled",
+		(ni->ni_flags & IEEE80211_NODE_HT) ? "enabled" : "disabled");
+}
+
+/*
+ * rt2860_updateslot
+ */
+static void rt2860_updateslot(struct ifnet *ifp)
+{
+	struct rt2860_softc *sc;
+
+	sc = ifp->if_softc;
+
+	rt2860_asic_updateslot(sc);
+}
+
+/*
+ * rt2860_update_promisc
+ */
+static void rt2860_update_promisc(struct ifnet *ifp)
+{
+	struct rt2860_softc *sc;
+
+	sc = ifp->if_softc;
+
+	RT2860_SOFTC_LOCK(sc);
+	rt2860_asic_update_promisc(sc);
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_update_mcast
+ */
+static void rt2860_update_mcast(struct ifnet *ifp)
+{
+	struct rt2860_softc *sc;
+
+	sc = ifp->if_softc;
+}
+
+/*
+ * rt2860_wme_update
+ */
+static int rt2860_wme_update(struct ieee80211com *ic)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	rt2860_asic_wme_update(sc);
+
+	return 0;
+}
+
+/*
+ * rt2860_raw_xmit
+ */
+static int rt2860_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+	const struct ieee80211_bpf_params *params)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+
+	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+		m_freem(m);
+		ieee80211_free_node(ni);
+
+		return ENETDOWN;
+	}
+
+	RT2860_SOFTC_TX_RING_LOCK(&sc->tx_ring[sc->tx_ring_mgtqid]);
+
+	if (sc->tx_ring[sc->tx_ring_mgtqid].data_queued >= RT2860_SOFTC_TX_RING_DATA_COUNT) {
+		RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]);
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+			"%s: raw xmit: Tx ring with qid=%d is full\n",
+			device_get_nameunit(sc->sc_dev), sc->tx_ring_mgtqid);
+
+		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+
+		m_freem(m);
+		ieee80211_free_node(ni);
+
+		sc->tx_data_queue_full[sc->tx_ring_mgtqid]++;
+
+		return ENOBUFS;
+	}
+
+	if (rt2860_tx_mgmt(sc, m, ni, sc->tx_ring_mgtqid) != 0) {
+		RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]);
+
+		ifp->if_oerrors++;
+
+		ieee80211_free_node(ni);
+
+		return EIO;
+	}
+
+	RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]);
+
+	sc->tx_timer = RT2860_TX_WATCHDOG_TIMEOUT;
+
+	return 0;
+}
+
+/*
+ * rt2860_recv_action
+ */
+static int rt2860_recv_action(struct ieee80211_node *ni,
+	const struct ieee80211_frame *wh,
+	const uint8_t *frm, const uint8_t *efrm)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_node *rni;
+	const struct ieee80211_action *ia;
+	uint16_t baparamset;
+	uint8_t wcid;
+	int tid;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rni = (struct rt2860_softc_node *) ni;
+
+	ia = (const struct ieee80211_action *) frm;
+
+	if (ia->ia_category == IEEE80211_ACTION_CAT_BA) {
+		switch (ia->ia_action) {
+		/* IEEE80211_ACTION_BA_DELBA */
+		case IEEE80211_ACTION_BA_DELBA:
+			baparamset = LE_READ_2(frm + 2);
+			tid = RT2860_MS(baparamset, IEEE80211_BAPS_TID);
+			wcid = rni->staid;
+
+			RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+				"%s: received DELBA request: associd=0x%04x, staid=0x%02x, tid=%d\n",
+				device_get_nameunit(sc->sc_dev), ni->ni_associd, rni->staid, tid);
+
+			if (rni->staid != 0) {
+				RT2860_SOFTC_LOCK(sc);
+
+				rt2860_asic_del_ba_session(sc, wcid, tid);
+				RT2860_SOFTC_UNLOCK(sc);
+
+			}
+			break;
+		}
+	}
+
+	return sc->recv_action(ni, wh, frm, efrm);
+}
+
+/*
+ * rt2860_send_action
+ */
+static int rt2860_send_action(struct ieee80211_node *ni,
+	int cat, int act, void *sa)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_node *rni;
+	uint16_t *args, status, baparamset;
+	uint8_t wcid;
+	int tid, bufsize;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rni = (struct rt2860_softc_node *) ni;
+
+	wcid = rni->staid;
+	args = sa;
+
+	if (cat == IEEE80211_ACTION_CAT_BA) {
+		switch (act) {
+			/* IEEE80211_ACTION_BA_ADDBA_RESPONSE */
+			case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
+				status = args[1];
+				baparamset = args[2];
+				tid = RT2860_MS(baparamset, IEEE80211_BAPS_TID);
+				bufsize = RT2860_MS(baparamset, IEEE80211_BAPS_BUFSIZ);
+
+				RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+					"%s: sending ADDBA response: associd=0x%04x, staid=0x%02x, status=%d, tid=%d, bufsize=%d\n",
+					device_get_nameunit(sc->sc_dev), ni->ni_associd, rni->staid, status, tid, bufsize);
+
+				if (status == IEEE80211_STATUS_SUCCESS) {
+					RT2860_SOFTC_LOCK(sc);
+
+					rt2860_asic_add_ba_session(sc, wcid, tid);
+					RT2860_SOFTC_UNLOCK(sc);
+
+				}
+			break;
+
+			/* IEEE80211_ACTION_BA_DELBA */
+			case IEEE80211_ACTION_BA_DELBA:
+				baparamset = RT2860_SM(args[0], IEEE80211_DELBAPS_TID) | args[1];
+				tid = RT2860_MS(baparamset, IEEE80211_DELBAPS_TID);
+
+				RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+					"%s: sending DELBA request: associd=0x%04x, staid=0x%02x, tid=%d\n",
+					device_get_nameunit(sc->sc_dev), ni->ni_associd, rni->staid, tid);
+
+				if (RT2860_MS(baparamset, IEEE80211_DELBAPS_INIT) != IEEE80211_DELBAPS_INIT) {
+					RT2860_SOFTC_LOCK(sc);
+
+					rt2860_asic_del_ba_session(sc, wcid, tid);
+					RT2860_SOFTC_UNLOCK(sc);
+
+				}
+			break;
+		}
+	}
+
+	return sc->send_action(ni, cat, act, sa);
+}
+
+/*
+ * rt2860_addba_response
+ */
+static int rt2860_addba_response(struct ieee80211_node *ni,
+	struct ieee80211_tx_ampdu *tap,
+	int status, int baparamset, int batimeout)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_node *rni;
+	ieee80211_seq seqno;
+	int ret, tid, old_bufsize, new_bufsize;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rni = (struct rt2860_softc_node *) ni;
+
+	tid = RT2860_MS(baparamset, IEEE80211_BAPS_TID);
+	old_bufsize = RT2860_MS(baparamset, IEEE80211_BAPS_BUFSIZ);
+	new_bufsize = old_bufsize;
+
+	if (status == IEEE80211_STATUS_SUCCESS) {
+		if (sc->mac_rev >= 0x28830300) {
+			if (sc->mac_rev >= 0x30700200)
+				new_bufsize = 13;
+			else
+				new_bufsize = 31;
+		} else if (sc->mac_rev >= 0x28720200) {
+			new_bufsize = 13;
+		} else {
+			new_bufsize = 7;
+		}
+
+		if (old_bufsize > new_bufsize) {
+			baparamset &= ~IEEE80211_BAPS_BUFSIZ;
+			baparamset = RT2860_SM(new_bufsize, IEEE80211_BAPS_BUFSIZ);
+		}
+
+		if (!(tap->txa_flags & IEEE80211_AGGR_RUNNING)) {
+			sc->tx_ampdu_sessions++;
+
+			if (sc->tx_ampdu_sessions == 1) {
+				RT2860_SOFTC_LOCK(sc);
+
+				rt2860_asic_updateprot(sc);
+				RT2860_SOFTC_UNLOCK(sc);
+
+			}
+		}
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+		"%s: received ADDBA response: associd=0x%04x, staid=0x%02x, status=%d, tid=%d, "
+		"old bufsize=%d, new bufsize=%d\n",
+		device_get_nameunit(sc->sc_dev), ni->ni_associd, rni->staid, status, tid,
+		old_bufsize, new_bufsize);
+
+	ret = sc->addba_response(ni, tap, status, baparamset, batimeout);
+
+	if (status == IEEE80211_STATUS_SUCCESS) {
+		seqno = ni->ni_txseqs[tid];
+
+		rt2860_send_bar(ni, tap, seqno);
+	}
+
+	return ret;
+}
+
+/*
+ * rt2860_addba_stop
+ */
+static void rt2860_addba_stop(struct ieee80211_node *ni,
+	struct ieee80211_tx_ampdu *tap)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_node *rni;
+	int tid;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rni = (struct rt2860_softc_node *) ni;
+
+	tid = WME_AC_TO_TID(tap->txa_ac);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+		"%s: stopping A-MPDU Tx: associd=0x%04x, staid=0x%02x, tid=%d\n",
+		device_get_nameunit(sc->sc_dev), ni->ni_associd, rni->staid, tid);
+
+	if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
+		if (sc->tx_ampdu_sessions > 0) {
+			sc->tx_ampdu_sessions--;
+
+			if (sc->tx_ampdu_sessions == 0) {
+				RT2860_SOFTC_LOCK(sc);
+				rt2860_asic_updateprot(sc);
+				RT2860_SOFTC_UNLOCK(sc);
+			}
+		} else {
+			printf("%s: number of A-MPDU Tx sessions cannot be negative\n",
+				device_get_nameunit(sc->sc_dev));
+		}
+	}
+
+	sc->addba_stop(ni, tap);
+}
+
+/*
+ * rt2860_ampdu_rx_start
+ */
+static int rt2860_ampdu_rx_start(struct ieee80211_node *ni,
+	struct ieee80211_rx_ampdu *rap,
+	int baparamset, int batimeout, int baseqctl)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_node *rni;
+	int tid;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rni = (struct rt2860_softc_node *) ni;
+
+	tid = RT2860_MS(baparamset, IEEE80211_BAPS_TID);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+		"%s: starting A-MPDU Rx: associd=0x%04x, staid=0x%02x, tid=%d\n",
+		device_get_nameunit(sc->sc_dev), ni->ni_associd, rni->staid, tid);
+
+	if (!(rap->rxa_flags & IEEE80211_AGGR_RUNNING))
+		sc->rx_ampdu_sessions++;
+
+	return sc->ampdu_rx_start(ni, rap, baparamset, batimeout, baseqctl);
+}
+
+/*
+ * rt2860_ampdu_rx_stop
+ */
+static void rt2860_ampdu_rx_stop(struct ieee80211_node *ni,
+	struct ieee80211_rx_ampdu *rap)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct rt2860_softc_node *rni;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rni = (struct rt2860_softc_node *) ni;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+		"%s: stopping A-MPDU Rx: associd=0x%04x, staid=0x%02x\n",
+		device_get_nameunit(sc->sc_dev), ni->ni_associd, rni->staid);
+
+	if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
+		if (sc->rx_ampdu_sessions > 0)
+			sc->rx_ampdu_sessions--;
+		else
+			printf("%s: number of A-MPDU Rx sessions cannot be negative\n",
+				device_get_nameunit(sc->sc_dev));
+	}
+
+	sc->ampdu_rx_stop(ni, rap);
+}
+
+/*
+ * rt2860_send_bar
+ */
+static int rt2860_send_bar(struct ieee80211_node *ni,
+	struct ieee80211_tx_ampdu *tap, ieee80211_seq seqno)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct ieee80211vap *vap;
+	struct ieee80211_frame_bar *bar;
+	struct rt2860_softc_node *rni;
+	struct mbuf *m;
+	uint16_t barctl, barseqctl;
+	uint8_t *frm;
+	int ret, tid;
+
+	ic = ni->ni_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	vap = ni->ni_vap;
+	rni = (struct rt2860_softc_node *) ni;
+
+	if (!(tap->txa_flags & IEEE80211_AGGR_RUNNING))
+		return EINVAL;
+
+	m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(struct ieee80211_frame_bar));
+	if (m == NULL)
+		return ENOMEM;
+
+	bar = mtod(m, struct ieee80211_frame_bar *);
+
+	bar->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
+	bar->i_fc[1] = 0;
+
+	IEEE80211_ADDR_COPY(bar->i_ra, ni->ni_macaddr);
+	IEEE80211_ADDR_COPY(bar->i_ta, vap->iv_myaddr);
+
+	tid = WME_AC_TO_TID(tap->txa_ac);
+
+	barctl = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?  0 : IEEE80211_BAR_NOACK) |
+		IEEE80211_BAR_COMP |
+		RT2860_SM(tid, IEEE80211_BAR_TID);
+	barseqctl = RT2860_SM(seqno, IEEE80211_BAR_SEQ_START);
+
+	bar->i_ctl = htole16(barctl);
+	bar->i_seq = htole16(barseqctl);
+
+	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_bar);
+
+	tap->txa_start = seqno;
+
+	ieee80211_ref_node(ni);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+		"%s: sending BAR: associd=0x%04x, staid=0x%02x, tid=%d, seqno=%d\n",
+		device_get_nameunit(sc->sc_dev), ni->ni_associd, rni->staid, tid, seqno);
+
+	ret = ic->ic_raw_xmit(ni, m, NULL);
+	if (ret != 0)
+		ieee80211_free_node(ni);
+
+	return ret;
+}
+
+/*
+ * rt2860_amrr_update_iter_func
+ */
+static void rt2860_amrr_update_iter_func(void *arg, struct ieee80211_node *ni)
+{
+	struct rt2860_softc *sc;
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	struct ieee80211vap *vap;
+	struct rt2860_softc_vap *rvap;
+	struct rt2860_softc_node *rni;
+	uint8_t wcid;
+
+	vap = arg;
+	ic = vap->iv_ic;
+	ifp = ic->ic_ifp;
+	sc = ifp->if_softc;
+	rvap = (struct rt2860_softc_vap *) vap;
+	rni = (struct rt2860_softc_node *) ni;
+
+	/* only associated stations */
+
+	if ((ni->ni_vap == vap) && (rni->staid != 0)) {
+		wcid = rni->staid;
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_RATE,
+			"%s: AMRR node: staid=0x%02x, txcnt=%d, success=%d, retrycnt=%d\n",
+			device_get_nameunit(sc->sc_dev),
+			rni->staid, sc->amrr_node[wcid].txcnt, sc->amrr_node[wcid].success, sc->amrr_node[wcid].retrycnt);
+
+		rt2860_amrr_choose(ni, &sc->amrr_node[wcid]);
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_RATE,
+			"%s:%s node Tx rate: associd=0x%04x, staid=0x%02x, rate=0x%02x, max rate=0x%02x\n",
+			device_get_nameunit(sc->sc_dev),
+			(ni->ni_flags & IEEE80211_NODE_HT) ? " HT" : "",
+			ni->ni_associd, rni->staid, ni->ni_txrate,
+			(ni->ni_flags & IEEE80211_NODE_HT) ?
+				(ni->ni_htrates.rs_rates[ni->ni_htrates.rs_nrates - 1] | IEEE80211_RATE_MCS) :
+				(ni->ni_rates.rs_rates[ni->ni_rates.rs_nrates - 1] & IEEE80211_RATE_VAL));
+	}
+}
+
+/*
+ * rt2860_periodic
+ */
+static void rt2860_periodic(void *arg)
+{
+	struct rt2860_softc *sc;
+
+	sc = arg;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_PERIODIC,
+		"%s: periodic\n",
+		device_get_nameunit(sc->sc_dev));
+
+	taskqueue_enqueue(sc->taskqueue, &sc->periodic_task);
+}
+
+/*
+ * rt2860_tx_watchdog
+ */
+static void rt2860_tx_watchdog(void *arg)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+
+	sc = arg;
+	ifp = sc->sc_ifp;
+
+	if (sc->sc_invalid)		/* card ejected */
+		return;
+
+	if (sc->tx_timer == 0)
+		return;
+
+	if (--sc->tx_timer == 0) {
+		printf("%s: Tx watchdog timeout: resetting\n",
+			device_get_nameunit(sc->sc_dev));
+
+		rt2860_stop_locked(sc);
+		rt2860_init_locked(sc);
+
+		ifp->if_oerrors++;
+
+		sc->tx_watchdog_timeouts++;
+	}
+
+	callout_reset(&sc->tx_watchdog_ch, hz, rt2860_tx_watchdog, sc);
+}
+
+/*
+ * rt2860_staid_alloc
+ */
+static int rt2860_staid_alloc(struct rt2860_softc *sc, int aid)
+{
+	int staid;
+
+	if ((aid > 0 && aid < RT2860_SOFTC_STAID_COUNT) && isclr(sc->staid_mask, aid)) {
+		staid = aid;
+	} else {
+		for (staid = 1; staid < RT2860_SOFTC_STAID_COUNT; staid++) {
+			if (isclr(sc->staid_mask, staid))
+				break;
+		}
+	}
+
+	setbit(sc->staid_mask, staid);
+
+	return staid;
+}
+
+/*
+ * rt2860_staid_delete
+ */
+static void rt2860_staid_delete(struct rt2860_softc *sc, int staid)
+{
+
+	clrbit(sc->staid_mask, staid);
+}
+
+/*
+ * rt2860_asic_set_bssid
+ */
+static void rt2860_asic_set_bssid(struct rt2860_softc *sc,
+	const uint8_t *bssid)
+{
+	uint32_t tmp;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: set bssid: bssid=%s\n",
+		device_get_nameunit(sc->sc_dev),
+		ether_sprintf(bssid));
+
+	tmp = bssid[0] | (bssid[1]) << 8 | (bssid[2] << 16) | (bssid[3] << 24);
+
+	rt2860_io_mac_write(sc, RT2860_REG_BSSID_DW0, tmp);
+
+	tmp = bssid[4] | (bssid[5] << 8);
+
+	rt2860_io_mac_write(sc, RT2860_REG_BSSID_DW1, tmp);
+}
+
+/*
+ * rt2860_asic_set_macaddr
+ */
+static void rt2860_asic_set_macaddr(struct rt2860_softc *sc,
+	const uint8_t *addr)
+{
+	uint32_t tmp;
+
+	tmp = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
+
+	rt2860_io_mac_write(sc, RT2860_REG_ADDR_DW0, tmp);
+
+	tmp = addr[4] | (addr[5] << 8) | (0xff << 16);
+
+	rt2860_io_mac_write(sc, RT2860_REG_ADDR_DW1, tmp);
+}
+
+/*
+ * rt2860_asic_enable_tsf_sync
+ */
+static void rt2860_asic_enable_tsf_sync(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211vap *vap;
+	uint32_t tmp;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	vap = TAILQ_FIRST(&ic->ic_vaps);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BEACON,
+		"%s: enabling TSF\n",
+		device_get_nameunit(sc->sc_dev));
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_BCN_TIME_CFG);
+
+	tmp &= ~0x1fffff;
+	tmp |= vap->iv_bss->ni_intval * 16;
+	tmp |= (RT2860_REG_TSF_TIMER_ENABLE | RT2860_REG_TBTT_TIMER_ENABLE);
+
+	if (vap->iv_opmode == IEEE80211_M_STA) {
+		tmp |= (RT2860_REG_TSF_SYNC_MODE_STA << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+	} else if (vap->iv_opmode == IEEE80211_M_IBSS) {
+		tmp |= RT2860_REG_BCN_TX_ENABLE;
+		tmp |= (RT2860_REG_TSF_SYNC_MODE_IBSS << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+	} else if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+		tmp |= RT2860_REG_BCN_TX_ENABLE;
+		tmp |= (RT2860_REG_TSF_SYNC_MODE_HOSTAP << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_BCN_TIME_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_disable_tsf_sync
+ */
+static void rt2860_asic_disable_tsf_sync(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BEACON,
+		"%s: disabling TSF\n",
+		device_get_nameunit(sc->sc_dev));
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_BCN_TIME_CFG);
+
+	tmp &= ~(RT2860_REG_BCN_TX_ENABLE |
+		RT2860_REG_TSF_TIMER_ENABLE |
+		RT2860_REG_TBTT_TIMER_ENABLE);
+
+	tmp &= ~(RT2860_REG_TSF_SYNC_MODE_MASK << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+	tmp |= (RT2860_REG_TSF_SYNC_MODE_DISABLE << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+
+	rt2860_io_mac_write(sc, RT2860_REG_BCN_TIME_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_enable_mrr
+ */
+static void rt2860_asic_enable_mrr(struct rt2860_softc *sc)
+{
+#define CCK(mcs)	(mcs)
+#define OFDM(mcs)	((1 << 3) | (mcs))
+#define HT(mcs)		(mcs)
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_LG_FBK_CFG0,
+		(OFDM(6) << 28) |	/* 54 -> 48 */
+		(OFDM(5) << 24) |	/* 48 -> 36 */
+		(OFDM(4) << 20) |	/* 36 -> 24 */
+		(OFDM(3) << 16) |	/* 24 -> 18 */
+		(OFDM(2) << 12) |	/* 18 -> 12 */
+		(OFDM(1) << 8)  |	/* 12 -> 9 */
+		(OFDM(0) << 4)  |	/*  9 -> 6 */
+		OFDM(0));			/*  6 -> 6 */
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_LG_FBK_CFG1,
+		(CCK(2) << 12) |	/* 11  -> 5.5 */
+		(CCK(1) << 8)  |	/* 5.5 -> 2 */
+		(CCK(0) << 4)  |	/*   2 -> 1 */
+		CCK(0));			/*   1 -> 1 */
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_HT_FBK_CFG0,
+		(HT(6) << 28) |
+		(HT(5) << 24) |
+		(HT(4) << 20) |
+		(HT(3) << 16) |
+		(HT(2) << 12) |
+		(HT(1) << 8)  |
+		(HT(0) << 4)  |
+		HT(0));
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_HT_FBK_CFG1,
+		(HT(14) << 28) |
+		(HT(13) << 24) |
+		(HT(12) << 20) |
+		(HT(11) << 16) |
+		(HT(10) << 12) |
+		(HT(9) << 8)   |
+		(HT(8) << 4)   |
+		HT(7));
+
+#undef HT
+#undef OFDM
+#undef CCK
+}
+
+/*
+ * rt2860_asic_set_txpreamble
+ */
+static void rt2860_asic_set_txpreamble(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	uint32_t tmp;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: %s short Tx preamble\n",
+		device_get_nameunit(sc->sc_dev),
+		(ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "enabling" : "disabling");
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_AUTO_RSP_CFG);
+
+	tmp &= ~RT2860_REG_CCK_SHORT_ENABLE;
+
+	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+		tmp |= RT2860_REG_CCK_SHORT_ENABLE;
+
+	rt2860_io_mac_write(sc, RT2860_REG_AUTO_RSP_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_set_basicrates
+ */
+static void rt2860_asic_set_basicrates(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	if (ic->ic_curmode == IEEE80211_MODE_11B)
+		rt2860_io_mac_write(sc, RT2860_REG_LEGACY_BASIC_RATE, 0xf);
+	else if (ic->ic_curmode == IEEE80211_MODE_11A)
+		rt2860_io_mac_write(sc, RT2860_REG_LEGACY_BASIC_RATE, 0x150);
+	else
+		rt2860_io_mac_write(sc, RT2860_REG_LEGACY_BASIC_RATE, 0x15f);
+}
+
+/*
+ * rt2860_asic_update_rtsthreshold
+ */
+static void rt2860_asic_update_rtsthreshold(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211vap *vap;
+	uint32_t tmp;
+	uint16_t threshold;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	vap = TAILQ_FIRST(&ic->ic_vaps);
+
+	if (vap == NULL)
+		threshold = IEEE80211_RTS_MAX;
+	else if (vap->iv_flags_ht & IEEE80211_FHT_AMSDU_TX)
+		threshold = 0x1000;
+	else
+		threshold = vap->iv_rtsthreshold;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+		"%s: updating RTS threshold: %d\n",
+		device_get_nameunit(sc->sc_dev), threshold);
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_RTS_CFG);
+
+	tmp &= ~(RT2860_REG_TX_RTS_THRESHOLD_MASK << RT2860_REG_TX_RTS_THRESHOLD_SHIFT);
+
+	tmp |= ((threshold & RT2860_REG_TX_RTS_THRESHOLD_MASK) <<
+		RT2860_REG_TX_RTS_THRESHOLD_SHIFT);
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_RTS_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_update_txpower
+ */
+static void rt2860_asic_update_txpower(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	uint32_t *txpow_rate;
+	int8_t delta;
+	uint8_t val;
+	uint32_t tmp;
+	int i;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: updating Tx power: %d\n",
+		device_get_nameunit(sc->sc_dev), ic->ic_txpowlimit);
+
+	if (!IEEE80211_IS_CHAN_HT40(ic->ic_curchan)) {
+		txpow_rate = sc->txpow_rate_20mhz;
+	} else {
+		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+			txpow_rate = sc->txpow_rate_40mhz_2ghz;
+		else
+			txpow_rate = sc->txpow_rate_40mhz_5ghz;
+	}
+
+	delta = 0;
+
+	val = rt2860_io_bbp_read(sc, 1);
+	val &= 0xfc;
+
+	if (ic->ic_txpowlimit > 90) {
+		/* do nothing */
+	} else if (ic->ic_txpowlimit > 60) {
+		delta -= 1;
+	} else if (ic->ic_txpowlimit > 30) {
+		delta -= 3;
+	} else if (ic->ic_txpowlimit > 15) {
+		val |= 0x1;
+	} else if (ic->ic_txpowlimit > 9) {
+		val |= 0x1;
+		delta -= 3;
+	} else {
+		val |= 0x2;
+	}
+
+	rt2860_io_bbp_write(sc, 1, val);
+
+	for (i = 0; i < RT2860_SOFTC_TXPOW_RATE_COUNT; i++) {
+		if (txpow_rate[i] == 0xffffffff)
+			continue;
+		tmp = rt2860_read_eeprom_txpow_rate_add_delta(txpow_rate[i], delta);
+		rt2860_io_mac_write(sc, RT2860_REG_TX_PWR_CFG(i), tmp);
+	}
+}
+
+/*
+ * rt2860_asic_update_promisc
+ */
+static void rt2860_asic_update_promisc(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	uint32_t tmp;
+
+	ifp = sc->sc_ifp;
+
+	printf("%s: %s promiscuous mode\n",
+		device_get_nameunit(sc->sc_dev),
+		(ifp->if_flags & IFF_PROMISC) ? "entering" : "leaving");
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_RX_FILTER_CFG);
+
+	tmp &= ~RT2860_REG_RX_FILTER_DROP_UC_NOME;
+
+	if (!(ifp->if_flags & IFF_PROMISC))
+		tmp |= RT2860_REG_RX_FILTER_DROP_UC_NOME;
+
+	rt2860_io_mac_write(sc, RT2860_REG_RX_FILTER_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_updateprot
+ */
+static void rt2860_asic_updateprot(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211vap *vap;
+	uint32_t cck_prot, ofdm_prot, mm20_prot, mm40_prot, gf20_prot, gf40_prot;
+	uint8_t htopmode;
+	enum ieee80211_protmode htprotmode;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	vap = TAILQ_FIRST(&ic->ic_vaps);
+
+	/* CCK frame protection */
+
+	cck_prot = RT2860_REG_RTSTH_ENABLE | RT2860_REG_PROT_NAV_SHORT |
+		RT2860_REG_TXOP_ALLOW_ALL | RT2860_REG_PROT_CTRL_NONE;
+
+	/* set up protection frame phy mode and rate (MCS code) */
+
+	if (ic->ic_curmode == IEEE80211_MODE_11A)
+		cck_prot |= (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+			(0 << RT2860_REG_PROT_MCS_SHIFT);
+	else
+		cck_prot |= ((RT2860_REG_PROT_PHYMODE_CCK << RT2860_REG_PROT_PHYMODE_SHIFT) |
+			(3 << RT2860_REG_PROT_MCS_SHIFT));
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_CCK_PROT_CFG, cck_prot);
+
+	/* OFDM frame protection */
+
+	ofdm_prot = RT2860_REG_RTSTH_ENABLE | RT2860_REG_PROT_NAV_SHORT |
+		RT2860_REG_TXOP_ALLOW_ALL;
+
+	if (ic->ic_flags & IEEE80211_F_USEPROT) {
+		RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+			"%s: updating protection mode: b/g protection mode=%s\n",
+			device_get_nameunit(sc->sc_dev),
+			(ic->ic_protmode == IEEE80211_PROT_RTSCTS) ? "RTS/CTS" :
+				((ic->ic_protmode == IEEE80211_PROT_CTSONLY) ? "CTS-to-self" : "none"));
+
+		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+			ofdm_prot |= RT2860_REG_PROT_CTRL_RTS_CTS;
+		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+			ofdm_prot |= RT2860_REG_PROT_CTRL_CTS;
+		else
+			ofdm_prot |= RT2860_REG_PROT_CTRL_NONE;
+	} else {
+		RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+			"%s: updating protection mode: b/g protection mode=%s\n",
+			device_get_nameunit(sc->sc_dev), "none");
+
+		ofdm_prot |= RT2860_REG_PROT_CTRL_NONE;
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_OFDM_PROT_CFG, ofdm_prot);
+
+	/* HT frame protection */
+
+	if ((vap != NULL) && (vap->iv_opmode == IEEE80211_M_STA) && (vap->iv_state == IEEE80211_S_RUN))
+		htopmode = vap->iv_bss->ni_htopmode;
+	else
+		htopmode = ic->ic_curhtprotmode;
+
+	htprotmode = ic->ic_htprotmode;
+
+	/* force HT mixed mode and RTS/CTS protection if A-MPDU Tx aggregation is enabled */
+
+	if (sc->tx_ampdu_sessions > 0) {
+		RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+			"%s: updating protection mode: forcing HT mixed mode and RTS/CTS protection\n",
+			device_get_nameunit(sc->sc_dev));
+
+		htopmode = IEEE80211_HTINFO_OPMODE_MIXED;
+		htprotmode = IEEE80211_PROT_RTSCTS;
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+		"%s: updating protection mode: HT operation mode=0x%02x, protection mode=%s\n",
+		device_get_nameunit(sc->sc_dev),
+		htopmode & IEEE80211_HTINFO_OPMODE,
+		(htprotmode == IEEE80211_PROT_RTSCTS) ? "RTS/CTS" :
+			((htprotmode == IEEE80211_PROT_CTSONLY) ? "CTS-to-self" : "none"));
+
+	switch (htopmode & IEEE80211_HTINFO_OPMODE) {
+	/* IEEE80211_HTINFO_OPMODE_HT20PR */
+	case IEEE80211_HTINFO_OPMODE_HT20PR:
+		mm20_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_PROT_CTRL_NONE |
+			RT2860_REG_TXOP_ALLOW_CCK | RT2860_REG_TXOP_ALLOW_OFDM |
+			RT2860_REG_TXOP_ALLOW_MM20 | RT2860_REG_TXOP_ALLOW_GF20 |
+			(RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+			(4 << RT2860_REG_PROT_MCS_SHIFT);
+
+		gf20_prot = mm20_prot;
+
+		mm40_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_TXOP_ALLOW_ALL |
+			(RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+			(0x84 << RT2860_REG_PROT_MCS_SHIFT);
+
+		if (htprotmode == IEEE80211_PROT_RTSCTS)
+			mm40_prot |= RT2860_REG_PROT_CTRL_RTS_CTS;
+		else if (htprotmode == IEEE80211_PROT_CTSONLY)
+			mm40_prot |= RT2860_REG_PROT_CTRL_CTS;
+		else
+			mm40_prot |= RT2860_REG_PROT_CTRL_NONE;
+
+		gf40_prot = mm40_prot;
+		break;
+
+	/* IEEE80211_HTINFO_OPMODE_MIXED */
+	case IEEE80211_HTINFO_OPMODE_MIXED:
+		mm20_prot = RT2860_REG_PROT_NAV_SHORT |
+			RT2860_REG_TXOP_ALLOW_CCK | RT2860_REG_TXOP_ALLOW_OFDM |
+			RT2860_REG_TXOP_ALLOW_MM20 | RT2860_REG_TXOP_ALLOW_GF20;
+
+		if (ic->ic_flags & IEEE80211_F_USEPROT)
+			mm20_prot |= (RT2860_REG_PROT_PHYMODE_CCK << RT2860_REG_PROT_PHYMODE_SHIFT) |
+				(3 << RT2860_REG_PROT_MCS_SHIFT);
+		else
+			mm20_prot |= (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+				(4 << RT2860_REG_PROT_MCS_SHIFT);
+
+		if (htprotmode == IEEE80211_PROT_RTSCTS)
+			mm20_prot |= RT2860_REG_PROT_CTRL_RTS_CTS;
+		else if (htprotmode == IEEE80211_PROT_CTSONLY)
+			mm20_prot |= RT2860_REG_PROT_CTRL_CTS;
+		else
+			mm20_prot |= RT2860_REG_PROT_CTRL_NONE;
+
+		gf20_prot = mm20_prot;
+
+		mm40_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_TXOP_ALLOW_ALL;
+
+		if (ic->ic_flags & IEEE80211_F_USEPROT)
+			mm40_prot |= (RT2860_REG_PROT_PHYMODE_CCK << RT2860_REG_PROT_PHYMODE_SHIFT) |
+				(3 << RT2860_REG_PROT_MCS_SHIFT);
+		else
+			mm40_prot |= (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+				(0x84 << RT2860_REG_PROT_MCS_SHIFT);
+
+		if (htprotmode == IEEE80211_PROT_RTSCTS)
+			mm40_prot |= RT2860_REG_PROT_CTRL_RTS_CTS;
+		else if (htprotmode == IEEE80211_PROT_CTSONLY)
+			mm40_prot |= RT2860_REG_PROT_CTRL_CTS;
+		else
+			mm40_prot |= RT2860_REG_PROT_CTRL_NONE;
+
+		gf40_prot = mm40_prot;
+		break;
+
+	/*
+	 * IEEE80211_HTINFO_OPMODE_PURE
+	 * IEEE80211_HTINFO_OPMODE_PROTOPT
+	 */
+	case IEEE80211_HTINFO_OPMODE_PURE:
+	case IEEE80211_HTINFO_OPMODE_PROTOPT:
+	default:
+		mm20_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_PROT_CTRL_NONE |
+			RT2860_REG_TXOP_ALLOW_CCK | RT2860_REG_TXOP_ALLOW_OFDM |
+			RT2860_REG_TXOP_ALLOW_MM20 | RT2860_REG_TXOP_ALLOW_GF20 |
+			(RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+			(4 << RT2860_REG_PROT_MCS_SHIFT);
+
+		gf20_prot = mm20_prot;
+
+		mm40_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_PROT_CTRL_NONE |
+			RT2860_REG_TXOP_ALLOW_ALL |
+			(RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+			(0x84 << RT2860_REG_PROT_MCS_SHIFT);
+
+		gf40_prot = mm40_prot;
+		break;
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_MM20_PROT_CFG, mm20_prot);
+	rt2860_io_mac_write(sc, RT2860_REG_TX_MM40_PROT_CFG, mm40_prot);
+	rt2860_io_mac_write(sc, RT2860_REG_TX_GF20_PROT_CFG, gf20_prot);
+	rt2860_io_mac_write(sc, RT2860_REG_TX_GF40_PROT_CFG, gf40_prot);
+}
+
+/*
+ * rt2860_asic_updateslot
+ */
+static void rt2860_asic_updateslot(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211vap *vap;
+	uint32_t tmp;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	vap = TAILQ_FIRST(&ic->ic_vaps);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+		"%s: %s short slot time\n",
+		device_get_nameunit(sc->sc_dev),
+		((ic->ic_flags & IEEE80211_F_SHSLOT) ||
+		 ((vap != NULL) && (vap->iv_flags & IEEE80211_F_BURST))) ? "enabling" : "disabling");
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_BKOFF_SLOT_CFG);
+
+	tmp &= ~0xff;
+
+	if ((ic->ic_flags & IEEE80211_F_SHSLOT) ||
+		((vap != NULL) && (vap->iv_flags & IEEE80211_F_BURST)))
+		tmp |= IEEE80211_DUR_SHSLOT;
+	else
+		tmp |= IEEE80211_DUR_SLOT;
+
+	rt2860_io_mac_write(sc, RT2860_REG_BKOFF_SLOT_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_wme_update
+ */
+static void rt2860_asic_wme_update(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211_wme_state *wme;
+	const struct wmeParams *wmep;
+	int i;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	wme = &ic->ic_wme;
+	wmep = wme->wme_chanParams.cap_wmeParams;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_WME,
+		"%s: wme update: WME_AC_VO=%d/%d/%d/%d, WME_AC_VI=%d/%d/%d/%d, "
+		"WME_AC_BK=%d/%d/%d/%d, WME_AC_BE=%d/%d/%d/%d\n",
+		device_get_nameunit(sc->sc_dev),
+		wmep[WME_AC_VO].wmep_aifsn,
+		wmep[WME_AC_VO].wmep_logcwmin, wmep[WME_AC_VO].wmep_logcwmax,
+		wmep[WME_AC_VO].wmep_txopLimit,
+		wmep[WME_AC_VI].wmep_aifsn,
+		wmep[WME_AC_VI].wmep_logcwmin, wmep[WME_AC_VI].wmep_logcwmax,
+		wmep[WME_AC_VI].wmep_txopLimit,
+		wmep[WME_AC_BK].wmep_aifsn,
+		wmep[WME_AC_BK].wmep_logcwmin, wmep[WME_AC_BK].wmep_logcwmax,
+		wmep[WME_AC_BK].wmep_txopLimit,
+		wmep[WME_AC_BE].wmep_aifsn,
+		wmep[WME_AC_BE].wmep_logcwmin, wmep[WME_AC_BE].wmep_logcwmax,
+		wmep[WME_AC_BE].wmep_txopLimit);
+
+	for (i = 0; i < WME_NUM_AC; i++)
+		rt2860_io_mac_write(sc, RT2860_REG_TX_EDCA_AC_CFG(i),
+			(wmep[i].wmep_logcwmax << 16) | (wmep[i].wmep_logcwmin << 12) |
+			(wmep[i].wmep_aifsn << 8) | wmep[i].wmep_txopLimit);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_AIFSN_CFG,
+		(wmep[WME_AC_VO].wmep_aifsn << 12) | (wmep[WME_AC_VI].wmep_aifsn << 8) |
+		(wmep[WME_AC_BK].wmep_aifsn << 4) | wmep[WME_AC_BE].wmep_aifsn);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_CWMIN_CFG,
+		(wmep[WME_AC_VO].wmep_logcwmin << 12) | (wmep[WME_AC_VI].wmep_logcwmin << 8) |
+		(wmep[WME_AC_BK].wmep_logcwmin << 4) | wmep[WME_AC_BE].wmep_logcwmin);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_CWMAX_CFG,
+		(wmep[WME_AC_VO].wmep_logcwmax << 12) | (wmep[WME_AC_VI].wmep_logcwmax << 8) |
+		(wmep[WME_AC_BK].wmep_logcwmax << 4) | wmep[WME_AC_BE].wmep_logcwmax);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_TXOP0_CFG,
+		(wmep[WME_AC_BK].wmep_txopLimit << 16) | wmep[WME_AC_BE].wmep_txopLimit);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_TXOP1_CFG,
+		(wmep[WME_AC_VO].wmep_txopLimit << 16) | wmep[WME_AC_VI].wmep_txopLimit);
+}
+
+/*
+ * rt2860_asic_update_beacon
+ */
+static void rt2860_asic_update_beacon(struct rt2860_softc *sc,
+	struct ieee80211vap *vap)
+{
+	struct rt2860_softc_vap *rvap;
+	struct mbuf *m;
+	struct rt2860_txwi *txwi;
+	uint32_t tmp;
+
+	rvap = (struct rt2860_softc_vap *) vap;
+
+	m = rvap->beacon_mbuf;
+	txwi = &rvap->beacon_txwi;
+
+	/* disable temporarily TSF sync */
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_BCN_TIME_CFG);
+
+	tmp &= ~(RT2860_REG_BCN_TX_ENABLE |
+		RT2860_REG_TSF_TIMER_ENABLE |
+		RT2860_REG_TBTT_TIMER_ENABLE);
+
+	rt2860_io_mac_write(sc, RT2860_REG_BCN_TIME_CFG, tmp);
+
+	/* write Tx wireless info and beacon frame to on-chip memory */
+
+	rt2860_io_mac_write_multi(sc, RT2860_REG_BEACON_BASE(0),
+		txwi, sizeof(struct rt2860_txwi));
+
+	rt2860_io_mac_write_multi(sc, RT2860_REG_BEACON_BASE(0) + sizeof(struct rt2860_txwi),
+		mtod(m, uint8_t *), m->m_pkthdr.len);
+
+	/* enable again TSF sync */
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_BCN_TIME_CFG);
+
+	tmp |= (RT2860_REG_BCN_TX_ENABLE |
+		RT2860_REG_TSF_TIMER_ENABLE |
+		RT2860_REG_TBTT_TIMER_ENABLE);
+
+	rt2860_io_mac_write(sc, RT2860_REG_BCN_TIME_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_clear_keytables
+ */
+static void rt2860_asic_clear_keytables(struct rt2860_softc *sc)
+{
+	int i;
+
+	/* clear Rx WCID search table (entries = 256, entry size = 8) */
+
+	for (i = 0; i < 256; i++) {
+		rt2860_io_mac_write(sc, RT2860_REG_WCID(i), 0xffffffff);
+		rt2860_io_mac_write(sc, RT2860_REG_WCID(i) + 4, 0x0000ffff);
+	}
+
+	/* clear WCID attribute table (entries = 256, entry size = 4) */
+
+	rt2860_io_mac_set_region_4(sc, RT2860_REG_WCID_ATTR(0), RT2860_REG_PKEY_ENABLE, 256);
+
+	/* clear IV/EIV table (entries = 256, entry size = 8) */
+
+	rt2860_io_mac_set_region_4(sc, RT2860_REG_IVEIV(0), 0, 2 * 256);
+
+	/* clear pairwise key table (entries = 64, entry size = 32) */
+
+	rt2860_io_mac_set_region_4(sc, RT2860_REG_PKEY(0), 0, 8 * 64);
+
+	/* clear shared key table (entries = 32, entry size = 32) */
+
+	rt2860_io_mac_set_region_4(sc, RT2860_REG_SKEY(0, 0), 0, 8 * 32);
+
+	/* clear shared key mode (entries = 32, entry size = 2) */
+
+	rt2860_io_mac_set_region_4(sc, RT2860_REG_SKEY_MODE(0), 0, 16);
+}
+
+/*
+ * rt2860_asic_add_ba_session
+ */
+static void rt2860_asic_add_ba_session(struct rt2860_softc *sc,
+	uint8_t wcid, int tid)
+{
+	uint32_t tmp;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+		"%s: adding BA session: wcid=0x%02x, tid=%d\n",
+		device_get_nameunit(sc->sc_dev), wcid, tid);
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_WCID(wcid) + 4);
+
+	tmp |= (0x10000 << tid);
+
+	rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid) + 4, tmp);
+}
+
+/*
+ * rt2860_asic_del_ba_session
+ */
+static void rt2860_asic_del_ba_session(struct rt2860_softc *sc,
+	uint8_t wcid, int tid)
+{
+	uint32_t tmp;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+		"%s: deleting BA session: wcid=0x%02x, tid=%d\n",
+		device_get_nameunit(sc->sc_dev), wcid, tid);
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_WCID(wcid) + 4);
+
+	tmp &= ~(0x10000 << tid);
+
+	rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid) + 4, tmp);
+}
+
+/*
+ * rt2860_beacon_alloc
+ */
+static int rt2860_beacon_alloc(struct rt2860_softc *sc,
+	struct ieee80211vap *vap)
+{
+	struct ieee80211com *ic;
+	struct rt2860_softc_vap *rvap;
+	struct mbuf *m;
+	struct rt2860_txwi txwi;
+	uint8_t rate, mcs;
+
+	ic = vap->iv_ic;
+	rvap = (struct rt2860_softc_vap *) vap;
+
+	m = ieee80211_beacon_alloc(vap->iv_bss, &rvap->beacon_offsets);
+	if (m == NULL)
+		return ENOMEM;
+
+	rate = IEEE80211_IS_CHAN_5GHZ(vap->iv_bss->ni_chan) ? 12 : 2;
+	mcs = rt2860_rate2mcs(rate);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_BEACON,
+		"%s: beacon allocate: mcs=0x%02x\n",
+		device_get_nameunit(sc->sc_dev), mcs);
+
+	memset(&txwi, 0, sizeof(struct rt2860_txwi));
+
+	txwi.wcid = RT2860_WCID_RESERVED;
+	txwi.pid_mpdu_len = ((htole16(m->m_pkthdr.len) & RT2860_TXWI_MPDU_LEN_MASK) <<
+		 RT2860_TXWI_MPDU_LEN_SHIFT);
+	txwi.txop = (RT2860_TXWI_TXOP_HT << RT2860_TXWI_TXOP_SHIFT);
+	txwi.mpdu_density_flags |=
+		(RT2860_TXWI_FLAGS_TS << RT2860_TXWI_FLAGS_SHIFT);
+	txwi.bawin_size_xflags |=
+		(RT2860_TXWI_XFLAGS_NSEQ << RT2860_TXWI_XFLAGS_SHIFT);
+
+	if (rate == 2) {
+		txwi.phymode_ifs_stbc_shortgi =
+			(RT2860_TXWI_PHYMODE_CCK << RT2860_TXWI_PHYMODE_SHIFT);
+
+		if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+			mcs |= RT2860_TXWI_MCS_SHOTPRE;
+	} else {
+		txwi.phymode_ifs_stbc_shortgi =
+			(RT2860_TXWI_PHYMODE_OFDM << RT2860_TXWI_PHYMODE_SHIFT);
+	}
+
+	txwi.bw_mcs = (RT2860_TXWI_BW_20 << RT2860_TXWI_BW_SHIFT) |
+		((mcs & RT2860_TXWI_MCS_MASK) << RT2860_TXWI_MCS_SHIFT);
+
+	if (rvap->beacon_mbuf != NULL) {
+		m_free(rvap->beacon_mbuf);
+		rvap->beacon_mbuf = NULL;
+	}
+
+	rvap->beacon_mbuf = m;
+	rvap->beacon_txwi = txwi;
+
+	return 0;
+}
+
+/*
+ * rt2860_rxrate
+ */
+static uint8_t rt2860_rxrate(struct rt2860_rxwi *rxwi)
+{
+	uint8_t mcs, phymode;
+	uint8_t rate;
+
+	mcs = (rxwi->bw_mcs >> RT2860_RXWI_MCS_SHIFT) & RT2860_RXWI_MCS_MASK;
+	phymode = (rxwi->phymode_stbc_shortgi >> RT2860_RXWI_PHYMODE_SHIFT) &
+		RT2860_RXWI_PHYMODE_MASK;
+
+	rate = 2;
+
+	switch (phymode) {
+	case RT2860_RXWI_PHYMODE_CCK:
+		switch (mcs & ~RT2860_RXWI_MCS_SHOTPRE) {
+		case 0: rate = 2; break;	/* 1 Mbps */
+		case 1: rate = 4; break;	/* 2 MBps */
+		case 2: rate = 11; break;	/* 5.5 Mbps */
+		case 3: rate = 22; break;	/* 11 Mbps */
+		}
+		break;
+
+	case RT2860_RXWI_PHYMODE_OFDM:
+		switch (mcs) {
+		case 0: rate = 12; break;	/* 6 Mbps */
+		case 1: rate = 18; break;	/* 9 Mbps */
+		case 2: rate = 24; break;	/* 12 Mbps */
+		case 3: rate = 36; break;	/* 18 Mbps */
+		case 4: rate = 48; break;	/* 24 Mbps */
+		case 5: rate = 72; break;	/* 36 Mbps */
+		case 6: rate = 96; break;	/* 48 Mbps */
+		case 7: rate = 108; break;	/* 54 Mbps */
+		}
+		break;
+
+	case RT2860_RXWI_PHYMODE_HT_MIXED:
+	case RT2860_RXWI_PHYMODE_HT_GF:
+		break;
+	}
+
+	return rate;
+}
+
+/*
+ * rt2860_maxrssi_rxpath
+ */
+static uint8_t rt2860_maxrssi_rxpath(struct rt2860_softc *sc,
+	const struct rt2860_rxwi *rxwi)
+{
+	uint8_t rxpath;
+
+	rxpath = 0;
+
+	if (sc->nrxpath > 1)
+		if (rxwi->rssi[1] > rxwi->rssi[rxpath])
+			rxpath = 1;
+
+	if (sc->nrxpath > 2)
+		if (rxwi->rssi[2] > rxwi->rssi[rxpath])
+			rxpath = 2;
+
+	return rxpath;
+}
+
+/*
+ * rt2860_rssi2dbm
+ */
+static int8_t rt2860_rssi2dbm(struct rt2860_softc *sc,
+	uint8_t rssi, uint8_t rxpath)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211_channel *c;
+	int chan;
+	int8_t rssi_off, lna_gain;
+
+	if (rssi == 0)
+		return -99;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	c = ic->ic_curchan;
+	chan = ieee80211_chan2ieee(ic, c);
+
+	if (IEEE80211_IS_CHAN_5GHZ(c)) {
+		rssi_off = sc->rssi_off_5ghz[rxpath];
+
+		if (chan <= 64)
+			lna_gain = sc->lna_gain[1];
+		else if (chan <= 128)
+			lna_gain = sc->lna_gain[2];
+		else
+			lna_gain = sc->lna_gain[3];
+	} else {
+		rssi_off = sc->rssi_off_2ghz[rxpath] - sc->lna_gain[0];
+		lna_gain = sc->lna_gain[0];
+	}
+
+	return (-12 - rssi_off - lna_gain - rssi);
+}
+
+/*
+ * rt2860_rate2mcs
+ */
+static uint8_t rt2860_rate2mcs(uint8_t rate)
+{
+	switch (rate) {
+	/* CCK rates */
+	case 2:	return 0;
+	case 4:	return 1;
+	case 11: return 2;
+	case 22: return 3;
+
+	/* OFDM rates */
+	case 12: return 0;
+	case 18: return 1;
+	case 24: return 2;
+	case 36: return 3;
+	case 48: return 4;
+	case 72: return 5;
+	case 96: return 6;
+	case 108: return 7;
+	}
+
+	return 0;
+}
+
+/*
+ * rt2860_tx_mgmt
+ */
+static int rt2860_tx_mgmt(struct rt2860_softc *sc,
+	struct mbuf *m, struct ieee80211_node *ni, int qid)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211vap *vap;
+	const struct ieee80211_txparam *tp;
+	struct rt2860_softc_node *rni;
+	struct rt2860_softc_tx_ring *ring;
+	struct rt2860_softc_tx_data *data;
+	struct rt2860_txdesc *desc;
+	struct rt2860_txwi *txwi;
+	struct ieee80211_frame *wh;
+	struct rt2860_softc_tx_radiotap_header *tap;
+	bus_dma_segment_t dma_seg[RT2860_SOFTC_MAX_SCATTER];
+	struct mbuf *m_d;
+	u_int hdrsize, hdrspace;
+	uint8_t rate, mcs, pid, qsel;
+	uint16_t len, dmalen, mpdu_len, dur;
+	int error, mimops, ndmasegs, ndescs, i, j;
+
+	KASSERT(qid >= 0 && qid < RT2860_SOFTC_TX_RING_COUNT,
+		("%s: Tx MGMT: invalid qid=%d\n",
+		 device_get_nameunit(sc->sc_dev), qid));
+
+	RT2860_SOFTC_TX_RING_ASSERT_LOCKED(&sc->tx_ring[qid]);
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	vap = ni->ni_vap;
+	rni = (struct rt2860_softc_node *) ni;
+	tp = ni->ni_txparms;
+
+	ring = &sc->tx_ring[qid];
+	desc = &ring->desc[ring->desc_cur];
+	data = &ring->data[ring->data_cur];
+	txwi = (struct rt2860_txwi *) (ring->seg0 + ring->data_cur * RT2860_TX_DATA_SEG0_SIZE);
+
+	wh = mtod(m, struct ieee80211_frame *);
+
+	rate = tp->mgmtrate & IEEE80211_RATE_VAL;
+	/* XXX */
+	if (!rate)
+		return EFBIG;
+
+	/* fill Tx wireless info */
+	if (ni->ni_flags & IEEE80211_NODE_HT)
+		mcs = rate;
+	else
+		mcs = rt2860_rate2mcs(rate);
+
+	/* calculate MPDU length without padding */
+
+	hdrsize = ieee80211_anyhdrsize(wh);
+	hdrspace = ieee80211_anyhdrspace(ic, wh);
+	mpdu_len = m->m_pkthdr.len - hdrspace + hdrsize;
+
+	memset(txwi, 0, sizeof(struct rt2860_txwi));
+
+	/* management frames do not need encryption */
+
+	txwi->wcid = RT2860_WCID_RESERVED;
+
+	/* MIMO power save */
+	if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_MIMO_PS)) {
+		if (mcs > 7) {
+			if (ni->ni_flags & IEEE80211_NODE_MIMO_RTS) {
+				/* dynamic MIMO power save */
+				txwi->mpdu_density_flags |=
+					(RT2860_TXWI_FLAGS_MIMOPS << RT2860_TXWI_FLAGS_SHIFT);
+			} else {
+				/* static MIMO power save */
+
+				mcs = 7;
+			}
+		}
+
+		mimops = 1;
+	} else {
+		mimops = 0;
+	}
+
+	pid = (mcs < 0xf) ? (mcs + 1) : mcs;
+
+	txwi->pid_mpdu_len = ((htole16(pid) & RT2860_TXWI_PID_MASK) <<
+		RT2860_TXWI_PID_SHIFT) | ((htole16(mpdu_len) & RT2860_TXWI_MPDU_LEN_MASK) <<
+			RT2860_TXWI_MPDU_LEN_SHIFT);
+
+	if (ni->ni_flags & IEEE80211_NODE_HT) {
+		txwi->phymode_ifs_stbc_shortgi |=
+			(RT2860_TXWI_PHYMODE_HT_MIXED << RT2860_TXWI_PHYMODE_SHIFT);
+	} else {
+		if (ieee80211_rate2phytype(ic->ic_rt, rate) != IEEE80211_T_OFDM) {
+			txwi->phymode_ifs_stbc_shortgi |=
+				(RT2860_TXWI_PHYMODE_CCK << RT2860_TXWI_PHYMODE_SHIFT);
+
+			if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+				mcs |= RT2860_TXWI_MCS_SHOTPRE;
+		} else {
+			txwi->phymode_ifs_stbc_shortgi |=
+				(RT2860_TXWI_PHYMODE_OFDM << RT2860_TXWI_PHYMODE_SHIFT);
+		}
+	}
+
+	txwi->bw_mcs = (RT2860_TXWI_BW_20 << RT2860_TXWI_BW_SHIFT) |
+		((mcs & RT2860_TXWI_MCS_MASK) << RT2860_TXWI_MCS_SHIFT);
+
+	txwi->txop = (RT2860_TXWI_TXOP_BACKOFF << RT2860_TXWI_TXOP_SHIFT);
+
+	/* skip ACKs for multicast frames */
+
+	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+		txwi->bawin_size_xflags |=
+			(RT2860_TXWI_XFLAGS_ACK << RT2860_TXWI_XFLAGS_SHIFT);
+
+		if (ni->ni_flags & IEEE80211_NODE_HT) {
+			/* preamble + plcp + signal extension + SIFS */
+
+			dur = 16 + 4 + 6 + 10;
+		} else {
+			dur = ieee80211_ack_duration(ic->ic_rt, rate,
+				ic->ic_flags & IEEE80211_F_SHPREAMBLE);
+		}
+
+		*(uint16_t *) wh->i_dur = htole16(dur);
+	}
+
+	/* ask MAC to insert timestamp into probe responses */
+
+	if ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
+		(IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
+		txwi->mpdu_density_flags |=
+			(RT2860_TXWI_FLAGS_TS << RT2860_TXWI_FLAGS_SHIFT);
+
+	if (ieee80211_radiotap_active_vap(vap)) {
+		tap = &sc->txtap;
+
+		tap->flags = IEEE80211_RADIOTAP_F_DATAPAD;
+		tap->chan_flags = htole32(ic->ic_curchan->ic_flags);
+		tap->chan_freq = htole16(ic->ic_curchan->ic_freq);
+		tap->chan_ieee = ic->ic_curchan->ic_ieee;
+		tap->chan_maxpow = 0;
+
+		if (ni->ni_flags & IEEE80211_NODE_HT)
+			tap->rate = mcs | IEEE80211_RATE_MCS;
+		else
+			tap->rate = rate;
+
+		if (mcs & RT2860_TXWI_MCS_SHOTPRE)
+			tap->flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+			tap->flags |= IEEE80211_RADIOTAP_F_WEP;
+
+		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+
+			ieee80211_radiotap_tx(vap, m);
+
+			wh->i_fc[1] |= IEEE80211_FC1_WEP;
+		} else {
+			ieee80211_radiotap_tx(vap, m);
+		}
+	}
+
+	/* copy and trim 802.11 header */
+
+	m_copydata(m, 0, hdrsize, (caddr_t) (txwi + 1));
+	m_adj(m, hdrspace);
+
+	error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m,
+	    dma_seg, &ndmasegs, BUS_DMA_NOWAIT);
+	if (error != 0) {
+		/* too many fragments, linearize */
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+			"%s: could not load mbuf DMA map, trying to linearize mbuf: ndmasegs=%d, len=%d, error=%d\n",
+			device_get_nameunit(sc->sc_dev), ndmasegs, m->m_pkthdr.len, error);
+
+		m_d = m_collapse(m, M_DONTWAIT, 16);
+		if (m_d == NULL) {
+			m_freem(m);
+			m = NULL;
+			return (ENOMEM);
+		}
+		m = m_d;
+
+		sc->tx_defrag_packets++;
+
+		error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m,
+	    	dma_seg, &ndmasegs, BUS_DMA_NOWAIT);
+		if (error != 0) {
+			printf("%s: could not load mbuf DMA map: ndmasegs=%d, len=%d, error=%d\n",
+				device_get_nameunit(sc->sc_dev), ndmasegs, m->m_pkthdr.len, error);
+			m_freem(m);
+			return error;
+		}
+	}
+
+	if (m->m_pkthdr.len == 0)
+		ndmasegs = 0;
+
+	/* determine how many Tx descs are required */
+
+	ndescs = 1 + ndmasegs / 2;
+	if ((ring->desc_queued + ndescs) > (RT2860_SOFTC_TX_RING_DESC_COUNT - 2)) {
+		RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+			"%s: there are not enough Tx descs\n",
+			device_get_nameunit(sc->sc_dev));
+
+		sc->no_tx_desc_avail++;
+
+		bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+		m_freem(m);
+		return EFBIG;
+	}
+
+	data->m = m;
+	data->ni = ni;
+
+	/* set up Tx descs */
+
+	/* first segment is Tx wireless info and 802.11 header */
+
+	len = sizeof(struct rt2860_txwi) + hdrsize;
+
+	/* align end on a 4-bytes boundary */
+
+	dmalen = (len + 3) & ~ 3;
+
+	memset((caddr_t) txwi + len, 0, dmalen - len);
+
+	qsel = RT2860_TXDESC_QSEL_EDCA;
+
+	desc->sdp0 = htole32(ring->seg0_phys_addr + ring->data_cur * RT2860_TX_DATA_SEG0_SIZE);
+	desc->sdl0 = htole16(dmalen);
+	desc->qsel_flags = (qsel << RT2860_TXDESC_QSEL_SHIFT);
+
+	/* set up payload segments */
+
+	for (i = ndmasegs, j = 0; i >= 2; i -= 2) {
+		desc->sdp1 = htole32(dma_seg[j].ds_addr);
+		desc->sdl1 = htole16(dma_seg[j].ds_len);
+
+		ring->desc_queued++;
+		ring->desc_cur = (ring->desc_cur + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+		j++;
+
+		desc = &ring->desc[ring->desc_cur];
+
+		desc->sdp0 = htole32(dma_seg[j].ds_addr);
+		desc->sdl0 = htole16(dma_seg[j].ds_len);
+		desc->qsel_flags = (qsel << RT2860_TXDESC_QSEL_SHIFT);
+
+		j++;
+	}
+
+	/* finalize last payload segment */
+
+	if (i > 0) {
+		desc->sdp1 = htole32(dma_seg[j].ds_addr);
+		desc->sdl1 = htole16(dma_seg[j].ds_len | RT2860_TXDESC_SDL1_LASTSEG);
+	} else {
+		desc->sdl0 |= htole16(RT2860_TXDESC_SDL0_LASTSEG);
+		desc->sdl1 = 0;
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+		"%s: sending MGMT frame: qid=%d, hdrsize=%d, hdrspace=%d, len=%d, "
+		"mcs=%d, mimops=%d, DMA len=%d, ndmasegs=%d, DMA ds_len=%d/%d/%d/%d/%d\n",
+		device_get_nameunit(sc->sc_dev),
+		qid, hdrsize, hdrspace, m->m_pkthdr.len + hdrsize,
+		mcs, mimops, dmalen, ndmasegs,
+		(int) dma_seg[0].ds_len, (int) dma_seg[1].ds_len, (int) dma_seg[2].ds_len, (int) dma_seg[3].ds_len, (int) dma_seg[4].ds_len);
+
+	bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map,
+		BUS_DMASYNC_PREWRITE);
+	bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+		BUS_DMASYNC_PREWRITE);
+	bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+		BUS_DMASYNC_PREWRITE);
+
+	ring->desc_queued++;
+	ring->desc_cur = (ring->desc_cur + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+	ring->data_queued++;
+	ring->data_cur = (ring->data_cur + 1) % RT2860_SOFTC_TX_RING_DATA_COUNT;
+
+	/* kick Tx */
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(qid), ring->desc_cur);
+
+	return 0;
+}
+
+/*
+ * rt2860_tx_data
+ */
+static int rt2860_tx_data(struct rt2860_softc *sc,
+	struct mbuf *m, struct ieee80211_node *ni, int qid)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211vap *vap;
+	const struct ieee80211_txparam *tp;
+	struct rt2860_softc_node *rni;
+	struct rt2860_softc_tx_ring *ring;
+	struct rt2860_softc_tx_data *data;
+	struct rt2860_txdesc *desc;
+	struct rt2860_txwi *txwi;
+	struct ieee80211_frame *wh;
+	struct ieee80211_tx_ampdu *tx_ampdu;
+	ieee80211_seq seqno;
+	struct rt2860_softc_tx_radiotap_header *tap;
+	bus_dma_segment_t dma_seg[RT2860_SOFTC_MAX_SCATTER];
+	u_int hdrsize, hdrspace;
+	uint8_t type, rate, bw, stbc, shortgi, mcs, pid, wcid, mpdu_density, bawin_size, qsel;
+	uint16_t qos, len, dmalen, mpdu_len, dur;
+	int error, hasqos, ac, tid, ampdu, mimops, ndmasegs, ndescs, i, j;
+
+	KASSERT(qid >= 0 && qid < RT2860_SOFTC_TX_RING_COUNT,
+		("%s: Tx data: invalid qid=%d\n",
+		 device_get_nameunit(sc->sc_dev), qid));
+
+	RT2860_SOFTC_TX_RING_ASSERT_LOCKED(&sc->tx_ring[qid]);
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	vap = ni->ni_vap;
+	rni = (struct rt2860_softc_node *) ni;
+	tp = ni->ni_txparms;
+
+	ring = &sc->tx_ring[qid];
+	desc = &ring->desc[ring->desc_cur];
+	data = &ring->data[ring->data_cur];
+	txwi = (struct rt2860_txwi *) (ring->seg0 + ring->data_cur * RT2860_TX_DATA_SEG0_SIZE);
+
+	wh = mtod(m, struct ieee80211_frame *);
+
+	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+	hasqos = IEEE80211_QOS_HAS_SEQ(wh);
+	if (hasqos) {
+		if (IEEE80211_HAS_ADDR4(wh))
+			qos = le16toh(*(const uint16_t *)
+				(((struct ieee80211_qosframe_addr4 *) wh)->i_qos));
+		else
+			qos = le16toh(*(const uint16_t *)
+				(((struct ieee80211_qosframe *) wh)->i_qos));
+	} else {
+		qos = 0;
+	}
+
+	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
+		rate = tp->mcastrate;
+	else if (m->m_flags & M_EAPOL)
+		rate = tp->mgmtrate;
+	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
+		rate = tp->ucastrate;
+	else
+		rate = ni->ni_txrate;
+
+	rate &= IEEE80211_RATE_VAL;
+/* XXX */
+	if (!rate)
+		return EFBIG;
+
+	/* fill Tx wireless info */
+
+	if (ni->ni_flags & IEEE80211_NODE_HT)
+		mcs = rate;
+	else
+		mcs = rt2860_rate2mcs(rate);
+
+	if (type == IEEE80211_FC0_TYPE_DATA)
+		wcid = !IEEE80211_IS_MULTICAST(wh->i_addr1) ? rni->staid : RT2860_WCID_MCAST;
+	else
+		wcid = RT2860_WCID_RESERVED;
+
+	/* calculate MPDU length without padding */
+
+	hdrsize = ieee80211_anyhdrsize(wh);
+	hdrspace = ieee80211_anyhdrspace(ic, wh);
+	mpdu_len = m->m_pkthdr.len - hdrspace + hdrsize;
+
+	memset(txwi, 0, sizeof(struct rt2860_txwi));
+
+	txwi->wcid = wcid;
+
+	/* MIMO power save */
+
+	if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_MIMO_PS)) {
+		if (mcs > 7) {
+			if (ni->ni_flags & IEEE80211_NODE_MIMO_RTS) {
+				/* dynamic MIMO power save */
+
+				txwi->mpdu_density_flags |=
+					(RT2860_TXWI_FLAGS_MIMOPS << RT2860_TXWI_FLAGS_SHIFT);
+			} else {
+				/* static MIMO power save */
+
+				mcs = 7;
+			}
+		}
+
+		mimops = 1;
+	} else {
+		mimops = 0;
+	}
+
+	pid = (mcs < 0xf) ? (mcs + 1) : mcs;
+
+	txwi->pid_mpdu_len = ((htole16(pid) & RT2860_TXWI_PID_MASK) <<
+		RT2860_TXWI_PID_SHIFT) | ((htole16(mpdu_len) & RT2860_TXWI_MPDU_LEN_MASK) <<
+			RT2860_TXWI_MPDU_LEN_SHIFT);
+
+	stbc = sc->tx_stbc && (mcs <= 7) && (vap->iv_htcaps & IEEE80211_HTCAP_TXSTBC) &&
+		(ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_htcap & IEEE80211_HTCAP_RXSTBC);
+
+	shortgi = ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && (ni->ni_flags & IEEE80211_NODE_SGI20) && (ni->ni_chw == 20)) ||
+		((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) && (ni->ni_flags & IEEE80211_NODE_SGI40) && (ni->ni_chw == 40));
+
+	txwi->phymode_ifs_stbc_shortgi |=
+		((stbc & RT2860_TXWI_STBC_MASK) << RT2860_TXWI_STBC_SHIFT) |
+		((shortgi & RT2860_TXWI_SHORTGI_MASK) << RT2860_TXWI_SHORTGI_SHIFT);
+
+	if (ni->ni_flags & IEEE80211_NODE_HT) {
+		txwi->phymode_ifs_stbc_shortgi |=
+			(RT2860_TXWI_PHYMODE_HT_MIXED << RT2860_TXWI_PHYMODE_SHIFT);
+	} else {
+		if (ieee80211_rate2phytype(ic->ic_rt, rate) != IEEE80211_T_OFDM) {
+			txwi->phymode_ifs_stbc_shortgi |=
+				(RT2860_TXWI_PHYMODE_CCK << RT2860_TXWI_PHYMODE_SHIFT);
+
+			if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+				mcs |= RT2860_TXWI_MCS_SHOTPRE;
+		} else {
+			txwi->phymode_ifs_stbc_shortgi |=
+				(RT2860_TXWI_PHYMODE_OFDM << RT2860_TXWI_PHYMODE_SHIFT);
+		}
+	}
+
+	if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_chw == 40))
+		bw = RT2860_TXWI_BW_40;
+	else
+		bw = RT2860_TXWI_BW_20;
+
+	txwi->bw_mcs = ((bw & RT2860_TXWI_BW_MASK) << RT2860_TXWI_BW_SHIFT) |
+		((mcs & RT2860_TXWI_MCS_MASK) << RT2860_TXWI_MCS_SHIFT);
+
+	txwi->txop = (RT2860_TXWI_TXOP_HT << RT2860_TXWI_TXOP_SHIFT);
+
+	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
+		IEEE80211_QOS_ACKPOLICY_NOACK)) {
+		txwi->bawin_size_xflags |=
+			(RT2860_TXWI_XFLAGS_ACK << RT2860_TXWI_XFLAGS_SHIFT);
+
+		if (ni->ni_flags & IEEE80211_NODE_HT) {
+			/* preamble + plcp + signal extension + SIFS */
+			dur = 16 + 4 + 6 + 10;
+		} else {
+			dur = ieee80211_ack_duration(ic->ic_rt, rate,
+				ic->ic_flags & IEEE80211_F_SHPREAMBLE);
+		}
+
+		*(uint16_t *) wh->i_dur = htole16(dur);
+	}
+
+	/* check for A-MPDU */
+	if (m->m_flags & M_AMPDU_MPDU) {
+		ac = M_WME_GETAC(m);
+		tid = WME_AC_TO_TID(ac);
+		tx_ampdu = &ni->ni_tx_ampdu[ac];
+
+		mpdu_density = RT2860_MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
+		bawin_size = tx_ampdu->txa_wnd;
+
+		txwi->mpdu_density_flags |=
+			((mpdu_density & RT2860_TXWI_MPDU_DENSITY_MASK) << RT2860_TXWI_MPDU_DENSITY_SHIFT) |
+			(RT2860_TXWI_FLAGS_AMPDU << RT2860_TXWI_FLAGS_SHIFT);
+
+		txwi->bawin_size_xflags |=
+			((bawin_size & RT2860_TXWI_BAWIN_SIZE_MASK) << RT2860_TXWI_BAWIN_SIZE_SHIFT);
+
+		seqno = ni->ni_txseqs[tid]++;
+
+		*(uint16_t *) &wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
+
+		ampdu = 1;
+	} else {
+		mpdu_density = 0;
+		bawin_size = 0;
+		ampdu = 0;
+	}
+
+	/* ask MAC to insert timestamp into probe responses */
+
+	if ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
+		(IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
+		txwi->mpdu_density_flags |=
+			(RT2860_TXWI_FLAGS_TS << RT2860_TXWI_FLAGS_SHIFT);
+
+	if (ieee80211_radiotap_active_vap(vap))
+	{
+		tap = &sc->txtap;
+
+		tap->flags = IEEE80211_RADIOTAP_F_DATAPAD;
+		tap->chan_flags = htole32(ic->ic_curchan->ic_flags);
+		tap->chan_freq = htole16(ic->ic_curchan->ic_freq);
+		tap->chan_ieee = ic->ic_curchan->ic_ieee;
+		tap->chan_maxpow = 0;
+
+		if (ni->ni_flags & IEEE80211_NODE_HT)
+			tap->rate = mcs | IEEE80211_RATE_MCS;
+		else
+			tap->rate = rate;
+
+		if (mcs & RT2860_TXWI_MCS_SHOTPRE)
+			tap->flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+		if (shortgi)
+			tap->flags |= IEEE80211_RADIOTAP_F_SHORTGI;
+
+		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+			tap->flags |= IEEE80211_RADIOTAP_F_WEP;
+
+		/* XXX use temporarily radiotap CFP flag as A-MPDU flag */
+
+		if (ampdu)
+			tap->flags |= IEEE80211_RADIOTAP_F_CFP;
+
+		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+		{
+			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+
+			ieee80211_radiotap_tx(vap, m);
+
+			wh->i_fc[1] |= IEEE80211_FC1_WEP;
+		}
+		else
+		{
+			ieee80211_radiotap_tx(vap, m);
+		}
+	}
+
+	/* copy and trim 802.11 header */
+
+	m_copydata(m, 0, hdrsize, (caddr_t) (txwi + 1));
+	m_adj(m, hdrspace);
+
+	error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m,
+	    dma_seg, &ndmasegs, BUS_DMA_NOWAIT);
+	if (error != 0)
+	{
+		/* too many fragments, linearize */
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+			"%s: could not load mbuf DMA map, trying to linearize mbuf: ndmasegs=%d, len=%d, error=%d\n",
+			device_get_nameunit(sc->sc_dev), ndmasegs, m->m_pkthdr.len, error);
+
+		m = m_defrag(m, M_DONTWAIT);
+		if (m == NULL)
+			return ENOMEM;
+
+		sc->tx_defrag_packets++;
+
+		error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m,
+	    	dma_seg, &ndmasegs, BUS_DMA_NOWAIT);
+		if (error != 0)
+		{
+			printf("%s: could not load mbuf DMA map: ndmasegs=%d, len=%d, error=%d\n",
+				device_get_nameunit(sc->sc_dev), ndmasegs, m->m_pkthdr.len, error);
+			m_freem(m);
+			return error;
+		}
+	}
+
+	if (m->m_pkthdr.len == 0)
+		ndmasegs = 0;
+
+	/* determine how many Tx descs are required */
+
+	ndescs = 1 + ndmasegs / 2;
+	if ((ring->desc_queued + ndescs) > (RT2860_SOFTC_TX_RING_DESC_COUNT - 2))
+	{
+		RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+			"%s: there are not enough Tx descs\n",
+			device_get_nameunit(sc->sc_dev));
+
+		sc->no_tx_desc_avail++;
+
+		bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+		m_freem(m);
+		return EFBIG;
+	}
+
+	data->m = m;
+	data->ni = ni;
+
+	/* set up Tx descs */
+
+	/* first segment is Tx wireless info and 802.11 header */
+
+	len = sizeof(struct rt2860_txwi) + hdrsize;
+
+	/* align end on a 4-bytes boundary */
+
+	dmalen = (len + 3) & ~ 3;
+
+	memset((caddr_t) txwi + len, 0, dmalen - len);
+
+	qsel = RT2860_TXDESC_QSEL_EDCA;
+
+	desc->sdp0 = htole32(ring->seg0_phys_addr + ring->data_cur * RT2860_TX_DATA_SEG0_SIZE);
+	desc->sdl0 = htole16(dmalen);
+	desc->qsel_flags = (qsel << RT2860_TXDESC_QSEL_SHIFT);
+
+	/* set up payload segments */
+
+	for (i = ndmasegs, j = 0; i >= 2; i -= 2)
+	{
+		desc->sdp1 = htole32(dma_seg[j].ds_addr);
+		desc->sdl1 = htole16(dma_seg[j].ds_len);
+
+		ring->desc_queued++;
+		ring->desc_cur = (ring->desc_cur + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+		j++;
+
+		desc = &ring->desc[ring->desc_cur];
+
+		desc->sdp0 = htole32(dma_seg[j].ds_addr);
+		desc->sdl0 = htole16(dma_seg[j].ds_len);
+		desc->qsel_flags = (qsel << RT2860_TXDESC_QSEL_SHIFT);
+
+		j++;
+	}
+
+	/* finalize last payload segment */
+
+	if (i > 0)
+	{
+		desc->sdp1 = htole32(dma_seg[j].ds_addr);
+		desc->sdl1 = htole16(dma_seg[j].ds_len | RT2860_TXDESC_SDL1_LASTSEG);
+	}
+	else
+	{
+		desc->sdl0 |= htole16(RT2860_TXDESC_SDL0_LASTSEG);
+		desc->sdl1 = 0;
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+		"%s: sending data: qid=%d, hdrsize=%d, hdrspace=%d, len=%d, "
+		"bw=%d, stbc=%d, shortgi=%d, mcs=%d, wcid=0x%02x, "
+		"ampdu=%d (density=%d, winsize=%d), mimops=%d, DMA len=%d, ndmasegs=%d, DMA ds_len=%d/%d/%d/%d/%d\n",
+		device_get_nameunit(sc->sc_dev),
+		qid, hdrsize, hdrspace, m->m_pkthdr.len + hdrsize,
+		bw, stbc, shortgi, mcs, wcid, ampdu, mpdu_density, bawin_size, mimops, dmalen, ndmasegs,
+		(int) dma_seg[0].ds_len, (int) dma_seg[1].ds_len, (int) dma_seg[2].ds_len, (int) dma_seg[3].ds_len, (int) dma_seg[4].ds_len);
+
+	bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map,
+		BUS_DMASYNC_PREWRITE);
+	bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+		BUS_DMASYNC_PREWRITE);
+	bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+		BUS_DMASYNC_PREWRITE);
+
+	ring->desc_queued++;
+	ring->desc_cur = (ring->desc_cur + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+	ring->data_queued++;
+	ring->data_cur = (ring->data_cur + 1) % RT2860_SOFTC_TX_RING_DATA_COUNT;
+
+	/* kick Tx */
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(qid), ring->desc_cur);
+
+	return 0;
+}
+
+/*
+ * rt2860_tx_raw
+static int rt2860_tx_raw(struct rt2860_softc *sc,
+	struct mbuf *m, struct ieee80211_node *ni,
+	const struct ieee80211_bpf_params *params)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+		"%s: Tx raw\n",
+		device_get_nameunit(sc->sc_dev));
+
+	return 0;
+}
+ */
+
+/*
+ * rt2860_intr
+ */
+void
+rt2860_intr(void *arg)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+	uint32_t status;
+
+	sc = arg;
+	ifp = sc->sc_ifp;
+
+	/* acknowledge interrupts */
+
+	status = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_INT_STATUS);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_STATUS, status);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: interrupt: status = 0x%08x\n",
+		device_get_nameunit(sc->sc_dev), status);
+
+	if (status == 0xffffffff ||		/* device likely went away */
+		status == 0)				/* not for us */
+		return;
+
+	sc->interrupts++;
+
+	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+		return;
+
+	if (status & RT2860_REG_INT_TX_COHERENT)
+		rt2860_tx_coherent_intr(sc);
+
+	if (status & RT2860_REG_INT_RX_COHERENT)
+		rt2860_rx_coherent_intr(sc);
+
+	if (status & RT2860_REG_INT_TXRX_COHERENT)
+		rt2860_txrx_coherent_intr(sc);
+
+	if (status & RT2860_REG_INT_FIFO_STA_FULL)
+		rt2860_fifo_sta_full_intr(sc);
+
+	if (status & RT2860_REG_INT_TX_MGMT_DONE)
+		rt2860_tx_intr(sc, 5);
+
+	if (status & RT2860_REG_INT_RX_DONE)
+		rt2860_rx_intr(sc);
+
+	if (status & RT2860_REG_INT_RX_DELAY_DONE)
+		rt2860_rx_delay_intr(sc);
+
+	if (status & RT2860_REG_INT_TX_HCCA_DONE)
+		rt2860_tx_intr(sc, 4);
+
+	if (status & RT2860_REG_INT_TX_AC3_DONE)
+		rt2860_tx_intr(sc, 3);
+
+	if (status & RT2860_REG_INT_TX_AC2_DONE)
+		rt2860_tx_intr(sc, 2);
+
+	if (status & RT2860_REG_INT_TX_AC1_DONE)
+		rt2860_tx_intr(sc, 1);
+
+	if (status & RT2860_REG_INT_TX_AC0_DONE)
+		rt2860_tx_intr(sc, 0);
+
+	if (status & RT2860_REG_INT_TX_DELAY_DONE)
+		rt2860_tx_delay_intr(sc);
+
+	if (status & RT2860_REG_INT_PRE_TBTT)
+		rt2860_pre_tbtt_intr(sc);
+
+	if (status & RT2860_REG_INT_TBTT)
+		rt2860_tbtt_intr(sc);
+
+	if (status & RT2860_REG_INT_MCU_CMD)
+		rt2860_mcu_cmd_intr(sc);
+
+	if (status & RT2860_REG_INT_AUTO_WAKEUP)
+		rt2860_auto_wakeup_intr(sc);
+
+	if (status & RT2860_REG_INT_GP_TIMER)
+		rt2860_gp_timer_intr(sc);
+
+}
+
+/*
+ * rt2860_tx_coherent_intr
+ */
+static void rt2860_tx_coherent_intr(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+	int i;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: Tx coherent interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->tx_coherent_interrupts++;
+
+	/* restart DMA engine */
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+
+	tmp &= ~(RT2860_REG_TX_WB_DDONE |
+		RT2860_REG_RX_DMA_ENABLE |
+		RT2860_REG_TX_DMA_ENABLE);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+	/* init Tx rings (4 EDCAs + HCCA + MGMT) */
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+		rt2860_reset_tx_ring(sc, &sc->tx_ring[i]);
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+	{
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_BASE_PTR(i),
+			sc->tx_ring[i].desc_phys_addr);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_MAX_CNT(i),
+			RT2860_SOFTC_TX_RING_DESC_COUNT);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(i), 0);
+	}
+
+	/* init Rx ring */
+
+	rt2860_reset_rx_ring(sc, &sc->rx_ring);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_BASE_PTR,
+		sc->rx_ring.desc_phys_addr);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_MAX_CNT,
+		RT2860_SOFTC_RX_RING_DATA_COUNT);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+		RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+
+	rt2860_txrx_enable(sc);
+}
+
+/*
+ * rt2860_rx_coherent_intr
+ */
+static void rt2860_rx_coherent_intr(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+	int i;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: Rx coherent interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->rx_coherent_interrupts++;
+
+	/* restart DMA engine */
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+
+	tmp &= ~(RT2860_REG_TX_WB_DDONE |
+		RT2860_REG_RX_DMA_ENABLE |
+		RT2860_REG_TX_DMA_ENABLE);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+	/* init Tx rings (4 EDCAs + HCCA + MGMT) */
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+		rt2860_reset_tx_ring(sc, &sc->tx_ring[i]);
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+	{
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_BASE_PTR(i),
+			sc->tx_ring[i].desc_phys_addr);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_MAX_CNT(i),
+			RT2860_SOFTC_TX_RING_DESC_COUNT);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(i), 0);
+	}
+
+	/* init Rx ring */
+
+	rt2860_reset_rx_ring(sc, &sc->rx_ring);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_BASE_PTR,
+		sc->rx_ring.desc_phys_addr);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_MAX_CNT,
+		RT2860_SOFTC_RX_RING_DATA_COUNT);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+		RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+
+	rt2860_txrx_enable(sc);
+}
+
+/*
+ * rt2860_txrx_coherent_intr
+ */
+static void rt2860_txrx_coherent_intr(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+	int i;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: Tx/Rx coherent interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->txrx_coherent_interrupts++;
+
+	/* restart DMA engine */
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+
+	tmp &= ~(RT2860_REG_TX_WB_DDONE |
+		RT2860_REG_RX_DMA_ENABLE |
+		RT2860_REG_TX_DMA_ENABLE);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+	/* init Tx rings (4 EDCAs + HCCA + MGMT) */
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+		rt2860_reset_tx_ring(sc, &sc->tx_ring[i]);
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+	{
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_BASE_PTR(i),
+			sc->tx_ring[i].desc_phys_addr);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_MAX_CNT(i),
+			RT2860_SOFTC_TX_RING_DESC_COUNT);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(i), 0);
+	}
+
+	/* init Rx ring */
+
+	rt2860_reset_rx_ring(sc, &sc->rx_ring);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_BASE_PTR,
+		sc->rx_ring.desc_phys_addr);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_MAX_CNT,
+		RT2860_SOFTC_RX_RING_DATA_COUNT);
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+		RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+
+	rt2860_txrx_enable(sc);
+}
+
+/*
+ * rt2860_fifo_sta_full_intr
+ */
+static void rt2860_fifo_sta_full_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: FIFO statistic full interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->fifo_sta_full_interrupts++;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	if (!(sc->intr_disable_mask & RT2860_REG_INT_FIFO_STA_FULL))
+	{
+		rt2860_intr_disable(sc, RT2860_REG_INT_FIFO_STA_FULL);
+
+		taskqueue_enqueue(sc->taskqueue, &sc->fifo_sta_full_task);
+	}
+
+	sc->intr_pending_mask |= RT2860_REG_INT_FIFO_STA_FULL;
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_rx_intr
+ */
+static void rt2860_rx_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: Rx interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->rx_interrupts++;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	if (!(sc->intr_disable_mask & RT2860_REG_INT_RX_DONE))
+	{
+		rt2860_intr_disable(sc, RT2860_REG_INT_RX_DONE);
+
+		taskqueue_enqueue(sc->taskqueue, &sc->rx_done_task);
+	}
+
+	sc->intr_pending_mask |= RT2860_REG_INT_RX_DONE;
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_rx_delay_intr
+ */
+static void rt2860_rx_delay_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: Rx delay interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->rx_delay_interrupts++;
+}
+
+/*
+ * rt2860_tx_intr
+ */
+static void rt2860_tx_intr(struct rt2860_softc *sc, int qid)
+{
+	KASSERT(qid >= 0 && qid < RT2860_SOFTC_TX_RING_COUNT,
+		("%s: Tx interrupt: invalid qid=%d\n",
+		 device_get_nameunit(sc->sc_dev), qid));
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: Tx interrupt: qid=%d\n",
+		device_get_nameunit(sc->sc_dev), qid);
+
+	sc->tx_interrupts[qid]++;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	if (!(sc->intr_disable_mask & (RT2860_REG_INT_TX_AC0_DONE << qid)))
+	{
+		rt2860_intr_disable(sc, (RT2860_REG_INT_TX_AC0_DONE << qid));
+
+		taskqueue_enqueue(sc->taskqueue, &sc->tx_done_task);
+	}
+
+	sc->intr_pending_mask |= (RT2860_REG_INT_TX_AC0_DONE << qid);
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_tx_delay_intr
+ */
+static void rt2860_tx_delay_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: Tx delay interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->tx_delay_interrupts++;
+}
+
+/*
+ * rt2860_pre_tbtt_intr
+ */
+static void rt2860_pre_tbtt_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: Pre-TBTT interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->pre_tbtt_interrupts++;
+}
+
+/*
+ * rt2860_tbtt_intr
+ */
+static void rt2860_tbtt_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: TBTT interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->tbtt_interrupts++;
+}
+
+/*
+ * rt2860_mcu_cmd_intr
+ */
+static void rt2860_mcu_cmd_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: MCU command interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->mcu_cmd_interrupts++;
+}
+
+/*
+ * rt2860_auto_wakeup_intr
+ */
+static void rt2860_auto_wakeup_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: auto wakeup interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->auto_wakeup_interrupts++;
+}
+
+/*
+ * rt2860_gp_timer_intr
+ */
+static void rt2860_gp_timer_intr(struct rt2860_softc *sc)
+{
+	RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+		"%s: GP timer interrupt\n",
+		device_get_nameunit(sc->sc_dev));
+
+	sc->gp_timer_interrupts++;
+}
+
+/*
+ * rt2860_rx_done_task
+ */
+static void rt2860_rx_done_task(void *context, int pending)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+	int again;
+
+	sc = context;
+	ifp = sc->sc_ifp;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+		"%s: Rx done task\n",
+		device_get_nameunit(sc->sc_dev));
+
+	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+		return;
+
+	sc->intr_pending_mask &= ~RT2860_REG_INT_RX_DONE;
+
+	again = rt2860_rx_eof(sc, sc->rx_process_limit);
+
+	RT2860_SOFTC_LOCK(sc);
+
+	if ((sc->intr_pending_mask & RT2860_REG_INT_RX_DONE) || again)
+	{
+		RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+			"%s: Rx done task: scheduling again\n",
+			device_get_nameunit(sc->sc_dev));
+
+		taskqueue_enqueue(sc->taskqueue, &sc->rx_done_task);
+	}
+	else
+	{
+		rt2860_intr_enable(sc, RT2860_REG_INT_RX_DONE);
+	}
+
+	RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_tx_done_task
+ */
+static void rt2860_tx_done_task(void *context, int pending)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+	uint32_t intr_mask;
+	int i;
+
+	sc = context;
+	ifp = sc->sc_ifp;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+		"%s: Tx done task\n",
+		device_get_nameunit(sc->sc_dev));
+
+	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+		return;
+
+	for (i = RT2860_SOFTC_TX_RING_COUNT - 1; i >= 0; i--)
+	{
+		if (sc->intr_pending_mask & (RT2860_REG_INT_TX_AC0_DONE << i))
+		{
+			sc->intr_pending_mask &= ~(RT2860_REG_INT_TX_AC0_DONE << i);
+
+			rt2860_tx_eof(sc, &sc->tx_ring[i]);
+		}
+	}
+
+	sc->tx_timer = 0;
+
+	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+	intr_mask = (RT2860_REG_INT_TX_MGMT_DONE |
+		RT2860_REG_INT_TX_HCCA_DONE |
+		RT2860_REG_INT_TX_AC3_DONE |
+		RT2860_REG_INT_TX_AC2_DONE |
+		RT2860_REG_INT_TX_AC1_DONE |
+		RT2860_REG_INT_TX_AC0_DONE);
+
+	RT2860_SOFTC_LOCK(sc);
+
+	rt2860_intr_enable(sc, ~sc->intr_pending_mask &
+		(sc->intr_disable_mask & intr_mask));
+
+	if (sc->intr_pending_mask & intr_mask)
+	{
+		RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+			"%s: Tx done task: scheduling again\n",
+			device_get_nameunit(sc->sc_dev));
+
+		taskqueue_enqueue(sc->taskqueue, &sc->tx_done_task);
+	}
+
+	RT2860_SOFTC_UNLOCK(sc);
+
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
+		rt2860_start(ifp);
+}
+
+/*
+ * rt2860_fifo_sta_full_task
+ */
+static void rt2860_fifo_sta_full_task(void *context, int pending)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+
+	sc = context;
+	ifp = sc->sc_ifp;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+		"%s: FIFO statistic full task\n",
+		device_get_nameunit(sc->sc_dev));
+
+	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+		return;
+
+	sc->intr_pending_mask &= ~RT2860_REG_INT_FIFO_STA_FULL;
+
+	rt2860_drain_fifo_stats(sc);
+
+	RT2860_SOFTC_LOCK(sc);
+
+	if (sc->intr_pending_mask & RT2860_REG_INT_FIFO_STA_FULL)
+	{
+		RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+			"%s: FIFO statistic full task: scheduling again\n",
+			device_get_nameunit(sc->sc_dev));
+
+		taskqueue_enqueue(sc->taskqueue, &sc->fifo_sta_full_task);
+	}
+	else
+	{
+		rt2860_intr_enable(sc, RT2860_REG_INT_FIFO_STA_FULL);
+	}
+
+	RT2860_SOFTC_UNLOCK(sc);
+
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
+		rt2860_start(ifp);
+}
+
+/*
+ * rt2860_periodic_task
+ */
+static void rt2860_periodic_task(void *context, int pending)
+{
+	struct rt2860_softc *sc;
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211vap *vap;
+
+	sc = context;
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	vap = TAILQ_FIRST(&ic->ic_vaps);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_PERIODIC,
+		"%s: periodic task: round=%lu\n",
+		device_get_nameunit(sc->sc_dev), sc->periodic_round);
+
+	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+		return;
+
+	RT2860_SOFTC_LOCK(sc);
+
+	sc->periodic_round++;
+
+	rt2860_update_stats(sc);
+
+	if ((sc->periodic_round % 10) == 0)
+	{
+		rt2860_bbp_tuning(sc);
+
+		rt2860_update_raw_counters(sc);
+
+		rt2860_watchdog(sc);
+
+		if (vap != NULL && vap->iv_opmode != IEEE80211_M_MONITOR && vap->iv_state == IEEE80211_S_RUN)
+		{
+			if (vap->iv_opmode == IEEE80211_M_STA)
+				rt2860_amrr_update_iter_func(vap, vap->iv_bss);
+			else
+				ieee80211_iterate_nodes(&ic->ic_sta, rt2860_amrr_update_iter_func, vap);
+		}
+	}
+
+	RT2860_SOFTC_UNLOCK(sc);
+
+	callout_reset(&sc->periodic_ch, hz / 10, rt2860_periodic, sc);
+}
+
+/*
+ * rt2860_rx_eof
+ */
+static int rt2860_rx_eof(struct rt2860_softc *sc, int limit)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211_frame *wh;
+	struct ieee80211_node *ni;
+	struct rt2860_softc_node *rni;
+	struct rt2860_softc_rx_radiotap_header *tap;
+	struct rt2860_softc_rx_ring *ring;
+	struct rt2860_rxdesc *desc;
+	struct rt2860_softc_rx_data *data;
+	struct rt2860_rxwi *rxwi;
+	struct mbuf *m, *mnew;
+	bus_dma_segment_t segs[1];
+	bus_dmamap_t dma_map;
+	uint32_t index, desc_flags;
+	uint8_t rssi, ant, phymode, bw, shortgi, stbc, mcs, tid, frag;
+#ifndef RT2860_NO_HW_CRYPTO
+	uint8_t cipher_err, keyidx;
+#endif
+	uint16_t seq;
+	int8_t rssi_dbm;
+	int error, nsegs, len, ampdu, amsdu, rssi_dbm_rel, nframes, i;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	ring = &sc->rx_ring;
+
+	nframes = 0;
+
+	while (limit != 0)
+	{
+		index = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_RX_DRX_IDX);
+		if (ring->cur == index)
+			break;
+
+		desc = &ring->desc[ring->cur];
+		data = &ring->data[ring->cur];
+
+		bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+			BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+#ifdef XXX_TESTED_AND_WORKED
+		if (!(desc->sdl0 & htole16(RT2860_RXDESC_SDL0_DDONE)))
+			break;
+#endif
+
+		nframes++;
+
+		mnew = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
+		if (mnew == NULL)
+		{
+			sc->rx_mbuf_alloc_errors++;
+			ifp->if_ierrors++;
+			goto skip;
+		}
+
+		mnew->m_len = mnew->m_pkthdr.len = MJUMPAGESIZE;
+
+		error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, ring->spare_dma_map,
+			mnew, segs, &nsegs, BUS_DMA_NOWAIT);
+		if (error != 0)
+		{
+			RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+				"%s: could not load Rx mbuf DMA map: error=%d, nsegs=%d\n",
+				device_get_nameunit(sc->sc_dev), error, nsegs);
+
+			m_freem(mnew);
+
+			sc->rx_mbuf_dmamap_errors++;
+			ifp->if_ierrors++;
+
+			goto skip;
+		}
+
+		KASSERT(nsegs == 1, ("%s: too many DMA segments",
+			device_get_nameunit(sc->sc_dev)));
+
+		bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+			BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+
+		dma_map = data->dma_map;
+		data->dma_map = ring->spare_dma_map;
+		ring->spare_dma_map = dma_map;
+
+		bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+			BUS_DMASYNC_PREREAD);
+
+		m = data->m;
+
+		data->m = mnew;
+		desc->sdp0 = htole32(segs[0].ds_addr);
+
+		desc_flags = le32toh(desc->flags);
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+			"%s: Rx frame: rxdesc flags=0x%08x\n",
+			device_get_nameunit(sc->sc_dev), desc_flags);
+
+		/* get Rx wireless info */
+
+		rxwi = mtod(m, struct rt2860_rxwi *);
+		len = (le16toh(rxwi->tid_size) >> RT2860_RXWI_SIZE_SHIFT) &
+			RT2860_RXWI_SIZE_MASK;
+
+		/* check for L2 padding between IEEE 802.11 frame header and body */
+
+		if (desc_flags & RT2860_RXDESC_FLAGS_L2PAD)
+		{
+			RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+				"%s: L2 padding: len=%d\n",
+				device_get_nameunit(sc->sc_dev), len);
+
+			len += 2;
+		}
+
+		m->m_pkthdr.rcvif = ifp;
+		m->m_data = (caddr_t) (rxwi + 1);
+		m->m_pkthdr.len = m->m_len = len;
+
+		/* check for crc errors */
+
+		if (desc_flags & RT2860_RXDESC_FLAGS_CRC_ERR)
+		{
+			RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+				"%s: rxdesc: crc error\n",
+				device_get_nameunit(sc->sc_dev));
+
+			ifp->if_ierrors++;
+
+			if (!(ifp->if_flags & IFF_PROMISC))
+			{
+				m_freem(m);
+				goto skip;
+			}
+		}
+
+		wh = (struct ieee80211_frame *) (rxwi + 1);
+
+		/* check for cipher errors */
+#ifndef RT2860_NO_HW_CRYPTO
+		if (desc_flags & RT2860_RXDESC_FLAGS_DECRYPTED)
+		{
+			cipher_err = ((desc_flags >> RT2860_RXDESC_FLAGS_CIPHER_ERR_SHIFT) &
+				RT2860_RXDESC_FLAGS_CIPHER_ERR_MASK);
+			if (cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_NONE)
+			{
+				if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+					wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+
+				m->m_flags |= M_WEP;
+
+				sc->rx_cipher_no_errors++;
+			}
+			else
+			{
+				RT2860_DPRINTF(sc, RT2860_DEBUG_RX_CRYPT,
+					"%s: rxdesc: cipher error=0x%02x keyidx=%d\n",
+					device_get_nameunit(sc->sc_dev), cipher_err,
+					(rxwi->udf_bssidx_keyidx >> RT2860_RXWI_KEYIDX_SHIFT) &
+							RT2860_RXWI_KEYIDX_MASK);
+
+				if (cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_ICV)
+					sc->rx_cipher_icv_errors++;
+				else if (cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_MIC)
+					sc->rx_cipher_mic_errors++;
+				else if (cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_INVALID_KEY)
+					sc->rx_cipher_invalid_key_errors++;
+
+				if ((cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_MIC) &&
+					(desc_flags & RT2860_RXDESC_FLAGS_MYBSS))
+				{
+					ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) wh);
+					if (ni != NULL)
+					{
+						keyidx = (rxwi->udf_bssidx_keyidx >> RT2860_RXWI_KEYIDX_SHIFT) &
+							RT2860_RXWI_KEYIDX_MASK;
+
+						ieee80211_notify_michael_failure(ni->ni_vap, wh, keyidx);
+
+						ieee80211_free_node(ni);
+					}
+				}
+
+				ifp->if_ierrors++;
+
+				if (!(ifp->if_flags & IFF_PROMISC))
+				{
+					m_free(m);
+					goto skip;
+				}
+			}
+		}
+		else
+		{
+			if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+			{
+				RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+					"%s: rxdesc: not decrypted but protected flag set\n",
+					device_get_nameunit(sc->sc_dev));
+
+				ifp->if_ierrors++;
+
+				if (!(ifp->if_flags & IFF_PROMISC))
+				{
+					m_free(m);
+					goto skip;
+				}
+			}
+		}
+#endif
+		/* check for A-MPDU */
+
+		if (desc_flags & RT2860_RXDESC_FLAGS_BA)
+		{
+			m->m_flags |= M_AMPDU;
+
+			sc->rx_ampdu++;
+
+			if (wh->i_fc[1] & IEEE80211_FC1_RETRY)
+				sc->rx_ampdu_retries++;
+
+			ampdu = 1;
+		}
+		else
+		{
+			ampdu = 0;
+		}
+
+		/* check for A-MSDU */
+
+		if (desc_flags & RT2860_RXDESC_FLAGS_AMSDU)
+		{
+			sc->rx_amsdu++;
+
+			amsdu = 1;
+		}
+		else
+		{
+			amsdu = 0;
+		}
+
+		ant = rt2860_maxrssi_rxpath(sc, rxwi);
+		rssi = rxwi->rssi[ant];
+		rssi_dbm = rt2860_rssi2dbm(sc, rssi, ant);
+		phymode = ((rxwi->phymode_stbc_shortgi >> RT2860_RXWI_PHYMODE_SHIFT) &
+			RT2860_RXWI_PHYMODE_MASK);
+		bw = ((rxwi->bw_mcs >> RT2860_RXWI_BW_SHIFT) & RT2860_RXWI_BW_MASK);
+		shortgi = ((rxwi->phymode_stbc_shortgi >> RT2860_RXWI_SHORTGI_SHIFT) &
+			RT2860_RXWI_SHORTGI_MASK);
+		stbc = ((rxwi->phymode_stbc_shortgi >> RT2860_RXWI_STBC_SHIFT) &
+			RT2860_RXWI_STBC_MASK);
+		mcs = ((rxwi->bw_mcs >> RT2860_RXWI_MCS_SHIFT) & RT2860_RXWI_MCS_MASK);
+		tid = ((rxwi->tid_size >> RT2860_RXWI_TID_SHIFT) & RT2860_RXWI_TID_MASK);
+		seq = ((rxwi->seq_frag >> RT2860_RXWI_SEQ_SHIFT) & RT2860_RXWI_SEQ_MASK);
+		frag = ((rxwi->seq_frag >> RT2860_RXWI_FRAG_SHIFT) & RT2860_RXWI_FRAG_MASK);
+
+		if (ieee80211_radiotap_active(ic))
+		{
+			tap = &sc->rxtap;
+
+			tap->flags = (desc_flags & RT2860_RXDESC_FLAGS_L2PAD) ? IEEE80211_RADIOTAP_F_DATAPAD : 0;
+			tap->dbm_antsignal = rssi_dbm;
+			tap->dbm_antnoise = RT2860_NOISE_FLOOR;
+			tap->antenna = ant;
+			tap->antsignal = rssi;
+			tap->chan_flags = htole32(ic->ic_curchan->ic_flags);
+			tap->chan_freq = htole16(ic->ic_curchan->ic_freq);
+			tap->chan_ieee = ic->ic_curchan->ic_ieee;
+			tap->chan_maxpow = 0;
+
+			if (phymode == RT2860_TXWI_PHYMODE_HT_MIXED || phymode == RT2860_TXWI_PHYMODE_HT_GF)
+				tap->rate = mcs | IEEE80211_RATE_MCS;
+			else
+				tap->rate = rt2860_rxrate(rxwi);
+
+			if (desc_flags & RT2860_RXDESC_FLAGS_CRC_ERR)
+				tap->flags |= IEEE80211_RADIOTAP_F_BADFCS;
+
+			if (desc_flags & RT2860_RXDESC_FLAGS_FRAG)
+				tap->flags |= IEEE80211_RADIOTAP_F_FRAG;
+
+			if (rxwi->bw_mcs & RT2860_RXWI_MCS_SHOTPRE)
+				tap->flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+			if ((desc_flags & RT2860_RXDESC_FLAGS_DECRYPTED) ||
+				(wh->i_fc[1] & IEEE80211_FC1_WEP))
+				tap->flags |= IEEE80211_RADIOTAP_F_WEP;
+
+			if (shortgi)
+				tap->flags |= IEEE80211_RADIOTAP_F_SHORTGI;
+
+			/* XXX use temporarily radiotap CFP flag as A-MPDU flag */
+
+			if (ampdu)
+				tap->flags |= IEEE80211_RADIOTAP_F_CFP;
+		}
+
+		/*
+		 * net80211 assumes that RSSI data are in the range [-127..127] and
+		 * in .5 dBm units relative to the current noise floor
+		 */
+
+		rssi_dbm_rel = (rssi_dbm - RT2860_NOISE_FLOOR) * 2;
+		if (rssi_dbm_rel > 127)
+			rssi_dbm_rel = 127;
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+			"%s: received frame: len=%d, phymode=%d, bw=%d, shortgi=%d, stbc=0x%02x, mcs=%d, "
+			"ant=%d, rssi=%d/%d/%d, snr=%d/%d, wcid=0x%02x, ampdu=%d, amsdu=%d, tid=%d, seq=%d, frag=%d, "
+			"retry=%d, rssi_dbm=%d, rssi_dbm_rel=%d\n",
+			device_get_nameunit(sc->sc_dev),
+			len, phymode, bw, shortgi, stbc, mcs,
+			ant, rxwi->rssi[0], rxwi->rssi[1], rxwi->rssi[2],
+			rxwi->snr[0], rxwi->snr[1],
+			rxwi->wcid, ampdu, amsdu, tid, seq, frag, (wh->i_fc[1] & IEEE80211_FC1_RETRY) ? 1 : 0,
+			rssi_dbm, rssi_dbm_rel);
+
+		ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *) wh);
+		if (ni != NULL)
+		{
+			rni = (struct rt2860_softc_node *) ni;
+
+			for (i = 0; i < RT2860_SOFTC_RSSI_COUNT; i++)
+			{
+				rni->last_rssi[i] = rxwi->rssi[i];
+				rni->last_rssi_dbm[i] = rt2860_rssi2dbm(sc, rxwi->rssi[i], i);
+			}
+
+			ieee80211_input(ni, m, rssi_dbm_rel, RT2860_NOISE_FLOOR);
+			ieee80211_free_node(ni);
+		}
+		else
+		{
+			ieee80211_input_all(ic, m, rssi_dbm_rel, RT2860_NOISE_FLOOR);
+		}
+
+skip:
+
+		desc->sdl0 &= ~htole16(RT2860_RXDESC_SDL0_DDONE);
+
+		bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+			BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+		ring->cur = (ring->cur + 1) % RT2860_SOFTC_RX_RING_DATA_COUNT;
+
+		limit--;
+	}
+
+	if (ring->cur == 0)
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+			RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+	else
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+			ring->cur - 1);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+		"%s: Rx eof: nframes=%d\n",
+		device_get_nameunit(sc->sc_dev), nframes);
+
+	sc->rx_packets += nframes;
+
+	return (limit == 0);
+}
+
+/*
+ * rt2860_tx_eof
+ */
+static void rt2860_tx_eof(struct rt2860_softc *sc,
+	struct rt2860_softc_tx_ring *ring)
+{
+	struct ifnet *ifp;
+	struct rt2860_txdesc *desc;
+	struct rt2860_softc_tx_data *data;
+	uint32_t index;
+	int ndescs, nframes;
+
+	ifp = sc->sc_ifp;
+
+	ndescs = 0;
+	nframes = 0;
+
+	for (;;)
+	{
+		index = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_TX_DTX_IDX(ring->qid));
+		if (ring->desc_next == index)
+			break;
+
+		ndescs++;
+
+		rt2860_drain_fifo_stats(sc);
+
+		desc = &ring->desc[ring->desc_next];
+
+		bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+			BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+		if (desc->sdl0 & htole16(RT2860_TXDESC_SDL0_LASTSEG) ||
+			desc->sdl1 & htole16(RT2860_TXDESC_SDL1_LASTSEG))
+		{
+			nframes++;
+
+			data = &ring->data[ring->data_next];
+
+			if (data->m->m_flags & M_TXCB)
+				ieee80211_process_callback(data->ni, data->m, 0);
+
+			bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+				BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+
+			m_freem(data->m);
+
+			ieee80211_free_node(data->ni);
+
+			data->m = NULL;
+			data->ni = NULL;
+
+			ifp->if_opackets++;
+
+			RT2860_SOFTC_TX_RING_LOCK(ring);
+
+			ring->data_queued--;
+			ring->data_next = (ring->data_next + 1) % RT2860_SOFTC_TX_RING_DATA_COUNT;
+
+			RT2860_SOFTC_TX_RING_UNLOCK(ring);
+		}
+
+		desc->sdl0 &= ~htole16(RT2860_TXDESC_SDL0_DDONE);
+
+		bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+			BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+		RT2860_SOFTC_TX_RING_LOCK(ring);
+
+		ring->desc_queued--;
+		ring->desc_next = (ring->desc_next + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+		RT2860_SOFTC_TX_RING_UNLOCK(ring);
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+		"%s: Tx eof: qid=%d, ndescs=%d, nframes=%d\n",
+		device_get_nameunit(sc->sc_dev), ring->qid, ndescs, nframes);
+}
+
+/*
+ * rt2860_update_stats
+ */
+static void rt2860_update_stats(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	uint32_t stacnt[3];
+	int beacons, noretryok, retryok, failed, underflows, zerolen;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+		"%s: update statistic\n",
+		device_get_nameunit(sc->sc_dev));
+
+	rt2860_drain_fifo_stats(sc);
+
+	/* read and clear Tx statistic registers */
+
+	rt2860_io_mac_read_multi(sc, RT2860_REG_TX_STA_CNT0,
+		stacnt, sizeof(stacnt));
+
+	stacnt[0] = le32toh(stacnt[0]);
+	stacnt[1] = le32toh(stacnt[1]);
+	stacnt[2] = le32toh(stacnt[2]);
+
+	beacons = stacnt[0] >> 16;
+	noretryok = stacnt[1] & 0xffff;
+	retryok = stacnt[1] >> 16;
+	failed = stacnt[0] & 0xffff;
+	underflows = stacnt[2] >> 16;
+	zerolen = stacnt[2] & 0xffff;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+		"%s: update statistic: beacons=%d, noretryok=%d, retryok=%d, failed=%d, underflows=%d, zerolen=%d\n",
+		device_get_nameunit(sc->sc_dev),
+		beacons, noretryok, retryok, failed, underflows, zerolen);
+
+	ifp->if_oerrors += failed;
+
+	sc->tx_beacons += beacons;
+	sc->tx_noretryok += noretryok;
+	sc->tx_retryok += retryok;
+	sc->tx_failed += failed;
+	sc->tx_underflows += underflows;
+	sc->tx_zerolen += zerolen;
+}
+
+/*
+ * rt2860_bbp_tuning
+ */
+static void rt2860_bbp_tuning(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	struct ieee80211vap *vap;
+	struct ieee80211_node *ni;
+	int chan, group;
+	int8_t rssi, old, new;
+
+	/* RT2860C does not support BBP tuning */
+
+	if (sc->mac_rev == 0x28600100)
+		return;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	vap = TAILQ_FIRST(&ic->ic_vaps);
+
+	if ((ic->ic_flags & IEEE80211_F_SCAN) || vap == NULL ||
+		vap->iv_opmode != IEEE80211_M_STA || vap->iv_state != IEEE80211_S_RUN)
+		return;
+
+	ni = vap->iv_bss;
+
+	chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+
+	if (chan <= 14)
+		group = 0;
+	else if (chan <= 64)
+		group = 1;
+	else if (chan <= 128)
+		group = 2;
+	else
+		group = 3;
+
+	rssi = ieee80211_getrssi(vap);
+
+	if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+	{
+		new = 0x2e + sc->lna_gain[group];
+	}
+	else
+	{
+		if (!IEEE80211_IS_CHAN_HT40(ni->ni_chan))
+			new = 0x32 + sc->lna_gain[group] * 5 / 3;
+		else
+			new = 0x3a + sc->lna_gain[group] * 5 / 3;
+	}
+
+	/* Tune if absolute average RSSI is greater than -80 */
+
+	if (rssi > 30)
+		new += 0x10;
+
+	old = rt2860_io_bbp_read(sc, 66);
+
+	if (old != new)
+		rt2860_io_bbp_write(sc, 66, new);
+}
+
+/*
+ * rt2860_watchdog
+ */
+static void rt2860_watchdog(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+	int ntries;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_PBF_TXRXQ_PCNT);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_WATCHDOG,
+		"%s: watchdog: TXRXQ_PCNT=0x%08x\n",
+		device_get_nameunit(sc->sc_dev), tmp);
+
+	if (((tmp >> RT2860_REG_TX0Q_PCNT_SHIFT) & RT2860_REG_TX0Q_PCNT_MASK) != 0)
+	{
+		sc->tx_queue_not_empty[0]++;
+
+		rt2860_io_mac_write(sc, RT2860_REG_PBF_CFG, 0xf40012);
+
+		for (ntries = 0; ntries < 10; ntries++)
+		{
+			tmp = rt2860_io_mac_read(sc, RT2860_REG_PBF_TXRXQ_PCNT);
+			if (((tmp >> RT2860_REG_TX0Q_PCNT_SHIFT) & RT2860_REG_TX0Q_PCNT_MASK) == 0)
+				break;
+
+			DELAY(1);
+		}
+
+		rt2860_io_mac_write(sc, RT2860_REG_PBF_CFG, 0xf40006);
+	}
+
+	if (((tmp >> RT2860_REG_TX1Q_PCNT_SHIFT) & RT2860_REG_TX1Q_PCNT_MASK) != 0)
+	{
+		sc->tx_queue_not_empty[1]++;
+
+		rt2860_io_mac_write(sc, RT2860_REG_PBF_CFG, 0xf4000a);
+
+		for (ntries = 0; ntries < 10; ntries++)
+		{
+			tmp = rt2860_io_mac_read(sc, RT2860_REG_PBF_TXRXQ_PCNT);
+			if (((tmp >> RT2860_REG_TX1Q_PCNT_SHIFT) & RT2860_REG_TX1Q_PCNT_MASK) == 0)
+				break;
+
+			DELAY(1);
+		}
+
+		rt2860_io_mac_write(sc, RT2860_REG_PBF_CFG, 0xf40006);
+	}
+}
+
+/*
+ * rt2860_drain_fifo_stats
+ */
+static void rt2860_drain_fifo_stats(struct rt2860_softc *sc)
+{
+	struct ifnet *ifp;
+	uint32_t stats;
+	uint8_t wcid, mcs, pid;
+	int ok, agg, retrycnt;
+
+	ifp = sc->sc_ifp;
+
+	/* drain Tx status FIFO (maxsize = 16) */
+
+	while ((stats = rt2860_io_mac_read(sc, RT2860_REG_TX_STA_FIFO)) &
+		RT2860_REG_TX_STA_FIFO_VALID)
+	{
+		wcid = (stats >> RT2860_REG_TX_STA_FIFO_WCID_SHIFT) &
+			RT2860_REG_TX_STA_FIFO_WCID_MASK;
+
+		/* if no ACK was requested, no feedback is available */
+
+		if (!(stats & RT2860_REG_TX_STA_FIFO_ACK_REQ) || wcid == RT2860_WCID_RESERVED)
+			continue;
+
+		/* update AMRR statistic */
+
+		ok = (stats & RT2860_REG_TX_STA_FIFO_TX_OK) ? 1 : 0;
+		agg = (stats & RT2860_REG_TX_STA_FIFO_AGG) ? 1 : 0;
+		mcs = (stats >> RT2860_REG_TX_STA_FIFO_MCS_SHIFT) &
+			RT2860_REG_TX_STA_FIFO_MCS_MASK;
+		pid = (stats >> RT2860_REG_TX_STA_FIFO_PID_SHIFT) &
+			RT2860_REG_TX_STA_FIFO_PID_MASK;
+		retrycnt = (mcs < 0xf) ? (pid - mcs - 1) : 0;
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+			"%s: FIFO statistic: wcid=0x%02x, ok=%d, agg=%d, mcs=0x%02x, pid=0x%02x, retrycnt=%d\n",
+			device_get_nameunit(sc->sc_dev),
+			wcid, ok, agg, mcs, pid, retrycnt);
+
+		rt2860_amrr_tx_complete(&sc->amrr_node[wcid], ok, retrycnt);
+
+		if (!ok)
+			ifp->if_oerrors++;
+	}
+}
+
+/*
+ * rt2860_update_raw_counters
+ */
+static void rt2860_update_raw_counters(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT);
+
+	sc->tx_nonagg += tmp & 0xffff;
+	sc->tx_agg += tmp >> 16;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT0);
+
+	sc->tx_ampdu += (tmp & 0xffff) / 1 + (tmp >> 16) / 2;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT1);
+
+	sc->tx_ampdu += (tmp & 0xffff) / 3 + (tmp >> 16) / 4;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT2);
+
+	sc->tx_ampdu += (tmp & 0xffff) / 5 + (tmp >> 16) / 6;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT3);
+
+	sc->tx_ampdu += (tmp & 0xffff) / 7 + (tmp >> 16) / 8;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT4);
+
+	sc->tx_ampdu += (tmp & 0xffff) / 9 + (tmp >> 16) / 10;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT5);
+
+	sc->tx_ampdu += (tmp & 0xffff) / 11 + (tmp >> 16) / 12;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT6);
+
+	sc->tx_ampdu += (tmp & 0xffff) / 13 + (tmp >> 16) / 14;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT7);
+
+	sc->tx_ampdu += (tmp & 0xffff) / 15 + (tmp >> 16) / 16;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_RX_STA_CNT0);
+
+	sc->rx_crc_errors += tmp & 0xffff;
+	sc->rx_phy_errors += tmp >> 16;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_RX_STA_CNT1);
+
+	sc->rx_false_ccas += tmp & 0xffff;
+	sc->rx_plcp_errors += tmp >> 16;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_RX_STA_CNT2);
+
+	sc->rx_dup_packets += tmp & 0xffff;
+	sc->rx_fifo_overflows += tmp >> 16;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TXRX_MPDU_DEN_CNT);
+
+	sc->tx_mpdu_zero_density += tmp & 0xffff;
+	sc->rx_mpdu_zero_density += tmp >> 16;
+}
+
+/*
+ * rt2860_intr_enable
+ */
+static void rt2860_intr_enable(struct rt2860_softc *sc, uint32_t intr_mask)
+{
+	uint32_t tmp;
+
+	sc->intr_disable_mask &= ~intr_mask;
+
+	tmp = sc->intr_enable_mask & ~sc->intr_disable_mask;
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_MASK, tmp);
+}
+
+/*
+ * rt2860_intr_disable
+ */
+static void rt2860_intr_disable(struct rt2860_softc *sc, uint32_t intr_mask)
+{
+	uint32_t tmp;
+
+	sc->intr_disable_mask |= intr_mask;
+
+	tmp = sc->intr_enable_mask & ~sc->intr_disable_mask;
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_MASK, tmp);
+}
+
+/*
+ * rt2860_txrx_enable
+ */
+static int rt2860_txrx_enable(struct rt2860_softc *sc)
+{
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	uint32_t tmp;
+	int ntries;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	/* enable Tx/Rx DMA engine */
+
+	rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL, RT2860_REG_TX_ENABLE);
+
+	for (ntries = 0; ntries < 200; ntries++)
+	{
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+		if (!(tmp & (RT2860_REG_TX_DMA_BUSY | RT2860_REG_RX_DMA_BUSY)))
+			break;
+
+		DELAY(1000);
+	}
+
+	if (ntries == 200)
+	{
+		printf("%s: timeout waiting for DMA engine\n",
+			device_get_nameunit(sc->sc_dev));
+		return -1;
+	}
+
+	DELAY(50);
+
+	tmp |= RT2860_REG_TX_WB_DDONE |
+		RT2860_REG_RX_DMA_ENABLE |
+		RT2860_REG_TX_DMA_ENABLE |
+		(RT2860_REG_WPDMA_BT_SIZE64 << RT2860_REG_WPDMA_BT_SIZE_SHIFT);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+	/* set Rx filter */
+
+	tmp = RT2860_REG_RX_FILTER_DROP_CRC_ERR |
+		RT2860_REG_RX_FILTER_DROP_PHY_ERR;
+
+	if (ic->ic_opmode != IEEE80211_M_MONITOR)
+	{
+		tmp |= RT2860_REG_RX_FILTER_DROP_DUPL |
+			RT2860_REG_RX_FILTER_DROP_CTS |
+			RT2860_REG_RX_FILTER_DROP_BA |
+			RT2860_REG_RX_FILTER_DROP_ACK |
+			RT2860_REG_RX_FILTER_DROP_VER_ERR |
+			RT2860_REG_RX_FILTER_DROP_CTRL_RSV |
+			RT2860_REG_RX_FILTER_DROP_CFACK |
+			RT2860_REG_RX_FILTER_DROP_CFEND;
+
+		if (ic->ic_opmode == IEEE80211_M_STA)
+			tmp |= RT2860_REG_RX_FILTER_DROP_RTS |
+				RT2860_REG_RX_FILTER_DROP_PSPOLL;
+
+		if (!(ifp->if_flags & IFF_PROMISC))
+			tmp |= RT2860_REG_RX_FILTER_DROP_UC_NOME;
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_RX_FILTER_CFG, tmp);
+
+	rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL,
+		RT2860_REG_RX_ENABLE | RT2860_REG_TX_ENABLE);
+
+	return 0;
+}
+
+/*
+ * rt2860_alloc_rx_ring
+ */
+static int rt2860_alloc_rx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_rx_ring *ring)
+{
+	struct rt2860_rxdesc *desc;
+	struct rt2860_softc_rx_data *data;
+	bus_dma_segment_t segs[1];
+	int i, nsegs, error;
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0, 
+		BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+		RT2860_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt2860_rxdesc), 1,
+		RT2860_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt2860_rxdesc),
+		0, NULL, NULL, &ring->desc_dma_tag);
+	if (error != 0)
+	{
+		printf("%s: could not create Rx desc DMA tag\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+
+	error = bus_dmamem_alloc(ring->desc_dma_tag, (void **) &ring->desc,
+	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_dma_map);
+	if (error != 0)
+	{
+		printf("%s: could not allocate Rx desc DMA memory\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+
+	error = bus_dmamap_load(ring->desc_dma_tag, ring->desc_dma_map,
+		ring->desc,
+		RT2860_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt2860_rxdesc),
+		rt2860_dma_map_addr, &ring->desc_phys_addr, 0);
+	if (error != 0)
+	{
+		printf("%s: could not load Rx desc DMA map\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0, 
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+		MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL,
+		&ring->data_dma_tag);
+	if (error != 0)
+	{
+		printf("%s: could not create Rx data DMA tag\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+
+	for (i = 0; i < RT2860_SOFTC_RX_RING_DATA_COUNT; i++)
+	{
+		desc = &ring->desc[i];
+		data = &ring->data[i];
+
+		error = bus_dmamap_create(ring->data_dma_tag, 0, &data->dma_map);
+		if (error != 0)
+		{
+			printf("%s: could not create Rx data DMA map\n",
+				device_get_nameunit(sc->sc_dev));
+			goto fail;
+		}
+
+		data->m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
+		if (data->m == NULL)
+		{
+			printf("%s: could not allocate Rx mbuf\n",
+				device_get_nameunit(sc->sc_dev));
+			error = ENOMEM;
+			goto fail;
+		}
+
+		data->m->m_len = data->m->m_pkthdr.len = MJUMPAGESIZE;
+
+		error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map,
+			data->m, segs, &nsegs, BUS_DMA_NOWAIT);
+		if (error != 0)
+		{
+			printf("%s: could not load Rx mbuf DMA map\n",
+				device_get_nameunit(sc->sc_dev));
+			goto fail;
+		}
+
+		KASSERT(nsegs == 1, ("%s: too many DMA segments",
+			device_get_nameunit(sc->sc_dev)));
+
+		desc->sdp0 = htole32(segs[0].ds_addr);
+		desc->sdl0 = htole16(MJUMPAGESIZE);
+	}
+
+	error = bus_dmamap_create(ring->data_dma_tag, 0, &ring->spare_dma_map);
+	if (error != 0)
+	{
+		printf("%s: could not create Rx spare DMA map\n",
+			device_get_nameunit(sc->sc_dev));
+		goto fail;
+	}
+
+	bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+		BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+	return 0;
+
+fail:
+	
+	rt2860_free_rx_ring(sc, ring);
+
+	return error;
+}
+
+/*
+ * rt2860_reset_rx_ring
+ */
+static void rt2860_reset_rx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_rx_ring *ring)
+{
+	struct rt2860_rxdesc *desc;
+	int i;
+
+	for (i = 0; i < RT2860_SOFTC_RX_RING_DATA_COUNT; i++) {
+		desc = &ring->desc[i];
+
+		desc->sdl0 &= ~htole16(RT2860_RXDESC_SDL0_DDONE);
+	}
+
+	bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+		BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+	ring->cur = 0;
+}
+
+/*
+ * rt2860_free_rx_ring
+ */
+static void rt2860_free_rx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_rx_ring *ring)
+{
+	struct rt2860_softc_rx_data *data;
+	int i;
+
+	if (ring->desc != NULL) {
+		bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+			BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(ring->desc_dma_tag, ring->desc_dma_map);
+		bus_dmamem_free(ring->desc_dma_tag, ring->desc,
+			ring->desc_dma_map);
+	}
+
+	if (ring->desc_dma_tag != NULL)
+		bus_dma_tag_destroy(ring->desc_dma_tag);
+
+	for (i = 0; i < RT2860_SOFTC_RX_RING_DATA_COUNT; i++) {
+		data = &ring->data[i];
+
+		if (data->m != NULL) {
+			bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+				BUS_DMASYNC_POSTREAD);
+			bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+			m_freem(data->m);
+		}
+
+		if (data->dma_map != NULL)
+			bus_dmamap_destroy(ring->data_dma_tag, data->dma_map);
+	}
+
+	if (ring->spare_dma_map != NULL)
+		bus_dmamap_destroy(ring->data_dma_tag, ring->spare_dma_map);
+
+	if (ring->data_dma_tag != NULL)
+		bus_dma_tag_destroy(ring->data_dma_tag);
+}
+
+/*
+ * rt2860_alloc_tx_ring
+ */
+static int rt2860_alloc_tx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_tx_ring *ring, int qid)
+{
+	struct rt2860_softc_tx_data *data;
+	int error, i, size;
+
+	size = RT2860_SOFTC_TX_RING_DESC_COUNT * sizeof(struct rt2860_txdesc);
+	mtx_init(&ring->lock, device_get_nameunit(sc->sc_dev), NULL, MTX_DEF);
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    size, 1, size, 0, NULL, NULL, &ring->desc_dma_tag);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create Tx desc DMA tag\n");
+		goto fail;
+	}
+
+	error = bus_dmamem_alloc(ring->desc_dma_tag, (void **) &ring->desc,
+	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_dma_map);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "could not allocate Tx desc DMA memory\n");
+		goto fail;
+	}
+
+	error = bus_dmamap_load(ring->desc_dma_tag, ring->desc_dma_map,
+	    ring->desc, size, rt2860_dma_map_addr, &ring->desc_phys_addr, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not load Tx desc DMA map\n");
+		goto fail;
+	}
+
+	ring->desc_queued = 0;
+	ring->desc_cur = 0;
+	ring->desc_next = 0;
+
+	size = RT2860_SOFTC_TX_RING_DATA_COUNT * RT2860_TX_DATA_SEG0_SIZE;
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    size, 1, size, 0, NULL, NULL, &ring->seg0_dma_tag);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create Tx seg0 DMA tag\n");
+		goto fail;
+	}
+
+	error = bus_dmamem_alloc(ring->seg0_dma_tag, (void **) &ring->seg0,
+	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->seg0_dma_map);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not allocate Tx seg0 DMA memory\n");
+		goto fail;
+	}
+
+	error = bus_dmamap_load(ring->seg0_dma_tag, ring->seg0_dma_map,
+	    ring->seg0, size, rt2860_dma_map_addr, &ring->seg0_phys_addr, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not load Tx seg0 DMA map\n");
+		goto fail;
+	}
+
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    MJUMPAGESIZE, RT2860_SOFTC_MAX_SCATTER, MJUMPAGESIZE, 0,
+	    NULL, NULL, &ring->data_dma_tag);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create Tx data DMA tag\n");
+		goto fail;
+	}
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_DATA_COUNT; i++){
+		data = &ring->data[i];
+
+		error = bus_dmamap_create(ring->data_dma_tag, 0,
+		    &data->dma_map);
+		if (error != 0) {
+			device_printf(sc->sc_dev, "could not create Tx data DMA map\n");
+			goto fail;
+		}
+	}
+
+	ring->data_queued = 0;
+	ring->data_cur = 0;
+	ring->data_next = 0;
+
+	ring->qid = qid;
+
+	return 0;
+
+fail:
+	
+	rt2860_free_tx_ring(sc, ring);
+
+	return error;
+}
+
+/*
+ * rt2860_reset_tx_ring
+ */
+static void rt2860_reset_tx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_tx_ring *ring)
+{
+	struct rt2860_softc_tx_data *data;
+	struct rt2860_txdesc *desc;
+	int i;
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_DESC_COUNT; i++)
+	{
+		desc = &ring->desc[i];
+
+		desc->sdl0 = 0;
+		desc->sdl1 = 0;
+	}
+
+	ring->desc_queued = 0;
+	ring->desc_cur = 0;
+	ring->desc_next = 0;
+
+	bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+		BUS_DMASYNC_PREWRITE);
+
+	bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map,
+		BUS_DMASYNC_PREWRITE);
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_DATA_COUNT; i++)
+	{
+		data = &ring->data[i];
+
+		if (data->m != NULL)
+		{
+			bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+				BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+			m_freem(data->m);
+			data->m = NULL;
+		}
+
+		if (data->ni != NULL)
+		{
+			ieee80211_free_node(data->ni);
+			data->ni = NULL;
+		}
+	}
+
+	ring->data_queued = 0;
+	ring->data_cur = 0;
+	ring->data_next = 0;
+}
+
+/*
+ * rt2860_free_tx_ring
+ */
+static void rt2860_free_tx_ring(struct rt2860_softc *sc,
+	struct rt2860_softc_tx_ring *ring)
+{
+	struct rt2860_softc_tx_data *data;
+	int i;
+
+	if (ring->desc != NULL)
+	{
+		bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+			BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(ring->desc_dma_tag, ring->desc_dma_map);
+		bus_dmamem_free(ring->desc_dma_tag, ring->desc,
+			ring->desc_dma_map);
+	}
+
+	if (ring->desc_dma_tag != NULL)
+		bus_dma_tag_destroy(ring->desc_dma_tag);
+
+	if (ring->seg0 != NULL)
+	{
+		bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map,
+			BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(ring->seg0_dma_tag, ring->seg0_dma_map);
+		bus_dmamem_free(ring->seg0_dma_tag, ring->seg0,
+			ring->seg0_dma_map);
+	}
+
+	if (ring->seg0_dma_tag != NULL)
+		bus_dma_tag_destroy(ring->seg0_dma_tag);
+
+	for (i = 0; i < RT2860_SOFTC_TX_RING_DATA_COUNT; i++)
+	{
+		data = &ring->data[i];
+
+		if (data->m != NULL)
+		{
+			bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+				BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+			m_freem(data->m);
+		}
+
+		if (data->ni != NULL)
+			ieee80211_free_node(data->ni);
+
+		if (data->dma_map != NULL)
+			bus_dmamap_destroy(ring->data_dma_tag, data->dma_map);
+	}
+
+	if (ring->data_dma_tag != NULL)
+		bus_dma_tag_destroy(ring->data_dma_tag);
+
+	mtx_destroy(&ring->lock);
+}
+
+/*
+ * rt2860_dma_map_addr
+ */
+static void rt2860_dma_map_addr(void *arg, bus_dma_segment_t *segs,
+	int nseg, int error)
+{
+	if (error != 0)
+		return;
+
+	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+
+	*(bus_addr_t *) arg = segs[0].ds_addr;
+}
+
+/*
+ * rt2860_sysctl_attach
+ */
+static void rt2860_sysctl_attach(struct rt2860_softc *sc)
+{
+	struct sysctl_ctx_list *ctx;
+	struct sysctl_oid *tree;
+	struct sysctl_oid *stats;
+
+	ctx = device_get_sysctl_ctx(sc->sc_dev);
+	tree = device_get_sysctl_tree(sc->sc_dev);
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+		"tx_stbc", CTLFLAG_RW, &sc->tx_stbc, 0,
+		"Tx STBC");
+
+	/* statistic counters */
+
+	stats = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+		"stats", CTLFLAG_RD, 0, "statistic");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"interrupts", CTLFLAG_RD, &sc->interrupts, 0,
+		"all interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_coherent_interrupts", CTLFLAG_RD, &sc->tx_coherent_interrupts, 0,
+		"Tx coherent interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_coherent_interrupts", CTLFLAG_RD, &sc->rx_coherent_interrupts, 0,
+		"Rx coherent interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"txrx_coherent_interrupts", CTLFLAG_RD, &sc->txrx_coherent_interrupts, 0,
+		"Tx/Rx coherent interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"fifo_sta_full_interrupts", CTLFLAG_RD, &sc->fifo_sta_full_interrupts, 0,
+		"FIFO statistic full interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_interrupts", CTLFLAG_RD, &sc->rx_interrupts, 0,
+		"Rx interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_delay_interrupts", CTLFLAG_RD, &sc->rx_delay_interrupts, 0,
+		"Rx delay interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_mgmt_interrupts", CTLFLAG_RD, &sc->tx_interrupts[5], 0,
+		"Tx MGMT interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_hcca_interrupts", CTLFLAG_RD, &sc->tx_interrupts[4], 0,
+		"Tx HCCA interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac3_interrupts", CTLFLAG_RD, &sc->tx_interrupts[3], 0,
+		"Tx AC3 interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac2_interrupts", CTLFLAG_RD, &sc->tx_interrupts[2], 0,
+		"Tx AC2 interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac1_interrupts", CTLFLAG_RD, &sc->tx_interrupts[1], 0,
+		"Tx AC1 interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac0_interrupts", CTLFLAG_RD, &sc->tx_interrupts[0], 0,
+		"Tx AC0 interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_delay_interrupts", CTLFLAG_RD, &sc->tx_delay_interrupts, 0,
+		"Tx delay interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"pre_tbtt_interrupts", CTLFLAG_RD, &sc->pre_tbtt_interrupts, 0,
+		"Pre-TBTT interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tbtt_interrupts", CTLFLAG_RD, &sc->tbtt_interrupts, 0,
+		"TBTT interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"mcu_cmd_interrupts", CTLFLAG_RD, &sc->mcu_cmd_interrupts, 0,
+		"MCU command interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"auto_wakeup_interrupts", CTLFLAG_RD, &sc->auto_wakeup_interrupts, 0,
+		"auto wakeup interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"gp_timer_interrupts", CTLFLAG_RD, &sc->gp_timer_interrupts, 0,
+		"GP timer interrupts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_mgmt_desc_queued", CTLFLAG_RD, &sc->tx_ring[5].desc_queued, 0,
+		"Tx MGMT descriptors queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_mgmt_data_queued", CTLFLAG_RD, &sc->tx_ring[5].data_queued, 0,
+		"Tx MGMT data queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_hcca_desc_queued", CTLFLAG_RD, &sc->tx_ring[4].desc_queued, 0,
+		"Tx HCCA descriptors queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_hcca_data_queued", CTLFLAG_RD, &sc->tx_ring[4].data_queued, 0,
+		"Tx HCCA data queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac3_desc_queued", CTLFLAG_RD, &sc->tx_ring[3].desc_queued, 0,
+		"Tx AC3 descriptors queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac3_data_queued", CTLFLAG_RD, &sc->tx_ring[3].data_queued, 0,
+		"Tx AC3 data queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac2_desc_queued", CTLFLAG_RD, &sc->tx_ring[2].desc_queued, 0,
+		"Tx AC2 descriptors queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac2_data_queued", CTLFLAG_RD, &sc->tx_ring[2].data_queued, 0,
+		"Tx AC2 data queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac1_desc_queued", CTLFLAG_RD, &sc->tx_ring[1].desc_queued, 0,
+		"Tx AC1 descriptors queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac1_data_queued", CTLFLAG_RD, &sc->tx_ring[1].data_queued, 0,
+		"Tx AC1 data queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac0_desc_queued", CTLFLAG_RD, &sc->tx_ring[0].desc_queued, 0,
+		"Tx AC0 descriptors queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac0_data_queued", CTLFLAG_RD, &sc->tx_ring[0].data_queued, 0,
+		"Tx AC0 data queued");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_mgmt_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[5], 0,
+		"Tx MGMT data queue full");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_hcca_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[4], 0,
+		"Tx HCCA data queue full");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac3_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[3], 0,
+		"Tx AC3 data queue full");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac2_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[2], 0,
+		"Tx AC2 data queue full");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac1_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[1], 0,
+		"Tx AC1 data queue full");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ac0_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[0], 0,
+		"Tx AC0 data queue full");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_watchdog_timeouts", CTLFLAG_RD, &sc->tx_watchdog_timeouts, 0,
+		"Tx watchdog timeouts");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_defrag_packets", CTLFLAG_RD, &sc->tx_defrag_packets, 0,
+		"Tx defragmented packets");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"no_tx_desc_avail", CTLFLAG_RD, &sc->no_tx_desc_avail, 0,
+		"no Tx descriptors available");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_mbuf_alloc_errors", CTLFLAG_RD, &sc->rx_mbuf_alloc_errors, 0,
+		"Rx mbuf allocation errors");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_mbuf_dmamap_errors", CTLFLAG_RD, &sc->rx_mbuf_dmamap_errors, 0,
+		"Rx mbuf DMA mapping errors");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_queue_0_not_empty", CTLFLAG_RD, &sc->tx_queue_not_empty[0], 0,
+		"Tx queue 0 not empty");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_queue_1_not_empty", CTLFLAG_RD, &sc->tx_queue_not_empty[1], 0,
+		"Tx queue 1 not empty");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_beacons", CTLFLAG_RD, &sc->tx_beacons, 0,
+		"Tx beacons");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_noretryok", CTLFLAG_RD, &sc->tx_noretryok, 0,
+		"Tx successfull without retries");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_retryok", CTLFLAG_RD, &sc->tx_retryok, 0,
+		"Tx successfull with retries");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_failed", CTLFLAG_RD, &sc->tx_failed, 0,
+		"Tx failed");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_underflows", CTLFLAG_RD, &sc->tx_underflows, 0,
+		"Tx underflows");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_zerolen", CTLFLAG_RD, &sc->tx_zerolen, 0,
+		"Tx zero length");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_nonagg", CTLFLAG_RD, &sc->tx_nonagg, 0,
+		"Tx non-aggregated");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_agg", CTLFLAG_RD, &sc->tx_agg, 0,
+		"Tx aggregated");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ampdu", CTLFLAG_RD, &sc->tx_ampdu, 0,
+		"Tx A-MPDU");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_mpdu_zero_density", CTLFLAG_RD, &sc->tx_mpdu_zero_density, 0,
+		"Tx MPDU with zero density");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"tx_ampdu_sessions", CTLFLAG_RD, &sc->tx_ampdu_sessions, 0,
+		"Tx A-MPDU sessions");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_packets", CTLFLAG_RD, &sc->rx_packets, 0,
+		"Rx packets");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_ampdu", CTLFLAG_RD, &sc->rx_ampdu, 0,
+		"Rx A-MPDU");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_ampdu_retries", CTLFLAG_RD, &sc->rx_ampdu_retries, 0,
+		"Rx A-MPDU retries");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_mpdu_zero_density", CTLFLAG_RD, &sc->rx_mpdu_zero_density, 0,
+		"Rx MPDU with zero density");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_ampdu_sessions", CTLFLAG_RD, &sc->rx_ampdu_sessions, 0,
+		"Rx A-MPDU sessions");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_amsdu", CTLFLAG_RD, &sc->rx_amsdu, 0,
+		"Rx A-MSDU");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_crc_errors", CTLFLAG_RD, &sc->rx_crc_errors, 0,
+		"Rx CRC errors");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_phy_errors", CTLFLAG_RD, &sc->rx_phy_errors, 0,
+		"Rx PHY errors");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_false_ccas", CTLFLAG_RD, &sc->rx_false_ccas, 0,
+		"Rx false CCAs");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_plcp_errors", CTLFLAG_RD, &sc->rx_plcp_errors, 0,
+		"Rx PLCP errors");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_dup_packets", CTLFLAG_RD, &sc->rx_dup_packets, 0,
+		"Rx duplicate packets");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_fifo_overflows", CTLFLAG_RD, &sc->rx_fifo_overflows, 0,
+		"Rx FIFO overflows");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_cipher_no_errors", CTLFLAG_RD, &sc->rx_cipher_no_errors, 0,
+		"Rx cipher no errors");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_cipher_icv_errors", CTLFLAG_RD, &sc->rx_cipher_icv_errors, 0,
+		"Rx cipher ICV errors");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_cipher_mic_errors", CTLFLAG_RD, &sc->rx_cipher_mic_errors, 0,
+		"Rx cipher MIC errors");
+
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+		"rx_cipher_invalid_key_errors", CTLFLAG_RD, &sc->rx_cipher_invalid_key_errors, 0,
+		"Rx cipher invalid key errors");
+}
+
+/*
+ * Defines and macros
+ */
+
+#define RT2860_AMRR_IS_SUCCESS(amrr_node)				((amrr_node)->retrycnt < (amrr_node)->txcnt / 10)
+
+#define RT2860_AMRR_IS_FAILURE(amrr_node)				((amrr_node)->retrycnt > (amrr_node)->txcnt / 3)
+
+#define RT2860_AMRR_IS_ENOUGH(amrr_node)				((amrr_node)->txcnt > 10)
+
+/*
+ * Static function prototypes
+ */
+
+static int rt2860_amrr_update(struct rt2860_amrr *amrr,
+	struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni);
+
+/*
+ * rt2860_amrr_init
+ */
+void rt2860_amrr_init(struct rt2860_amrr *amrr, struct ieee80211vap *vap,
+	int ntxpath, int min_success_threshold, int max_success_threshold, int msecs)
+{
+	int t;
+
+	amrr->ntxpath = ntxpath;
+
+	amrr->min_success_threshold = min_success_threshold;
+	amrr->max_success_threshold = max_success_threshold;
+
+	if (msecs < 100)
+		msecs = 100;
+
+	t = msecs_to_ticks(msecs);
+
+	amrr->interval = (t < 1) ? 1 : t;
+}
+
+/*
+ * rt2860_amrr_cleanup
+ */
+void rt2860_amrr_cleanup(struct rt2860_amrr *amrr)
+{
+}
+
+/*
+ * rt2860_amrr_node_init
+ */
+void rt2860_amrr_node_init(struct rt2860_amrr *amrr,
+    struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni)
+{
+	const struct ieee80211_rateset *rs;
+
+	amrr_node->amrr = amrr;
+	amrr_node->success = 0;
+	amrr_node->recovery = 0;
+	amrr_node->txcnt = 0;
+	amrr_node->retrycnt = 0;
+	amrr_node->success_threshold = amrr->min_success_threshold;
+
+	if (ni->ni_flags & IEEE80211_NODE_HT)
+	{
+		rs = (const struct ieee80211_rateset *) &ni->ni_htrates;
+
+		for (amrr_node->rate_index = rs->rs_nrates - 1;
+			amrr_node->rate_index > 0 && (rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL) > 4;
+			amrr_node->rate_index--) ;
+
+		ni->ni_txrate = rs->rs_rates[amrr_node->rate_index] | IEEE80211_RATE_MCS;
+	}
+	else
+	{
+		rs = &ni->ni_rates;
+
+		for (amrr_node->rate_index = rs->rs_nrates - 1;
+			amrr_node->rate_index > 0 && (rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL) > 72;
+			amrr_node->rate_index--) ;
+
+		ni->ni_txrate = rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL;
+	}
+
+	amrr_node->ticks = ticks;
+}
+
+/*
+ * rt2860_amrr_choose
+ */
+int rt2860_amrr_choose(struct ieee80211_node *ni,
+	struct rt2860_amrr_node *amrr_node)
+{
+	struct rt2860_amrr *amrr;
+	int rate_index;
+
+	amrr = amrr_node->amrr;
+
+	if (RT2860_AMRR_IS_ENOUGH(amrr_node) &&
+		(ticks - amrr_node->ticks) > amrr->interval)
+	{
+		rate_index = rt2860_amrr_update(amrr, amrr_node, ni);
+		if (rate_index != amrr_node->rate_index)
+		{
+			if (ni->ni_flags & IEEE80211_NODE_HT)
+				ni->ni_txrate = ni->ni_htrates.rs_rates[rate_index] | IEEE80211_RATE_MCS;
+			else
+				ni->ni_txrate = ni->ni_rates.rs_rates[rate_index] & IEEE80211_RATE_VAL;
+
+			amrr_node->rate_index = rate_index;
+		}
+
+		amrr_node->ticks = ticks;
+	}
+	else
+	{
+		rate_index = amrr_node->rate_index;
+	}
+
+	return rate_index;
+}
+
+/*
+ * rt2860_amrr_update
+ */
+static int rt2860_amrr_update(struct rt2860_amrr *amrr,
+	struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni)
+{
+	const struct ieee80211_rateset *rs;
+	int rate_index;
+
+	KASSERT(RT2860_AMRR_IS_ENOUGH(amrr_node),
+		("not enough Tx count: txcnt=%d",
+		 amrr_node->txcnt));
+
+	if (ni->ni_flags & IEEE80211_NODE_HT)
+		rs = (const struct ieee80211_rateset *) &ni->ni_htrates;
+	else
+		rs = &ni->ni_rates;
+
+	rate_index = amrr_node->rate_index;
+
+	if (RT2860_AMRR_IS_SUCCESS(amrr_node))
+	{
+		amrr_node->success++;
+		if ((amrr_node->success >= amrr_node->success_threshold) &&
+		    (rate_index + 1 < rs->rs_nrates) &&
+			(!(ni->ni_flags & IEEE80211_NODE_HT) || (rs->rs_rates[rate_index + 1] & IEEE80211_RATE_VAL) < (amrr->ntxpath * 8)))
+		{
+			amrr_node->recovery = 1;
+			amrr_node->success = 0;
+
+			rate_index++;
+		}
+		else
+		{
+			amrr_node->recovery = 0;
+		}
+	}
+	else if (RT2860_AMRR_IS_FAILURE(amrr_node))
+	{
+		amrr_node->success = 0;
+
+		if (rate_index > 0)
+		{
+			if (amrr_node->recovery)
+			{
+				amrr_node->success_threshold *= 2;
+				if (amrr_node->success_threshold > amrr->max_success_threshold)
+					amrr_node->success_threshold = amrr->max_success_threshold;
+			}
+			else
+			{
+				amrr_node->success_threshold = amrr->min_success_threshold;
+			}
+
+			rate_index--;
+		}
+
+		amrr_node->recovery = 0;
+	}
+
+	amrr_node->txcnt = 0;
+	amrr_node->retrycnt = 0;
+
+	return rate_index;
+}
+
+/*
+ * Defines and macros
+ */
+
+/*
+ * RT2860_IO_EEPROM_RAISE_CLK
+ */
+#define RT2860_IO_EEPROM_RAISE_CLK(sc, val)				\
+do									\
+{									\
+	(val) |= RT2860_REG_EESK;					\
+									\
+	rt2860_io_mac_write((sc), RT2860_REG_EEPROM_CSR, (val));	\
+									\
+	DELAY(1);							\
+} while (0)
+
+/*
+ * RT2860_IO_EEPROM_LOWER_CLK
+ */
+#define RT2860_IO_EEPROM_LOWER_CLK(sc, val)				\
+do									\
+{									\
+	(val) &= ~RT2860_REG_EESK;					\
+									\
+	rt2860_io_mac_write((sc), RT2860_REG_EEPROM_CSR, (val));	\
+									\
+	DELAY(1);							\
+} while (0)
+
+#define RT2860_IO_BYTE_CRC16(byte, crc)					\
+	((uint16_t) (((crc) << 8) ^					\
+	    rt2860_io_ccitt16[(((crc) >> 8) ^ (byte)) & 255]))
+
+/*
+ * Static function prototypes
+ */
+
+static void rt2860_io_eeprom_shiftout_bits(struct rt2860_softc *sc,
+	uint16_t val, uint16_t count);
+
+static uint16_t rt2860_io_eeprom_shiftin_bits(struct rt2860_softc *sc);
+
+static uint8_t rt2860_io_byte_rev(uint8_t byte);
+
+/* #ifdef RT305X_SOC */
+static const uint16_t rt3052_eeprom[] = 
+{
+	0x3052, 0x0101, 0x0c00, 0x3043, 0x8852, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0x0c00, 0x3043, 0x7752, 0x0c00,
+	0x3043, 0x6652, 0x0822, 0x0024, 0xffff, 0x012f, 0x7755, 0xaaa8,
+	0x888c, 0xffff, 0x000c, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff,
+	0xffff, 0x0d0d, 0x0d0d, 0x0c0c, 0x0c0c, 0x0c0c, 0x0c0c, 0x0c0c,
+	0x1010, 0x1111, 0x1211, 0x1212, 0x1313, 0x1413, 0x1414, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x6666,
+	0xaacc, 0x6688, 0xaacc, 0x6688, 0xaacc, 0x6688, 0xaacc, 0x6688,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+};
+
+uint8_t rt3052_rf_default[] = {
+	0x50, /* 0 */
+	0x01,
+	0xF7,
+	0x75,
+	0x40,
+	0x03,
+	0x42,
+	0x50,
+	0x39,
+	0x0F,
+	0x60, /* 10 */
+	0x21,
+	0x75,
+	0x75,
+	0x90,
+	0x58,
+	0xB3,
+	0x92,
+	0x2C,
+	0x02,
+	0xBA, /* 20 */
+	0xDB,
+	0x00,
+	0x31,
+	0x08,
+	0x01,
+	0x25, /* Core Power: 0x25=1.25V */
+	0x23, /* RF: 1.35V */
+      	0x13, /* ADC: must consist with R27 */
+	0x83,
+	0x00, /* 30 */
+	0x00,
+};
+/* #endif */
+
+
+/*
+ * Static variables
+ */
+
+static const uint16_t rt2860_io_ccitt16[] =
+{
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+/*
+ * rt2860_io_mac_read
+ */
+uint32_t rt2860_io_mac_read(struct rt2860_softc *sc, uint16_t reg)
+{
+
+	return bus_space_read_4(sc->sc_st, sc->sc_sh, reg);
+}
+
+/*
+ * rt2860_io_mac_read_multi
+ */
+void rt2860_io_mac_read_multi(struct rt2860_softc *sc,
+	uint16_t reg, void *buf, size_t len)
+{
+
+	bus_space_read_region_1(sc->sc_st, sc->sc_sh, reg, buf, len);
+}
+
+/*
+ * rt2860_io_mac_write
+ */
+void rt2860_io_mac_write(struct rt2860_softc *sc,
+	uint16_t reg, uint32_t val)
+{
+
+	bus_space_write_4(sc->sc_st, sc->sc_sh, reg, val);
+}
+
+/*
+ * rt2860_io_mac_write_multi
+ */
+void rt2860_io_mac_write_multi(struct rt2860_softc *sc,
+	uint16_t reg, const void *buf, size_t len)
+{
+	int i;
+	const uint8_t *p;
+
+	p = buf;
+	for (i = 0; i < len; i ++)
+		bus_space_write_1(sc->sc_st, sc->sc_sh, reg + i, *(p+i));
+
+#ifdef notyet
+	bus_space_write_region_1(sc->sc_st, sc->sc_sh, reg, buf, len);
+#endif
+}
+
+/*
+ * rt2860_io_mac_set_region_4
+ */
+void rt2860_io_mac_set_region_4(struct rt2860_softc *sc,
+	uint16_t reg, uint32_t val, size_t len)
+{
+	int i;
+
+	for (i = 0; i < len; i += sizeof(uint32_t))
+		rt2860_io_mac_write(sc, reg + i, val);
+}
+
+/* Read 16-bit from eFUSE ROM (>=RT3071 only.) */
+static uint16_t
+rt3090_efuse_read_2(struct rt2860_softc *sc, uint16_t addr)
+{
+	uint32_t tmp;
+	uint16_t reg;
+	int ntries;
+
+	addr *= 2;
+	/*-
+	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
+	 * DATA0: F E D C
+	 * DATA1: B A 9 8
+	 * DATA2: 7 6 5 4
+	 * DATA3: 3 2 1 0
+	 */
+	tmp = rt2860_io_mac_read(sc, RT3070_EFUSE_CTRL);
+	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
+	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
+	rt2860_io_mac_write(sc, RT3070_EFUSE_CTRL, tmp);
+	for (ntries = 0; ntries < 500; ntries++) {
+		tmp = rt2860_io_mac_read(sc, RT3070_EFUSE_CTRL);
+		if (!(tmp & RT3070_EFSROM_KICK))
+			break;
+		DELAY(2);
+	}
+	if (ntries == 500)
+		return 0xffff;
+
+	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK)
+		return 0xffff;	/* address not found */
+
+	/* determine to which 32-bit register our 16-bit word belongs */
+	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
+	tmp = rt2860_io_mac_read(sc, reg);
+
+	return (addr & 2) ? tmp >> 16 : tmp & 0xffff;
+}
+
+
+/*
+ * rt2860_io_eeprom_read
+ */
+uint16_t rt2860_io_eeprom_read(struct rt2860_softc *sc, uint16_t addr)
+{
+	uint32_t tmp;
+	uint16_t val;
+
+	addr = (addr >> 1);
+
+	if (sc->mac_rev == 0x28720200) {
+		return (rt3052_eeprom[addr]);
+	} else if ((sc->mac_rev & 0xffff0000) >= 0x30710000) {
+		tmp = rt2860_io_mac_read(sc, RT3070_EFUSE_CTRL);
+		if (tmp & RT3070_SEL_EFUSE)
+			return (rt3090_efuse_read_2(sc, addr));
+	}
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+	tmp &= ~(RT2860_REG_EEDI | RT2860_REG_EEDO | RT2860_REG_EESK);
+	tmp |= RT2860_REG_EECS;
+
+	rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp);
+
+	if (((sc->mac_rev & 0xffff0000) != 0x30710000) &&
+		((sc->mac_rev & 0xffff0000) != 0x30900000) &&
+		((sc->mac_rev & 0xffff0000) != 0x35720000) &&
+		((sc->mac_rev & 0xffff0000) != 0x33900000))
+	{
+		RT2860_IO_EEPROM_RAISE_CLK(sc, tmp);
+		RT2860_IO_EEPROM_LOWER_CLK(sc, tmp);
+	}
+
+	rt2860_io_eeprom_shiftout_bits(sc, RT2860_REG_EEOP_READ, 3);
+	rt2860_io_eeprom_shiftout_bits(sc, addr, sc->eeprom_addr_num);
+
+	val = rt2860_io_eeprom_shiftin_bits(sc);
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+	tmp &= ~(RT2860_REG_EECS | RT2860_REG_EEDI);
+
+	rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp);
+
+	RT2860_IO_EEPROM_RAISE_CLK(sc, tmp);
+	RT2860_IO_EEPROM_LOWER_CLK(sc, tmp);
+
+	return val;
+}
+
+/*
+ * rt2860_io_eeprom_read_multi
+ */
+void rt2860_io_eeprom_read_multi(struct rt2860_softc *sc,
+	uint16_t addr, void *buf, size_t len)
+{
+	uint16_t *ptr;
+	int i;
+
+	len += len % sizeof(uint16_t);
+	ptr = buf;
+
+	i = 0;
+
+	do
+	{
+		*ptr++ = rt2860_io_eeprom_read(sc, addr + i);
+
+		i += sizeof(uint16_t);
+		len -= sizeof(uint16_t);
+	} while (len > 0);
+}
+
+/*
+ * rt2860_io_bbp_read
+ */
+uint8_t rt2860_io_bbp_read(struct rt2860_softc *sc, uint8_t reg)
+{
+	int ntries;
+	uint32_t tmp;
+
+	if (sc->mac_rev == 0x28720200)
+	{
+		for (ntries = 0; ntries < 100; ntries ++) {
+			if ( !(rt2860_io_mac_read(sc, RT2860_REG_BBP_CSR_CFG) & 
+			    RT2860_REG_BBP_CSR_BUSY) )
+				break;
+			DELAY(1);
+		}
+		if (ntries == 100) {
+			printf("%s:%s: BBP busy after 100 probes\n",
+				device_get_nameunit(sc->sc_dev), __func__);
+			return (0);
+		}
+		rt2860_io_mac_write(sc, RT2860_REG_BBP_CSR_CFG, 
+		    RT2860_REG_BBP_CSR_READ |
+		    RT2860_REG_BBP_CSR_KICK | RT2860_REG_BBP_RW_MODE_PARALLEL |
+		    (reg & RT2860_REG_BBP_REG_MASK) << RT2860_REG_BBP_REG_SHIFT);
+		for (ntries = 0; ntries < 100; ntries ++) {
+			if ( !(rt2860_io_mac_read(sc, RT2860_REG_BBP_CSR_CFG) & 
+			    RT2860_REG_BBP_CSR_BUSY) )
+				break;
+			DELAY(1);
+		}
+		if (ntries == 100) {
+			printf("%s:%s: BBP busy after 100 probes\n",
+				device_get_nameunit(sc->sc_dev), __func__);
+			return (0);
+		}
+		else {
+			return 
+			    ((rt2860_io_mac_read(sc, RT2860_REG_BBP_CSR_CFG) >>
+			    RT2860_REG_BBP_VAL_SHIFT) & 
+			    RT2860_REG_BBP_VAL_MASK);
+		}
+		return (0);
+	}
+
+	for (ntries = 0; ntries < 100; ntries++)
+	{
+		if (!(rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT) &
+			RT2860_REG_BBP_CSR_BUSY))
+			break;
+
+		DELAY(1);
+	}
+
+	if (ntries == 100)
+	{
+		printf("%s: could not read from BBP through MCU: reg=0x%02x\n",
+			device_get_nameunit(sc->sc_dev), reg);
+		return 0;
+	}
+
+	tmp = RT2860_REG_BBP_RW_MODE_PARALLEL |
+		RT2860_REG_BBP_CSR_BUSY |
+		RT2860_REG_BBP_CSR_READ |
+		((reg & RT2860_REG_BBP_REG_MASK) << RT2860_REG_BBP_REG_SHIFT);
+
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT, tmp);
+
+	rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_BBP,
+		RT2860_REG_H2M_TOKEN_NO_INTR, 0);
+
+	DELAY(1000);
+
+	for (ntries = 0; ntries < 100; ntries++)
+	{
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT);
+		if (!(tmp & RT2860_REG_BBP_CSR_BUSY))
+			return ((tmp >> RT2860_REG_BBP_VAL_SHIFT) &
+				RT2860_REG_BBP_VAL_MASK);
+
+		DELAY(1);
+	}
+
+	printf("%s: could not read from BBP through MCU: reg=0x%02x\n",
+		device_get_nameunit(sc->sc_dev), reg);
+
+	return 0;
+}
+
+/*
+ * rt2860_io_bbp_write
+ */
+void rt2860_io_bbp_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val)
+{
+	int ntries;
+	uint32_t tmp;
+
+	if (sc->mac_rev == 0x28720200)
+	{
+		for (ntries = 0; ntries < 100; ntries ++) {
+			if ( !(rt2860_io_mac_read(sc, RT2860_REG_BBP_CSR_CFG) & 
+			    RT2860_REG_BBP_CSR_BUSY) )
+				break;
+			DELAY(1);
+		}
+		if (ntries == 100) {
+			printf("%s:%s: BBP busy after 100 probes\n",
+				device_get_nameunit(sc->sc_dev), __func__);
+			return;
+		}
+		rt2860_io_mac_write(sc, RT2860_REG_BBP_CSR_CFG, 
+		    RT2860_REG_BBP_CSR_KICK | RT2860_REG_BBP_RW_MODE_PARALLEL |
+		    (reg & RT2860_REG_BBP_REG_MASK) << RT2860_REG_BBP_REG_SHIFT | 
+		    (val & RT2860_REG_BBP_VAL_MASK) << RT2860_REG_BBP_VAL_SHIFT );
+		rt2860_io_bbp_read(sc, reg);
+		return;
+	}
+
+	for (ntries = 0; ntries < 100; ntries++)
+	{
+		if (!(rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT) &
+			RT2860_REG_BBP_CSR_BUSY))
+			break;
+
+		DELAY(1);
+	}
+
+	if (ntries == 100)
+	{
+		printf("%s: could not write to BBP through MCU: reg=0x%02x\n",
+			device_get_nameunit(sc->sc_dev), reg);
+		return;
+	}
+
+	tmp = RT2860_REG_BBP_RW_MODE_PARALLEL |
+		RT2860_REG_BBP_CSR_BUSY |
+		((reg & RT2860_REG_BBP_REG_MASK) << RT2860_REG_BBP_REG_SHIFT) |
+		((val & RT2860_REG_BBP_VAL_MASK) << RT2860_REG_BBP_VAL_SHIFT);
+
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT, tmp);
+
+	rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_BBP,
+		RT2860_REG_H2M_TOKEN_NO_INTR, 0);
+
+	DELAY(1000);
+}
+
+/*
+ * rt2860_io_rf_write
+ */
+void rt2860_io_rf_write(struct rt2860_softc *sc, uint8_t reg, uint32_t val)
+{
+	int ntries;
+	if (sc->mac_rev == 0x28720200)
+	{
+		for (ntries = 0; ntries < 100; ntries ++) {
+			if ( !(rt2860_io_mac_read(sc, RT2872_REG_RF_CSR_CFG) &
+			    RT2872_REG_RF_CSR_BUSY) )
+				break;
+			DELAY(1);
+		}
+		if (ntries == 100) {
+			printf("%s:%s: RF busy after 100 probes\n",
+				device_get_nameunit(sc->sc_dev), __func__);
+			return;
+		}
+		rt2860_io_mac_write(sc, RT2872_REG_RF_CSR_CFG, 
+		    RT2872_REG_RF_CSR_KICK | RT2872_REG_RF_CSR_WRITE |
+		    (reg & RT2872_REG_RF_ID_MASK) << RT2872_REG_RF_ID_SHIFT | 
+		    (val & RT2872_REG_RF_VAL_MASK) << RT2872_REG_RF_VAL_SHIFT );
+		rt2860_io_rf_read(sc, reg);
+		return;
+	}
+
+
+	for (ntries = 0; ntries < 100; ntries++)
+		if (!(rt2860_io_mac_read(sc, RT2860_REG_RF_CSR_CFG0) &
+			RT2860_REG_RF_BUSY))
+			break;
+
+	if (ntries == 100)
+	{
+		printf("%s: could not write to RF: reg=0x%02x\n",
+			device_get_nameunit(sc->sc_dev), reg);
+		return;
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_RF_CSR_CFG0, val);
+}
+
+/*
+ * rt2860_io_rf_read
+ */
+int32_t rt2860_io_rf_read(struct rt2860_softc *sc, uint8_t reg)
+{
+	int ntries;
+	if (sc->mac_rev == 0x28720200)
+	{
+		for (ntries = 0; ntries < 100; ntries ++) {
+			if ( !(rt2860_io_mac_read(sc, RT2872_REG_RF_CSR_CFG) & 
+			    RT2872_REG_RF_CSR_BUSY) )
+				break;
+			DELAY(1);
+		}
+		if (ntries == 100) {
+			printf("%s:%s: RF busy after 100 probes\n",
+				device_get_nameunit(sc->sc_dev), __func__);
+			return (-1);
+		}
+		rt2860_io_mac_write(sc, RT2872_REG_RF_CSR_CFG, 
+		    RT2872_REG_RF_CSR_KICK |
+		    (reg & RT2872_REG_RF_ID_MASK) << RT2872_REG_RF_ID_SHIFT );
+
+		for (ntries = 0; ntries < 100; ntries ++) {
+			if ( !(rt2860_io_mac_read(sc, RT2872_REG_RF_CSR_CFG) &
+			    RT2872_REG_RF_CSR_BUSY) )
+				break;
+			DELAY(1);
+		}
+		if (ntries == 100) {
+			printf("%s:%s: RF busy after 100 probes\n",
+				device_get_nameunit(sc->sc_dev), __func__);
+		}
+
+		return (rt2860_io_mac_read(sc, RT2872_REG_RF_CSR_CFG) & RT2872_REG_RF_VAL_MASK);
+	}
+	return (-1);
+}
+
+/*
+ * rt2860_io_rf_load_defaults
+ */
+void rt2860_io_rf_load_defaults(struct rt2860_softc *sc)
+{
+	int i;
+
+	if (sc->mac_rev == 0x28720200) {
+		for (i = 0; i < 32; i ++)
+			rt2860_io_rf_write(sc, i, rt3052_rf_default[i]);
+	}
+}
+
+/*
+ * rt2860_io_mcu_cmd
+ */
+void rt2860_io_mcu_cmd(struct rt2860_softc *sc, uint8_t cmd,
+	uint8_t token, uint16_t arg)
+{
+	uint32_t tmp;
+	int ntries;
+
+	if (sc->mac_rev == 0x28720200)
+		return;
+
+	for (ntries = 0; ntries < 100; ntries++)
+	{
+		if (!(rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX) &
+			RT2860_REG_H2M_BUSY))
+			break;
+
+		DELAY(2);
+	}
+
+	if (ntries == 100)
+	{
+		printf("%s: could not read H2M: cmd=0x%02x\n",
+			device_get_nameunit(sc->sc_dev), cmd);
+		return;
+	}
+
+	tmp = RT2860_REG_H2M_BUSY | (token << 16) | arg;
+
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX, tmp);
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_HOST_CMD, cmd);
+}
+
+/*
+ * rt2860_io_mcu_cmd_check
+ */
+int rt2860_io_mcu_cmd_check(struct rt2860_softc *sc, uint8_t cid)
+{
+	uint32_t tmp, mask, status;
+	int result, ntries;
+
+	result = -1;
+
+	for (ntries = 0; ntries < 200; ntries++)
+	{
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_CID);
+
+		if (((cid >> RT2860_REG_H2M_CID0_SHIFT) & RT2860_REG_H2M_CID_MASK) == cid)
+		{
+			mask = (RT2860_REG_H2M_CID_MASK << RT2860_REG_H2M_CID0_SHIFT);
+			break;
+		}
+		else if (((tmp >> RT2860_REG_H2M_CID1_SHIFT) & RT2860_REG_H2M_CID_MASK) == cid)
+		{
+			mask = (RT2860_REG_H2M_CID_MASK << RT2860_REG_H2M_CID1_SHIFT);
+			break;
+		}
+		else if (((tmp >> RT2860_REG_H2M_CID2_SHIFT) & RT2860_REG_H2M_CID_MASK) == cid)
+		{
+			mask = (RT2860_REG_H2M_CID_MASK << RT2860_REG_H2M_CID2_SHIFT);
+			break;
+		}
+		else if (((tmp >> RT2860_REG_H2M_CID3_SHIFT) & RT2860_REG_H2M_CID_MASK) == cid)
+		{
+			mask = (RT2860_REG_H2M_CID_MASK << RT2860_REG_H2M_CID3_SHIFT);
+			break;
+		}
+
+		DELAY(100);
+	}
+
+	status = rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_STATUS);
+
+	if (ntries < 200)
+	{
+		status &= mask;
+
+		if ((status == 0x1) ||
+			(status == 0x100) ||
+			(status == 0x10000) ||
+			(status == 0x1000000))
+			result = 0;
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_STATUS, 0xffffffff);
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_CID, 0xffffffff);
+
+	return result;
+}
+
+/*
+ * rt2860_io_mcu_load_ucode
+ */
+int rt2860_io_mcu_load_ucode(struct rt2860_softc *sc,
+	const uint8_t *ucode, size_t len)
+{
+	int i, ntries;
+	uint16_t crc;
+
+	for (i = 0, crc = 0xffff; i < len - 2; i++)
+		crc = RT2860_IO_BYTE_CRC16(rt2860_io_byte_rev(ucode[i]), crc);
+
+	if (ucode[len - 2] != rt2860_io_byte_rev(crc >> 8) ||
+		ucode[len - 1] != rt2860_io_byte_rev(crc))
+	{
+		printf("%s: wrong microcode crc\n",
+			device_get_nameunit(sc->sc_dev));
+		return EINVAL;
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, RT2860_REG_HST_PM_SEL);
+
+	for(i = 0; i < len; i += 4)
+	{
+		rt2860_io_mac_write(sc, RT2860_REG_MCU_UCODE_BASE + i, 
+		    (ucode[i+3] << 24) | (ucode[i+2] << 16) | 
+		    (ucode[i+1] << 8) | ucode[i]);
+	}
+
+	if (sc->mac_rev != 0x28720200)
+		rt2860_io_mac_write_multi(sc, RT2860_REG_MCU_UCODE_BASE,
+		    ucode, len);
+
+	rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0);
+
+	if (sc->mac_rev != 0x28720200)
+		rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL,
+		    RT2860_REG_MCU_RESET);
+
+	DELAY(10000);
+
+	/* initialize BBP R/W access agent */
+
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT, 0);
+	rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX, 0);
+
+	if (sc->mac_rev != 0x28720200) {
+
+		for (ntries = 0; ntries < 1000; ntries++)
+		{
+			if (rt2860_io_mac_read(sc, RT2860_REG_PBF_SYS_CTRL) &
+				RT2860_REG_MCU_READY)
+				break;
+
+			DELAY(1000);
+		}
+
+		if (ntries == 1000)
+		{
+			printf("%s: timeout waiting for MCU to initialize\n",
+				device_get_nameunit(sc->sc_dev));
+			return ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * rt2860_io_eeprom_shiftout_bits
+ */
+static void rt2860_io_eeprom_shiftout_bits(struct rt2860_softc *sc,
+	uint16_t val, uint16_t count)
+{
+	uint32_t mask, tmp; 
+
+	mask = (1 << (count - 1));
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+	tmp &= ~(RT2860_REG_EEDO | RT2860_REG_EEDI);
+
+	do
+	{
+	    tmp &= ~RT2860_REG_EEDI;
+
+	    if(val & mask)
+			tmp |= RT2860_REG_EEDI;
+
+		rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp);
+
+		RT2860_IO_EEPROM_RAISE_CLK(sc, tmp);
+		RT2860_IO_EEPROM_LOWER_CLK(sc, tmp);
+
+	    mask = (mask >> 1);
+	} while (mask);
+
+	tmp &= ~RT2860_REG_EEDI;
+
+	rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp);
+}
+
+/*
+ * rt2860_io_eeprom_shiftin_bits
+ */
+static uint16_t rt2860_io_eeprom_shiftin_bits(struct rt2860_softc *sc)
+{
+	uint32_t tmp; 
+	uint16_t val;
+	int i;
+
+	val = 0;
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+	tmp &= ~(RT2860_REG_EEDO | RT2860_REG_EEDI);
+
+	for(i = 0; i < 16; i++)
+	{
+		val = (val << 1);
+
+		RT2860_IO_EEPROM_RAISE_CLK(sc, tmp);
+
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+		RT2860_IO_EEPROM_LOWER_CLK(sc, tmp);
+		
+		tmp &= ~RT2860_REG_EEDI;
+		if(tmp & RT2860_REG_EEDO)
+		    val |= 1;
+	}
+
+	return val;
+}
+
+/*
+ * rt2860_io_byte_rev
+ */
+static uint8_t rt2860_io_byte_rev(uint8_t byte)
+{
+	int i;
+	uint8_t tmp;
+
+	for(i = 0, tmp = 0; ; i++)
+	{
+		if(byte & 0x80)
+			tmp |= 0x80;
+
+		if(i == 7)
+			break;
+
+		byte <<= 1;
+		tmp >>= 1;
+	}
+
+	return tmp;
+}
+
+/*
+ * rt2860_led_brightness
+ */
+void rt2860_led_brightness(struct rt2860_softc *sc, uint8_t brightness)
+{
+	uint8_t polarity;
+	uint16_t tmp;
+
+	polarity = (sc->led_cntl & RT2860_EEPROM_LED_POLARITY) ? 1 : 0;
+
+	tmp = (polarity << 8) | brightness;
+
+	rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LED_BRIGHTNESS,
+		RT2860_REG_H2M_TOKEN_NO_INTR, tmp);
+}
+
+/*
+ * rt2860_led_cmd
+ */
+void rt2860_led_cmd(struct rt2860_softc *sc, uint8_t cmd)
+{
+	uint16_t tmp;
+
+	tmp = (cmd << 8) | (sc->led_cntl & RT2860_EEPROM_LED_MODE_MASK);
+
+	rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LEDS,
+		RT2860_REG_H2M_TOKEN_NO_INTR, tmp);
+}
+
+/*
+ * rt2860_read_eeprom
+ */
+void rt2860_read_eeprom(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+	uint16_t val;
+	int i;
+
+	/* read EEPROM address number */
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+	if((tmp & 0x30) == 0)
+		sc->eeprom_addr_num = 6;
+	else if((tmp & 0x30) == 0x10)
+		sc->eeprom_addr_num = 8;
+	else
+		sc->eeprom_addr_num = 8;
+
+	/* read EEPROM version */
+
+	sc->eeprom_rev = rt2860_io_eeprom_read(sc, RT2860_EEPROM_VERSION);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM rev=0x%04x\n",
+		device_get_nameunit(sc->sc_dev), sc->eeprom_rev);
+
+	/* read MAC address */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_ADDRESS01);
+
+	sc->mac_addr[0] = (val & 0xff);
+	sc->mac_addr[1] = (val >> 8);
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_ADDRESS23);
+
+	sc->mac_addr[2] = (val & 0xff);
+	sc->mac_addr[3] = (val >> 8);
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_ADDRESS45);
+
+	sc->mac_addr[4] = (val & 0xff);
+	sc->mac_addr[5] = (val >> 8);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM mac address=%s\n",
+		device_get_nameunit(sc->sc_dev), ether_sprintf(sc->mac_addr));
+
+	/* read RF information */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_ANTENNA);
+	if (val == 0xffff)
+	{
+		printf("%s: invalid EEPROM antenna info\n",
+			device_get_nameunit(sc->sc_dev));
+
+		sc->rf_rev = RT2860_EEPROM_RF_2820;
+		sc->ntxpath = 1;
+		sc->nrxpath = 2;
+	}
+	else
+	{
+		sc->rf_rev = (val >> 8) & 0xf;
+		sc->ntxpath = (val >> 4) & 0xf;
+		sc->nrxpath = (val & 0xf);
+	}
+
+	if ((sc->mac_rev != 0x28830300) && (sc->nrxpath > 2))
+	{
+		/* only 2 Rx streams for RT2860 series */
+
+		sc->nrxpath = 2;
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM RF rev=0x%04x, paths=%dT%dR\n",
+		device_get_nameunit(sc->sc_dev), sc->rf_rev, sc->ntxpath, sc->nrxpath);
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_NIC_CONFIG);
+	if ((val & 0xff00) != 0xff00)
+		sc->patch_dac = (val >> 15) & 1;
+
+	sc->hw_radio_cntl = ((val & RT2860_EEPROM_HW_RADIO_CNTL) ? 1 : 0);
+	sc->tx_agc_cntl = ((val & RT2860_EEPROM_TX_AGC_CNTL) ? 1 : 0);
+	sc->ext_lna_2ghz = ((val & RT2860_EEPROM_EXT_LNA_2GHZ) ? 1 : 0);
+	sc->ext_lna_5ghz = ((val & RT2860_EEPROM_EXT_LNA_5GHZ) ? 1 : 0);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM NIC config: HW radio cntl=%d, Tx AGC cntl=%d, ext LNA gains=%d/%d\n",
+		device_get_nameunit(sc->sc_dev),
+		sc->hw_radio_cntl, sc->tx_agc_cntl, sc->ext_lna_2ghz, sc->ext_lna_5ghz);
+
+	/* read country code */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_COUNTRY);
+
+	sc->country_2ghz = (val >> 8) & 0xff;
+	sc->country_5ghz = (val & 0xff);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM country code=%d/%d\n",
+		device_get_nameunit(sc->sc_dev), sc->country_2ghz, sc->country_5ghz);
+
+	/* read RF frequency offset */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RF_FREQ_OFF);
+
+	if ((val & 0xff) != 0xff)
+	{
+		sc->rf_freq_off = (val & 0xff);
+	}
+	else
+	{
+		printf("%s: invalid EEPROM RF freq offset\n",
+			device_get_nameunit(sc->sc_dev));
+
+		sc->rf_freq_off = 0;
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM freq offset=0x%02x\n",
+		device_get_nameunit(sc->sc_dev), sc->rf_freq_off);
+
+	/* read LEDs operating mode */
+
+	if (((val >> 8) & 0xff) != 0xff)
+	{
+		sc->led_cntl = ((val >> 8) & 0xff);
+		sc->led_off[0] = rt2860_io_eeprom_read(sc, RT2860_EEPROM_LED1_OFF);
+		sc->led_off[1] = rt2860_io_eeprom_read(sc, RT2860_EEPROM_LED2_OFF);
+		sc->led_off[2] = rt2860_io_eeprom_read(sc, RT2860_EEPROM_LED3_OFF);
+	}
+	else
+	{
+		printf("%s: invalid EEPROM LED settings\n",
+			device_get_nameunit(sc->sc_dev));
+
+		sc->led_cntl = RT2860_EEPROM_LED_CNTL_DEFAULT;
+		sc->led_off[0] = RT2860_EEPROM_LED1_OFF_DEFAULT;
+		sc->led_off[1] = RT2860_EEPROM_LED2_OFF_DEFAULT;
+		sc->led_off[2] = RT2860_EEPROM_LED3_OFF_DEFAULT;
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM LED cntl=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
+		device_get_nameunit(sc->sc_dev), sc->led_cntl,
+		sc->led_off[0], sc->led_off[1], sc->led_off[2]);
+
+	/* read RSSI offsets and LNA gains */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_LNA_GAIN);
+	if ((sc->mac_rev & 0xffff0000) >= 0x30710000)
+		sc->lna_gain[0] = RT3090_DEF_LNA;
+	else				/* channel group 0 */
+		sc->lna_gain[0] = val & 0xff;
+
+	sc->lna_gain[1] = (val >> 8) & 0xff;
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RSSI_OFF_2GHZ_BASE);
+
+	sc->rssi_off_2ghz[0] = (val & 0xff);
+	sc->rssi_off_2ghz[1] = (val >> 8) & 0xff;
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RSSI_OFF_2GHZ_BASE + 2);
+
+	if ((sc->mac_rev & 0xffff0000) >= 0x30710000) {
+		/*
+		 * On RT3090 chips (limited to 2 Rx chains), this ROM
+		 * field contains the Tx mixer gain for the 2GHz band.
+		 */
+		if ((val & 0xff) != 0xff)
+			sc->txmixgain_2ghz = val & 0x7;
+	} else
+		sc->rssi_off_2ghz[2] = val & 0xff;	/* Ant C */
+	sc->lna_gain[2] = (val >> 8) & 0xff;
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RSSI_OFF_5GHZ_BASE);
+
+	sc->rssi_off_5ghz[0] = (val & 0xff);
+	sc->rssi_off_5ghz[1] = (val >> 8) & 0xff;
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RSSI_OFF_5GHZ_BASE + 2);
+
+	sc->rssi_off_5ghz[2] = (val & 0xff);
+	sc->lna_gain[3] = (val >> 8) & 0xff;
+
+	for (i = 2; i < RT2860_SOFTC_LNA_GAIN_COUNT; i++)
+	{
+		if (sc->lna_gain[i] == 0x00 || sc->lna_gain[i] == (int8_t) 0xff)
+		{
+			printf("%s: invalid EEPROM LNA gain #%d: 0x%02x\n",
+				device_get_nameunit(sc->sc_dev), i, sc->lna_gain[i]);
+
+			sc->lna_gain[i] = sc->lna_gain[1];
+		}
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM LNA gains=0x%02x/0x%02x/0x%02x/0x%02x\n",
+		device_get_nameunit(sc->sc_dev),
+		sc->lna_gain[0], sc->lna_gain[1], sc->lna_gain[2], sc->lna_gain[3]);
+
+	for (i = 0; i < RT2860_SOFTC_RSSI_OFF_COUNT; i++)
+	{
+		if (sc->rssi_off_2ghz[i] < RT2860_EEPROM_RSSI_OFF_MIN ||
+			sc->rssi_off_2ghz[i] > RT2860_EEPROM_RSSI_OFF_MAX)
+		{
+			printf("%s: invalid EEPROM RSSI offset #%d (2GHz): 0x%02x\n",
+				device_get_nameunit(sc->sc_dev), i, sc->rssi_off_2ghz[i]);
+
+			sc->rssi_off_2ghz[i] = 0;
+		}
+
+		if (sc->rssi_off_5ghz[i] < RT2860_EEPROM_RSSI_OFF_MIN ||
+			sc->rssi_off_5ghz[i] > RT2860_EEPROM_RSSI_OFF_MAX)
+		{
+			printf("%s: invalid EEPROM RSSI offset #%d (5GHz): 0x%02x\n",
+				device_get_nameunit(sc->sc_dev), i, sc->rssi_off_5ghz[i]);
+
+			sc->rssi_off_5ghz[i] = 0;
+		}
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM RSSI offsets 2GHz=%d/%d/%d\n",
+		device_get_nameunit(sc->sc_dev),
+		sc->rssi_off_2ghz[0], sc->rssi_off_2ghz[1], sc->rssi_off_2ghz[2]);
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM RSSI offsets 5GHz=%d/%d/%d\n",
+		device_get_nameunit(sc->sc_dev),
+		sc->rssi_off_5ghz[0], sc->rssi_off_5ghz[1], sc->rssi_off_5ghz[2]);
+
+	/* read Tx power settings for 2GHz channels */
+
+	for (i = 0; i < 14; i += 2)
+	{
+		val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW1_2GHZ_BASE + i / 2);
+
+		sc->txpow1[i + 0] = (int8_t) (val & 0xff);
+		sc->txpow1[i + 1] = (int8_t) (val >> 8);
+
+		val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW2_2GHZ_BASE + i / 2);
+
+		sc->txpow2[i + 0] = (int8_t) (val & 0xff);
+		sc->txpow2[i + 1] = (int8_t) (val >> 8);
+	}
+
+	/* read Tx power settings for 5GHz channels */
+
+	for (; i < RT2860_SOFTC_TXPOW_COUNT; i += 2)
+	{
+		val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW1_5GHZ_BASE + i / 2);
+
+		sc->txpow1[i + 0] = (int8_t) (val & 0xff);
+		sc->txpow1[i + 1] = (int8_t) (val >> 8);
+
+		val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW2_5GHZ_BASE + i / 2);
+
+		sc->txpow2[i + 0] = (int8_t) (val & 0xff);
+		sc->txpow2[i + 1] = (int8_t) (val >> 8);
+	}
+
+	/* fix broken Tx power settings */
+
+    for (i = 0; i < 14; i++)
+	{
+		if (sc->txpow1[i] < RT2860_EEPROM_TXPOW_2GHZ_MIN ||
+			sc->txpow1[i] > RT2860_EEPROM_TXPOW_2GHZ_MAX)
+		{
+			printf("%s: invalid EEPROM Tx power1 #%d (2GHz): 0x%02x\n",
+				device_get_nameunit(sc->sc_dev), i, sc->txpow1[i]);
+
+			sc->txpow1[i] = RT2860_EEPROM_TXPOW_2GHZ_DEFAULT;
+		}
+
+		if (sc->txpow2[i] < RT2860_EEPROM_TXPOW_2GHZ_MIN ||
+			sc->txpow2[i] > RT2860_EEPROM_TXPOW_2GHZ_MAX)
+		{
+			printf("%s: invalid EEPROM Tx power2 #%d (2GHz): 0x%02x\n",
+				device_get_nameunit(sc->sc_dev), i, sc->txpow2[i]);
+
+			sc->txpow2[i] = RT2860_EEPROM_TXPOW_2GHZ_DEFAULT;
+		}
+	}
+
+	for (; i < RT2860_SOFTC_TXPOW_COUNT; i++)
+	{
+		if (sc->txpow1[i] < RT2860_EEPROM_TXPOW_5GHZ_MIN ||
+			sc->txpow1[i] > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+		{
+			printf("%s: invalid EEPROM Tx power1 #%d (5GHz): 0x%02x\n",
+				device_get_nameunit(sc->sc_dev), i, sc->txpow1[i]);
+
+			sc->txpow1[i] = RT2860_EEPROM_TXPOW_5GHZ_DEFAULT;
+		}
+
+		if (sc->txpow2[i] < RT2860_EEPROM_TXPOW_5GHZ_MIN ||
+			sc->txpow2[i] > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+		{
+			printf("%s: invalid EEPROM Tx power2 #%d (5GHz): 0x%02x\n",
+				device_get_nameunit(sc->sc_dev), i, sc->txpow2[i]);
+
+			sc->txpow2[i] = RT2860_EEPROM_TXPOW_5GHZ_DEFAULT;
+		}
+	}
+
+	/* read Tx power per rate deltas */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW_RATE_DELTA);
+
+	sc->txpow_rate_delta_2ghz = 0;
+	sc->txpow_rate_delta_5ghz = 0;
+
+	if ((val & 0xff) != 0xff)
+	{
+		if (val & 0x80)
+			sc->txpow_rate_delta_2ghz = (val & 0xf);
+
+		if (!(val & 0x40))
+			sc->txpow_rate_delta_2ghz = -sc->txpow_rate_delta_2ghz;
+	}
+
+	val >>= 8;
+
+	if ((val & 0xff) != 0xff)
+	{
+		if (val & 0x80)
+			sc->txpow_rate_delta_5ghz = (val & 0xf);
+
+		if (!(val & 0x40))
+			sc->txpow_rate_delta_5ghz = -sc->txpow_rate_delta_5ghz;
+	}
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM Tx power per rate deltas=%d(2MHz), %d(5MHz)\n",
+		device_get_nameunit(sc->sc_dev),
+		sc->txpow_rate_delta_2ghz, sc->txpow_rate_delta_5ghz);
+
+	/* read Tx power per rate */
+
+	for (i = 0; i < RT2860_SOFTC_TXPOW_RATE_COUNT; i++)
+	{
+		rt2860_io_eeprom_read_multi(sc, RT2860_EEPROM_TXPOW_RATE_BASE + i * sizeof(uint32_t),
+			&tmp, sizeof(uint32_t));
+
+		sc->txpow_rate_20mhz[i] = tmp;
+		sc->txpow_rate_40mhz_2ghz[i] =
+			rt2860_read_eeprom_txpow_rate_add_delta(tmp, sc->txpow_rate_delta_2ghz);
+		sc->txpow_rate_40mhz_5ghz[i] =
+			rt2860_read_eeprom_txpow_rate_add_delta(tmp, sc->txpow_rate_delta_5ghz);
+
+		RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+			"%s: EEPROM Tx power per rate #%d=0x%08x(20MHz), 0x%08x(40MHz/2GHz), 0x%08x(40MHz/5GHz)\n",
+			device_get_nameunit(sc->sc_dev), i,
+			sc->txpow_rate_20mhz[i], sc->txpow_rate_40mhz_2ghz[i], sc->txpow_rate_40mhz_5ghz[i]);
+	}
+
+	if (sc->tx_agc_cntl)
+		sc->tx_agc_cntl_2ghz = sc->tx_agc_cntl_5ghz = 1;
+
+	/* read factory-calibrated samples for temperature compensation */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE);
+
+	sc->tssi_2ghz[0] = (val & 0xff);	/* [-4] */
+	sc->tssi_2ghz[1] = (val >> 8);		/* [-3] */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE + 2);
+
+	sc->tssi_2ghz[2] = (val & 0xff);	/* [-2] */
+	sc->tssi_2ghz[3] = (val >> 8);		/* [-1] */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE + 2 * 2);
+
+	sc->tssi_2ghz[4] = (val & 0xff);	/* [0] */
+	sc->tssi_2ghz[5] = (val >> 8);		/* [+1] */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE + 3 * 2);
+
+	sc->tssi_2ghz[6] = (val & 0xff);	/* [+2] */
+	sc->tssi_2ghz[7] = (val >> 8);		/* [+3] */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE + 4 * 2);
+
+	sc->tssi_2ghz[8] = (val & 0xff);	/* [+4] */
+	sc->tssi_step_2ghz = (val >> 8);
+
+	if (sc->tssi_2ghz[4] == 0xff)
+		sc->tx_agc_cntl_2ghz = 0;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM TSSI 2GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
+		"0x%02x, 0x%02x, step=%d\n",
+		device_get_nameunit(sc->sc_dev),
+		sc->tssi_2ghz[0], sc->tssi_2ghz[1], sc->tssi_2ghz[2],
+		sc->tssi_2ghz[3], sc->tssi_2ghz[4], sc->tssi_2ghz[5],
+		sc->tssi_2ghz[6], sc->tssi_2ghz[7], sc->tssi_2ghz[8],
+		sc->tssi_step_2ghz);
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE);
+
+	sc->tssi_5ghz[0] = (val & 0xff);	/* [-4] */
+	sc->tssi_5ghz[1] = (val >> 8);		/* [-3] */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE + 2);
+
+	sc->tssi_5ghz[2] = (val & 0xff);	/* [-2] */
+	sc->tssi_5ghz[3] = (val >> 8);		/* [-1] */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE + 2 * 2);
+
+	sc->tssi_5ghz[4] = (val & 0xff);	/* [0] */
+	sc->tssi_5ghz[5] = (val >> 8);		/* [+1] */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE + 3 * 2);
+
+	sc->tssi_5ghz[6] = (val & 0xff);	/* [+2] */
+	sc->tssi_5ghz[7] = (val >> 8);		/* [+3] */
+
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE + 4 * 2);
+
+	sc->tssi_5ghz[8] = (val & 0xff);	/* [+4] */
+	sc->tssi_step_5ghz = (val >> 8);
+
+	if (sc->tssi_5ghz[4] == 0xff)
+		sc->tx_agc_cntl_5ghz = 0;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM TSSI 5GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
+		"0x%02x, 0x%02x, step=%d\n",
+		device_get_nameunit(sc->sc_dev),
+		sc->tssi_5ghz[0], sc->tssi_5ghz[1], sc->tssi_5ghz[2],
+		sc->tssi_5ghz[3], sc->tssi_5ghz[4], sc->tssi_5ghz[5],
+		sc->tssi_5ghz[6], sc->tssi_5ghz[7], sc->tssi_5ghz[8],
+		sc->tssi_step_5ghz);
+
+	/* read default BBP settings */
+
+	rt2860_io_eeprom_read_multi(sc, RT2860_EEPROM_BBP_BASE,
+		sc->bbp_eeprom, RT2860_SOFTC_BBP_EEPROM_COUNT * 2);
+
+	if ((sc->mac_rev & 0xffff0000) >= 0x30710000) {
+		/* read vendor RF settings */
+		rt2860_io_eeprom_read_multi(sc, RT3071_EEPROM_RF_BASE, sc->rf, 10 * 2);
+	}
+
+	/* read powersave level */
+	val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_POWERSAVE_LEVEL);
+
+	sc->powersave_level = val & 0xff;
+
+	if ((sc->powersave_level & 0xff) == 0xff)
+		printf("%s: invalid EEPROM powersave level\n",
+			device_get_nameunit(sc->sc_dev));
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+		"%s: EEPROM powersave level=0x%02x\n",
+		device_get_nameunit(sc->sc_dev), sc->powersave_level);
+}
+
+/*
+ * rt2860_read_eeprom_txpow_rate_add_delta
+ */
+uint32_t rt2860_read_eeprom_txpow_rate_add_delta(uint32_t txpow_rate,
+	int8_t delta)
+{
+	int8_t b4;
+	int i;
+
+	for (i = 0; i < 8; i++)
+	{
+		b4 = txpow_rate & 0xf;
+		b4 += delta;
+
+		if (b4 < 0)
+			b4 = 0;
+		else if (b4 > 0xf)
+			b4 = 0xf;
+
+		txpow_rate = (txpow_rate >> 4) | (b4 << 28);
+	}
+
+	return txpow_rate;
+}
+
+
+uint8_t
+rt3090_rf_read(struct rt2860_softc *sc, uint8_t reg)
+{
+	uint32_t tmp;
+	int ntries;
+
+	for (ntries = 0; ntries < 100; ntries++) {
+		if (!(rt2860_io_mac_read(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK))
+			break;
+		DELAY(1);
+	}
+	if (ntries == 100) {
+		device_printf(sc->sc_dev, "could not read RF register\n");
+		return 0xff;
+	}
+	tmp = RT3070_RF_KICK | reg << 8;
+	rt2860_io_mac_write(sc, RT3070_RF_CSR_CFG, tmp);
+
+	for (ntries = 0; ntries < 100; ntries++) {
+		tmp = rt2860_io_mac_read(sc, RT3070_RF_CSR_CFG);
+		if (!(tmp & RT3070_RF_KICK))
+			break;
+		DELAY(1);
+	}
+	if (ntries == 100) {
+		device_printf(sc->sc_dev, "could not read RF register\n");
+		return 0xff;
+	}
+	return tmp & 0xff;
+}
+
+void
+rt3090_rf_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val)
+{
+	uint32_t tmp;
+	int ntries;
+
+	for (ntries = 0; ntries < 10; ntries++) {
+		if (!(rt2860_io_mac_read(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK))
+			break;
+		DELAY(10);
+	}
+	if (ntries == 10) {
+		device_printf(sc->sc_dev, "could not write to RF\n");
+		return;
+	}
+
+	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
+	rt2860_io_mac_write(sc, RT3070_RF_CSR_CFG, tmp);
+}
+
+/*
+ * rt2860_rf_name
+ */
+const char *rt2860_rf_name(int rf_rev)
+{
+	switch (rf_rev)
+	{
+		case RT2860_EEPROM_RF_2820:
+			return "RT2820 2.4G 2T3R";
+
+		case RT2860_EEPROM_RF_2850:
+			return "RT2850 2.4G/5G 2T3R";
+
+		case RT2860_EEPROM_RF_2720:
+			return "RT2720 2.4G 1T2R";
+
+		case RT2860_EEPROM_RF_2750:
+			return "RT2750 2.4G/5G 1T2R";
+
+		case RT2860_EEPROM_RF_3020:
+			return "RT3020 2.4G 1T1R";
+
+		case RT2860_EEPROM_RF_2020:
+			return "RT2020 2.4G B/G";
+
+		case RT2860_EEPROM_RF_3021:
+			return "RT3021 2.4G 1T2R";
+
+		case RT2860_EEPROM_RF_3022:
+			return "RT3022 2.4G 2T2R";
+
+		case RT2860_EEPROM_RF_3052:
+			return "RT3052 2.4G/5G 2T2R";
+
+		case RT2860_EEPROM_RF_2853:
+			return "RT2853 2.4G.5G 3T3R";
+
+		case RT2860_EEPROM_RF_3320:
+			return "RT3320 2.4G 1T1R with PA";
+
+		case RT2860_EEPROM_RF_3322:
+			return "RT3322 2.4G 2T2R with PA";
+
+		case RT2860_EEPROM_RF_3053:
+			return "RT3053 2.4G/5G 3T3R";
+
+		default:
+			return "unknown";
+	}
+}
+
+/*
+ * rt2860_rf_select_chan_group
+ */
+void rt2860_rf_select_chan_group(struct rt2860_softc *sc,
+	struct ieee80211_channel *c)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	int chan, group;
+	uint32_t tmp;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+
+	chan = ieee80211_chan2ieee(ic, c);
+	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
+		return;
+
+	if (chan <= 14)
+		group = 0;
+	else if (chan <= 64)
+		group = 1;
+	else if (chan <= 128)
+		group = 2;
+	else
+		group = 3;
+
+	rt2860_io_bbp_write(sc, 62, 0x37 - sc->lna_gain[group]);
+	rt2860_io_bbp_write(sc, 63, 0x37 - sc->lna_gain[group]);
+	rt2860_io_bbp_write(sc, 64, 0x37 - sc->lna_gain[group]);
+	rt2860_io_bbp_write(sc, 86, 0x00);
+
+	if (group == 0)
+	{
+		if (sc->ext_lna_2ghz)
+		{
+			rt2860_io_bbp_write(sc, 82, 0x62);
+			rt2860_io_bbp_write(sc, 75, 0x46);
+		}
+		else
+		{
+			rt2860_io_bbp_write(sc, 82, 0x84);
+			rt2860_io_bbp_write(sc, 75, 0x50);
+		}
+	}
+	else
+	{
+		rt2860_io_bbp_write(sc, 82, 0xf2);
+
+		if (sc->ext_lna_5ghz)
+			rt2860_io_bbp_write(sc, 75, 0x46);
+		else
+			rt2860_io_bbp_write(sc, 75, 0x50);
+	}
+
+	if (group == 0)
+	{
+		tmp = 0x2e + sc->lna_gain[group];
+	}
+	else
+	{
+		if ((ic->ic_flags & IEEE80211_F_SCAN) || !IEEE80211_IS_CHAN_HT40(c))
+			tmp = 0x32 + sc->lna_gain[group] * 5 / 3;
+		else
+			tmp = 0x3a + sc->lna_gain[group] * 5 / 3;
+	}
+
+	rt2860_io_bbp_write(sc, 66, tmp);
+
+	tmp = RT2860_REG_RFTR_ENABLE |
+		RT2860_REG_TRSW_ENABLE |
+		RT2860_REG_LNA_PE_G1_ENABLE |
+		RT2860_REG_LNA_PE_A1_ENABLE |
+		RT2860_REG_LNA_PE_G0_ENABLE |
+		RT2860_REG_LNA_PE_A0_ENABLE;
+
+	if (group == 0)
+		tmp |= RT2860_REG_PA_PE_G1_ENABLE |
+			RT2860_REG_PA_PE_G0_ENABLE;
+	else
+		tmp |= RT2860_REG_PA_PE_A1_ENABLE |
+			RT2860_REG_PA_PE_A0_ENABLE;
+
+	if (sc->ntxpath == 1)
+		tmp &= ~(RT2860_REG_PA_PE_G1_ENABLE | RT2860_REG_PA_PE_A1_ENABLE);
+
+	if (sc->nrxpath == 1)
+		tmp &= ~(RT2860_REG_LNA_PE_G1_ENABLE | RT2860_REG_LNA_PE_A1_ENABLE);
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_PIN_CFG, tmp);
+
+	tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_BAND_CFG);
+
+	tmp &= ~(RT2860_REG_TX_BAND_BG | RT2860_REG_TX_BAND_A | RT2860_REG_TX_BAND_HT40_ABOVE);
+
+	if (group == 0)
+		tmp |= RT2860_REG_TX_BAND_BG;
+	else
+		tmp |= RT2860_REG_TX_BAND_A;
+
+	/* set central channel position */
+
+	if (IEEE80211_IS_CHAN_HT40U(c))
+		tmp |= RT2860_REG_TX_BAND_HT40_BELOW;
+	else if (IEEE80211_IS_CHAN_HT40D(c))
+		tmp |= RT2860_REG_TX_BAND_HT40_ABOVE;
+	else
+		tmp |= RT2860_REG_TX_BAND_HT40_BELOW;
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_BAND_CFG, tmp);
+
+	/* set bandwidth (20MHz or 40MHz) */
+
+	tmp = rt2860_io_bbp_read(sc, 4);
+
+	tmp &= ~0x18;
+
+	if (IEEE80211_IS_CHAN_HT40(c))
+		tmp |= 0x10;
+
+	rt2860_io_bbp_write(sc, 4, tmp);
+
+	/* set central channel position */
+
+	tmp = rt2860_io_bbp_read(sc, 3);
+
+	tmp &= ~0x20;
+
+	if (IEEE80211_IS_CHAN_HT40D(c))
+		tmp |= 0x20;
+
+	rt2860_io_bbp_write(sc, 3, tmp);
+
+	if (sc->mac_rev == 0x28600100)
+	{
+		if (!IEEE80211_IS_CHAN_HT40(c))
+		{
+			rt2860_io_bbp_write(sc, 69, 0x16);
+			rt2860_io_bbp_write(sc, 70, 0x08);
+			rt2860_io_bbp_write(sc, 73, 0x12);
+		}
+		else
+		{
+			rt2860_io_bbp_write(sc, 69, 0x1a);
+			rt2860_io_bbp_write(sc, 70, 0x0a);
+			rt2860_io_bbp_write(sc, 73, 0x16);
+		}
+	}
+
+}
+
+void
+rt3090_set_chan(struct rt2860_softc *sc, u_int chan)
+{
+	int8_t txpow1, txpow2;
+	uint8_t rf;
+	int i;
+
+	KASSERT((chan >= 1 && chan <= 14), "RT3090 is 2GHz only");	/* RT3090 is 2GHz only */
+
+	/* find the settings for this channel (we know it exists) */
+	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
+
+	/* use Tx power values from EEPROM */
+	txpow1 = sc->txpow1[i];
+	txpow2 = sc->txpow2[i];
+
+	rt3090_rf_write(sc, 2, rt3090_freqs[i].n);
+	rf = rt3090_rf_read(sc, 3);
+	rf = (rf & ~0x0f) | rt3090_freqs[i].k;
+	rt3090_rf_write(sc, 3, rf);
+	rf = rt3090_rf_read(sc, 6);
+	rf = (rf & ~0x03) | rt3090_freqs[i].r;
+	rt3090_rf_write(sc, 6, rf);
+
+	/* set Tx0 power */
+	rf = rt3090_rf_read(sc, 12);
+	rf = (rf & ~0x1f) | txpow1;
+	rt3090_rf_write(sc, 12, rf);
+
+	/* set Tx1 power */
+	rf = rt3090_rf_read(sc, 13);
+	rf = (rf & ~0x1f) | txpow2;
+	rt3090_rf_write(sc, 13, rf);
+
+	rf = rt3090_rf_read(sc, 1);
+	rf &= ~0xfc;
+	if (sc->ntxpath == 1)
+		rf |= RT3070_TX1_PD | RT3070_TX2_PD;
+	else if (sc->ntxpath == 2)
+		rf |= RT3070_TX2_PD;
+	if (sc->nrxpath == 1)
+		rf |= RT3070_RX1_PD | RT3070_RX2_PD;
+	else if (sc->nrxpath == 2)
+		rf |= RT3070_RX2_PD;
+	rt3090_rf_write(sc, 1, rf);
+
+	/* set RF offset */
+	rf = rt3090_rf_read(sc, 23);
+	rf = (rf & ~0x7f) | sc->rf_freq_off;
+	rt3090_rf_write(sc, 23, rf);
+
+	/* program RF filter */
+	rf = rt3090_rf_read(sc, 24);	/* Tx */
+	rf = (rf & ~0x3f) | sc->rf24_20mhz;
+	rt3090_rf_write(sc, 24, rf);
+	rf = rt3090_rf_read(sc, 31);	/* Rx */
+	rf = (rf & ~0x3f) | sc->rf24_20mhz;
+	rt3090_rf_write(sc, 31, rf);
+
+	/* enable RF tuning */
+	rf = rt3090_rf_read(sc, 7);
+	rt3090_rf_write(sc, 7, rf | RT3070_TUNE);
+}
+
+int
+rt3090_rf_init(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+	uint8_t rf, bbp;
+	int i;
+
+	rf = rt3090_rf_read(sc, 30);
+	/* toggle RF R30 bit 7 */
+	rt3090_rf_write(sc, 30, rf | 0x80);
+	DELAY(1000);
+	rt3090_rf_write(sc, 30, rf & ~0x80);
+
+	tmp = rt2860_io_mac_read(sc, RT3070_LDO_CFG0);
+	tmp &= ~0x1f000000;
+	if (sc->patch_dac && (sc->mac_rev & 0x0000ffff) < 0x0211)
+		tmp |= 0x0d000000;	/* 1.35V */
+	else
+		tmp |= 0x01000000;	/* 1.2V */
+	rt2860_io_mac_write(sc, RT3070_LDO_CFG0, tmp);
+
+	/* patch LNA_PE_G1 */
+	tmp = rt2860_io_mac_read(sc, RT3070_GPIO_SWITCH);
+	rt2860_io_mac_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
+
+	/* initialize RF registers to default value */
+	for (i = 0; i < (sizeof(rt3090_def_rf)/2); i++) {
+		rt3090_rf_write(sc, rt3090_def_rf[i].reg,
+		    rt3090_def_rf[i].val);
+	}
+
+	/* select 20MHz bandwidth */
+	rt3090_rf_write(sc, 31, 0x14);
+
+	rf = rt3090_rf_read(sc, 6);
+	rt3090_rf_write(sc, 6, rf | 0x40);
+
+	if ((sc->mac_rev & 0xffff0000) != 0x35930000) {
+		/* calibrate filter for 20MHz bandwidth */
+		sc->rf24_20mhz = 0x1f;	/* default value */
+		rt3090_filter_calib(sc, 0x07, 0x16, &sc->rf24_20mhz);
+
+		/* select 40MHz bandwidth */
+		bbp = rt2860_io_bbp_read(sc, 4);
+		rt2860_io_bbp_write(sc, 4, (bbp & ~0x08) | 0x10);
+		rf = rt3090_rf_read(sc, 31);
+		rt3090_rf_write(sc, 31, rf | 0x20);
+
+		/* calibrate filter for 40MHz bandwidth */
+		sc->rf24_40mhz = 0x2f;	/* default value */
+		rt3090_filter_calib(sc, 0x27, 0x19, &sc->rf24_40mhz);
+
+		/* go back to 20MHz bandwidth */
+		bbp = rt2860_io_bbp_read(sc, 4);
+		rt2860_io_bbp_write(sc, 4, bbp & ~0x18);
+	}
+	if ((sc->mac_rev & 0x0000ffff) < 0x0211)
+		rt3090_rf_write(sc, 27, 0x03);
+
+	tmp = rt2860_io_mac_read(sc, RT3070_OPT_14);
+	rt2860_io_mac_write(sc, RT3070_OPT_14, tmp | 1);
+
+	if (sc->rf_rev == RT2860_EEPROM_RF_3020)
+		rt3090_set_rx_antenna(sc, 0);
+
+	bbp = rt2860_io_bbp_read(sc, 138);
+	if ((sc->mac_rev & 0xffff0000) == 0x35930000) {
+		if (sc->ntxpath == 1)
+			bbp |= 0x60;	/* turn off DAC1 and DAC2 */
+		else if (sc->ntxpath == 2)
+			bbp |= 0x40;	/* turn off DAC2 */
+		if (sc->nrxpath == 1)
+			bbp &= ~0x06;	/* turn off ADC1 and ADC2 */
+		else if (sc->nrxpath == 2)
+			bbp &= ~0x04;	/* turn off ADC2 */
+	} else {
+		if (sc->ntxpath == 1)
+			bbp |= 0x20;	/* turn off DAC1 */
+		if (sc->nrxpath == 1)
+			bbp &= ~0x02;	/* turn off ADC1 */
+	}
+	rt2860_io_bbp_write(sc, 138, bbp);
+
+	rf = rt3090_rf_read(sc, 1);
+	rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
+	rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
+	rt3090_rf_write(sc, 1, rf);
+
+	rf = rt3090_rf_read(sc, 15);
+	rt3090_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
+
+	rf = rt3090_rf_read(sc, 17);
+	rf &= ~RT3070_TX_LO1;
+	if ((sc->mac_rev & 0x0000ffff) >= 0x0211 && !sc->ext_lna_2ghz)
+		rf |= 0x20;	/* fix for long range Rx issue */
+	if (sc->txmixgain_2ghz >= 2)
+		rf = (rf & ~0x7) | sc->txmixgain_2ghz;
+	rt3090_rf_write(sc, 17, rf);
+
+	rf = rt3090_rf_read(sc, 20);
+	rt3090_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
+
+	rf = rt3090_rf_read(sc, 21);
+	rt3090_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
+
+	return 0;
+}
+
+void
+rt3090_set_rx_antenna(struct rt2860_softc *sc, int aux)
+{
+	uint32_t tmp;
+
+	if (aux) {
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+		rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp & ~RT2860_REG_EESK);
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG, (tmp & ~0x0808) | 0x08);
+	} else {
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+		rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp | RT2860_REG_EESK);
+		tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG);
+		rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG, tmp & ~0x0808);
+	}
+}
+
+void
+rt3090_rf_wakeup(struct rt2860_softc *sc)
+{
+	uint32_t tmp;
+	uint8_t rf;
+
+	if ((sc->mac_rev & 0xffff0000) == 0x35930000) {
+		/* enable VCO */
+		rf = rt3090_rf_read(sc, 1);
+		rt3090_rf_write(sc, 1, rf | RT3593_VCO);
+
+		/* initiate VCO calibration */
+		rf = rt3090_rf_read(sc, 3);
+		rt3090_rf_write(sc, 3, rf | RT3593_VCOCAL);
+
+		/* enable VCO bias current control */
+		rf = rt3090_rf_read(sc, 6);
+		rt3090_rf_write(sc, 6, rf | RT3593_VCO_IC);
+
+		/* initiate res calibration */
+		rf = rt3090_rf_read(sc, 2);
+		rt3090_rf_write(sc, 2, rf | RT3593_RESCAL);
+
+		/* set reference current control to 0.33 mA */
+		rf = rt3090_rf_read(sc, 22);
+		rf &= ~RT3593_CP_IC_MASK;
+		rf |= 1 << RT3593_CP_IC_SHIFT;
+		rt3090_rf_write(sc, 22, rf);
+
+		/* enable RX CTB */
+		rf = rt3090_rf_read(sc, 46);
+		rt3090_rf_write(sc, 46, rf | RT3593_RX_CTB);
+
+		rf = rt3090_rf_read(sc, 20);
+		rf &= ~(RT3593_LDO_RF_VC_MASK | RT3593_LDO_PLL_VC_MASK);
+		rt3090_rf_write(sc, 20, rf);
+	} else {
+		/* enable RF block */
+		rf = rt3090_rf_read(sc, 1);
+		rt3090_rf_write(sc, 1, rf | RT3070_RF_BLOCK);
+
+		/* enable VCO bias current control */
+		rf = rt3090_rf_read(sc, 7);
+		rt3090_rf_write(sc, 7, rf | 0x30);
+
+		rf = rt3090_rf_read(sc, 9);
+		rt3090_rf_write(sc, 9, rf | 0x0e);
+
+		/* enable RX CTB */
+		rf = rt3090_rf_read(sc, 21);
+		rt3090_rf_write(sc, 21, rf | RT3070_RX_CTB);
+
+		/* fix Tx to Rx IQ glitch by raising RF voltage */
+		rf = rt3090_rf_read(sc, 27);
+		rf &= ~0x77;
+		if ((sc->mac_rev & 0x0000ffff) < 0x0211)
+			rf |= 0x03;
+		rt3090_rf_write(sc, 27, rf);
+	}
+	if (sc->patch_dac && (sc->mac_rev & 0x0000ffff) < 0x0211) {
+		tmp = rt2860_io_mac_read(sc, RT3070_LDO_CFG0);
+		tmp = (tmp & ~0x1f000000) | 0x0d000000;
+		rt2860_io_mac_write(sc, RT3070_LDO_CFG0, tmp);
+	}
+}
+
+int
+rt3090_filter_calib(struct rt2860_softc *sc, uint8_t init, uint8_t target,
+    uint8_t *val)
+{
+	uint8_t rf22, rf24;
+	uint8_t bbp55_pb, bbp55_sb, delta;
+	int ntries;
+
+	/* program filter */
+	rf24 = rt3090_rf_read(sc, 24);
+	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
+	rt3090_rf_write(sc, 24, rf24);
+
+	/* enable baseband loopback mode */
+	rf22 = rt3090_rf_read(sc, 22);
+	rt3090_rf_write(sc, 22, rf22 | RT3070_BB_LOOPBACK);
+
+	/* set power and frequency of passband test tone */
+	rt2860_io_bbp_write(sc, 24, 0x00);
+	for (ntries = 0; ntries < 100; ntries++) {
+		/* transmit test tone */
+		rt2860_io_bbp_write(sc, 25, 0x90);
+		DELAY(1000);
+		/* read received power */
+		bbp55_pb = rt2860_io_bbp_read(sc, 55);
+		if (bbp55_pb != 0)
+			break;
+	}
+	if (ntries == 100)
+		return ETIMEDOUT;
+
+	/* set power and frequency of stopband test tone */
+	rt2860_io_bbp_write(sc, 24, 0x06);
+	for (ntries = 0; ntries < 100; ntries++) {
+		/* transmit test tone */
+		rt2860_io_bbp_write(sc, 25, 0x90);
+		DELAY(1000);
+		/* read received power */
+		bbp55_sb = rt2860_io_bbp_read(sc, 55);
+
+		delta = bbp55_pb - bbp55_sb;
+		if (delta > target)
+			break;
+
+		/* reprogram filter */
+		rf24++;
+		rt3090_rf_write(sc, 24, rf24);
+	}
+	if (ntries < 100) {
+		if (rf24 != init)
+			rf24--;	/* backtrack */
+		*val = rf24;
+		rt3090_rf_write(sc, 24, rf24);
+	}
+
+	/* restore initial state */
+	rt2860_io_bbp_write(sc, 24, 0x00);
+
+	/* disable baseband loopback mode */
+	rf22 = rt3090_rf_read(sc, 22);
+	rt3090_rf_write(sc, 22, rf22 & ~RT3070_BB_LOOPBACK);
+
+	return 0;
+}
+
+void
+rt3090_rf_setup(struct rt2860_softc *sc)
+{
+	uint8_t bbp;
+	int i;
+
+	if ((sc->mac_rev & 0x0000ffff) >= 0x0211) {
+		/* enable DC filter */
+		rt2860_io_bbp_write(sc, 103, 0xc0);
+
+		/* improve power consumption */
+		bbp = rt2860_io_bbp_read(sc, 31);
+		rt2860_io_bbp_write(sc, 31, bbp & ~0x03);
+	}
+
+	rt2860_io_mac_write(sc, RT2860_REG_TX_SW_CFG1, 0);
+	if ((sc->mac_rev & 0x0000ffff) < 0x0211) {
+		rt2860_io_mac_write(sc, RT2860_REG_TX_SW_CFG2,
+		    sc->patch_dac ? 0x2c : 0x0f);
+	} else
+		rt2860_io_mac_write(sc, RT2860_REG_TX_SW_CFG2, 0);
+
+	/* initialize RF registers from ROM */
+	for (i = 0; i < 10; i++) {
+		if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
+			continue;
+		rt3090_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
+	}
+}
+
+
+/*
+ * rt2860_rf_set_chan
+ */
+void rt2860_rf_set_chan(struct rt2860_softc *sc,
+	struct ieee80211_channel *c)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	const struct rt2860_rf_prog *prog;
+	uint32_t r1, r2, r3, r4;
+	int8_t txpow1, txpow2;
+	int i, chan;
+
+	if (sc->mac_rev == 0x28720200) {
+		rt2872_rf_set_chan(sc, c);
+		return;
+	} 
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	prog = rt2860_rf_2850;
+
+	/* get central channel position */
+
+	chan = ieee80211_chan2ieee(ic, c);
+
+	if ((sc->mac_rev & 0xffff0000) >= 0x30710000) {
+		rt3090_set_chan(sc, chan);
+		return;
+	}
+
+	if (IEEE80211_IS_CHAN_HT40U(c))
+		chan += 2;
+	else if (IEEE80211_IS_CHAN_HT40D(c))
+		chan -= 2;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_CHAN,
+		"%s: RF set channel: channel=%u, HT%s%s\n",
+		device_get_nameunit(sc->sc_dev),
+		ieee80211_chan2ieee(ic, c),
+		!IEEE80211_IS_CHAN_HT(c) ? " disabled" :
+			IEEE80211_IS_CHAN_HT20(c) ? "20":
+				IEEE80211_IS_CHAN_HT40U(c) ? "40U" : "40D",
+		(ic->ic_flags & IEEE80211_F_SCAN) ? ", scanning" : "");
+
+	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
+		return;
+
+	for (i = 0; prog[i].chan != chan; i++);
+
+	r1 = prog[i].r1;
+	r2 = prog[i].r2;
+	r3 = prog[i].r3;
+	r4 = prog[i].r4;
+
+	txpow1 = sc->txpow1[i];
+	txpow2 = sc->txpow2[i];
+
+	if (sc->ntxpath == 1)
+		r2 |= (1 << 14);
+
+	if (sc->nrxpath == 2)
+		r2 |= (1 << 6);
+	else if (sc->nrxpath == 1)
+		r2 |= (1 << 17) | (1 << 6);
+
+	if (IEEE80211_IS_CHAN_2GHZ(c))
+	{
+		r3 = (r3 & 0xffffc1ff) | (txpow1 << 9);
+		r4 = (r4 & ~0x001f87c0) | (sc->rf_freq_off << 15) |
+		    (txpow2 << 6);
+	}
+	else
+	{
+		r3 = r3 & 0xffffc1ff;
+		r4 = (r4 & ~0x001f87c0) | (sc->rf_freq_off << 15);
+
+		if (txpow1 >= RT2860_EEPROM_TXPOW_5GHZ_MIN && txpow1 < 0)
+		{
+			txpow1 = (-RT2860_EEPROM_TXPOW_5GHZ_MIN + txpow1);
+			if (txpow1 > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+				txpow1 = RT2860_EEPROM_TXPOW_5GHZ_MAX;
+
+			r3 |= (txpow1 << 10);
+		}
+		else
+		{
+			if (txpow1 > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+				txpow1 = RT2860_EEPROM_TXPOW_5GHZ_MAX;
+
+			r3 |= (txpow1 << 10) | (1 << 9);
+		}
+
+		if (txpow2 >= RT2860_EEPROM_TXPOW_5GHZ_MIN && txpow2 < 0)
+		{
+			txpow2 = (-RT2860_EEPROM_TXPOW_5GHZ_MIN + txpow2);
+			if (txpow2 > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+				txpow2 = RT2860_EEPROM_TXPOW_5GHZ_MAX;
+
+			r4 |= (txpow2 << 7);
+		}
+		else
+		{
+			if (txpow2 > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+				txpow2 = RT2860_EEPROM_TXPOW_5GHZ_MAX;
+
+			r4 |= (txpow2 << 7) | (1 << 6);
+		}
+	}
+
+	if (!(ic->ic_flags & IEEE80211_F_SCAN) && IEEE80211_IS_CHAN_HT40(c))
+		r4 |= (1 << 21);
+
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1);
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2);
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 & ~(1 << 2));
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4);
+
+	DELAY(200);
+
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1);
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2);
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 | (1 << 2));
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4);
+
+	DELAY(200);
+
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1);
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2);
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 & ~(1 << 2));
+	rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4);
+
+	rt2860_rf_select_chan_group(sc, c);
+
+	DELAY(1000);
+}
+
+/*
+ * rt2872_rf_set_chan
+ */
+static void 
+rt2872_rf_set_chan(struct rt2860_softc *sc,
+	struct ieee80211_channel *c)
+{
+	struct ifnet *ifp;
+	struct ieee80211com *ic;
+	const struct rt2860_rf_prog *prog;
+	uint32_t r1, r2, r3, r4;
+	uint32_t r6, r7, r12, r13, r23, r24;
+	int8_t txpow1, txpow2;
+	int i, chan;
+
+	ifp = sc->sc_ifp;
+	ic = ifp->if_l2com;
+	prog = rt2860_rf_2850;
+
+	/* get central channel position */
+
+	chan = ieee80211_chan2ieee(ic, c);
+
+	if (IEEE80211_IS_CHAN_HT40U(c))
+		chan += 2;
+	else if (IEEE80211_IS_CHAN_HT40D(c))
+		chan -= 2;
+
+	RT2860_DPRINTF(sc, RT2860_DEBUG_CHAN,
+		"%s: RF set channel: channel=%u, HT%s%s\n",
+		device_get_nameunit(sc->sc_dev),
+		ieee80211_chan2ieee(ic, c),
+		!IEEE80211_IS_CHAN_HT(c) ? " disabled" :
+			IEEE80211_IS_CHAN_HT20(c) ? "20":
+				IEEE80211_IS_CHAN_HT40U(c) ? "40U" : "40D",
+		(ic->ic_flags & IEEE80211_F_SCAN) ? ", scanning" : "");
+
+	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
+		return;
+
+	for (i = 0; prog[i].chan != chan; i++);
+
+	r1 = prog[i].r1;
+	r2 = prog[i].r2;
+	r3 = prog[i].r3;
+	r4 = prog[i].r4;
+
+	txpow1 = sc->txpow1[i];
+	txpow2 = sc->txpow2[i];
+
+	for (i = 0; rt2860_rf_fi3020[i].channel != chan; i++);
+
+	/* Programm channel parameters */
+	r2 = rt2860_rf_fi3020[i].n;
+	rt2860_io_rf_write(sc, 2 , r2 );
+	r3 = rt2860_rf_fi3020[i].k;
+	rt2860_io_rf_write(sc, 3 , r3 );
+
+	r6 = (rt3052_rf_default[6] & 0xFC) | (rt2860_rf_fi3020[i].r & 0x03);
+	rt2860_io_rf_write(sc, 6 , r6 );
+
+	/* Set Tx Power */
+	r12 = (rt3052_rf_default[12] & 0xE0) | (txpow1 & 0x1f);
+	rt2860_io_rf_write(sc, 12, r12);
+
+	/* Set Tx1 Power */
+	r13 = (rt3052_rf_default[13] & 0xE0) | (txpow2 & 0x1f);
+	rt2860_io_rf_write(sc, 13, r13);
+
+	/* Set RF offset */
+	r23 = (rt3052_rf_default[23] & 0x80) | (sc->rf_freq_off);
+	rt2860_io_rf_write(sc, 23, r23);
+
+	/* Set BW */
+	r24 = (rt3052_rf_default[24] & 0xDF);
+	if (!(ic->ic_flags & IEEE80211_F_SCAN) && IEEE80211_IS_CHAN_HT40(c))
+	    r24 |= 0x20;
+	rt2860_io_rf_write(sc, 24, r24);
+
+	/* Enable RF tuning */
+	r7 = (rt3052_rf_default[7]) | 1;
+	rt2860_io_rf_write(sc, 7 , r7 );
+
+	/* Antenna */
+	r1 = (rt3052_rf_default[1] & 0xab) | ((sc->nrxpath == 1)?0x10:0) |
+	    ((sc->ntxpath == 1)?0x20:0);
+	rt2860_io_rf_write(sc, 1 , r1 );
+
+	DELAY(200);
+
+	rt2860_rf_select_chan_group(sc, c);
+
+	DELAY(1000);
+}
+
+
diff -r 5624b06c8184 -r ac5b1ebb1990 head/sys/dev/ral/rt2860reg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ral/rt2860reg.h	Tue Mar 13 01:18:04 2012 +0200
@@ -0,0 +1,560 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar at gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini at free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _RT2860_REG_H_
+#define _RT2860_REG_H_
+
+#define RT2860_REG_PCI_CFG					0x0000
+#define RT2860_REG_EEPROM_CSR					0x0004
+#define RT2860_REG_PCI_MCU_CSR					0x0008
+#define RT2860_REG_PCI_SYS_CSR					0x000c
+#define RT2860_REG_PCIE_JTAG					0x0010
+
+#define RT2860_REG_SCHDMA_INT_STATUS				0x0200
+#define RT2860_REG_SCHDMA_INT_MASK					0x0204
+#define RT2860_REG_SCHDMA_WPDMA_GLO_CFG				0x0208
+#define RT2860_REG_SCHDMA_WPDMA_RST_IDX				0x020c
+#define RT2860_REG_SCHDMA_DELAY_INT_CFG				0x0210
+#define RT2860_REG_SCHDMA_WMM_AIFSN_CFG				0x0214
+#define RT2860_REG_SCHDMA_WMM_CWMIN_CFG				0x0218
+#define RT2860_REG_SCHDMA_WMM_CWMAX_CFG				0x021c
+#define RT2860_REG_SCHDMA_WMM_TXOP0_CFG    			0x0220
+#define RT2860_REG_SCHDMA_WMM_TXOP1_CFG    			0x0224
+#define RT2860_REG_SCHDMA_GPIO_CTRL_CFG    			0x0228
+#define RT2860_REG_SCHDMA_RX_BASE_PTR				0x0290
+#define RT2860_REG_SCHDMA_RX_MAX_CNT				0x0294
+#define RT2860_REG_SCHDMA_RX_CALC_IDX				0x0298
+#define RT2860_REG_SCHDMA_RX_DRX_IDX				0x029c
+#define RT2860_REG_SCHDMA_TX_BASE_PTR(qid)			(0x0230 + (qid) * 16)
+#define RT2860_REG_SCHDMA_TX_MAX_CNT(qid)			(0x0234 + (qid) * 16)
+#define RT2860_REG_SCHDMA_TX_CTX_IDX(qid)			(0x0238 + (qid) * 16)
+#define RT2860_REG_SCHDMA_TX_DTX_IDX(qid)			(0x023c + (qid) * 16)
+#define RT2860_REG_SCHDMA_US_CYC_CNT				0x02a4
+
+#define RT2860_REG_PBF_SYS_CTRL						0x0400
+#define RT2860_REG_PBF_HOST_CMD						0x0404
+#define RT2860_REG_PBF_CFG						0x0408
+#define RT2860_REG_PBF_MAX_PCNT						0x040c
+#define RT2860_REG_PBF_BUF_CTRL						0x0410
+#define RT2860_REG_PBF_MCU_INT_STA					0x0414
+#define RT2860_REG_PBF_MCU_INT_ENA					0x0418
+#define RT2860_REG_PBF_TX0Q_IO						0x041c
+#define RT2860_REG_PBF_TX1Q_IO						0x0420
+#define RT2860_REG_PBF_TX2Q_IO						0x0424
+#define RT2860_REG_PBF_RX0Q_IO						0x0428
+#define RT2860_REG_PBF_BCN_OFFSET0					0x042c
+#define RT2860_REG_PBF_BCN_OFFSET1					0x0430
+#define RT2860_REG_PBF_TXRXQ_STA					0x0434
+#define RT2860_REG_PBF_TXRXQ_PCNT					0x0438
+#define RT2860_REG_PBF_DBG						0x043c
+#define RT2860_REG_PBF_CAP_CTRL						0x0440
+
+#define RT2872_REG_RF_CSR_CFG						0x500
+#define RT2872_REG_RF_SETTING						0x504
+#define RT2872_REG_RF_TEST_CONTROL					0x508
+
+#define RT2860_REG_MAC_CSR0						0x1000
+#define RT2860_REG_SYS_CTRL						0x1004
+#define RT2860_REG_ADDR_DW0						0x1008
+#define RT2860_REG_ADDR_DW1						0x100c
+#define RT2860_REG_BSSID_DW0						0x1010
+#define RT2860_REG_BSSID_DW1						0x1014
+#define RT2860_REG_MAX_LEN_CFG						0x1018
+#define RT2860_REG_BBP_CSR_CFG						0x101c
+#define RT2860_REG_RF_CSR_CFG0						0x1020
+#define RT2860_REG_LED_CFG						0x102c
+#define RT2860_REG_AMPDU_MAX_LEN_20M1S					0x1030
+#define RT2860_REG_AMPDU_MAX_LEN_20M2S					0x1034
+#define RT2860_REG_AMPDU_MAX_LEN_40M1S					0x1038
+#define RT2860_REG_AMPDU_MAX_LEN_40M2S					0x103c
+#define RT2860_REG_AMPDU_BA_WINSIZE					0x1040
+
+#define RT2860_REG_XIFS_TIME_CFG             				0x1100
+#define RT2860_REG_BKOFF_SLOT_CFG					0x1104
+#define RT2860_REG_NAV_TIME_CFG						0x1108
+#define RT2860_REG_CH_TIME_CFG						0x110c
+#define RT2860_REG_PBF_LIFE_TIMER					0x1110
+#define RT2860_REG_BCN_TIME_CFG						0x1114
+#define RT2860_REG_TBTT_SYNC_CFG					0x1118
+#define RT2860_REG_TSF_TIMER_DW0					0x111c
+#define RT2860_REG_TSF_TIMER_DW1					0x1120
+#define RT2860_REG_TBTT_TIMER						0x1124
+#define RT2860_REG_INT_TIMER						0x1128
+#define RT2860_REG_INT_TIMER_EN						0x112c
+#define RT2860_REG_CH_IDLE_STA						0x1130
+
+#define RT2860_REG_STATUS_CFG						0x1200
+#define RT2860_REG_PWR_PIN_CFG						0x1204
+#define RT2860_REG_AUTO_WAKEUP_CFG					0x1208
+
+#define RT2860_REG_TX_EDCA_AC_CFG(aci)					(0x1300 + (aci) * 4)
+#define RT2860_REG_TX_EDCA_TID_AC_MAP					0x1310
+#define RT2860_REG_TX_PWR_CFG(ridx)					(0x1314 + (ridx) * 4)
+#define RT2860_REG_TX_PIN_CFG						0x1328
+#define RT2860_REG_TX_BAND_CFG						0x132c
+#define RT2860_REG_TX_SW_CFG0						0x1330
+#define RT2860_REG_TX_SW_CFG1						0x1334
+#define RT2860_REG_TX_SW_CFG2						0x1338
+#define RT2860_REG_TX_TXOP_THRES_CFG					0x133c
+#define RT2860_REG_TX_TXOP_CTRL_CFG					0x1340
+#define RT2860_REG_TX_RTS_CFG						0x1344
+#define RT2860_REG_TX_TIMEOUT_CFG					0x1348
+#define RT2860_REG_TX_RTY_CFG						0x134c
+#define RT2860_REG_TX_LINK_CFG						0x1350
+#define RT2860_REG_TX_HT_FBK_CFG0					0x1354
+#define RT2860_REG_TX_HT_FBK_CFG1					0x1358
+#define RT2860_REG_TX_LG_FBK_CFG0					0x135c
+#define RT2860_REG_TX_LG_FBK_CFG1					0x1360
+#define RT2860_REG_TX_CCK_PROT_CFG					0x1364
+#define RT2860_REG_TX_OFDM_PROT_CFG					0x1368
+#define RT2860_REG_TX_MM20_PROT_CFG					0x136c
+#define RT2860_REG_TX_MM40_PROT_CFG					0x1370
+#define RT2860_REG_TX_GF20_PROT_CFG					0x1374
+#define RT2860_REG_TX_GF40_PROT_CFG					0x1378
+#define RT2860_REG_TX_EXP_CTS_TIME					0x137c
+#define RT2860_REG_TX_EXP_ACK_TIME					0x1380
+
+#define RT2860_REG_RX_FILTER_CFG					0x1400
+#define RT2860_REG_AUTO_RSP_CFG						0x1404
+#define RT2860_REG_LEGACY_BASIC_RATE					0x1408
+#define RT2860_REG_HT_BASIC_RATE					0x140c
+#define RT2860_REG_HT_CTRL_CFG						0x1410
+#define RT2860_REG_SIFS_COST_CFG					0x1414
+#define RT2860_REG_RX_PARSER_CFG					0x1418
+
+#define RT2860_REG_TX_SEC_CNT0						0x1500
+#define RT2860_REG_RX_SEC_CNT0						0x1504
+#define RT2860_REG_CCMP_FC_MUTE						0x1508
+
+#define RT2860_REG_HCCAPSMP_TXOP_HLDR_ADDR0				0x1600
+#define RT2860_REG_HCCAPSMP_TXOP_HLDR_ADDR1				0x1604
+#define RT2860_REG_HCCAPSMP_TXOP_HLDR_ET				0x1608
+#define RT2860_REG_HCCAPSMP_QOS_CFPOLL_RA_DW0				0x160c
+#define RT2860_REG_HCCAPSMP_QOS_CFPOLL_A1_DW1				0x1610
+#define RT2860_REG_HCCAPSMP_QOS_CFPOLL_QC				0x1614
+
+#define RT2860_REG_RX_STA_CNT0						0x1700
+#define RT2860_REG_RX_STA_CNT1						0x1704
+#define RT2860_REG_RX_STA_CNT2						0x1708
+#define RT2860_REG_TX_STA_CNT0						0x170c
+#define RT2860_REG_TX_STA_CNT1						0x1710
+#define RT2860_REG_TX_STA_CNT2						0x1714
+#define RT2860_REG_TX_STA_FIFO						0x1718
+#define RT2860_REG_TX_AGG_CNT						0x171c
+#define RT2860_REG_TX_AGG_CNT0						0x1720
+#define RT2860_REG_TX_AGG_CNT1						0x1724
+#define RT2860_REG_TX_AGG_CNT2						0x1728
+#define RT2860_REG_TX_AGG_CNT3						0x172c
+#define RT2860_REG_TX_AGG_CNT4						0x1730
+#define RT2860_REG_TX_AGG_CNT5						0x1734
+#define RT2860_REG_TX_AGG_CNT6						0x1738
+#define RT2860_REG_TX_AGG_CNT7						0x173c
+#define RT2860_REG_TXRX_MPDU_DEN_CNT					0x1740
+
+#define RT2860_REG_WCID(wcid)						(0x1800 + (wcid) * 8)
+#define RT2860_REG_PKEY(wcid)						(0x4000 + (wcid) * 32)
+#define RT2860_REG_IVEIV(wcid)						(0x6000 + (wcid) * 8)
+#define RT2860_REG_WCID_ATTR(wcid)					(0x6800 + (wcid) * 4)
+#define RT2860_REG_SKEY(vap, kidx)					(0x6c00 + ((vap) * 4 + (kidx)) * 32)
+#define RT2860_REG_SKEY_MODE(vap)					(0x7000 + ((vap) / 2) * 4)
+#define RT2860_REG_SKEY_MODE_0_7					0x7000
+
+#define RT2860_REG_MCU_UCODE_BASE					0x2000
+
+#define RT2860_REG_H2M_HOST_CMD						0x0404
+#define RT2860_REG_H2M_MAILBOX						0x7010
+#define RT2860_REG_H2M_MAILBOX_CID					0x7014
+#define RT2860_REG_H2M_MAILBOX_STATUS				0x701c
+#define RT2860_REG_H2M_MAILBOX_BBP_AGENT			0x7028
+
+#define RT2860_REG_BEACON_BASE(vap)					(0x7800 + (vap) * 512)
+
+/* RT3070 registers */
+#define RT3070_RF_CSR_CFG		0x0500
+#define RT3070_EFUSE_CTRL		0x0580
+#define RT3070_EFUSE_DATA0		0x0590
+#define RT3070_EFUSE_DATA1		0x0594
+#define RT3070_EFUSE_DATA2		0x0598
+#define RT3070_EFUSE_DATA3		0x059c
+#define RT3090_OSC_CTRL			0x05a4
+#define RT3070_LDO_CFG0			0x05d4
+#define RT3070_GPIO_SWITCH		0x05dc
+
+#define RT3090_AUX_CTRL			0x010c
+#define RT3070_OPT_14			0x0114
+
+/* possible flags for register RF_CSR_CFG */
+#define RT3070_RF_KICK		(1 << 17)
+#define RT3070_RF_WRITE		(1 << 16)
+
+/* possible flags for register EFUSE_CTRL */
+#define RT3070_SEL_EFUSE	(1 << 31)
+#define RT3070_EFSROM_KICK	(1 << 30)
+#define RT3070_EFSROM_AIN_MASK	0x03ff0000
+#define RT3070_EFSROM_AIN_SHIFT	16
+#define RT3070_EFSROM_MODE_MASK	0x000000c0
+#define RT3070_EFUSE_AOUT_MASK	0x0000003f
+
+/* possible flags for RT3020 RF register 1 */
+#define RT3070_RF_BLOCK	(1 << 0)
+#define RT3070_RX0_PD	(1 << 2)
+#define RT3070_TX0_PD	(1 << 3)
+#define RT3070_RX1_PD	(1 << 4)
+#define RT3070_TX1_PD	(1 << 5)
+#define RT3070_RX2_PD	(1 << 6)
+#define RT3070_TX2_PD	(1 << 7)
+
+/* possible flags for RT3020 RF register 1 */
+#define RT3070_RF_BLOCK	(1 << 0)
+#define RT3070_RX0_PD	(1 << 2)
+#define RT3070_TX0_PD	(1 << 3)
+#define RT3070_RX1_PD	(1 << 4)
+#define RT3070_TX1_PD	(1 << 5)
+#define RT3070_RX2_PD	(1 << 6)
+#define RT3070_TX2_PD	(1 << 7)
+
+/* possible flags for RT3020 RF register 7 */
+#define RT3070_TUNE	(1 << 0)
+
+/* possible flags for RT3020 RF register 15 */
+#define RT3070_TX_LO2	(1 << 3)
+
+/* possible flags for RT3020 RF register 17 */
+#define RT3070_TX_LO1	(1 << 3)
+
+/* possible flags for RT3020 RF register 20 */
+#define RT3070_RX_LO1	(1 << 3)
+
+/* possible flags for RT3020 RF register 21 */
+#define RT3070_RX_LO2	(1 << 3)
+#define RT3070_RX_CTB	(1 << 7)
+
+/* possible flags for RT3020 RF register 22 */
+#define RT3070_BB_LOOPBACK	(1 << 0)
+
+/* possible flags for RT3053 RF register 1 */
+#define RT3593_VCO	(1 << 0)
+
+/* possible flags for RT3053 RF register 2 */
+#define RT3593_RESCAL	(1 << 7)
+
+/* possible flags for RT3053 RF register 3 */
+#define RT3593_VCOCAL	(1 << 7)
+
+/* possible flags for RT3053 RF register 6 */
+#define RT3593_VCO_IC	(1 << 6)
+
+/* possible flags for RT3053 RF register 20 */
+#define RT3593_LDO_PLL_VC_MASK	0x0e
+#define RT3593_LDO_RF_VC_MASK	0xe0
+
+/* possible flags for RT3053 RF register 22 */
+#define RT3593_CP_IC_MASK	0xe0
+#define RT3593_CP_IC_SHIFT	5
+
+/* possible flags for RT3053 RF register 46 */
+#define RT3593_RX_CTB	(1 << 5)
+
+#define RT3090_DEF_LNA	10
+
+
+#define RT2860_REG_RF_R1							0
+#define RT2860_REG_RF_R2							1
+#define RT2860_REG_RF_R3							2
+#define RT2860_REG_RF_R4							3
+
+/*
+ * RT2860_REG_EEPROM_CSR flags
+ */
+#define RT2860_REG_EERL								(1 << 7)
+#define RT2860_REG_EEDO								(1 << 3)
+#define RT2860_REG_EEDI								(1 << 2)
+#define RT2860_REG_EECS								(1 << 1)
+#define RT2860_REG_EESK								(1 << 0)
+#define RT2860_REG_EEOP_READ						0x6
+
+/*
+ * RT2860_REG_SCHDMA_INT_STATUS
+ * RT2860_REG_SCHDMA_INT_MASK flags
+ */
+#define RT2860_REG_INT_TX_COHERENT					(1 << 17)
+#define RT2860_REG_INT_RX_COHERENT					(1 << 16)
+#define RT2860_REG_INT_GP_TIMER						(1 << 15)
+#define RT2860_REG_INT_AUTO_WAKEUP					(1 << 14)
+#define RT2860_REG_INT_FIFO_STA_FULL				(1 << 13)
+#define RT2860_REG_INT_PRE_TBTT						(1 << 12)
+#define RT2860_REG_INT_TBTT							(1 << 11)
+#define RT2860_REG_INT_TXRX_COHERENT				(1 << 10)
+#define RT2860_REG_INT_MCU_CMD						(1 << 9)
+#define RT2860_REG_INT_TX_MGMT_DONE					(1 << 8)
+#define RT2860_REG_INT_TX_HCCA_DONE					(1 << 7)
+#define RT2860_REG_INT_TX_AC3_DONE					(1 << 6)
+#define RT2860_REG_INT_TX_AC2_DONE					(1 << 5)
+#define RT2860_REG_INT_TX_AC1_DONE					(1 << 4)
+#define RT2860_REG_INT_TX_AC0_DONE					(1 << 3)
+#define RT2860_REG_INT_RX_DONE						(1 << 2)
+#define RT2860_REG_INT_TX_DELAY_DONE				(1 << 1)
+#define RT2860_REG_INT_RX_DELAY_DONE				(1 << 0)
+
+/*
+ * RT2860_REG_SCHDMA_WPDMA_GLO_CFG flags
+ */
+#define RT2860_REG_TX_WB_DDONE						(1 << 6)
+#define RT2860_REG_RX_DMA_BUSY						(1 << 3)
+#define RT2860_REG_RX_DMA_ENABLE					(1 << 2)
+#define RT2860_REG_TX_DMA_BUSY						(1 << 1)
+#define RT2860_REG_TX_DMA_ENABLE					(1 << 0)
+#define RT2860_REG_WPDMA_BT_SIZE_SHIFT				4
+#define RT2860_REG_WPDMA_BT_SIZE16					0
+#define RT2860_REG_WPDMA_BT_SIZE32					1
+#define RT2860_REG_WPDMA_BT_SIZE64					2
+#define RT2860_REG_WPDMA_BT_SIZE128					3
+
+/*
+ * RT2860_REG_SCHDMA_WPDMA_RST_IDX flags
+ */
+#define RT2860_REG_RST_IDX_RX						(1 << 16)
+#define RT2860_REG_RST_IDX_TX_MGMT					(1 << 5)
+#define RT2860_REG_RST_IDX_TX_HCCA					(1 << 4)
+#define RT2860_REG_RST_IDX_TX_AC3					(1 << 3)
+#define RT2860_REG_RST_IDX_TX_AC2					(1 << 2)
+#define RT2860_REG_RST_IDX_TX_AC1					(1 << 1)
+#define RT2860_REG_RST_IDX_TX_AC0					(1 << 0)
+
+/*
+ * RT2860_REG_SCHDMA_DELAY_INT_CFG flags
+ */
+#define RT2860_REG_INT_TX_DELAY_ENABLE				(1 << 31)
+#define RT2860_REG_INT_TX_MAX_PINT_SHIFT			24
+#define RT2860_REG_INT_TX_MAX_PINT_MASK				0x7
+#define RT2860_REG_INT_TX_MAX_PTIME_SHIFT			16
+#define RT2860_REG_INT_TX_MAX_PTIME_MASK			0x8
+#define RT2860_REG_INT_RX_DELAY_ENABLE				(1 << 15)
+#define RT2860_REG_INT_RX_MAX_PINT_SHIFT			8
+#define RT2860_REG_INT_RX_MAX_PINT_MASK				0x7
+#define RT2860_REG_INT_RX_MAX_PTIME_SHIFT			0
+#define RT2860_REG_INT_RX_MAX_PTIME_MASK			0x8
+
+/*
+ * RT2860_REG_PBF_SYS_CTRL flags
+ */
+#define RT2860_REG_HST_PM_SEL						(1 << 16)
+#define RT2860_REG_MCU_READY						(1 << 7)
+#define RT2860_REG_MCU_RESET						(1 << 0)
+
+/*
+ * RT2860_REG_PBF_TXRXQ_PCNT flags
+ */
+#define RT2860_REG_RXQ_PCNT_SHIFT					24
+#define RT2860_REG_RXQ_PCNT_MASK					0xff
+#define RT2860_REG_TX2Q_PCNT_SHIFT					16
+#define RT2860_REG_TX2Q_PCNT_MASK					0xff
+#define RT2860_REG_TX1Q_PCNT_SHIFT					8
+#define RT2860_REG_TX1Q_PCNT_MASK					0xff
+#define RT2860_REG_TX0Q_PCNT_SHIFT					0
+#define RT2860_REG_TX0Q_PCNT_MASK					0xff
+
+/*
+ * RT2860_REG_SYS_CTRL flags
+ */
+#define RT2860_REG_RX_ENABLE						(1 << 3)
+#define RT2860_REG_TX_ENABLE						(1 << 2)
+#define RT2860_REG_BBP_HRST							(1 << 1)
+#define RT2860_REG_MAC_SRST							(1 << 0)
+
+/*
+ * RT2872_REG_RF_CSR_CFG flags
+ */
+#define RT2872_REG_RF_CSR_BUSY						(1 << 17)
+#define RT2872_REG_RF_CSR_KICK						(1 << 17)
+#define RT2872_REG_RF_CSR_WRITE						(1 << 16)
+#define RT2872_REG_RF_ID_SHIFT						8
+#define RT2872_REG_RF_ID_MASK						0x1f
+#define RT2872_REG_RF_VAL_SHIFT						0
+#define RT2872_REG_RF_VAL_MASK						0xff
+
+/*
+ * RT2860_REG_BBP_CSR_CFG flags
+ */
+#define RT2860_REG_BBP_RW_MODE_PARALLEL					(1 << 19)
+#define RT2860_REG_BBP_PAR_DUR						(1 << 19)
+#define RT2860_REG_BBP_CSR_BUSY						(1 << 17)
+#define RT2860_REG_BBP_CSR_KICK						(1 << 17)
+#define RT2860_REG_BBP_CSR_READ						(1 << 16)
+#define RT2860_REG_BBP_REG_SHIFT					8
+#define RT2860_REG_BBP_REG_MASK						0xff
+#define RT2860_REG_BBP_VAL_SHIFT					0
+#define RT2860_REG_BBP_VAL_MASK						0xff
+
+/*
+ * RT2860_REG_RF_CSR_CFG0 flags
+ */
+#define RT2860_REG_RF_BUSY							(1 << 31)
+
+/*
+ * RT2860_REG_BCN_TIME_CFG flags
+ */
+#define RT2860_REG_BCN_TX_ENABLE					(1 << 20)
+#define RT2860_REG_TBTT_TIMER_ENABLE				(1 << 19)
+#define RT2860_REG_TSF_TIMER_ENABLE					(1 << 16)
+#define RT2860_REG_TSF_SYNC_MODE_SHIFT				17
+#define RT2860_REG_TSF_SYNC_MODE_MASK				0x3
+#define RT2860_REG_TSF_SYNC_MODE_DISABLE			0
+#define RT2860_REG_TSF_SYNC_MODE_STA				1
+#define RT2860_REG_TSF_SYNC_MODE_IBSS				2
+#define RT2860_REG_TSF_SYNC_MODE_HOSTAP				3
+
+/*
+ * RT2860_REG_STATUS_CFG flags
+ */
+#define RT2860_REG_STATUS_RX_BUSY					(1 << 1)
+#define RT2860_REG_STATUS_TX_BUSY					(1 << 0)
+
+/*
+ * RT2860_REG_TX_PIN_CFG flags
+ */
+#define RT2860_REG_TRSW_ENABLE						(1 << 18)
+#define RT2860_REG_RFTR_ENABLE						(1 << 16)
+#define RT2860_REG_LNA_PE_G1_ENABLE					(1 << 11)
+#define RT2860_REG_LNA_PE_A1_ENABLE					(1 << 10)
+#define RT2860_REG_LNA_PE_G0_ENABLE					(1 << 9)
+#define RT2860_REG_LNA_PE_A0_ENABLE					(1 << 8)
+#define RT2860_REG_PA_PE_G1_ENABLE					(1 << 3)
+#define RT2860_REG_PA_PE_A1_ENABLE					(1 << 2)
+#define RT2860_REG_PA_PE_G0_ENABLE					(1 << 1)
+#define RT2860_REG_PA_PE_A0_ENABLE					(1 << 0)
+
+/*
+ * RT2860_REG_TX_BAND_CFG flags
+ */
+#define RT2860_REG_TX_BAND_BG						(1 << 2)
+#define RT2860_REG_TX_BAND_A						(1 << 1)
+#define RT2860_REG_TX_BAND_HT40_ABOVE				(1 << 0)
+#define RT2860_REG_TX_BAND_HT40_BELOW				(0 << 0)
+
+/*
+ * RT2860_REG_TX_RTS_CFG flags
+ */
+#define RT2860_REG_TX_RTS_THRESHOLD_SHIFT			8
+#define RT2860_REG_TX_RTS_THRESHOLD_MASK			0xffff
+
+/*
+ * RT2860_REG_TX_CCK_PROT_CFG
+ * RT2860_REG_TX_OFDM_PROT_CFG
+ * RT2860_REG_TX_MM20_PROT_CFG
+ * RT2860_REG_TX_MM40_PROT_CFG
+ * RT2860_REG_TX_GF20_PROT_CFG
+ * RT2860_REG_TX_GF40_PROT_CFG flags
+ */
+#define RT2860_REG_RTSTH_ENABLE						(1 << 26)
+#define RT2860_REG_TXOP_ALLOW_GF40					(1 << 25)
+#define RT2860_REG_TXOP_ALLOW_GF20					(1 << 24)
+#define RT2860_REG_TXOP_ALLOW_MM40					(1 << 23)
+#define RT2860_REG_TXOP_ALLOW_MM20					(1 << 22)
+#define RT2860_REG_TXOP_ALLOW_OFDM					(1 << 21)
+#define RT2860_REG_TXOP_ALLOW_CCK					(1 << 20)
+#define RT2860_REG_TXOP_ALLOW_ALL					(0x3f << 20)
+#define RT2860_REG_PROT_NAV_NONE					(0 << 18)
+#define RT2860_REG_PROT_NAV_SHORT					(1 << 18)
+#define RT2860_REG_PROT_NAV_LONG					(2 << 18)
+#define RT2860_REG_PROT_CTRL_NONE					(0 << 16)
+#define RT2860_REG_PROT_CTRL_RTS_CTS				(1 << 16)
+#define RT2860_REG_PROT_CTRL_CTS					(2 << 16)
+#define RT2860_REG_PROT_PHYMODE_SHIFT				14
+#define RT2860_REG_PROT_PHYMODE_MASK				0x3
+#define RT2860_REG_PROT_PHYMODE_CCK					0
+#define RT2860_REG_PROT_PHYMODE_OFDM				1
+#define RT2860_REG_PROT_MCS_SHIFT					0
+#define RT2860_REG_PROT_MCS_MASK					0x7f
+
+/*
+ * RT2860_REG_RX_FILTER_CFG flags
+ */
+#define RT2860_REG_RX_FILTER_DROP_CTRL_RSV			(1 << 16)
+#define RT2860_REG_RX_FILTER_DROP_BAR				(1 << 15)
+#define RT2860_REG_RX_FILTER_DROP_BA				(1 << 14)
+#define RT2860_REG_RX_FILTER_DROP_PSPOLL			(1 << 13)
+#define RT2860_REG_RX_FILTER_DROP_RTS				(1 << 12)
+#define RT2860_REG_RX_FILTER_DROP_CTS				(1 << 11)
+#define RT2860_REG_RX_FILTER_DROP_ACK				(1 << 10)
+#define RT2860_REG_RX_FILTER_DROP_CFEND				(1 << 9)
+#define RT2860_REG_RX_FILTER_DROP_CFACK				(1 << 8)
+#define RT2860_REG_RX_FILTER_DROP_DUPL				(1 << 7)
+#define RT2860_REG_RX_FILTER_DROP_BCAST				(1 << 6)
+#define RT2860_REG_RX_FILTER_DROP_MCAST				(1 << 5)
+#define RT2860_REG_RX_FILTER_DROP_VER_ERR			(1 << 4)
+#define RT2860_REG_RX_FILTER_DROP_NOT_MYBSS			(1 << 3)
+#define RT2860_REG_RX_FILTER_DROP_UC_NOME			(1 << 2)
+#define RT2860_REG_RX_FILTER_DROP_PHY_ERR			(1 << 1)
+#define RT2860_REG_RX_FILTER_DROP_CRC_ERR			(1 << 0)
+
+/*
+ * RT2860_REG_AUTO_RSP_CFG flags
+ */
+#define RT2860_REG_CCK_SHORT_ENABLE					(1 << 4)
+
+/*
+ * RT2860_REG_TX_STA_FIFO flags
+ */
+#define RT2860_REG_TX_STA_FIFO_MCS_SHIFT			16
+#define RT2860_REG_TX_STA_FIFO_MCS_MASK				0x7f
+#define RT2860_REG_TX_STA_FIFO_WCID_SHIFT			8
+#define RT2860_REG_TX_STA_FIFO_WCID_MASK			0xff
+#define RT2860_REG_TX_STA_FIFO_PID_SHIFT			1
+#define RT2860_REG_TX_STA_FIFO_PID_MASK				0xf
+#define RT2860_REG_TX_STA_FIFO_ACK_REQ				(1 << 7)
+#define RT2860_REG_TX_STA_FIFO_AGG					(1 << 6)
+#define RT2860_REG_TX_STA_FIFO_TX_OK				(1 << 5)
+#define RT2860_REG_TX_STA_FIFO_VALID				(1 << 0)
+
+/*
+ * RT2860_REG_WCID_ATTR flags
+ */
+#define RT2860_REG_VAP_SHIFT						4
+#define RT2860_REG_VAP_MASK							0x7
+#define RT2860_REG_CIPHER_MODE_SHIFT				1
+#define RT2860_REG_CIPHER_MODE_MASK					0x7
+#define RT2860_REG_CIPHER_MODE_NONE					0
+#define RT2860_REG_CIPHER_MODE_WEP40				1
+#define RT2860_REG_CIPHER_MODE_WEP104				2
+#define RT2860_REG_CIPHER_MODE_TKIP					3
+#define RT2860_REG_CIPHER_MODE_AES_CCMP				4
+#define RT2860_REG_CIPHER_MODE_CKIP40				5
+#define RT2860_REG_CIPHER_MODE_CKIP104				6
+#define RT2860_REG_CIPHER_MODE_CKIP128				7
+#define RT2860_REG_PKEY_ENABLE						(1 << 0)
+
+/*
+ * RT2860_REG_H2M_MAILBOX flags
+ */
+#define RT2860_REG_H2M_BUSY							(1 << 24)
+#define RT2860_REG_H2M_TOKEN_POWERSAVE				1
+#define RT2860_REG_H2M_TOKEN_RADIOOFF				2
+#define RT2860_REG_H2M_TOKEN_WAKEUP					3
+#define RT2860_REG_H2M_TOKEN_NO_INTR				0xff
+
+/*
+ * RT2860_REG_H2M_MAILBOX_CID flags
+ */
+#define RT2860_REG_H2M_CID0_SHIFT					0
+#define RT2860_REG_H2M_CID1_SHIFT					8
+#define RT2860_REG_H2M_CID2_SHIFT					16
+#define RT2860_REG_H2M_CID3_SHIFT					24
+#define RT2860_REG_H2M_CID_MASK						0xff
+
+#endif /* #ifndef _RT2860_REG_H_ */
diff -r 5624b06c8184 -r ac5b1ebb1990 head/sys/dev/ral/rt2860ucode.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ral/rt2860ucode.h	Tue Mar 13 01:18:04 2012 +0200
@@ -0,0 +1,2104 @@
+
+/*
+ Copyright (c) 2007, Ralink Technology Corporation
+ All rights reserved.
+
+ Redistribution.  Redistribution and use in binary form, without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 	* Redistributions must reproduce the above copyright notice and the
+ 	following disclaimer in the documentation and/or other materials
+ 	provided with the distribution.
+ 	* Neither the name of Ralink Technology Corporation nor the names of its
+ 	suppliers may be used to endorse or promote products derived from this
+ 	software without specific prior written permission.
+ 	* No reverse engineering, decompilation, or disassembly of this software
+ 	is permitted.
+
+ Limited patent license. Ralink Technology Corporation grants a world-wide,
+ royalty-free, non-exclusive license under patents it now or hereafter
+ owns or controls to make, have made, use, import, offer to sell and
+ sell ("Utilize") this software, but solely to the extent that any
+ such patent is necessary to Utilize the software alone, or in
+ combination with an operating system licensed under an approved Open
+ Source license as listed by the Open Source Initiative at
+ http://opensource.org/licenses.  The patent license shall not apply to
+ any other combinations which include this software.  No hardware per
+ se is licensed hereunder.
+
+ DISCLAIMER.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+*/
+
+#ifndef _RT2860_UCODE_H_
+#define _RT2860_UCODE_H_
+
+/*
+ * RT2860 microcode v26
+ */
+static const uint8_t rt2860_ucode[] =
+{
+	0x02, 0x03, 0x5E, 0x02, 
+	0x02, 0xB1, 0x22, 0x22, 
+	0xFF, 0xFF, 0xFF, 0x02, 
+	0x01, 0x82, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0x02, 
+	0x00, 0x1E, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0x02, 
+	0x01, 0x33, 0xC0, 0xE0, 
+	0xC0, 0xF0, 0xC0, 0x83, 
+	0xC0, 0x82, 0xC0, 0xD0, 
+	0x75, 0xD0, 0x18, 0xC2, 
+	0xAF, 0x30, 0x45, 0x03, 
+	0x12, 0x10, 0x09, 0x90, 
+	0x04, 0x16, 0xE0, 0x30, 
+	0xE3, 0x03, 0x74, 0x08, 
+	0xF0, 0x90, 0x04, 0x14, 
+	0xE0, 0x20, 0xE7, 0x03, 
+	0x02, 0x00, 0xCB, 0x74, 
+	0x80, 0xF0, 0x90, 0x70, 
+	0x12, 0xE0, 0xF5, 0x2F, 
+	0x90, 0x04, 0x04, 0xE0, 
+	0x24, 0xCF, 0x60, 0x30, 
+	0x14, 0x60, 0x42, 0x24, 
+	0xE2, 0x60, 0x47, 0x14, 
+	0x60, 0x55, 0x24, 0x21, 
+	0x70, 0x60, 0xE5, 0x55, 
+	0x24, 0xFE, 0x60, 0x07, 
+	0x14, 0x60, 0x08, 0x24, 
+	0x02, 0x70, 0x08, 0x7D, 
+	0x01, 0x80, 0x28, 0x7D, 
+	0x02, 0x80, 0x24, 0x90, 
+	0x70, 0x10, 0xE0, 0xF5, 
+	0x50, 0x85, 0x2F, 0x40, 
+	0xD2, 0x01, 0x80, 0x3E, 
+	0xE5, 0x55, 0x64, 0x03, 
+	0x60, 0x04, 0xE5, 0x55, 
+	0x70, 0x04, 0x7D, 0x02, 
+	0x80, 0x09, 0x85, 0x2F, 
+	0x41, 0xD2, 0x02, 0x80, 
+	0x29, 0xAD, 0x55, 0xAF, 
+	0x2F, 0x12, 0x02, 0x8D, 
+	0x80, 0x20, 0x90, 0x70, 
+	0x10, 0xE0, 0xF5, 0x47, 
+	0x90, 0x70, 0x11, 0xE0, 
+	0xF5, 0x44, 0x12, 0x10, 
+	0x25, 0x80, 0x06, 0x90, 
+	0x70, 0x10, 0xE0, 0xF5, 
+	0x45, 0xE4, 0xFD, 0xAF, 
+	0x2F, 0x12, 0x02, 0x8D, 
+	0xD2, 0x04, 0x90, 0x70, 
+	0x13, 0xE4, 0xF0, 0xD2, 
+	0xAF, 0xD0, 0xD0, 0xD0, 
+	0x82, 0xD0, 0x83, 0xD0, 
+	0xF0, 0xD0, 0xE0, 0x32, 
+	0x90, 0x70, 0x2A, 0xE0, 
+	0x30, 0xE1, 0x53, 0xC2, 
+	0xAF, 0x90, 0x70, 0x28, 
+	0xE0, 0x90, 0x10, 0x1C, 
+	0xF0, 0x90, 0x70, 0x29, 
+	0xE0, 0x90, 0x10, 0x1D, 
+	0xF0, 0x90, 0x70, 0x2A, 
+	0xE0, 0x90, 0x10, 0x1E, 
+	0xF0, 0x90, 0x10, 0x1C, 
+	0xE0, 0xF5, 0x30, 0x90, 
+	0x10, 0x1E, 0xE0, 0x20, 
+	0xE1, 0xF3, 0x90, 0x10, 
+	0x1C, 0xE0, 0x90, 0x70, 
+	0x28, 0xF0, 0x90, 0x10, 
+	0x1D, 0xE0, 0x90, 0x70, 
+	0x29, 0xF0, 0x90, 0x10, 
+	0x1E, 0xE0, 0x90, 0x70, 
+	0x2A, 0xF0, 0x30, 0x4A, 
+	0x0D, 0x90, 0x70, 0x24, 
+	0xE0, 0x44, 0x01, 0xF0, 
+	0x90, 0x02, 0x2C, 0x74, 
+	0xFF, 0xF0, 0xC2, 0x05, 
+	0xD2, 0xAF, 0x22, 0xC0, 
+	0xE0, 0xC0, 0xF0, 0xC0, 
+	0x83, 0xC0, 0x82, 0xC0, 
+	0xD0, 0xE8, 0xC0, 0xE0, 
+	0xE9, 0xC0, 0xE0, 0xEA, 
+	0xC0, 0xE0, 0xEB, 0xC0, 
+	0xE0, 0xEC, 0xC0, 0xE0, 
+	0xED, 0xC0, 0xE0, 0xEE, 
+	0xC0, 0xE0, 0xEF, 0xC0, 
+	0xE0, 0xC2, 0xAF, 0x30, 
+	0x45, 0x03, 0x12, 0x10, 
+	0x12, 0xD2, 0xAF, 0xD0, 
+	0xE0, 0xFF, 0xD0, 0xE0, 
+	0xFE, 0xD0, 0xE0, 0xFD, 
+	0xD0, 0xE0, 0xFC, 0xD0, 
+	0xE0, 0xFB, 0xD0, 0xE0, 
+	0xFA, 0xD0, 0xE0, 0xF9, 
+	0xD0, 0xE0, 0xF8, 0xD0, 
+	0xD0, 0xD0, 0x82, 0xD0, 
+	0x83, 0xD0, 0xF0, 0xD0, 
+	0xE0, 0x32, 0xC0, 0xE0, 
+	0xC0, 0xF0, 0xC0, 0x83, 
+	0xC0, 0x82, 0xC0, 0xD0, 
+	0x75, 0xD0, 0x10, 0xC2, 
+	0xAF, 0x30, 0x45, 0x03, 
+	0x12, 0x10, 0x0C, 0x30, 
+	0x58, 0x0A, 0xE5, 0x54, 
+	0x60, 0x04, 0x15, 0x54, 
+	0x80, 0x02, 0xC2, 0x58, 
+	0x30, 0x59, 0x0A, 0xE5, 
+	0x50, 0x60, 0x04, 0x15, 
+	0x50, 0x80, 0x02, 0xC2, 
+	0x59, 0xD5, 0x53, 0x07, 
+	0x30, 0x60, 0x04, 0x15, 
+	0x46, 0xD2, 0x04, 0x30, 
+	0x45, 0x03, 0x12, 0x10, 
+	0x0F, 0xC2, 0x8D, 0xD2, 
+	0xAF, 0xD0, 0xD0, 0xD0, 
+	0x82, 0xD0, 0x83, 0xD0, 
+	0xF0, 0xD0, 0xE0, 0x32, 
+	0x12, 0x02, 0xD3, 0x30, 
+	0x45, 0x03, 0x12, 0x10, 
+	0x03, 0x30, 0x01, 0x06, 
+	0x20, 0x09, 0x03, 0x12, 
+	0x10, 0x1C, 0x30, 0x02, 
+	0x06, 0x20, 0x0A, 0x03, 
+	0x12, 0x10, 0x1F, 0x30, 
+	0x03, 0x06, 0x20, 0x0B, 
+	0x03, 0x12, 0x10, 0x1F, 
+	0x30, 0x04, 0x06, 0x20, 
+	0x0C, 0x03, 0x12, 0x10, 
+	0x22, 0x20, 0x13, 0x09, 
+	0x20, 0x11, 0x06, 0xE5, 
+	0x2B, 0x45, 0x2C, 0x60, 
+	0x03, 0xD3, 0x80, 0x01, 
+	0xC3, 0x92, 0xA9, 0x12, 
+	0x02, 0xEC, 0x80, 0xBF, 
+	0xC2, 0x43, 0xD2, 0x45, 
+	0xE4, 0xF5, 0x20, 0xF5, 
+	0x21, 0xF5, 0x53, 0xF5, 
+	0x46, 0xF5, 0x2B, 0xF5, 
+	0x2C, 0xC2, 0x42, 0xF5, 
+	0x51, 0xF5, 0x52, 0xF5, 
+	0x55, 0x90, 0x04, 0x18, 
+	0x74, 0x80, 0xF0, 0x90, 
+	0x04, 0x1A, 0x74, 0x08, 
+	0xF0, 0xC2, 0x19, 0xC2, 
+	0x18, 0xC2, 0x1A, 0x22, 
+	0xC8, 0xEF, 0xC8, 0xE6, 
+	0xFA, 0x08, 0xE6, 0x4A, 
+	0x60, 0x0C, 0xC8, 0xEF, 
+	0xC8, 0x08, 0xE6, 0x16, 
+	0x18, 0x70, 0x01, 0x16, 
+	0xC3, 0x22, 0xED, 0x24, 
+	0xFF, 0xFD, 0xEC, 0x34, 
+	0xFF, 0xC8, 0xEF, 0xC8, 
+	0xF6, 0x08, 0xC6, 0xED, 
+	0xC6, 0xD3, 0x22, 0xD0, 
+	0x83, 0xD0, 0x82, 0xF8, 
+	0xE4, 0x93, 0x70, 0x12, 
+	0x74, 0x01, 0x93, 0x70, 
+	0x0D, 0xA3, 0xA3, 0x93, 
+	0xF8, 0x74, 0x01, 0x93, 
+	0xF5, 0x82, 0x88, 0x83, 
+	0xE4, 0x73, 0x74, 0x02, 
+	0x93, 0x68, 0x60, 0xEF, 
+	0xA3, 0xA3, 0xA3, 0x80, 
+	0xDF, 0xEF, 0xF4, 0x60, 
+	0x1F, 0xE4, 0xFE, 0x12, 
+	0x03, 0x6A, 0xE0, 0xB4, 
+	0xFF, 0x12, 0x12, 0x03, 
+	0x6A, 0xEF, 0xF0, 0x74, 
+	0x1C, 0x2E, 0xF5, 0x82, 
+	0xE4, 0x34, 0x70, 0xF5, 
+	0x83, 0xED, 0xF0, 0x22, 
+	0x0E, 0xBE, 0x04, 0xE3, 
+	0x22, 0xC0, 0xE0, 0xC0, 
+	0xF0, 0xC0, 0x83, 0xC0, 
+	0x82, 0xC0, 0xD0, 0x75, 
+	0xD0, 0x08, 0xC2, 0xAF, 
+	0x30, 0x45, 0x03, 0x12, 
+	0x10, 0x06, 0xD2, 0xAF, 
+	0xD0, 0xD0, 0xD0, 0x82, 
+	0xD0, 0x83, 0xD0, 0xF0, 
+	0xD0, 0xE0, 0x32, 0xC2, 
+	0xAF, 0x12, 0x00, 0x06, 
+	0x12, 0x02, 0x14, 0x12, 
+	0x03, 0x1C, 0xE4, 0xF5, 
+	0x22, 0xF5, 0x47, 0x90, 
+	0x04, 0x00, 0x74, 0x80, 
+	0xF0, 0xD2, 0xAF, 0x22, 
+	0x30, 0x45, 0x03, 0x12, 
+	0x10, 0x15, 0xE5, 0x20, 
+	0x70, 0x03, 0x20, 0x10, 
+	0x03, 0x30, 0x11, 0x03, 
+	0x43, 0x87, 0x01, 0x22, 
+	0xC0, 0x2A, 0x74, 0x03, 
+	0xC0, 0xE0, 0xC0, 0x82, 
+	0xC0, 0x83, 0x75, 0x2A, 
+	0x0A, 0x22, 0xC0, 0x2A, 
+	0x74, 0x03, 0xC0, 0xE0, 
+	0xC0, 0x82, 0xC0, 0x83, 
+	0x75, 0x2A, 0x18, 0x22, 
+	0x75, 0x89, 0x02, 0xE4, 
+	0xF5, 0x8C, 0xF5, 0x8A, 
+	0xF5, 0x88, 0xF5, 0xB8, 
+	0xF5, 0xE8, 0x75, 0x90, 
+	0x18, 0xD2, 0x8C, 0x75, 
+	0xA8, 0x05, 0x22, 0xCE, 
+	0xEF, 0xCE, 0xEE, 0x60, 
+	0x08, 0x7F, 0xFF, 0x12, 
+	0x03, 0x80, 0x1E, 0x80, 
+	0xF5, 0x22, 0xC8, 0xEF, 
+	0xC8, 0xE6, 0x60, 0x03, 
+	0x16, 0xC3, 0x22, 0xED, 
+	0x14, 0xF6, 0xD3, 0x22, 
+	0xC8, 0xEF, 0xC8, 0xE6, 
+	0x60, 0x06, 0x16, 0xE6, 
+	0x24, 0xFF, 0xB3, 0x22, 
+	0xC3, 0x22, 0x78, 0x7F, 
+	0xE4, 0xF6, 0xD8, 0xFD, 
+	0x75, 0x81, 0x5F, 0x02, 
+	0x01, 0xD0, 0x74, 0x14, 
+	0x2E, 0xF5, 0x82, 0xE4, 
+	0x34, 0x70, 0xF5, 0x83, 
+	0x22, 0xEF, 0x90, 0x03, 
+	0x7E, 0x93, 0x90, 0x03, 
+	0x00, 0x73, 0x0A, 0x18, 
+	0xEF, 0x60, 0x03, 0x1F, 
+	0x80, 0xFA, 0x22, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0x02, 
+	0x10, 0x28, 0x02, 0x10, 
+	0x3B, 0x02, 0x10, 0x3C, 
+	0x02, 0x12, 0xB8, 0x02, 
+	0x12, 0xB9, 0x02, 0x13, 
+	0x3E, 0x02, 0x13, 0x3F, 
+	0xC3, 0x22, 0xFF, 0xFF, 
+	0x02, 0x16, 0x56, 0x02, 
+	0x17, 0x6B, 0x02, 0x14, 
+	0x2A, 0x02, 0x13, 0x40, 
+	0x30, 0x05, 0x06, 0x20, 
+	0x0D, 0x03, 0x12, 0x00, 
+	0xD8, 0x30, 0x06, 0x06, 
+	0x20, 0x0E, 0x03, 0x12, 
+	0x18, 0x5E, 0x22, 0x22, 
+	0x90, 0x04, 0x14, 0xE0, 
+	0x20, 0xE7, 0x03, 0x02, 
+	0x12, 0xB7, 0x90, 0x70, 
+	0x12, 0xE0, 0xF5, 0x56, 
+	0x90, 0x04, 0x04, 0xE0, 
+	0x12, 0x02, 0x67, 0x11, 
+	0x4E, 0x30, 0x11, 0x25, 
+	0x31, 0x10, 0x87, 0x33, 
+	0x10, 0xAA, 0x34, 0x10, 
+	0xC3, 0x35, 0x11, 0x57, 
+	0x50, 0x11, 0x7B, 0x51, 
+	0x11, 0x84, 0x52, 0x11, 
+	0x84, 0x53, 0x11, 0x84, 
+	0x54, 0x11, 0xC5, 0x55, 
+	0x11, 0xDC, 0x70, 0x12, 
+	0x07, 0x71, 0x12, 0x34, 
+	0x72, 0x12, 0x5E, 0x80, 
+	0x12, 0x81, 0x83, 0x00, 
+	0x00, 0x12, 0xB7, 0x75, 
+	0x24, 0x05, 0x75, 0x25, 
+	0xDC, 0x90, 0x70, 0x9F, 
+	0x74, 0x12, 0xF0, 0xD2, 
+	0x18, 0xD2, 0x61, 0x75, 
+	0x35, 0x0D, 0xE4, 0x90, 
+	0x70, 0x13, 0xF0, 0xE5, 
+	0x56, 0xF4, 0x70, 0x03, 
+	0x02, 0x12, 0xB7, 0x02, 
+	0x12, 0xAA, 0xC2, 0x18, 
+	0x90, 0x01, 0x14, 0xE0, 
+	0x54, 0xFD, 0xF0, 0xE4, 
+	0x90, 0x70, 0x13, 0xF0, 
+	0xE5, 0x56, 0xF4, 0x70, 
+	0x03, 0x02, 0x12, 0xB7, 
+	0x02, 0x12, 0xAA, 0xE5, 
+	0x55, 0x64, 0x02, 0x70, 
+	0x37, 0x90, 0x70, 0x10, 
+	0xE0, 0x60, 0x08, 0x90, 
+	0x01, 0x0D, 0x74, 0x09, 
+	0xF0, 0x80, 0x25, 0xE5, 
+	0x34, 0x14, 0x60, 0x0A, 
+	0x14, 0x60, 0x0F, 0x14, 
+	0x60, 0x14, 0x24, 0x03, 
+	0x70, 0x16, 0x90, 0x01, 
+	0x0D, 0x74, 0x08, 0xF0, 
+	0x80, 0x0E, 0x90, 0x01, 
+	0x0D, 0x74, 0x0B, 0xF0, 
+	0x80, 0x06, 0x90, 0x01, 
+	0x0D, 0x74, 0x1B, 0xF0, 
+	0x7D, 0x01, 0x80, 0x02, 
+	0x7D, 0x02, 0xAF, 0x56, 
+	0x12, 0x02, 0x8D, 0x90, 
+	0x70, 0x11, 0xE0, 0x24, 
+	0xFF, 0x92, 0x1B, 0x90, 
+	0x04, 0x14, 0x74, 0x80, 
+	0xF0, 0xE4, 0x90, 0x70, 
+	0x13, 0xF0, 0xE5, 0x56, 
+	0xF4, 0x70, 0x03, 0x02, 
+	0x12, 0xB7, 0x02, 0x12, 
+	0xAA, 0x20, 0x02, 0x03, 
+	0x30, 0x03, 0x1D, 0x7D, 
+	0x02, 0xAF, 0x56, 0x12, 
+	0x02, 0x8D, 0x90, 0x04, 
+	0x14, 0x74, 0x80, 0xF0, 
+	0xE4, 0x90, 0x70, 0x13, 
+	0xF0, 0xE5, 0x56, 0xF4, 
+	0x70, 0x03, 0x02, 0x12, 
+	0xB7, 0x02, 0x12, 0xAA, 
+	0x85, 0x56, 0x41, 0xD2, 
+	0x02, 0x22, 0x90, 0x70, 
+	0x11, 0xE0, 0x24, 0xFF, 
+	0x92, 0x1B, 0x22, 0x90, 
+	0x70, 0x10, 0xE0, 0x54, 
+	0x7F, 0x64, 0x02, 0x60, 
+	0x03, 0x02, 0x12, 0xB7, 
+	0x90, 0x70, 0x11, 0xE0, 
+	0x64, 0x08, 0x60, 0x08, 
+	0xE0, 0x64, 0x20, 0x60, 
+	0x03, 0x02, 0x12, 0xB7, 
+	0x75, 0x4E, 0x03, 0x75, 
+	0x4F, 0x20, 0x22, 0x90, 
+	0x70, 0x11, 0xE0, 0x24, 
+	0xFF, 0x92, 0x47, 0x22, 
+	0x90, 0x04, 0x04, 0xE0, 
+	0x25, 0xE0, 0x24, 0x5D, 
+	0xF5, 0x57, 0x90, 0x70, 
+	0x10, 0xE0, 0xFF, 0x74, 
+	0x47, 0x25, 0x57, 0xF8, 
+	0xC6, 0xEF, 0xC6, 0x90, 
+	0x70, 0x11, 0xE0, 0xFF, 
+	0x74, 0x48, 0x25, 0x57, 
+	0xF8, 0xC6, 0xEF, 0xC6, 
+	0xE4, 0xFD, 0xAF, 0x56, 
+	0x12, 0x02, 0x8D, 0x90, 
+	0x04, 0x14, 0x74, 0x80, 
+	0xF0, 0xE4, 0x90, 0x70, 
+	0x13, 0xF0, 0xE5, 0x56, 
+	0xF4, 0x70, 0x03, 0x02, 
+	0x12, 0xB7, 0x02, 0x12, 
+	0xAA, 0xE5, 0x47, 0xB4, 
+	0x07, 0x08, 0x90, 0x70, 
+	0x11, 0xE0, 0x54, 0x07, 
+	0xF5, 0x26, 0xE4, 0xFD, 
+	0xAF, 0x56, 0x12, 0x02, 
+	0x8D, 0xD2, 0x04, 0x22, 
+	0x90, 0x70, 0x10, 0xE0, 
+	0xFE, 0x90, 0x70, 0x11, 
+	0xE0, 0xFD, 0xED, 0xF8, 
+	0xE6, 0xF5, 0x57, 0xFD, 
+	0xAF, 0x56, 0x12, 0x02, 
+	0x8D, 0x90, 0x04, 0x14, 
+	0x74, 0x80, 0xF0, 0xE4, 
+	0x90, 0x70, 0x13, 0xF0, 
+	0xE5, 0x56, 0xF4, 0x70, 
+	0x03, 0x02, 0x12, 0xB7, 
+	0x02, 0x12, 0xAA, 0x90, 
+	0x70, 0x10, 0xE0, 0xFE, 
+	0x90, 0x70, 0x11, 0xE0, 
+	0xFD, 0xED, 0xF5, 0x82, 
+	0x8E, 0x83, 0xE0, 0xF5, 
+	0x57, 0xFD, 0xAF, 0x56, 
+	0x12, 0x02, 0x8D, 0x90, 
+	0x04, 0x14, 0x74, 0x80, 
+	0xF0, 0xE4, 0x90, 0x70, 
+	0x13, 0xF0, 0xE5, 0x56, 
+	0xF4, 0x70, 0x03, 0x02, 
+	0x12, 0xB7, 0x80, 0x76, 
+	0xE4, 0xF5, 0x4E, 0xF5, 
+	0x4F, 0x75, 0x26, 0xFF, 
+	0xC2, 0x19, 0xC2, 0x18, 
+	0xC2, 0x1A, 0x75, 0x34, 
+	0xFF, 0xAD, 0x57, 0xAF, 
+	0x56, 0x12, 0x02, 0x8D, 
+	0x90, 0x04, 0x14, 0x74, 
+	0x80, 0xF0, 0xE4, 0x90, 
+	0x70, 0x13, 0xF0, 0xE5, 
+	0x56, 0xF4, 0x60, 0x5B, 
+	0x80, 0x4C, 0x90, 0x70, 
+	0x10, 0xE0, 0x24, 0xFF, 
+	0x92, 0x4A, 0xD2, 0x05, 
+	0xAD, 0x57, 0xAF, 0x56, 
+	0x12, 0x02, 0x8D, 0x90, 
+	0x04, 0x14, 0x74, 0x80, 
+	0xF0, 0xE4, 0x90, 0x70, 
+	0x13, 0xF0, 0xE5, 0x56, 
+	0xF4, 0x60, 0x38, 0x80, 
+	0x29, 0x90, 0x70, 0x10, 
+	0xE0, 0xF5, 0x34, 0xD3, 
+	0x94, 0x00, 0x40, 0x07, 
+	0x90, 0x01, 0x0D, 0xE0, 
+	0x54, 0xFB, 0xF0, 0xAD, 
+	0x57, 0xAF, 0x56, 0x12, 
+	0x02, 0x8D, 0x90, 0x04, 
+	0x14, 0x74, 0x80, 0xF0, 
+	0xE4, 0x90, 0x70, 0x13, 
+	0xF0, 0xE5, 0x56, 0xF4, 
+	0x60, 0x0D, 0x90, 0x70, 
+	0x25, 0xE0, 0x44, 0x01, 
+	0xF0, 0x90, 0x02, 0x2C, 
+	0x74, 0xFF, 0xF0, 0x22, 
+	0x22, 0xE5, 0x53, 0x60, 
+	0x03, 0x02, 0x13, 0x3D, 
+	0xE5, 0x4F, 0x45, 0x4E, 
+	0x60, 0x08, 0xE5, 0x4F, 
+	0x15, 0x4F, 0x70, 0x02, 
+	0x15, 0x4E, 0xA2, 0x19, 
+	0xE4, 0x33, 0x90, 0x70, 
+	0x90, 0xF0, 0xA2, 0x18, 
+	0xE4, 0x33, 0xA3, 0xF0, 
+	0x30, 0x19, 0x4D, 0x90, 
+	0x70, 0x98, 0x74, 0x23, 
+	0xF0, 0xA3, 0xE5, 0x25, 
+	0xF0, 0xE5, 0x24, 0xA3, 
+	0xF0, 0x7F, 0x35, 0x7D, 
+	0x32, 0x12, 0x03, 0x42, 
+	0x50, 0x09, 0x90, 0x10, 
+	0x04, 0xE0, 0x54, 0xF7, 
+	0xF0, 0xD2, 0x06, 0xE5, 
+	0x35, 0xD3, 0x94, 0x10, 
+	0x40, 0x1E, 0x30, 0x1A, 
+	0x1B, 0xC2, 0x1A, 0xA2, 
+	0x18, 0x92, 0x19, 0x20, 
+	0x19, 0x12, 0x90, 0x04, 
+	0x09, 0xE0, 0x54, 0xDD, 
+	0xF0, 0x90, 0x10, 0x04, 
+	0xE0, 0x44, 0x08, 0xF0, 
+	0xC2, 0x61, 0xD2, 0x03, 
+	0xE5, 0x35, 0xB4, 0x0B, 
+	0x14, 0xD2, 0x03, 0x22, 
+	0xE4, 0xF5, 0x35, 0xA2, 
+	0x18, 0x92, 0x19, 0x30, 
+	0x19, 0x07, 0x90, 0x04, 
+	0x09, 0xE0, 0x44, 0x22, 
+	0xF0, 0x22, 0x22, 0x22, 
+	0xC2, 0x4B, 0xC2, 0x4C, 
+	0xE5, 0x44, 0x12, 0x02, 
+	0x67, 0x13, 0x62, 0x00, 
+	0x13, 0xF5, 0x04, 0x13, 
+	0xF1, 0x08, 0x13, 0xCC, 
+	0x10, 0x13, 0x76, 0x20, 
+	0x13, 0x96, 0x60, 0x13, 
+	0xA7, 0xA0, 0x00, 0x00, 
+	0x13, 0xF7, 0x85, 0x48, 
+	0x43, 0x85, 0x4A, 0x42, 
+	0x85, 0x4C, 0x5E, 0xE5, 
+	0x47, 0x64, 0x06, 0x60, 
+	0x03, 0x02, 0x13, 0xF7, 
+	0x80, 0x1B, 0xE5, 0x48, 
+	0xC4, 0x54, 0x0F, 0xF5, 
+	0x43, 0xE5, 0x4A, 0xC4, 
+	0x54, 0x0F, 0xF5, 0x42, 
+	0xE5, 0x4C, 0xC4, 0x54, 
+	0x0F, 0xF5, 0x5E, 0xE5, 
+	0x47, 0x64, 0x06, 0x70, 
+	0x66, 0x53, 0x43, 0x0F, 
+	0x80, 0x61, 0x85, 0x49, 
+	0x43, 0x85, 0x4B, 0x42, 
+	0x85, 0x4D, 0x5E, 0xE5, 
+	0x47, 0x64, 0x06, 0x70, 
+	0x52, 0x80, 0x1B, 0xE5, 
+	0x49, 0xC4, 0x54, 0x0F, 
+	0xF5, 0x43, 0xE5, 0x4B, 
+	0xC4, 0x54, 0x0F, 0xF5, 
+	0x42, 0xE5, 0x4D, 0xC4, 
+	0x54, 0x0F, 0xF5, 0x5E, 
+	0xE5, 0x47, 0x64, 0x06, 
+	0x70, 0x35, 0xE5, 0x43, 
+	0x54, 0x0F, 0x44, 0x10, 
+	0xF5, 0x43, 0x80, 0x2B, 
+	0xE5, 0x47, 0xB4, 0x04, 
+	0x06, 0x53, 0x5E, 0xFB, 
+	0x75, 0x42, 0x09, 0xE5, 
+	0x47, 0xB4, 0x05, 0x06, 
+	0x43, 0x5E, 0x04, 0x75, 
+	0x42, 0x09, 0xE5, 0x47, 
+	0xB4, 0x06, 0x10, 0xE5, 
+	0x43, 0x54, 0x0F, 0x44, 
+	0x30, 0xF5, 0x43, 0x80, 
+	0x06, 0xD2, 0x4B, 0x80, 
+	0x02, 0xD2, 0x4C, 0xE4, 
+	0xF5, 0x38, 0xE5, 0x42, 
+	0xC4, 0x54, 0xF0, 0xFF, 
+	0xE5, 0x43, 0x54, 0x0F, 
+	0x4F, 0xF5, 0x5F, 0x90, 
+	0x70, 0x44, 0xF0, 0xA3, 
+	0xE5, 0x5E, 0xF0, 0xA3, 
+	0xE5, 0x4A, 0xF0, 0xA3, 
+	0xE5, 0x48, 0xF0, 0xA3, 
+	0xE5, 0x4C, 0xF0, 0xA3, 
+	0xE5, 0x44, 0xF0, 0xA3, 
+	0xE5, 0x42, 0xF0, 0xA3, 
+	0xE5, 0x43, 0xF0, 0xD2, 
+	0x60, 0x22, 0xE5, 0x47, 
+	0x60, 0x10, 0x24, 0xC0, 
+	0x70, 0x03, 0x12, 0x16, 
+	0x36, 0x12, 0x14, 0x3F, 
+	0xC2, 0xAF, 0xC2, 0x04, 
+	0xD2, 0xAF, 0x22, 0xC2, 
+	0xAF, 0x90, 0x04, 0x14, 
+	0xE0, 0x54, 0x0E, 0x60, 
+	0x04, 0xD2, 0x1C, 0x80, 
+	0x08, 0xE5, 0x4E, 0x45, 
+	0x4F, 0x24, 0xFF, 0x92, 
+	0x1C, 0xD2, 0xAF, 0x90, 
+	0x04, 0x14, 0xE0, 0xA2, 
+	0xE4, 0x92, 0x1D, 0x74, 
+	0x1E, 0xF0, 0xE5, 0x5F, 
+	0x54, 0x0F, 0xF5, 0x2D, 
+	0xE5, 0x38, 0x70, 0x13, 
+	0x30, 0x1C, 0x05, 0xE5, 
+	0x5F, 0x20, 0xE5, 0x0B, 
+	0x30, 0x1D, 0x19, 0xE5, 
+	0x5F, 0x54, 0x30, 0xFF, 
+	0xBF, 0x30, 0x11, 0xE5, 
+	0x38, 0x70, 0x05, 0x75, 
+	0x38, 0x0C, 0x80, 0x02, 
+	0x15, 0x38, 0xD2, 0x6C, 
+	0xD2, 0x6D, 0x80, 0x0F, 
+	0xE5, 0x5F, 0x30, 0xE6, 
+	0x06, 0xC2, 0x6C, 0xD2, 
+	0x6D, 0x80, 0x04, 0xD2, 
+	0x6C, 0xC2, 0x6D, 0xE5, 
+	0x47, 0x64, 0x03, 0x70, 
+	0x21, 0x30, 0x4B, 0x06, 
+	0xC2, 0x6C, 0xD2, 0x6D, 
+	0x80, 0x18, 0xE5, 0x38, 
+	0x70, 0x03, 0x30, 0x4C, 
+	0x11, 0xC2, 0x4C, 0xE5, 
+	0x38, 0x70, 0x05, 0x75, 
+	0x38, 0x07, 0x80, 0x02, 
+	0x15, 0x38, 0xD2, 0x6C, 
+	0xD2, 0x6D, 0x90, 0x70, 
+	0x46, 0xE5, 0x2D, 0xF0, 
+	0x20, 0x69, 0x07, 0xE5, 
+	0x5E, 0x20, 0xE0, 0x02, 
+	0xB2, 0x68, 0x20, 0x6B, 
+	0x07, 0xE5, 0x5E, 0x20, 
+	0xE1, 0x02, 0xB2, 0x6A, 
+	0x20, 0x6D, 0x07, 0xE5, 
+	0x5E, 0x20, 0xE2, 0x02, 
+	0xB2, 0x6C, 0x90, 0x70, 
+	0x47, 0xE5, 0x2D, 0xF0, 
+	0x75, 0x2E, 0x40, 0x20, 
+	0x69, 0x04, 0xA2, 0x68, 
+	0x80, 0x15, 0x30, 0x68, 
+	0x06, 0xE5, 0x46, 0xA2, 
+	0xE3, 0x80, 0x0C, 0xE5, 
+	0x46, 0x54, 0xF0, 0xFF, 
+	0xBF, 0xF0, 0x03, 0xD3, 
+	0x80, 0x01, 0xC3, 0x92, 
+	0x73, 0x92, 0x72, 0x20, 
+	0x6B, 0x04, 0xA2, 0x6A, 
+	0x80, 0x15, 0x30, 0x6A, 
+	0x06, 0xE5, 0x46, 0xA2, 
+	0xE3, 0x80, 0x0C, 0xE5, 
+	0x46, 0x54, 0xF0, 0xFF, 
+	0xBF, 0xF0, 0x03, 0xD3, 
+	0x80, 0x01, 0xC3, 0x92, 
+	0x75, 0x92, 0x74, 0x20, 
+	0x6D, 0x04, 0xA2, 0x6C, 
+	0x80, 0x15, 0x30, 0x6C, 
+	0x06, 0xE5, 0x46, 0xA2, 
+	0xE3, 0x80, 0x0C, 0xE5, 
+	0x46, 0x54, 0xF0, 0xFF, 
+	0xBF, 0xF0, 0x03, 0xD3, 
+	0x80, 0x01, 0xC3, 0x92, 
+	0x71, 0x92, 0x70, 0x90, 
+	0x10, 0x2F, 0xE5, 0x2E, 
+	0xF0, 0xE5, 0x47, 0x64, 
+	0x06, 0x70, 0x46, 0x90, 
+	0x02, 0x29, 0xE0, 0x54, 
+	0xFE, 0xF0, 0xE5, 0x43, 
+	0xC4, 0x54, 0x0F, 0x14, 
+	0x60, 0x14, 0x24, 0xFE, 
+	0x60, 0x1F, 0x24, 0x03, 
+	0x60, 0x03, 0x02, 0x16, 
+	0x35, 0x90, 0x02, 0x28, 
+	0xE0, 0x30, 0x47, 0x0D, 
+	0x80, 0x07, 0x90, 0x02, 
+	0x28, 0xE0, 0x20, 0x47, 
+	0x04, 0x54, 0xFE, 0xF0, 
+	0x22, 0x44, 0x01, 0xF0, 
+	0x22, 0xE5, 0x46, 0x30, 
+	0xE3, 0x04, 0x7F, 0x01, 
+	0x80, 0x02, 0x7F, 0x00, 
+	0x90, 0x02, 0x28, 0xE0, 
+	0x54, 0xFE, 0x4F, 0xF0, 
+	0x22, 0xE5, 0x47, 0x64, 
+	0x07, 0x60, 0x03, 0x02, 
+	0x16, 0x35, 0xF5, 0x27, 
+	0x90, 0x02, 0x29, 0xE0, 
+	0x54, 0xFC, 0xF0, 0xE5, 
+	0x26, 0x14, 0x60, 0x26, 
+	0x14, 0x60, 0x2E, 0x14, 
+	0x60, 0x36, 0x24, 0x03, 
+	0x70, 0x5F, 0xE5, 0x46, 
+	0x13, 0x13, 0x13, 0x54, 
+	0x1F, 0x75, 0xF0, 0x03, 
+	0x84, 0xAF, 0xF0, 0x20, 
+	0x47, 0x04, 0x7E, 0x01, 
+	0x80, 0x02, 0x7E, 0x00, 
+	0xEF, 0x6E, 0x24, 0xFF, 
+	0x80, 0x02, 0xA2, 0x47, 
+	0x92, 0x39, 0xA2, 0x47, 
+	0xB3, 0x92, 0x38, 0x80, 
+	0x3F, 0xE5, 0x46, 0x30, 
+	0xE3, 0x03, 0xD3, 0x80, 
+	0x27, 0xC3, 0x80, 0x24, 
+	0xE5, 0x46, 0x30, 0xE3, 
+	0x0D, 0x54, 0x70, 0xC3, 
+	0x94, 0x60, 0x50, 0x06, 
+	0x7E, 0x00, 0x7F, 0x01, 
+	0x80, 0x04, 0x7E, 0x00, 
+	0x7F, 0x00, 0x20, 0x47, 
+	0x04, 0x7D, 0x01, 0x80, 
+	0x02, 0x7D, 0x00, 0xEF, 
+	0x6D, 0x4E, 0x24, 0xFF, 
+	0x92, 0x38, 0xA2, 0x47, 
+	0xB3, 0x92, 0x39, 0x80, 
+	0x07, 0xA2, 0x47, 0xB3, 
+	0x92, 0x38, 0x92, 0x39, 
+	0x90, 0x02, 0x28, 0xE0, 
+	0x54, 0xFC, 0x45, 0x27, 
+	0xF0, 0x22, 0xE4, 0x90, 
+	0x02, 0x29, 0xF0, 0x30, 
+	0x47, 0x04, 0xAF, 0x45, 
+	0x80, 0x04, 0xE5, 0x45, 
+	0xF4, 0xFF, 0x90, 0x02, 
+	0x28, 0xEF, 0xF0, 0x22, 
+	0x8F, 0x50, 0xD2, 0x59, 
+	0x22, 0x8F, 0x54, 0xD2, 
+	0x58, 0x22, 0xE4, 0xF5, 
+	0x30, 0xC2, 0xAF, 0xE5, 
+	0x51, 0x14, 0x60, 0x4A, 
+	0x14, 0x60, 0x6A, 0x24, 
+	0x02, 0x60, 0x03, 0x02, 
+	0x17, 0x4C, 0xD2, 0x59, 
+	0x75, 0x55, 0x01, 0x20, 
+	0x19, 0x1C, 0x90, 0x02, 
+	0x08, 0xE0, 0x54, 0xFE, 
+	0xF0, 0xE0, 0x20, 0xE1, 
+	0x23, 0x90, 0x04, 0x34, 
+	0xE0, 0xB4, 0x02, 0x1C, 
+	0xA3, 0xE0, 0xB4, 0x02, 
+	0x17, 0xA3, 0xE0, 0xB4, 
+	0x02, 0x12, 0x7F, 0x20, 
+	0x12, 0x16, 0x4C, 0x90, 
+	0x10, 0x04, 0xE0, 0x54, 
+	0xF3, 0xF0, 0x75, 0x51, 
+	0x01, 0x02, 0x17, 0x4C, 
+	0xE5, 0x50, 0x70, 0x06, 
+	0x75, 0x30, 0x03, 0x02, 
+	0x17, 0x4C, 0x90, 0x12, 
+	0x00, 0xE0, 0x54, 0x03, 
+	0x70, 0x15, 0x7F, 0x20, 
+	0x12, 0x16, 0x4C, 0x20, 
+	0x19, 0x07, 0x90, 0x02, 
+	0x08, 0xE0, 0x54, 0xFB, 
+	0xF0, 0x75, 0x51, 0x02, 
+	0x02, 0x17, 0x4C, 0xE5, 
+	0x50, 0x70, 0x02, 0x80, 
+	0x7A, 0x20, 0x19, 0x0F, 
+	0x90, 0x02, 0x08, 0xE0, 
+	0x20, 0xE3, 0x6C, 0x90, 
+	0x04, 0x37, 0xE0, 0x64, 
+	0x22, 0x70, 0x64, 0x90, 
+	0x12, 0x04, 0x74, 0x0A, 
+	0xF0, 0x30, 0x1B, 0x11, 
+	0x90, 0x13, 0x28, 0xE0, 
+	0x54, 0xF0, 0xF0, 0xA3, 
+	0xE0, 0x54, 0xF0, 0xF0, 
+	0xA3, 0xE0, 0x54, 0xFA, 
+	0xF0, 0x20, 0x19, 0x07, 
+	0x90, 0x04, 0x01, 0xE0, 
+	0x44, 0x10, 0xF0, 0xE5, 
+	0x34, 0xF4, 0x90, 0x04, 
+	0x01, 0x60, 0x06, 0xE0, 
+	0x54, 0xFB, 0xF0, 0x80, 
+	0x04, 0xE0, 0x54, 0xF9, 
+	0xF0, 0x20, 0x19, 0x07, 
+	0x90, 0x12, 0x04, 0xE0, 
+	0x44, 0x04, 0xF0, 0xE5, 
+	0x34, 0xF4, 0x60, 0x14, 
+	0x90, 0x01, 0x0D, 0xE0, 
+	0xF5, 0x33, 0xE5, 0x34, 
+	0xD3, 0x94, 0x02, 0x40, 
+	0x07, 0x90, 0x12, 0x04, 
+	0xE0, 0x54, 0xFD, 0xF0, 
+	0x75, 0x30, 0x01, 0x75, 
+	0x55, 0x02, 0xE4, 0xF5, 
+	0x51, 0x80, 0x09, 0xE5, 
+	0x50, 0x70, 0x05, 0x75, 
+	0x30, 0x03, 0xF5, 0x51, 
+	0xE5, 0x30, 0x60, 0x18, 
+	0xC2, 0x01, 0xE4, 0xF5, 
+	0x51, 0xC2, 0x59, 0x20, 
+	0x19, 0x0E, 0xAD, 0x30, 
+	0xAF, 0x40, 0x12, 0x18, 
+	0x2A, 0xE5, 0x30, 0xB4, 
+	0x03, 0x02, 0xD2, 0x03, 
+	0xD2, 0xAF, 0x22, 0xC2, 
+	0xAF, 0x30, 0x01, 0x0E, 
+	0xE4, 0xF5, 0x51, 0xC2, 
+	0x59, 0xC2, 0x01, 0x7D, 
+	0x02, 0xAF, 0x40, 0x12, 
+	0x18, 0x2A, 0xE5, 0x52, 
+	0x14, 0x60, 0x55, 0x14, 
+	0x60, 0x2F, 0x24, 0x02, 
+	0x60, 0x03, 0x02, 0x18, 
+	0x27, 0xE5, 0x34, 0xF4, 
+	0x60, 0x23, 0xE5, 0x34, 
+	0xD3, 0x94, 0x02, 0x40, 
+	0x16, 0x90, 0x12, 0x04, 
+	0xE0, 0x44, 0x02, 0xF0, 
+	0x90, 0x01, 0x0D, 0xE0, 
+	0x20, 0xE3, 0x03, 0x02, 
+	0x18, 0x27, 0x7F, 0x50, 
+	0x12, 0x16, 0x51, 0x75, 
+	0x52, 0x02, 0x75, 0x55, 
+	0x03, 0xE5, 0x34, 0xF4, 
+	0x60, 0x0A, 0xE5, 0x54, 
+	0x70, 0x69, 0x90, 0x01, 
+	0x0D, 0xE5, 0x33, 0xF0, 
+	0x90, 0x12, 0x04, 0xE0, 
+	0x54, 0xFB, 0xF0, 0x7F, 
+	0x20, 0x12, 0x16, 0x51, 
+	0x75, 0x52, 0x01, 0x75, 
+	0x55, 0x03, 0x80, 0x4F, 
+	0xE5, 0x54, 0x70, 0x4B, 
+	0x90, 0x04, 0x01, 0xE0, 
+	0x44, 0x0E, 0xF0, 0x20, 
+	0x19, 0x04, 0xE0, 0x54, 
+	0xEF, 0xF0, 0x90, 0x13, 
+	0x28, 0xE0, 0x44, 0x0F, 
+	0xF0, 0xA3, 0xE0, 0x44, 
+	0x0F, 0xF0, 0xA3, 0xE0, 
+	0x44, 0x05, 0xF0, 0x90, 
+	0x12, 0x04, 0x74, 0x03, 
+	0xF0, 0x20, 0x19, 0x07, 
+	0x90, 0x02, 0x08, 0xE0, 
+	0x44, 0x05, 0xF0, 0x90, 
+	0x10, 0x04, 0xE0, 0x44, 
+	0x0C, 0xF0, 0xE4, 0xF5, 
+	0x52, 0xF5, 0x55, 0x30, 
+	0x02, 0x0B, 0xC2, 0x02, 
+	0x7D, 0x01, 0xAF, 0x41, 
+	0x12, 0x18, 0x2A, 0x80, 
+	0x02, 0xC2, 0x03, 0xD2, 
+	0xAF, 0x22, 0xEF, 0xF4, 
+	0x60, 0x2D, 0xE4, 0xFE, 
+	0x74, 0x14, 0x2E, 0xF5, 
+	0x82, 0xE4, 0x34, 0x70, 
+	0xF5, 0x83, 0xE0, 0xB4, 
+	0xFF, 0x19, 0x74, 0x14, 
+	0x2E, 0xF5, 0x82, 0xE4, 
+	0x34, 0x70, 0xF5, 0x83, 
+	0xEF, 0xF0, 0x74, 0x1C, 
+	0x2E, 0xF5, 0x82, 0xE4, 
+	0x34, 0x70, 0xF5, 0x83, 
+	0xED, 0xF0, 0x22, 0x0E, 
+	0xBE, 0x04, 0xD5, 0x22, 
+	0x22, 0x22, 0x20, 0x19, 
+	0x03, 0x02, 0x19, 0x0F, 
+	0x90, 0x70, 0x80, 0xE0, 
+	0x04, 0xF0, 0x90, 0x04, 
+	0x37, 0xE0, 0x30, 0xE5, 
+	0x03, 0x02, 0x19, 0x0B, 
+	0x90, 0x04, 0x28, 0xE0, 
+	0xF5, 0x31, 0xA3, 0xE0, 
+	0xF5, 0x30, 0xF5, 0x32, 
+	0xE4, 0xF5, 0x37, 0x90, 
+	0x70, 0x81, 0xE0, 0x04, 
+	0xF0, 0x90, 0x70, 0x82, 
+	0xE0, 0x04, 0xF0, 0xE5, 
+	0x32, 0x75, 0xF0, 0x80, 
+	0xA4, 0x24, 0x00, 0xFF, 
+	0xE5, 0xF0, 0x34, 0x80, 
+	0xFE, 0xE5, 0x30, 0x65, 
+	0x32, 0x70, 0x05, 0xFC, 
+	0x7D, 0x18, 0x80, 0x04, 
+	0x7C, 0x00, 0x7D, 0x00, 
+	0xEF, 0x2D, 0xFF, 0xEE, 
+	0x3C, 0xFE, 0x12, 0x19, 
+	0x10, 0x50, 0x25, 0x90, 
+	0x70, 0x83, 0xE0, 0x04, 
+	0xF0, 0x90, 0x01, 0x14, 
+	0xE0, 0x44, 0x02, 0xF0, 
+	0xE0, 0x30, 0xE1, 0x06, 
+	0x90, 0x70, 0x92, 0x74, 
+	0x45, 0xF0, 0x90, 0x70, 
+	0x93, 0xE0, 0x04, 0xF0, 
+	0x90, 0x04, 0x01, 0xE0, 
+	0x90, 0x70, 0x94, 0xF0, 
+	0xE5, 0x32, 0x65, 0x31, 
+	0x60, 0x10, 0xE4, 0x25, 
+	0x32, 0xFF, 0xE4, 0x34, 
+	0x80, 0x8F, 0x82, 0xF5, 
+	0x83, 0xE0, 0xF5, 0x32, 
+	0x80, 0x97, 0x90, 0x04, 
+	0x10, 0x74, 0x01, 0xF0, 
+	0x90, 0x04, 0x28, 0xE5, 
+	0x31, 0xF0, 0xA3, 0xE5, 
+	0x30, 0xF0, 0x90, 0x04, 
+	0x11, 0x74, 0x01, 0xF0, 
+	0x02, 0x18, 0x6A, 0xC2, 
+	0x06, 0xD2, 0x1A, 0x22, 
+	0x90, 0x70, 0x84, 0xE5, 
+	0x37, 0xF0, 0xC3, 0x94, 
+	0x06, 0x50, 0x19, 0x8F, 
+	0x82, 0x8E, 0x83, 0xE0, 
+	0xB4, 0xFF, 0x07, 0x05, 
+	0x37, 0xE4, 0xF5, 0x36, 
+	0x80, 0x59, 0xE4, 0xF5, 
+	0x37, 0x8F, 0x82, 0x8E, 
+	0x83, 0xF0, 0x80, 0x4F, 
+	0xE5, 0x36, 0x75, 0xF0, 
+	0x06, 0x84, 0x74, 0x08, 
+	0x25, 0xF0, 0xF5, 0x82, 
+	0xE4, 0x34, 0x10, 0xF5, 
+	0x83, 0xE0, 0xFD, 0x8F, 
+	0x82, 0x8E, 0x83, 0xE0, 
+	0xFC, 0x6D, 0x70, 0x30, 
+	0x90, 0x70, 0x88, 0xE0, 
+	0x04, 0xF0, 0xA3, 0xE0, 
+	0xFD, 0xD3, 0x95, 0x37, 
+	0x40, 0x02, 0x80, 0x02, 
+	0xAD, 0x37, 0x90, 0x70, 
+	0x89, 0xED, 0xF0, 0x05, 
+	0x37, 0x05, 0x36, 0xE5, 
+	0x36, 0x75, 0xF0, 0x06, 
+	0x84, 0x74, 0x8A, 0x25, 
+	0xF0, 0xF5, 0x82, 0xE4, 
+	0x34, 0x70, 0xF5, 0x83, 
+	0xEC, 0xF0, 0x80, 0x03, 
+	0xE4, 0xF5, 0x37, 0x0F, 
+	0xBF, 0x00, 0x01, 0x0E, 
+	0xEF, 0x54, 0x7F, 0x60, 
+	0x0A, 0xE5, 0x37, 0xC3, 
+	0x94, 0x4E, 0x50, 0x03, 
+	0x02, 0x19, 0x10, 0xE5, 
+	0x37, 0xB4, 0x4E, 0x03, 
+	0xD3, 0x80, 0x01, 0xC3, 
+	0x22, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x0B, 0x94, 0xEB, 
+};
+
+#endif /* _RT2860_UCODE_H_ */
+
+
diff -r 5624b06c8184 -r ac5b1ebb1990 head/sys/dev/ral/rt2860var.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ral/rt2860var.h	Tue Mar 13 01:18:04 2012 +0200
@@ -0,0 +1,762 @@
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar at gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini at free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _RT2860VAR_H_
+#define _RT2860VAR_H_
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/taskqueue.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_input.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
+
+#ifdef RT2860_DEBUG
+
+enum
+{
+	RT2860_DEBUG_EEPROM =	0x00000001,
+	RT2860_DEBUG_RX =	0x00000002,
+	RT2860_DEBUG_TX =	0x00000004,
+	RT2860_DEBUG_INTR =	0x00000008,
+	RT2860_DEBUG_STATE =	0x00000010,
+	RT2860_DEBUG_CHAN =	0x00000020,
+	RT2860_DEBUG_NODE =	0x00000040,
+	RT2860_DEBUG_KEY =	0x00000080,
+	RT2860_DEBUG_PROT =	0x00000100,
+	RT2860_DEBUG_WME =	0x00000200,
+	RT2860_DEBUG_BEACON =	0x00000400,
+	RT2860_DEBUG_BA =	0x00000800,
+	RT2860_DEBUG_STATS =	0x00001000,
+	RT2860_DEBUG_RATE =	0x00002000,
+	RT2860_DEBUG_PERIODIC =	0x00004000,
+	RT2860_DEBUG_WATCHDOG =	0x00008000,
+	RT2860_DEBUG_RX_CRYPT = 0x00010000,
+	RT2860_DEBUG_TX_CRYPT = 0x00020000,
+	RT2860_DEBUG_ANY = 0xffffffff
+};
+
+#define RT2860_DPRINTF(sc, m, fmt, ...)		\
+    do { if ((sc)->debug & (m)) printf(fmt, __VA_ARGS__); } while (0)
+
+#else
+
+#define RT2860_DPRINTF(sc, m, fmt, ...)
+
+#endif /* #ifdef RT2860_DEBUG */
+
+#define RT2860_RXDESC_SDL0_DDONE			(1 << 15)
+
+#define RT2860_RXDESC_FLAGS_LAST_AMSDU			(1 << 19)
+#define RT2860_RXDESC_FLAGS_CIPHER_ALG			(1 << 18)
+#define RT2860_RXDESC_FLAGS_PLCP_RSSIL			(1 << 17)
+#define RT2860_RXDESC_FLAGS_DECRYPTED			(1 << 16)
+#define RT2860_RXDESC_FLAGS_AMPDU			(1 << 15)
+#define RT2860_RXDESC_FLAGS_L2PAD			(1 << 14)
+#define RT2860_RXDESC_FLAGS_RSSI			(1 << 13)
+#define RT2860_RXDESC_FLAGS_HTC				(1 << 12)
+#define RT2860_RXDESC_FLAGS_AMSDU			(1 << 11)
+#define RT2860_RXDESC_FLAGS_CRC_ERR			(1 << 8)
+#define RT2860_RXDESC_FLAGS_MYBSS			(1 << 7)
+#define RT2860_RXDESC_FLAGS_BCAST			(1 << 6)
+#define RT2860_RXDESC_FLAGS_MCAST			(1 << 5)
+#define RT2860_RXDESC_FLAGS_U2M				(1 << 4)
+#define RT2860_RXDESC_FLAGS_FRAG			(1 << 3)
+#define RT2860_RXDESC_FLAGS_NULL_DATA			(1 << 2)
+#define RT2860_RXDESC_FLAGS_DATA			(1 << 1)
+#define RT2860_RXDESC_FLAGS_BA				(1 << 0)
+
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_SHIFT		9
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_MASK		0x3
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_NONE		0
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_ICV		1
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_MIC		2
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_INVALID_KEY	3
+
+#define RT2860_RXDESC_FLAGS_PLCP_SIGNAL_SHIFT		20
+#define RT2860_RXDESC_FLAGS_PLCP_SIGNAL_MASK		0xfff
+
+struct rt2860_rxdesc
+{
+	uint32_t sdp0;
+	uint16_t sdl1;
+	uint16_t sdl0;
+	uint32_t sdp1;
+	uint32_t flags;
+} __packed;
+
+#define RT2860_TXDESC_SDL1_BURST						(1 << 15)
+#define RT2860_TXDESC_SDL1_LASTSEG						(1 << 14)
+
+#define RT2860_TXDESC_SDL0_DDONE						(1 << 15)
+#define RT2860_TXDESC_SDL0_LASTSEG						(1 << 14)
+
+#define RT2860_TXDESC_FLAGS_SHIFT						0
+#define RT2860_TXDESC_FLAGS_MASK						0xf9
+#define RT2860_TXDESC_FLAGS_WI_VALID					(1 << 0)
+
+#define RT2860_TXDESC_QSEL_SHIFT						1
+#define RT2860_TXDESC_QSEL_MASK							0x3
+#define RT2860_TXDESC_QSEL_MGMT							0
+#define RT2860_TXDESC_QSEL_HCCA							1
+#define RT2860_TXDESC_QSEL_EDCA							2
+
+struct rt2860_txdesc
+{
+	uint32_t sdp0;
+	uint16_t sdl1;
+	uint16_t sdl0;
+	uint32_t sdp1;
+	uint8_t	reserved[3];
+	uint8_t qsel_flags;
+} __packed;
+
+#define RT2860_TXWI_FLAGS_SHIFT					0
+#define RT2860_TXWI_FLAGS_MASK					0x1f
+#define RT2860_TXWI_FLAGS_AMPDU					(1 << 4)
+#define RT2860_TXWI_FLAGS_TS					(1 << 3)
+#define RT2860_TXWI_FLAGS_CFACK					(1 << 2)
+#define RT2860_TXWI_FLAGS_MIMOPS				(1 << 1)
+#define RT2860_TXWI_FLAGS_FRAG					(1 << 0)
+
+#define RT2860_TXWI_MPDU_DENSITY_SHIFT			5
+#define RT2860_TXWI_MPDU_DENSITY_MASK			0x7
+
+#define RT2860_TXWI_TXOP_SHIFT					0
+#define RT2860_TXWI_TXOP_MASK					0x3
+#define RT2860_TXWI_TXOP_HT						0
+#define RT2860_TXWI_TXOP_PIFS					1
+#define RT2860_TXWI_TXOP_SIFS					2
+#define RT2860_TXWI_TXOP_BACKOFF				3
+
+#define RT2860_TXWI_MCS_SHIFT					0
+#define RT2860_TXWI_MCS_MASK					0x7f
+#define RT2860_TXWI_MCS_SHOTPRE					(1 << 3)
+
+#define RT2860_TXWI_BW_SHIFT					7
+#define RT2860_TXWI_BW_MASK						0x1
+#define RT2860_TXWI_BW_20						0
+#define RT2860_TXWI_BW_40						1
+
+#define RT2860_TXWI_SHORTGI_SHIFT				0
+#define RT2860_TXWI_SHORTGI_MASK				0x1
+
+#define RT2860_TXWI_STBC_SHIFT					1
+#define RT2860_TXWI_STBC_MASK					0x3
+
+#define RT2860_TXWI_IFS_SHIFT					3
+#define RT2860_TXWI_IFS_MASK					0x1
+
+#define RT2860_TXWI_PHYMODE_SHIFT				6
+#define RT2860_TXWI_PHYMODE_MASK				0x3
+#define RT2860_TXWI_PHYMODE_CCK					0
+#define RT2860_TXWI_PHYMODE_OFDM				1
+#define RT2860_TXWI_PHYMODE_HT_MIXED			2
+#define RT2860_TXWI_PHYMODE_HT_GF				3
+
+#define RT2860_TXWI_XFLAGS_SHIFT				0
+#define RT2860_TXWI_XFLAGS_MASK					0x3
+#define RT2860_TXWI_XFLAGS_NSEQ					(1 << 1)
+#define RT2860_TXWI_XFLAGS_ACK					(1 << 0)
+
+#define RT2860_TXWI_BAWIN_SIZE_SHIFT			2
+#define RT2860_TXWI_BAWIN_SIZE_MASK				0x3f
+
+#define RT2860_TXWI_MPDU_LEN_SHIFT				0
+#define RT2860_TXWI_MPDU_LEN_MASK				0xfff
+
+#define RT2860_TXWI_PID_SHIFT					12
+#define RT2860_TXWI_PID_MASK					0xf
+
+struct rt2860_txwi
+{
+	uint8_t mpdu_density_flags;
+	uint8_t txop;
+	uint8_t bw_mcs;
+	uint8_t phymode_ifs_stbc_shortgi;
+	uint8_t bawin_size_xflags;
+	uint8_t wcid;
+	uint16_t pid_mpdu_len;
+	uint32_t iv;
+	uint32_t eiv;
+} __packed;
+
+#define RT2860_RXWI_KEYIDX_SHIFT			0
+#define RT2860_RXWI_KEYIDX_MASK				0x3
+
+#define RT2860_RXWI_BSSIDX_SHIFT			2
+#define RT2860_RXWI_BSSIDX_MASK				0x7
+
+#define RT2860_RXWI_UDF_SHIFT				5
+#define RT2860_RXWI_UDF_MASK				0x7
+
+#define RT2860_RXWI_SIZE_SHIFT				0
+#define RT2860_RXWI_SIZE_MASK				0xfff
+
+#define RT2860_RXWI_TID_SHIFT				12
+#define RT2860_RXWI_TID_MASK				0xf
+
+#define RT2860_RXWI_FRAG_SHIFT				0
+#define RT2860_RXWI_FRAG_MASK				0xf
+
+#define RT2860_RXWI_SEQ_SHIFT				4
+#define RT2860_RXWI_SEQ_MASK				0xfff
+
+#define RT2860_RXWI_MCS_SHIFT				0
+#define RT2860_RXWI_MCS_MASK				0x7f
+#define RT2860_RXWI_MCS_SHOTPRE				(1 << 3)
+
+#define RT2860_RXWI_BW_SHIFT				7
+#define RT2860_RXWI_BW_MASK					0x1
+#define RT2860_RXWI_BW_20					0
+#define RT2860_RXWI_BW_40					1
+
+#define RT2860_RXWI_SHORTGI_SHIFT			0
+#define RT2860_RXWI_SHORTGI_MASK			0x1
+
+#define RT2860_RXWI_STBC_SHIFT				1
+#define RT2860_RXWI_STBC_MASK				0x3
+
+#define RT2860_RXWI_PHYMODE_SHIFT			6
+#define RT2860_RXWI_PHYMODE_MASK			0x3
+#define RT2860_RXWI_PHYMODE_CCK				0
+#define RT2860_RXWI_PHYMODE_OFDM			1
+#define RT2860_RXWI_PHYMODE_HT_MIXED		2
+#define RT2860_RXWI_PHYMODE_HT_GF			3
+
+struct rt2860_rxwi
+{
+	uint8_t wcid;
+	uint8_t udf_bssidx_keyidx;
+	uint16_t tid_size;
+	uint16_t seq_frag;
+	uint8_t bw_mcs;
+	uint8_t phymode_stbc_shortgi;
+	uint8_t rssi[3];
+	uint8_t reserved1;
+	uint8_t snr[2];
+	uint16_t reserved2;
+} __packed;
+
+#define RT2860_AMRR_MIN_SUCCESS_THRESHOLD	 				1
+#define RT2860_AMRR_MAX_SUCCESS_THRESHOLD					15
+
+struct rt2860_amrr
+{
+	int ntxpath;
+
+	unsigned int min_success_threshold;
+	unsigned int max_success_threshold;
+
+	int	interval;
+};
+
+struct rt2860_amrr_node
+{
+	struct rt2860_amrr *amrr;
+
+	int	rate_index;
+
+	int	ticks;
+
+	unsigned int txcnt;
+	unsigned int success;
+	unsigned int success_threshold;
+	unsigned int recovery;
+	unsigned int retrycnt;
+};
+
+#define RT2860_SOFTC_LOCK(sc)				mtx_lock(&(sc)->sc_mtx)
+#define RT2860_SOFTC_UNLOCK(sc)				\
+		mtx_unlock(&(sc)->sc_mtx)
+#define	RT2860_SOFTC_ASSERT_LOCKED(sc)			\
+		mtx_assert(&(sc)->sc_mtx, MA_OWNED)
+
+#define RT2860_SOFTC_TX_RING_LOCK(ring)			mtx_lock(&(ring)->lock)
+#define RT2860_SOFTC_TX_RING_UNLOCK(ring)		\
+		mtx_unlock(&(ring)->lock)
+#define	RT2860_SOFTC_TX_RING_ASSERT_LOCKED(ring)	\
+		mtx_assert(&(ring)->lock, MA_OWNED)
+
+#define RT2860_SOFTC_FLAGS_UCODE_LOADED			(1 << 0)
+#define RT2860_SOFTC_LED_OFF_COUNT			3
+#define RT2860_SOFTC_RSSI_OFF_COUNT			3
+#define RT2860_SOFTC_LNA_GAIN_COUNT			4
+#define RT2860_SOFTC_TXPOW_COUNT			50
+#define RT2860_SOFTC_TXPOW_RATE_COUNT			5
+#define RT2860_SOFTC_TSSI_COUNT				9
+#define RT2860_SOFTC_BBP_EEPROM_COUNT			8
+#define RT2860_SOFTC_RSSI_COUNT				3
+#define RT2860_SOFTC_STAID_COUNT			64
+#define RT2860_SOFTC_TX_RING_COUNT			6
+#define RT2860_SOFTC_RX_RING_DATA_COUNT			128
+#define RT2860_SOFTC_MAX_SCATTER			10
+#define RT2860_SOFTC_TX_RING_DATA_COUNT			256
+#define RT2860_SOFTC_TX_RING_DESC_COUNT					\
+	(RT2860_SOFTC_TX_RING_DATA_COUNT * RT2860_SOFTC_MAX_SCATTER)
+
+#define RT2860_SOFTC_RX_RADIOTAP_PRESENT				\
+	((1 << IEEE80211_RADIOTAP_FLAGS) |				\
+	 (1 << IEEE80211_RADIOTAP_RATE) |				\
+	 (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |			\
+	 (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |			\
+	 (1 << IEEE80211_RADIOTAP_ANTENNA) |				\
+	 (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |			\
+	 (1 << IEEE80211_RADIOTAP_XCHANNEL))
+
+#define RT2860_SOFTC_TX_RADIOTAP_PRESENT				\
+	((1 << IEEE80211_RADIOTAP_FLAGS) |				\
+	 (1 << IEEE80211_RADIOTAP_RATE) |				\
+	 (1 << IEEE80211_RADIOTAP_XCHANNEL))
+
+struct rt2860_softc_rx_data
+{
+	bus_dmamap_t dma_map;
+	struct mbuf *m;
+};
+
+struct rt2860_softc_rx_ring
+{
+	bus_dma_tag_t desc_dma_tag;
+	bus_dmamap_t desc_dma_map;
+	bus_addr_t desc_phys_addr;
+	struct rt2860_rxdesc *desc;
+	bus_dma_tag_t data_dma_tag;
+	bus_dmamap_t spare_dma_map;
+	struct rt2860_softc_rx_data data[RT2860_SOFTC_RX_RING_DATA_COUNT];
+	int cur;
+};
+
+struct rt2860_softc_tx_data
+{
+	bus_dmamap_t dma_map;
+	struct ieee80211_node *ni;
+	struct mbuf *m;
+};
+
+struct rt2860_softc_tx_ring
+{
+	struct mtx lock;
+	bus_dma_tag_t desc_dma_tag;
+	bus_dmamap_t desc_dma_map;
+	bus_addr_t desc_phys_addr;
+	struct rt2860_txdesc *desc;
+	int desc_queued;
+	int desc_cur;
+	int desc_next;
+	bus_dma_tag_t seg0_dma_tag;
+	bus_dmamap_t seg0_dma_map;
+	bus_addr_t seg0_phys_addr;
+	uint8_t *seg0;
+	bus_dma_tag_t data_dma_tag;
+	struct rt2860_softc_tx_data data[RT2860_SOFTC_TX_RING_DATA_COUNT];
+	int data_queued;
+	int data_cur;
+	int data_next;
+	int qid;
+};
+
+struct rt2860_softc_node
+{
+	struct ieee80211_node ni;
+
+	uint8_t staid;
+
+	uint8_t last_rssi[RT2860_SOFTC_RSSI_COUNT];
+	int8_t last_rssi_dbm[RT2860_SOFTC_RSSI_COUNT];
+};
+
+struct rt2860_softc_vap
+{
+	struct ieee80211vap	vap;
+
+	struct ieee80211_beacon_offsets beacon_offsets;
+	struct mbuf *beacon_mbuf;
+	struct rt2860_txwi beacon_txwi;
+
+	struct rt2860_amrr amrr;
+
+	int	(*newstate)(struct ieee80211vap *vap,
+		enum ieee80211_state nstate, int arg);
+};
+
+struct rt2860_softc_rx_radiotap_header
+{
+	struct ieee80211_radiotap_header ihdr;
+	uint8_t	flags;
+	uint8_t	rate;
+	int8_t dbm_antsignal;
+	int8_t dbm_antnoise;
+	uint8_t	antenna;
+	uint8_t	antsignal;
+	uint8_t pad[2];
+	uint32_t chan_flags;
+	uint16_t chan_freq;
+	uint8_t chan_ieee;
+	int8_t chan_maxpow;
+} __packed;
+
+struct rt2860_softc_tx_radiotap_header
+{
+	struct ieee80211_radiotap_header ihdr;
+	uint8_t flags;
+	uint8_t	rate;
+	uint8_t pad[2];
+	uint32_t chan_flags;
+	uint16_t chan_freq;
+	uint8_t chan_ieee;
+	int8_t chan_maxpow;
+} __packed;
+
+struct rt2860_softc
+{
+	struct ifnet			*sc_ifp;
+	device_t			sc_dev;
+	bus_space_tag_t			sc_st;
+	bus_space_handle_t		sc_sh;
+
+	struct mtx			sc_mtx;
+
+	struct callout			watchdog_ch;
+
+	int				sc_tx_timer;
+	int                             sc_invalid;
+	int				sc_debug;
+/*
+ * The same in both up to here
+ * ------------------------------------------------
+ */
+	int			id;
+	uint32_t 		flags;
+	int			mem_rid; /* XXX: bus glue handle res */
+	struct resource		*mem;
+
+	int			irq_rid;
+	struct resource 	*irq;
+	void 			*irqh;
+
+	int			if_flags;
+
+	int			nvaps;
+	int			napvaps;
+	int nadhocvaps;
+	int nstavaps;
+	int nwdsvaps;
+
+	void (*node_cleanup)(struct ieee80211_node *ni);
+
+	int (*recv_action)(struct ieee80211_node *ni,
+		const struct ieee80211_frame *wh,
+		const uint8_t *frm, const uint8_t *efrm);
+
+	int (*send_action)(struct ieee80211_node *ni,
+		int cat, int act, void *sa);
+
+	int (*addba_response)(struct ieee80211_node *ni,
+		struct ieee80211_tx_ampdu *tap,
+		int status, int baparamset, int batimeout);
+
+	void (*addba_stop)(struct ieee80211_node *ni,
+		struct ieee80211_tx_ampdu *tap);
+
+	int (*ampdu_rx_start)(struct ieee80211_node *ni,
+		struct ieee80211_rx_ampdu *rap,
+		int baparamset, int batimeout, int baseqctl);
+
+	void (*ampdu_rx_stop)(struct ieee80211_node *ni,
+		struct ieee80211_rx_ampdu *rap);
+
+	struct rt2860_amrr_node amrr_node[RT2860_SOFTC_STAID_COUNT];
+
+	uint32_t mac_rev;
+	uint8_t eeprom_addr_num;
+	uint16_t eeprom_rev;
+	uint8_t rf_rev;
+
+	uint8_t mac_addr[IEEE80211_ADDR_LEN];
+
+	uint8_t ntxpath;
+	uint8_t nrxpath;
+
+	int hw_radio_cntl;
+	int tx_agc_cntl;
+	int ext_lna_2ghz;
+	int ext_lna_5ghz;
+
+	uint8_t country_2ghz;
+	uint8_t country_5ghz;
+
+	uint8_t rf_freq_off;
+
+	uint8_t led_cntl;
+	uint16_t led_off[RT2860_SOFTC_LED_OFF_COUNT];
+
+	int8_t rssi_off_2ghz[RT2860_SOFTC_RSSI_OFF_COUNT];
+	int8_t rssi_off_5ghz[RT2860_SOFTC_RSSI_OFF_COUNT];
+
+	int8_t lna_gain[RT2860_SOFTC_LNA_GAIN_COUNT];
+
+	int8_t txpow1[RT2860_SOFTC_TXPOW_COUNT];
+	int8_t txpow2[RT2860_SOFTC_TXPOW_COUNT];
+
+	int8_t txpow_rate_delta_2ghz;
+	int8_t txpow_rate_delta_5ghz;
+	uint32_t txpow_rate_20mhz[RT2860_SOFTC_TXPOW_RATE_COUNT];
+	uint32_t txpow_rate_40mhz_2ghz[RT2860_SOFTC_TXPOW_RATE_COUNT];
+	uint32_t txpow_rate_40mhz_5ghz[RT2860_SOFTC_TXPOW_RATE_COUNT];
+
+	int tx_agc_cntl_2ghz;
+	int tx_agc_cntl_5ghz;
+
+	uint8_t tssi_2ghz[RT2860_SOFTC_TSSI_COUNT];
+	uint8_t tssi_step_2ghz;
+	uint8_t tssi_5ghz[RT2860_SOFTC_TSSI_COUNT];
+	uint8_t tssi_step_5ghz;
+
+	struct
+	{
+		uint8_t	val;
+		uint8_t	reg;
+	} __packed bbp_eeprom[RT2860_SOFTC_BBP_EEPROM_COUNT], rf[10];
+
+	uint16_t powersave_level;
+
+	uint8_t staid_mask[RT2860_SOFTC_STAID_COUNT / NBBY];
+
+	uint32_t intr_enable_mask;
+	uint32_t intr_disable_mask;
+	uint32_t intr_pending_mask;
+
+	struct task rx_done_task;
+	int rx_process_limit;
+
+	struct task tx_done_task;
+
+	struct task fifo_sta_full_task;
+
+	struct task periodic_task;
+	struct callout periodic_ch;
+	unsigned long periodic_round;
+
+	struct taskqueue *taskqueue;
+
+	struct rt2860_softc_rx_ring rx_ring;
+
+	struct rt2860_softc_tx_ring tx_ring[RT2860_SOFTC_TX_RING_COUNT];
+	int tx_ring_mgtqid;
+
+	struct callout tx_watchdog_ch;
+	int tx_timer;
+
+	struct rt2860_softc_rx_radiotap_header rxtap;
+	struct rt2860_softc_tx_radiotap_header txtap;
+
+	/* statistic counters */
+
+	unsigned long interrupts;
+	unsigned long tx_coherent_interrupts;
+	unsigned long rx_coherent_interrupts;
+	unsigned long txrx_coherent_interrupts;
+	unsigned long fifo_sta_full_interrupts;
+	unsigned long rx_interrupts;
+	unsigned long rx_delay_interrupts;
+	unsigned long tx_interrupts[RT2860_SOFTC_TX_RING_COUNT];
+	unsigned long tx_delay_interrupts;
+	unsigned long pre_tbtt_interrupts;
+	unsigned long tbtt_interrupts;
+	unsigned long mcu_cmd_interrupts;
+	unsigned long auto_wakeup_interrupts;
+	unsigned long gp_timer_interrupts;
+
+	unsigned long tx_data_queue_full[RT2860_SOFTC_TX_RING_COUNT];
+
+	unsigned long tx_watchdog_timeouts;
+
+	unsigned long tx_defrag_packets;
+
+	unsigned long no_tx_desc_avail;
+
+	unsigned long rx_mbuf_alloc_errors;
+	unsigned long rx_mbuf_dmamap_errors;
+
+	unsigned long tx_queue_not_empty[2];
+
+	unsigned long tx_beacons;
+	unsigned long tx_noretryok;
+	unsigned long tx_retryok;
+	unsigned long tx_failed;
+	unsigned long tx_underflows;
+	unsigned long tx_zerolen;
+	unsigned long tx_nonagg;
+	unsigned long tx_agg;
+	unsigned long tx_ampdu;
+	unsigned long tx_mpdu_zero_density;
+	unsigned long tx_ampdu_sessions;
+
+	unsigned long rx_packets;
+	unsigned long rx_ampdu;
+	unsigned long rx_ampdu_retries;
+	unsigned long rx_mpdu_zero_density;
+	unsigned long rx_ampdu_sessions;
+	unsigned long rx_amsdu;
+	unsigned long rx_crc_errors;
+	unsigned long rx_phy_errors;
+	unsigned long rx_false_ccas;
+	unsigned long rx_plcp_errors;
+	unsigned long rx_dup_packets;
+	unsigned long rx_fifo_overflows;
+	unsigned long rx_cipher_no_errors;
+	unsigned long rx_cipher_icv_errors;
+	unsigned long rx_cipher_mic_errors;
+	unsigned long rx_cipher_invalid_key_errors;
+
+	int tx_stbc;
+
+	uint8_t rf24_20mhz;
+	uint8_t	rf24_40mhz;
+	uint8_t	patch_dac;
+	uint8_t	txmixgain_2ghz;
+	uint8_t	txmixgain_5ghz;
+
+#ifdef RT2860_DEBUG
+	int debug;
+#endif
+};
+
+#define RT2860_EEPROM_VERSION					0x0002
+#define RT2860_EEPROM_ADDRESS01					0x0004
+#define RT2860_EEPROM_ADDRESS23					0x0006
+#define RT2860_EEPROM_ADDRESS45					0x0008
+#define RT2860_EEPROM_POWERSAVE_LEVEL			0x0022
+#define RT2860_EEPROM_ANTENNA					0x0034
+#define RT2860_EEPROM_NIC_CONFIG				0x0036
+#define RT2860_EEPROM_COUNTRY					0x0038
+#define RT2860_EEPROM_RF_FREQ_OFF				0x003a
+#define RT2860_EEPROM_LED1_OFF					0x003c
+#define RT2860_EEPROM_LED2_OFF					0x003e
+#define RT2860_EEPROM_LED3_OFF					0x0040
+#define RT2860_EEPROM_LNA_GAIN					0x0044
+#define RT2860_EEPROM_RSSI_OFF_2GHZ_BASE		0x0046
+#define RT2860_EEPROM_RSSI2_OFF_2GHZ_BASE		0x0048
+#define RT2860_EEPROM_RSSI_OFF_5GHZ_BASE		0x004a
+#define RT2860_EEPROM_RSSI2_OFF_5GHZ_BASE		0x004c
+#define RT2860_EEPROM_TXPOW_RATE_DELTA			0x0050
+#define RT2860_EEPROM_TXPOW1_2GHZ_BASE			0x0052
+#define RT2860_EEPROM_TXPOW2_2GHZ_BASE			0x0060
+#define RT2860_EEPROM_TSSI_2GHZ_BASE			0x006e
+#define RT2860_EEPROM_TXPOW1_5GHZ_BASE			0x0078
+#define RT2860_EEPROM_TXPOW2_5GHZ_BASE			0x00a6
+#define RT2860_EEPROM_TSSI_5GHZ_BASE			0x00d4
+#define RT2860_EEPROM_TXPOW_RATE_BASE			0x00de
+#define RT2860_EEPROM_BBP_BASE				0x00f0
+#define RT3071_EEPROM_RF_BASE				0x0082
+
+#define RT2860_EEPROM_RF_2820					1 /* 2.4GHz 2T3R */
+#define RT2860_EEPROM_RF_2850					2 /* 2.4/5GHz 2T3R */
+#define RT2860_EEPROM_RF_2720					3 /* 2.4GHz 1T2R */
+#define RT2860_EEPROM_RF_2750					4 /* 2.4G/5GHz 1T2R */
+#define RT2860_EEPROM_RF_3020					5 /* 2.4G 1T1R */
+#define RT2860_EEPROM_RF_2020					6 /* 2.4G B/G */
+#define RT2860_EEPROM_RF_3021					7 /* 2.4G 1T2R */
+#define RT2860_EEPROM_RF_3022					8 /* 2.4G 2T2R */
+#define RT2860_EEPROM_RF_3052					9 /* 2.4G/5G 2T2R */
+#define RT2860_EEPROM_RF_2853					10 /* 2.4G.5G 3T3R */
+#define RT2860_EEPROM_RF_3320					11 /* 2.4G 1T1R with PA (RT3350/RT3370/RT3390) */
+#define RT2860_EEPROM_RF_3322					12 /* 2.4G 2T2R with PA (RT3352/RT3371/RT3372/RT3391/RT3392) */
+#define RT2860_EEPROM_RF_3053					13 /* 2.4G/5G 3T3R (RT3883/RT3563/RT3573/RT3593/RT3662) */
+#define RT2860_EEPROM_RF_3853					13 /* 2.4G/5G 3T3R (RT3883/RT3563/RT3573/RT3593/RT3662) */
+
+/*
+ * RT2860_EEPROM_NIC_CONFIG flags
+ */
+#define RT2860_EEPROM_EXT_LNA_5GHZ				(1 << 3)
+#define RT2860_EEPROM_EXT_LNA_2GHZ				(1 << 2)
+#define RT2860_EEPROM_TX_AGC_CNTL				(1 << 1)
+#define RT2860_EEPROM_HW_RADIO_CNTL				(1 << 0)
+
+#define RT2860_EEPROM_LED_POLARITY				(1 << 7)
+#define RT2860_EEPROM_LED_MODE_MASK				0x7f
+
+#define RT2860_EEPROM_LED_CNTL_DEFAULT			0x01
+#define RT2860_EEPROM_LED1_OFF_DEFAULT			0x5555
+#define RT2860_EEPROM_LED2_OFF_DEFAULT			0x2221
+#define RT2860_EEPROM_LED3_OFF_DEFAULT			0xa9f8
+
+#define RT2860_EEPROM_RSSI_OFF_MIN				-10
+#define RT2860_EEPROM_RSSI_OFF_MAX				10
+
+#define RT2860_EEPROM_TXPOW_2GHZ_MIN			0
+#define RT2860_EEPROM_TXPOW_2GHZ_MAX			31
+#define RT2860_EEPROM_TXPOW_2GHZ_DEFAULT		5
+#define RT2860_EEPROM_TXPOW_5GHZ_MIN			-7
+#define RT2860_EEPROM_TXPOW_5GHZ_MAX			15
+#define RT2860_EEPROM_TXPOW_5GHZ_DEFAULT		5
+
+#define RT2860_IO_MCU_CMD_SLEEP				0x30
+#define RT2860_IO_MCU_CMD_WAKEUP			0x31
+#define RT2860_IO_MCU_CMD_RADIOOFF			0x35
+#define RT2860_IO_MCU_CMD_LEDS				0x50
+#define RT2860_IO_MCU_CMD_LED_BRIGHTNESS		0x51
+#define RT2860_IO_MCU_CMD_LED1				0x52
+#define RT2860_IO_MCU_CMD_LED2				0x53
+#define RT2860_IO_MCU_CMD_LED3				0x54
+#define RT2860_IO_MCU_CMD_BOOT				0x72
+#define RT2860_IO_MCU_CMD_BBP				0x80
+#define RT2860_IO_MCU_CMD_POWERSAVE_LEVEL		0x83
+
+#define RT2860_LED_CMD_RADIO_OFF				0
+#define RT2860_LED_CMD_RADIO_ON					(1 << 5)
+#define RT2860_LED_CMD_LINK_2GHZ				(1 << 6)
+#define RT2860_LED_CMD_LINK_5GHZ				(1 << 7)
+
+/*
+ * Global function prototypes, used in bus depended interfaces
+ */
+
+int rt2860_attach(device_t, int);
+int rt2860_detach(void *);
+void rt2860_shutdown(void *);
+void rt2860_suspend(void *);
+void rt2860_resume(void *);
+void rt2860_intr(void *arg);
+
+
+#endif /* #ifndef _RT2860VAR_H_ */
+


More information about the Zrouter-src-freebsd mailing list