[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