Index: freebsd/sys/dev/rtwn/if_rtwn.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,2020 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU/RTL8812AU/RTL8821AU.
+ */
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+#include <sys/firmware.h>
+#include <sys/kdb.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_var.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 <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_beacon.h>
+#include <dev/rtwn/if_rtwn_calib.h>
+#include <dev/rtwn/if_rtwn_cam.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_efuse.h>
+#include <dev/rtwn/if_rtwn_fw.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_rx.h>
+#include <dev/rtwn/if_rtwn_task.h>
+#include <dev/rtwn/if_rtwn_tx.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+
+static void		rtwn_radiotap_attach(struct rtwn_softc *);
+static void		rtwn_vap_decrement_counters(struct rtwn_softc *,
+			    enum ieee80211_opmode, int);
+static void		rtwn_set_ic_opmode(struct rtwn_softc *);
+static struct ieee80211vap *rtwn_vap_create(struct ieee80211com *,
+			    const char [IFNAMSIZ], int, enum ieee80211_opmode,
+			    int, const uint8_t [IEEE80211_ADDR_LEN],
+			    const uint8_t [IEEE80211_ADDR_LEN]);
+static void		rtwn_vap_delete(struct ieee80211vap *);
+static int		rtwn_read_chipid(struct rtwn_softc *);
+static int		rtwn_ioctl_reset(struct ieee80211vap *, u_long);
+#ifndef RTWN_WITHOUT_UCODE
+static void		rtwn_set_media_status(struct rtwn_softc *,
+			    union sec_param *);
+static int		rtwn_tx_fwpkt_check(struct rtwn_softc *,
+			    struct ieee80211vap *);
+static int		rtwn_construct_nulldata(struct rtwn_softc *,
+			    struct ieee80211vap *, uint8_t *, int);
+static int		rtwn_push_nulldata(struct rtwn_softc *,
+			    struct ieee80211vap *);
+static void		rtwn_pwrmode_init(void *);
+static void		rtwn_set_pwrmode_cb(struct rtwn_softc *,
+			    union sec_param *);
+#endif
+static void		rtwn_tsf_sync_adhoc(void *);
+static void		rtwn_tsf_sync_adhoc_task(void *, int);
+static void		rtwn_tsf_sync_enable(struct rtwn_softc *,
+			    struct ieee80211vap *);
+static void		rtwn_set_ack_preamble(struct rtwn_softc *);
+static void		rtwn_set_mode(struct rtwn_softc *, uint8_t, int);
+static int		rtwn_monitor_newstate(struct ieee80211vap *,
+			    enum ieee80211_state, int);
+static int		rtwn_newstate(struct ieee80211vap *,
+			    enum ieee80211_state, int);
+static void		rtwn_calc_basicrates(struct rtwn_softc *);
+static int		rtwn_run(struct rtwn_softc *,
+			    struct ieee80211vap *);
+#ifndef D4054
+static void		rtwn_watchdog(void *);
+#endif
+static void		rtwn_parent(struct ieee80211com *);
+static int		rtwn_llt_write(struct rtwn_softc *, uint32_t,
+			    uint32_t);
+static int		rtwn_llt_init(struct rtwn_softc *);
+static int		rtwn_dma_init(struct rtwn_softc *);
+static int		rtwn_mac_init(struct rtwn_softc *);
+static void		rtwn_mrr_init(struct rtwn_softc *);
+static void		rtwn_scan_start(struct ieee80211com *);
+static void		rtwn_scan_curchan(struct ieee80211_scan_state *,
+			    unsigned long);
+static void		rtwn_scan_end(struct ieee80211com *);
+static void		rtwn_getradiocaps(struct ieee80211com *, int, int *,
+			    struct ieee80211_channel[]);
+static void		rtwn_update_chw(struct ieee80211com *);
+static void		rtwn_set_channel(struct ieee80211com *);
+static int		rtwn_wme_update(struct ieee80211com *);
+static void		rtwn_update_slot(struct ieee80211com *);
+static void		rtwn_update_slot_cb(struct rtwn_softc *,
+			    union sec_param *);
+static void		rtwn_update_aifs(struct rtwn_softc *, uint8_t);
+static void		rtwn_update_promisc(struct ieee80211com *);
+static void		rtwn_update_mcast(struct ieee80211com *);
+static int		rtwn_set_bssid(struct rtwn_softc *,
+			    const uint8_t *, int);
+static int		rtwn_set_macaddr(struct rtwn_softc *,
+			    const uint8_t *, int);
+static struct ieee80211_node *rtwn_node_alloc(struct ieee80211vap *,
+			    const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void		rtwn_newassoc(struct ieee80211_node *, int);
+static void		rtwn_node_free(struct ieee80211_node *);
+static void		rtwn_init_beacon_reg(struct rtwn_softc *);
+static int		rtwn_init(struct rtwn_softc *);
+static void		rtwn_stop(struct rtwn_softc *);
+
+MALLOC_DEFINE(M_RTWN_PRIV, "rtwn_priv", "rtwn driver private state");
+
+static const uint8_t rtwn_chan_2ghz[] =
+	{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
+
+static const uint16_t wme2reg[] =
+	{ R92C_EDCA_BE_PARAM, R92C_EDCA_BK_PARAM,
+	  R92C_EDCA_VI_PARAM, R92C_EDCA_VO_PARAM };
+
+int
+rtwn_attach(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	int error;
+
+	sc->cur_bcnq_id = RTWN_VAP_ID_INVALID;
+
+	RTWN_NT_LOCK_INIT(sc);
+	rtwn_cmdq_init(sc);
+#ifndef D4054
+	callout_init_mtx(&sc->sc_watchdog_to, &sc->sc_mtx, 0);
+#endif
+	callout_init(&sc->sc_calib_to, 0);
+	callout_init(&sc->sc_pwrmode_init, 0);
+	mbufq_init(&sc->sc_snd, ifqmaxlen);
+
+	RTWN_LOCK(sc);
+	error = rtwn_read_chipid(sc);
+	RTWN_UNLOCK(sc);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "unsupported test chip\n");
+		goto detach;
+	}
+
+	error = rtwn_read_rom(sc);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "%s: cannot read rom, error %d\n",
+		    __func__, error);
+		goto detach;
+	}
+
+	if (sc->macid_limit > RTWN_MACID_LIMIT) {
+		device_printf(sc->sc_dev,
+		    "macid limit will be reduced from %d to %d\n",
+		    sc->macid_limit, RTWN_MACID_LIMIT);
+		sc->macid_limit = RTWN_MACID_LIMIT;
+	}
+	if (sc->cam_entry_limit > RTWN_CAM_ENTRY_LIMIT) {
+		device_printf(sc->sc_dev,
+		    "cam entry limit will be reduced from %d to %d\n",
+		    sc->cam_entry_limit, RTWN_CAM_ENTRY_LIMIT);
+		sc->cam_entry_limit = RTWN_CAM_ENTRY_LIMIT;
+	}
+	if (sc->txdesc_len > RTWN_TX_DESC_SIZE) {
+		device_printf(sc->sc_dev,
+		    "adjust size for Tx descriptor (current %d, needed %d)\n",
+		    RTWN_TX_DESC_SIZE, sc->txdesc_len);
+		goto detach;
+	}
+
+	device_printf(sc->sc_dev, "MAC/BB %s, RF 6052 %dT%dR\n",
+	    sc->name, sc->ntxchains, sc->nrxchains);
+
+	ic->ic_softc = sc;
+	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
+	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
+
+	/* set device capabilities */
+	ic->ic_caps =
+		  IEEE80211_C_STA		/* station mode */
+		| IEEE80211_C_MONITOR		/* monitor mode */
+		| IEEE80211_C_IBSS		/* adhoc mode */
+		| IEEE80211_C_HOSTAP		/* hostap mode */
+#if 0	/* TODO: HRPWM register setup */
+#ifndef RTWN_WITHOUT_UCODE
+		| IEEE80211_C_PMGT		/* Station-side power mgmt */
+#endif
+#endif
+		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
+		| IEEE80211_C_SHSLOT		/* short slot time supported */
+#if 0
+		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
+#endif
+		| IEEE80211_C_WPA		/* 802.11i */
+		| IEEE80211_C_WME		/* 802.11e */
+		| IEEE80211_C_SWAMSDUTX		/* Do software A-MSDU TX */
+		| IEEE80211_C_FF		/* Atheros fast-frames */
+		;
+
+	if (sc->sc_hwcrypto != RTWN_CRYPTO_SW) {
+		ic->ic_cryptocaps =
+		    IEEE80211_CRYPTO_WEP |
+		    IEEE80211_CRYPTO_TKIP |
+		    IEEE80211_CRYPTO_AES_CCM;
+	}
+
+	ic->ic_htcaps =
+	      IEEE80211_HTCAP_SHORTGI20		/* short GI in 20MHz */
+	    | IEEE80211_HTCAP_MAXAMSDU_3839	/* max A-MSDU length */
+	    | IEEE80211_HTCAP_SMPS_OFF		/* SM PS mode disabled */
+	    /* s/w capabilities */
+	    | IEEE80211_HTC_HT			/* HT operation */
+	    | IEEE80211_HTC_AMPDU		/* A-MPDU tx */
+	    | IEEE80211_HTC_AMSDU		/* A-MSDU tx */
+	    ;
+
+	if (sc->sc_ht40) {
+		ic->ic_htcaps |=
+		      IEEE80211_HTCAP_CHWIDTH40	/* 40 MHz channel width */
+		    | IEEE80211_HTCAP_SHORTGI40	/* short GI in 40MHz */
+		    ;
+	}
+
+	ic->ic_txstream = sc->ntxchains;
+	ic->ic_rxstream = sc->nrxchains;
+
+	/* Enable TX watchdog */
+#ifdef D4054
+	ic->ic_flags_ext |= IEEE80211_FEXT_WATCHDOG;
+#endif
+
+	/* Adjust capabilities. */
+	rtwn_adj_devcaps(sc);
+
+	rtwn_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,
+	    ic->ic_channels);
+
+	/* XXX TODO: setup regdomain if R92C_CHANNEL_PLAN_BY_HW bit is set. */
+
+	ieee80211_ifattach(ic);
+	ic->ic_raw_xmit = rtwn_raw_xmit;
+	ic->ic_scan_start = rtwn_scan_start;
+	sc->sc_scan_curchan = ic->ic_scan_curchan;
+	ic->ic_scan_curchan = rtwn_scan_curchan;
+	ic->ic_scan_end = rtwn_scan_end;
+	ic->ic_getradiocaps = rtwn_getradiocaps;
+	ic->ic_update_chw = rtwn_update_chw;
+	ic->ic_set_channel = rtwn_set_channel;
+	ic->ic_transmit = rtwn_transmit;
+	ic->ic_parent = rtwn_parent;
+	ic->ic_vap_create = rtwn_vap_create;
+	ic->ic_vap_delete = rtwn_vap_delete;
+	ic->ic_wme.wme_update = rtwn_wme_update;
+	ic->ic_updateslot = rtwn_update_slot;
+	ic->ic_update_promisc = rtwn_update_promisc;
+	ic->ic_update_mcast = rtwn_update_mcast;
+	ic->ic_node_alloc = rtwn_node_alloc;
+	ic->ic_newassoc = rtwn_newassoc;
+	sc->sc_node_free = ic->ic_node_free;
+	ic->ic_node_free = rtwn_node_free;
+
+	rtwn_postattach(sc);
+	rtwn_radiotap_attach(sc);
+
+	if (bootverbose)
+		ieee80211_announce(ic);
+
+	return (0);
+
+detach:
+	return (ENXIO);			/* failure */
+}
+
+static void
+rtwn_radiotap_attach(struct rtwn_softc *sc)
+{
+	struct rtwn_rx_radiotap_header *rxtap = &sc->sc_rxtap;
+	struct rtwn_tx_radiotap_header *txtap = &sc->sc_txtap;
+
+	ieee80211_radiotap_attach(&sc->sc_ic,
+	    &txtap->wt_ihdr, sizeof(*txtap), RTWN_TX_RADIOTAP_PRESENT,
+	    &rxtap->wr_ihdr, sizeof(*rxtap), RTWN_RX_RADIOTAP_PRESENT);
+}
+
+void
+rtwn_sysctlattach(struct rtwn_softc *sc)
+{
+	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+
+#if 1
+	sc->sc_ht40 = 0;
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "ht40", CTLFLAG_RDTUN, &sc->sc_ht40,
+	    sc->sc_ht40, "Enable 40 MHz mode support");
+#endif
+
+#ifdef RTWN_DEBUG
+	SYSCTL_ADD_U32(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "debug", CTLFLAG_RWTUN, &sc->sc_debug, sc->sc_debug,
+	    "Control debugging printfs");
+#endif
+
+	sc->sc_hwcrypto = RTWN_CRYPTO_PAIR;
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "hwcrypto", CTLFLAG_RDTUN, &sc->sc_hwcrypto,
+	    sc->sc_hwcrypto, "Enable h/w crypto: "
+	    "0 - disable, 1 - pairwise keys, 2 - all keys");
+	if (sc->sc_hwcrypto >= RTWN_CRYPTO_MAX)
+		sc->sc_hwcrypto = RTWN_CRYPTO_FULL;
+
+	sc->sc_ratectl_sysctl = RTWN_RATECTL_NET80211;
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "ratectl", CTLFLAG_RDTUN, &sc->sc_ratectl_sysctl,
+	    sc->sc_ratectl_sysctl, "Select rate control mechanism: "
+	    "0 - disabled, 1 - via net80211, 2 - via firmware");
+	if (sc->sc_ratectl_sysctl >= RTWN_RATECTL_MAX)
+		sc->sc_ratectl_sysctl = RTWN_RATECTL_FW;
+
+	sc->sc_ratectl = sc->sc_ratectl_sysctl;
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "ratectl_selected", CTLFLAG_RD, &sc->sc_ratectl,
+	    sc->sc_ratectl,
+	    "Currently selected rate control mechanism (by the driver)");
+}
+
+void
+rtwn_detach(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	if (ic->ic_softc == sc) {
+		/* Stop command queue. */
+		RTWN_CMDQ_LOCK(sc);
+		sc->sc_detached = 1;
+		RTWN_CMDQ_UNLOCK(sc);
+
+		ieee80211_draintask(ic, &sc->cmdq_task);
+		ieee80211_ifdetach(ic);
+	}
+
+	rtwn_cmdq_destroy(sc);
+	if (RTWN_NT_LOCK_INITIALIZED(sc))
+		RTWN_NT_LOCK_DESTROY(sc);
+}
+
+void
+rtwn_suspend(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	ieee80211_suspend_all(ic);
+}
+
+void
+rtwn_resume(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	ieee80211_resume_all(ic);
+}
+
+static void
+rtwn_vap_decrement_counters(struct rtwn_softc *sc,
+    enum ieee80211_opmode opmode, int id)
+{
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	if (id != RTWN_VAP_ID_INVALID) {
+		KASSERT(id == 0 || id == 1, ("wrong vap id %d!\n", id));
+		KASSERT(sc->vaps[id] != NULL, ("vap pointer is NULL\n"));
+		sc->vaps[id] = NULL;
+	}
+
+	switch (opmode) {
+	case IEEE80211_M_HOSTAP:
+		sc->ap_vaps--;
+		/* FALLTHROUGH */
+	case IEEE80211_M_IBSS:
+		sc->bcn_vaps--;
+		/* FALLTHROUGH */
+	case IEEE80211_M_STA:
+		sc->nvaps--;
+		break;
+	case IEEE80211_M_MONITOR:
+		sc->mon_vaps--;
+		break;
+	default:
+		KASSERT(0, ("wrong opmode %d\n", opmode));
+		break;
+	}
+
+	KASSERT(sc->vaps_running >= 0 && sc->monvaps_running >= 0,
+	    ("number of running vaps is negative (vaps %d, monvaps %d)\n",
+	    sc->vaps_running, sc->monvaps_running));
+	KASSERT(sc->vaps_running - sc->monvaps_running <= RTWN_PORT_COUNT,
+	    ("number of running vaps is too big (vaps %d, monvaps %d)\n",
+	    sc->vaps_running, sc->monvaps_running));
+
+	KASSERT(sc->nvaps >= 0 && sc->nvaps <= RTWN_PORT_COUNT,
+	    ("wrong value %d for nvaps\n", sc->nvaps));
+	KASSERT(sc->mon_vaps >= 0, ("mon_vaps is negative (%d)\n",
+	    sc->mon_vaps));
+	KASSERT(sc->bcn_vaps >= 0 && ((RTWN_CHIP_HAS_BCNQ1(sc) &&
+	    sc->bcn_vaps <= RTWN_PORT_COUNT) || sc->bcn_vaps <= 1),
+	    ("bcn_vaps value %d is wrong\n", sc->bcn_vaps));
+	KASSERT(sc->ap_vaps >= 0 && ((RTWN_CHIP_HAS_BCNQ1(sc) &&
+	    sc->ap_vaps <= RTWN_PORT_COUNT) || sc->ap_vaps <= 1),
+	    ("ap_vaps value %d is wrong\n", sc->ap_vaps));
+}
+
+static void
+rtwn_set_ic_opmode(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	/* for ieee80211_reset_erp() */
+	if (sc->bcn_vaps - sc->ap_vaps > 0)
+		ic->ic_opmode = IEEE80211_M_IBSS;
+	else if (sc->ap_vaps > 0)
+		ic->ic_opmode = IEEE80211_M_HOSTAP;
+	else if (sc->nvaps > 0)
+		ic->ic_opmode = IEEE80211_M_STA;
+	else
+		ic->ic_opmode = IEEE80211_M_MONITOR;
+}
+
+static struct ieee80211vap *
+rtwn_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 rtwn_softc *sc = ic->ic_softc;
+	struct rtwn_vap *uvp;
+	struct ieee80211vap *vap;
+	int id = RTWN_VAP_ID_INVALID;
+
+	RTWN_LOCK(sc);
+	KASSERT(sc->nvaps <= RTWN_PORT_COUNT,
+	    ("nvaps overflow (%d > %d)\n", sc->nvaps, RTWN_PORT_COUNT));
+	KASSERT(sc->ap_vaps <= RTWN_PORT_COUNT,
+	    ("ap_vaps overflow (%d > %d)\n", sc->ap_vaps, RTWN_PORT_COUNT));
+	KASSERT(sc->bcn_vaps <= RTWN_PORT_COUNT,
+	    ("bcn_vaps overflow (%d > %d)\n", sc->bcn_vaps, RTWN_PORT_COUNT));
+
+	if (opmode != IEEE80211_M_MONITOR) {
+		switch (sc->nvaps) {
+		case 0:
+			id = 0;
+			break;
+		case 1:
+			if (sc->vaps[1] == NULL)
+				id = 1;
+			else if (sc->vaps[0] == NULL)
+				id = 0;
+			KASSERT(id != RTWN_VAP_ID_INVALID,
+			    ("no free ports left\n"));
+			break;
+		case 2:
+		default:
+			goto fail;
+		}
+
+		if (opmode == IEEE80211_M_IBSS ||
+		    opmode == IEEE80211_M_HOSTAP) {
+			if ((sc->bcn_vaps == 1 && !RTWN_CHIP_HAS_BCNQ1(sc)) ||
+			    sc->bcn_vaps == RTWN_PORT_COUNT)
+				goto fail;
+		}
+	}
+
+	switch (opmode) {
+	case IEEE80211_M_HOSTAP:
+		sc->ap_vaps++;
+		/* FALLTHROUGH */
+	case IEEE80211_M_IBSS:
+		sc->bcn_vaps++;
+		/* FALLTHROUGH */
+	case IEEE80211_M_STA:
+		sc->nvaps++;
+		break;
+	case IEEE80211_M_MONITOR:
+		sc->mon_vaps++;
+		break;
+	default:
+		KASSERT(0, ("unknown opmode %d\n", opmode));
+		goto fail;
+	}
+	RTWN_UNLOCK(sc);
+
+	uvp = malloc(sizeof(struct rtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO);
+	uvp->id = id;
+	if (id != RTWN_VAP_ID_INVALID) {
+		RTWN_LOCK(sc);
+		sc->vaps[id] = uvp;
+		RTWN_UNLOCK(sc);
+	}
+	vap = &uvp->vap;
+	/* enable s/w bmiss handling for sta mode */
+
+	if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
+	    flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) {
+		/* out of memory */
+		free(uvp, M_80211_VAP);
+
+		RTWN_LOCK(sc);
+		rtwn_vap_decrement_counters(sc, opmode, id);
+		RTWN_UNLOCK(sc);
+
+		return (NULL);
+	}
+
+	rtwn_beacon_init(sc, &uvp->bcn_desc.txd[0], uvp->id);
+	rtwn_vap_preattach(sc, vap);
+
+	/* override state transition machine */
+	uvp->newstate = vap->iv_newstate;
+	if (opmode == IEEE80211_M_MONITOR)
+		vap->iv_newstate = rtwn_monitor_newstate;
+	else
+		vap->iv_newstate = rtwn_newstate;
+	vap->iv_update_beacon = rtwn_update_beacon;
+	vap->iv_reset = rtwn_ioctl_reset;
+	vap->iv_key_alloc = rtwn_key_alloc;
+	vap->iv_key_set = rtwn_key_set;
+	vap->iv_key_delete = rtwn_key_delete;
+	vap->iv_max_aid = sc->macid_limit;
+
+	/* 802.11n parameters */
+	vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16;
+	vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K;
+
+	TIMEOUT_TASK_INIT(taskqueue_thread, &uvp->tx_beacon_csa, 0,
+	    rtwn_tx_beacon_csa, vap);
+	if (opmode == IEEE80211_M_IBSS) {
+		uvp->recv_mgmt = vap->iv_recv_mgmt;
+		vap->iv_recv_mgmt = rtwn_adhoc_recv_mgmt;
+		TASK_INIT(&uvp->tsf_sync_adhoc_task, 0,
+		    rtwn_tsf_sync_adhoc_task, vap);
+		callout_init(&uvp->tsf_sync_adhoc, 0);
+	}
+
+	/*
+	 * NB: driver can select net80211 RA even when user requests
+	 * another mechanism.
+	 */
+	ieee80211_ratectl_init(vap);
+
+	/* complete setup */
+	ieee80211_vap_attach(vap, ieee80211_media_change,
+	    ieee80211_media_status, mac);
+
+	RTWN_LOCK(sc);
+	rtwn_set_ic_opmode(sc);
+	if (sc->sc_flags & RTWN_RUNNING) {
+		if (uvp->id != RTWN_VAP_ID_INVALID)
+			rtwn_set_macaddr(sc, vap->iv_myaddr, uvp->id);
+
+		rtwn_rxfilter_update(sc);
+	}
+	RTWN_UNLOCK(sc);
+
+	return (vap);
+
+fail:
+	RTWN_UNLOCK(sc);
+	return (NULL);
+}
+
+static void
+rtwn_vap_delete(struct ieee80211vap *vap)
+{
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+
+	/* Put vap into INIT state + stop device if needed. */
+	ieee80211_stop(vap);
+	ieee80211_draintask(ic, &vap->iv_nstate_task);
+	ieee80211_draintask(ic, &ic->ic_parent_task);
+
+	RTWN_LOCK(sc);
+	/* Cancel any unfinished Tx. */
+	rtwn_reset_lists(sc, vap);
+	if (uvp->bcn_mbuf != NULL)
+		m_freem(uvp->bcn_mbuf);
+	rtwn_vap_decrement_counters(sc, vap->iv_opmode, uvp->id);
+	rtwn_set_ic_opmode(sc);
+	if (sc->sc_flags & RTWN_RUNNING)
+		rtwn_rxfilter_update(sc);
+	RTWN_UNLOCK(sc);
+
+	if (vap->iv_opmode == IEEE80211_M_IBSS) {
+		ieee80211_draintask(ic, &uvp->tsf_sync_adhoc_task);
+		callout_drain(&uvp->tsf_sync_adhoc);
+	}
+
+	ieee80211_ratectl_deinit(vap);
+	ieee80211_vap_detach(vap);
+	free(uvp, M_80211_VAP);
+}
+
+static int
+rtwn_read_chipid(struct rtwn_softc *sc)
+{
+	uint32_t reg;
+
+	reg = rtwn_read_4(sc, R92C_SYS_CFG);
+	if (reg & R92C_SYS_CFG_TRP_VAUX_EN)	/* test chip */
+		return (EOPNOTSUPP);
+
+	rtwn_read_chipid_vendor(sc, reg);
+
+	return (0);
+}
+
+static int
+rtwn_ioctl_reset(struct ieee80211vap *vap, u_long cmd)
+{
+	int error;
+
+	switch (cmd) {
+#ifndef RTWN_WITHOUT_UCODE
+	case IEEE80211_IOC_POWERSAVE:
+	case IEEE80211_IOC_POWERSAVESLEEP:
+	{
+		struct rtwn_softc *sc = vap->iv_ic->ic_softc;
+		struct rtwn_vap *uvp = RTWN_VAP(vap);
+
+		if (vap->iv_opmode == IEEE80211_M_STA && uvp->id == 0) {
+			RTWN_LOCK(sc);
+			if (sc->sc_flags & RTWN_RUNNING)
+				error = rtwn_set_pwrmode(sc, vap, 1);
+			else
+				error = 0;
+			RTWN_UNLOCK(sc);
+			if (error != 0)
+				error = ENETRESET;
+		} else
+			error = EOPNOTSUPP;
+		break;
+	}
+#endif
+	case IEEE80211_IOC_SHORTGI:
+	case IEEE80211_IOC_RTSTHRESHOLD:
+	case IEEE80211_IOC_PROTMODE:
+	case IEEE80211_IOC_HTPROTMODE:
+		error = 0;
+		break;
+	default:
+		error = ENETRESET;
+		break;
+	}
+
+	return (error);
+}
+
+#ifndef RTWN_WITHOUT_UCODE
+static void
+rtwn_set_media_status(struct rtwn_softc *sc, union sec_param *data)
+{
+	sc->sc_set_media_status(sc, data->macid);
+}
+
+static int
+rtwn_tx_fwpkt_check(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	int ntries, error;
+
+	for (ntries = 0; ntries < 5; ntries++) {
+		error = rtwn_push_nulldata(sc, vap);
+		if (error == 0)
+			break;
+	}
+	if (ntries == 5) {
+		device_printf(sc->sc_dev,
+		    "%s: cannot push f/w frames into chip, error %d!\n",
+		    __func__, error);
+		return (error);
+	}
+
+	return (0);
+}
+
+static int
+rtwn_construct_nulldata(struct rtwn_softc *sc, struct ieee80211vap *vap,
+    uint8_t *ptr, int qos)
+{
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct rtwn_tx_desc_common *txd;
+	struct ieee80211_frame *wh;
+	int pktlen;
+
+	/* XXX obtain from net80211 */
+	wh = (struct ieee80211_frame *)(ptr + sc->txdesc_len);
+	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
+	wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
+	IEEE80211_ADDR_COPY(wh->i_addr1, vap->iv_bss->ni_bssid);
+	IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
+	IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_macaddr);
+
+	txd = (struct rtwn_tx_desc_common *)ptr;
+	txd->offset = sc->txdesc_len;
+	pktlen = sc->txdesc_len;
+	if (qos) {
+		struct ieee80211_qosframe *qwh;
+		const int tid = WME_AC_TO_TID(WME_AC_BE);
+
+		qwh = (struct ieee80211_qosframe *)wh;
+		qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS_NULL;
+		qwh->i_qos[0] = tid & IEEE80211_QOS_TID;
+
+		txd->pktlen = htole16(sizeof(struct ieee80211_qosframe));
+		pktlen += sizeof(struct ieee80211_qosframe);
+	} else {
+		wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_NODATA;
+
+		txd->pktlen = htole16(sizeof(struct ieee80211_frame));
+		pktlen += sizeof(struct ieee80211_frame);
+	}
+
+	rtwn_fill_tx_desc_null(sc, ptr,
+	    ic->ic_curmode == IEEE80211_MODE_11B, qos, uvp->id);
+
+	return (pktlen);
+}
+
+static int
+rtwn_push_nulldata(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211com *ic = vap->iv_ic;
+	struct ieee80211_channel *c = ic->ic_curchan;
+	struct mbuf *m;
+	uint8_t *ptr;
+	int required_size, bcn_size, null_size, null_data, error;
+
+	if (!(sc->sc_flags & RTWN_FW_LOADED))
+		return (0);	/* requires firmware */
+
+	KASSERT(sc->page_size > 0, ("page size was not set!\n"));
+
+	/* Leave some space for beacon (multi-vap) */
+	bcn_size = roundup(RTWN_BCN_MAX_SIZE, sc->page_size);
+	/* 1 page for Null Data + 1 page for Qos Null Data frames. */
+	required_size = bcn_size + sc->page_size * 2;
+
+	m = m_get2(required_size, M_NOWAIT, MT_DATA, M_PKTHDR);
+	if (m == NULL)
+		return (ENOMEM);
+
+	/* Setup beacon descriptor. */
+	rtwn_beacon_set_rate(sc, &uvp->bcn_desc.txd[0],
+	    IEEE80211_IS_CHAN_5GHZ(c));
+
+	ptr = mtod(m, uint8_t *);
+	memset(ptr, 0, required_size - sc->txdesc_len);
+
+	/* Construct Null Data frame. */
+	ptr += bcn_size - sc->txdesc_len;
+	null_size = rtwn_construct_nulldata(sc, vap, ptr, 0);
+	KASSERT(null_size < sc->page_size,
+	    ("recalculate size for Null Data frame\n"));
+
+	/* Construct Qos Null Data frame. */
+	ptr += roundup(null_size, sc->page_size);
+	null_size = rtwn_construct_nulldata(sc, vap, ptr, 1);
+	KASSERT(null_size < sc->page_size,
+	    ("recalculate size for Qos Null Data frame\n"));
+
+	/* Do not try to detect a beacon here. */
+	rtwn_setbits_1_shift(sc, R92C_CR, 0, R92C_CR_ENSWBCN, 1);
+	rtwn_setbits_1_shift(sc, R92C_FWHW_TXQ_CTRL,
+	    R92C_FWHW_TXQ_CTRL_REAL_BEACON, 0, 2);
+
+	if (uvp->bcn_mbuf != NULL) {
+		rtwn_beacon_unload(sc, uvp->id);
+		m_freem(uvp->bcn_mbuf);
+	}
+
+	m->m_pkthdr.len = m->m_len = required_size - sc->txdesc_len;
+	uvp->bcn_mbuf = m;
+
+	error = rtwn_tx_beacon_check(sc, uvp);
+	if (error != 0) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON,
+		    "%s: frame was not recognized!\n", __func__);
+		goto fail;
+	}
+
+	/* Setup addresses in firmware. */
+	null_data = howmany(bcn_size, sc->page_size);
+	error = rtwn_set_rsvd_page(sc, 0, null_data, null_data + 1);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: CMD_RSVD_PAGE was not sent, error %d\n",
+		    __func__, error);
+		goto fail;
+	}
+
+fail:
+	/* Re-enable beacon detection. */
+	rtwn_setbits_1_shift(sc, R92C_FWHW_TXQ_CTRL,
+	    0, R92C_FWHW_TXQ_CTRL_REAL_BEACON, 2);
+	rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSWBCN, 0, 1);
+
+	/* Restore beacon (if present). */
+	if (sc->bcn_vaps > 0 && sc->vaps[!uvp->id] != NULL) {
+		struct rtwn_vap *uvp2 = sc->vaps[!uvp->id];
+
+		if (uvp2->curr_mode != R92C_MSR_NOLINK)
+			error = rtwn_tx_beacon_check(sc, uvp2);
+	}
+
+	return (error);
+}
+
+static void
+rtwn_pwrmode_init(void *arg)
+{
+	struct rtwn_softc *sc = arg;
+
+	rtwn_cmd_sleepable(sc, NULL, 0, rtwn_set_pwrmode_cb);
+}
+
+static void
+rtwn_set_pwrmode_cb(struct rtwn_softc *sc, union sec_param *data)
+{
+	struct ieee80211vap *vap = &sc->vaps[0]->vap;
+
+	if (vap != NULL)
+		rtwn_set_pwrmode(sc, vap, 1);
+}
+#endif
+
+static void
+rtwn_tsf_sync_adhoc(void *arg)
+{
+	struct ieee80211vap *vap = arg;
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+
+	if (uvp->curr_mode != R92C_MSR_NOLINK) {
+		/* Do it in process context. */
+		ieee80211_runtask(ic, &uvp->tsf_sync_adhoc_task);
+	}
+}
+
+/*
+ * Workaround for TSF synchronization:
+ * when BSSID filter in IBSS mode is not set
+ * (and TSF synchronization is enabled), then any beacon may update it.
+ * This routine synchronizes it when BSSID matching is enabled (IBSS merge
+ * is not possible during this period).
+ *
+ * NOTE: there is no race with rtwn_newstate(), since it uses the same
+ * taskqueue.
+ */
+static void
+rtwn_tsf_sync_adhoc_task(void *arg, int pending)
+{
+	struct ieee80211vap *vap = arg;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct rtwn_softc *sc = vap->iv_ic->ic_softc;
+	struct ieee80211_node *ni;
+
+	RTWN_LOCK(sc);
+	ni = ieee80211_ref_node(vap->iv_bss);
+
+	/* Accept beacons with the same BSSID. */
+	rtwn_set_rx_bssid_all(sc, 0);
+
+	/* Deny RCR updates. */
+	sc->sc_flags |= RTWN_RCR_LOCKED;
+
+	/* Enable synchronization. */
+	rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id),
+	    R92C_BCN_CTRL_DIS_TSF_UDT0, 0);
+
+	/* Synchronize. */
+	rtwn_delay(sc, ni->ni_intval * 5 * 1000);
+
+	/* Disable synchronization. */
+	rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id),
+	    0, R92C_BCN_CTRL_DIS_TSF_UDT0);
+
+	/* Accept all beacons. */
+	sc->sc_flags &= ~RTWN_RCR_LOCKED;
+	rtwn_set_rx_bssid_all(sc, 1);
+
+	/* Schedule next TSF synchronization. */
+	callout_reset(&uvp->tsf_sync_adhoc, 60*hz, rtwn_tsf_sync_adhoc, vap);
+
+	ieee80211_free_node(ni);
+	RTWN_UNLOCK(sc);
+}
+
+static void
+rtwn_tsf_sync_enable(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+
+	/* Reset TSF. */
+	rtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RESET(uvp->id));
+
+	switch (vap->iv_opmode) {
+	case IEEE80211_M_STA:
+		/* Enable TSF synchronization. */
+		rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id),
+		    R92C_BCN_CTRL_DIS_TSF_UDT0, 0);
+		break;
+	case IEEE80211_M_IBSS:
+		ieee80211_runtask(ic, &uvp->tsf_sync_adhoc_task);
+		/* FALLTHROUGH */
+	case IEEE80211_M_HOSTAP:
+		/* Enable beaconing. */
+		rtwn_beacon_enable(sc, uvp->id, 1);
+		break;
+	default:
+		device_printf(sc->sc_dev, "undefined opmode %d\n",
+		    vap->iv_opmode);
+		return;
+	}
+}
+
+static void
+rtwn_set_ack_preamble(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint32_t reg;
+
+	reg = rtwn_read_4(sc, R92C_WMAC_TRXPTCL_CTL);
+	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+		reg |= R92C_WMAC_TRXPTCL_SHPRE;
+	else
+		reg &= ~R92C_WMAC_TRXPTCL_SHPRE;
+	rtwn_write_4(sc, R92C_WMAC_TRXPTCL_CTL, reg);
+}
+
+static void
+rtwn_set_mode(struct rtwn_softc *sc, uint8_t mode, int id)
+{
+
+	rtwn_setbits_1(sc, R92C_MSR, R92C_MSR_MASK << id * 2, mode << id * 2);
+	if (sc->vaps[id] != NULL)
+		sc->vaps[id]->curr_mode = mode;
+}
+
+static int
+rtwn_monitor_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate,
+    int arg)
+{
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s -> %s\n",
+	    ieee80211_state_name[vap->iv_state],
+	    ieee80211_state_name[nstate]);
+
+	if (vap->iv_state != nstate) {
+		IEEE80211_UNLOCK(ic);
+		RTWN_LOCK(sc);
+
+		switch (nstate) {
+		case IEEE80211_S_INIT:
+			sc->vaps_running--;
+			sc->monvaps_running--;
+
+			if (sc->vaps_running == 0) {
+				/* Turn link LED off. */
+				rtwn_set_led(sc, RTWN_LED_LINK, 0);
+			}
+			break;
+		case IEEE80211_S_RUN:
+			sc->vaps_running++;
+			sc->monvaps_running++;
+
+			if (sc->vaps_running == 1) {
+				/* Turn link LED on. */
+				rtwn_set_led(sc, RTWN_LED_LINK, 1);
+			}
+			break;
+		default:
+			/* NOTREACHED */
+			break;
+		}
+
+		RTWN_UNLOCK(sc);
+		IEEE80211_LOCK(ic);
+	}
+
+	return (uvp->newstate(vap, nstate, arg));
+}
+
+static int
+rtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rtwn_softc *sc = ic->ic_softc;
+	enum ieee80211_state ostate;
+	int error, early_newstate;
+
+	ostate = vap->iv_state;
+	RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s -> %s\n",
+	    ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
+
+	if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC &&
+	    ostate == IEEE80211_S_INIT && nstate == IEEE80211_S_RUN) {
+		/* need to call iv_newstate() firstly */
+		error = uvp->newstate(vap, nstate, arg);
+		if (error != 0)
+			return (error);
+
+		early_newstate = 1;
+	} else
+		early_newstate = 0;
+
+	if (ostate == IEEE80211_S_CSA) {
+		taskqueue_cancel_timeout(taskqueue_thread,
+		    &uvp->tx_beacon_csa, NULL);
+
+		/*
+		 * In multi-vap case second counter may not be cleared
+		 * properly.
+		 */
+		vap->iv_csa_count = 0;
+	}
+	IEEE80211_UNLOCK(ic);
+	RTWN_LOCK(sc);
+
+	if (ostate == IEEE80211_S_CSA) {
+		/* Unblock all queues (multi-vap case). */
+		rtwn_write_1(sc, R92C_TXPAUSE, 0);
+	}
+
+	if ((ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_CSA) ||
+	    ostate == IEEE80211_S_CSA) {
+		sc->vaps_running--;
+
+		/* Set media status to 'No Link'. */
+		rtwn_set_mode(sc, R92C_MSR_NOLINK, uvp->id);
+
+		if (vap->iv_opmode == IEEE80211_M_IBSS) {
+			/* Stop periodical TSF synchronization. */
+			callout_stop(&uvp->tsf_sync_adhoc);
+		}
+
+		/* Disable TSF synchronization / beaconing. */
+		rtwn_beacon_enable(sc, uvp->id, 0);
+		rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id),
+		    0, R92C_BCN_CTRL_DIS_TSF_UDT0);
+
+		/* NB: monitor mode vaps are using port 0. */
+		if (uvp->id != 0 || sc->monvaps_running == 0) {
+			/* Reset TSF. */
+			rtwn_write_1(sc, R92C_DUAL_TSF_RST,
+			    R92C_DUAL_TSF_RESET(uvp->id));
+		}
+
+#ifndef RTWN_WITHOUT_UCODE
+		if ((ic->ic_caps & IEEE80211_C_PMGT) != 0 && uvp->id == 0) {
+			/* Disable power management. */
+			callout_stop(&sc->sc_pwrmode_init);
+			rtwn_set_pwrmode(sc, vap, 0);
+		}
+#endif
+		if (sc->vaps_running - sc->monvaps_running > 0) {
+			/* Recalculate basic rates bitmap. */
+			rtwn_calc_basicrates(sc);
+		}
+
+		if (sc->vaps_running == sc->monvaps_running) {
+			/* Stop calibration. */
+			callout_stop(&sc->sc_calib_to);
+
+			/* Stop Rx of data frames. */
+			rtwn_write_2(sc, R92C_RXFLTMAP2, 0);
+
+			/* Reset EDCA parameters. */
+			rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217);
+			rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317);
+			rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320);
+			rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444);
+
+			if (sc->vaps_running == 0) {
+				/* Turn link LED off. */
+				rtwn_set_led(sc, RTWN_LED_LINK, 0);
+			}
+		}
+	}
+
+	error = 0;
+	switch (nstate) {
+	case IEEE80211_S_SCAN:
+		/* Pause AC Tx queues. */
+		if (sc->vaps_running == 0)
+			rtwn_setbits_1(sc, R92C_TXPAUSE, 0, R92C_TX_QUEUE_AC);
+		break;
+	case IEEE80211_S_RUN:
+		error = rtwn_run(sc, vap);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "%s: could not move to RUN state\n", __func__);
+			break;
+		}
+
+		sc->vaps_running++;
+		break;
+	case IEEE80211_S_CSA:
+		/* Block all Tx queues (except beacon queue). */
+		rtwn_setbits_1(sc, R92C_TXPAUSE, 0,
+		    R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH);
+		break;
+	default:
+		break;
+	}
+
+	RTWN_UNLOCK(sc);
+	IEEE80211_LOCK(ic);
+	if (error != 0)
+		return (error);
+
+	return (early_newstate ? 0 : uvp->newstate(vap, nstate, arg));
+}
+
+static void
+rtwn_calc_basicrates(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint32_t basicrates;
+	int i;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	if (ic->ic_flags & IEEE80211_F_SCAN)
+		return;		/* will be done by rtwn_scan_end(). */
+
+	basicrates = 0;
+	for (i = 0; i < nitems(sc->vaps); i++) {
+		struct rtwn_vap *rvp;
+		struct ieee80211vap *vap;
+		struct ieee80211_node *ni;
+		uint32_t rates;
+
+		rvp = sc->vaps[i];
+		if (rvp == NULL || rvp->curr_mode == R92C_MSR_NOLINK)
+			continue;
+
+		vap = &rvp->vap;
+		if (vap->iv_bss == NULL)
+			continue;
+
+		ni = ieee80211_ref_node(vap->iv_bss);
+		rtwn_get_rates(sc, &ni->ni_rates, NULL, &rates, NULL, 1);
+		basicrates |= rates;
+		ieee80211_free_node(ni);
+	}
+
+	if (basicrates == 0)
+		return;
+
+	/* XXX initial RTS rate? */
+	rtwn_set_basicrates(sc, basicrates);
+}
+
+static int
+rtwn_run(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211_node *ni;
+	uint8_t mode;
+	int error;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	error = 0;
+	ni = ieee80211_ref_node(vap->iv_bss);
+
+	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC ||
+	    ni->ni_chan == IEEE80211_CHAN_ANYC) {
+		error = EINVAL;
+		goto fail;
+	}
+
+	switch (vap->iv_opmode) {
+	case IEEE80211_M_STA:
+		mode = R92C_MSR_INFRA;
+		break;
+	case IEEE80211_M_IBSS:
+		mode = R92C_MSR_ADHOC;
+		break;
+	case IEEE80211_M_HOSTAP:
+		mode = R92C_MSR_AP;
+		break;
+	default:
+		KASSERT(0, ("undefined opmode %d\n", vap->iv_opmode));
+		error = EINVAL;
+		goto fail;
+	}
+
+	/* Set media status to 'Associated'. */
+	rtwn_set_mode(sc, mode, uvp->id);
+
+	/* Set AssocID. */
+	/* XXX multi-vap? */
+	rtwn_write_2(sc, R92C_BCN_PSR_RPT,
+	    0xc000 | IEEE80211_NODE_AID(ni));
+
+	/* Set BSSID. */
+	rtwn_set_bssid(sc, ni->ni_bssid, uvp->id);
+
+	/* Set beacon interval. */
+	rtwn_write_2(sc, R92C_BCN_INTERVAL(uvp->id), ni->ni_intval);
+
+	if (sc->vaps_running == sc->monvaps_running) {
+		/* Enable Rx of data frames. */
+		rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+
+		/* Flush all AC queues. */
+		rtwn_write_1(sc, R92C_TXPAUSE, 0);
+	}
+
+#ifndef RTWN_WITHOUT_UCODE
+	/* Upload (QoS) Null Data frame to firmware. */
+	/* Note: do this for port 0 only. */
+	if ((ic->ic_caps & IEEE80211_C_PMGT) != 0 &&
+	    vap->iv_opmode == IEEE80211_M_STA && uvp->id == 0) {
+		error = rtwn_tx_fwpkt_check(sc, vap);
+		if (error != 0)
+			goto fail;
+
+		/* Setup power management. */
+		/*
+		 * NB: it will be enabled immediately - delay it,
+		 * so 4-Way handshake will not be interrupted.
+		 */
+		callout_reset(&sc->sc_pwrmode_init, 5*hz,
+		    rtwn_pwrmode_init, sc);
+	}
+#endif
+
+	/* Enable TSF synchronization. */
+	rtwn_tsf_sync_enable(sc, vap);
+
+	if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
+	    vap->iv_opmode == IEEE80211_M_IBSS) {
+		error = rtwn_setup_beacon(sc, ni);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "unable to push beacon into the chip, "
+			    "error %d\n", error);
+			goto fail;
+		}
+	}
+
+	/* Set ACK preamble type. */
+	rtwn_set_ack_preamble(sc);
+
+	/* Set basic rates mask. */
+	rtwn_calc_basicrates(sc);
+
+#ifdef RTWN_TODO
+	rtwn_write_1(sc, R92C_SIFS_CCK + 1, 10);
+	rtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10);
+	rtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10);
+	rtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10);
+	rtwn_write_1(sc, R92C_R2T_SIFS + 1, 10);
+	rtwn_write_1(sc, R92C_T2T_SIFS + 1, 10);
+#endif
+
+	if (sc->vaps_running == sc->monvaps_running) {
+		/* Reset temperature calibration state machine. */
+		sc->sc_flags &= ~RTWN_TEMP_MEASURED;
+		sc->thcal_temp = sc->thermal_meter;
+
+		/* Start periodic calibration. */
+		callout_reset(&sc->sc_calib_to, 2*hz, rtwn_calib_to,
+		    sc);
+
+		if (sc->vaps_running == 0) {
+			/* Turn link LED on. */
+			rtwn_set_led(sc, RTWN_LED_LINK, 1);
+		}
+	}
+
+fail:
+	ieee80211_free_node(ni);
+
+	return (error);
+}
+
+#ifndef D4054
+static void
+rtwn_watchdog(void *arg)
+{
+	struct rtwn_softc *sc = arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	KASSERT(sc->sc_flags & RTWN_RUNNING, ("not running"));
+
+	if (sc->sc_tx_timer != 0 && --sc->sc_tx_timer == 0) {
+		ic_printf(ic, "device timeout\n");
+		ieee80211_restart_all(ic);
+		return;
+	}
+	callout_reset(&sc->sc_watchdog_to, hz, rtwn_watchdog, sc);
+}
+#endif
+
+static void
+rtwn_parent(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct ieee80211vap *vap;
+
+	if (ic->ic_nrunning > 0) {
+		if (rtwn_init(sc) != 0) {
+			IEEE80211_LOCK(ic);
+			TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
+				ieee80211_stop_locked(vap);
+			IEEE80211_UNLOCK(ic);
+		} else
+			ieee80211_start_all(ic);
+	} else
+		rtwn_stop(sc);
+}
+
+
+static int
+rtwn_llt_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data)
+{
+	int ntries, error;
+
+	error = rtwn_write_4(sc, R92C_LLT_INIT,
+	    SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) |
+	    SM(R92C_LLT_INIT_ADDR, addr) |
+	    SM(R92C_LLT_INIT_DATA, data));
+	if (error != 0)
+		return (error);
+	/* Wait for write operation to complete. */
+	for (ntries = 0; ntries < 20; ntries++) {
+		if (MS(rtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) ==
+		    R92C_LLT_INIT_OP_NO_ACTIVE)
+			return (0);
+		rtwn_delay(sc, 10);
+	}
+	return (ETIMEDOUT);
+}
+
+static int
+rtwn_llt_init(struct rtwn_softc *sc)
+{
+	int i, error;
+
+	/* Reserve pages [0; page_count]. */
+	for (i = 0; i < sc->page_count; i++) {
+		if ((error = rtwn_llt_write(sc, i, i + 1)) != 0)
+			return (error);
+	}
+	/* NB: 0xff indicates end-of-list. */
+	if ((error = rtwn_llt_write(sc, i, 0xff)) != 0)
+		return (error);
+	/*
+	 * Use pages [page_count + 1; pktbuf_count - 1]
+	 * as ring buffer.
+	 */
+	for (++i; i < sc->pktbuf_count - 1; i++) {
+		if ((error = rtwn_llt_write(sc, i, i + 1)) != 0)
+			return (error);
+	}
+	/* Make the last page point to the beginning of the ring buffer. */
+	error = rtwn_llt_write(sc, i, sc->page_count + 1);
+	return (error);
+}
+
+static int
+rtwn_dma_init(struct rtwn_softc *sc)
+{
+#define RTWN_CHK(res) do {	\
+	if (res != 0)		\
+		return (EIO);	\
+} while(0)
+	uint16_t reg;
+	uint8_t tx_boundary;
+	int error;
+
+	/* Initialize LLT table. */
+	error = rtwn_llt_init(sc);
+	if (error != 0)
+		return (error);
+
+	/* Set the number of pages for each queue. */
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+	    "%s: pages per queue: high %d, normal %d, low %d, public %d\n",
+	    __func__, sc->nhqpages, sc->nnqpages, sc->nlqpages,
+	    sc->npubqpages);
+
+	RTWN_CHK(rtwn_write_1(sc, R92C_RQPN_NPQ, sc->nnqpages));
+	RTWN_CHK(rtwn_write_4(sc, R92C_RQPN,
+	    /* Set number of pages for public queue. */
+	    SM(R92C_RQPN_PUBQ, sc->npubqpages) |
+	    /* Set number of pages for high priority queue. */
+	    SM(R92C_RQPN_HPQ, sc->nhqpages) |
+	    /* Set number of pages for low priority queue. */
+	    SM(R92C_RQPN_LPQ, sc->nlqpages) |
+	    /* Load values. */
+	    R92C_RQPN_LD));
+
+	/* Initialize TX buffer boundary. */
+	KASSERT(sc->page_count < 255 && sc->page_count > 0,
+	    ("page_count is %d\n", sc->page_count));
+	tx_boundary = sc->page_count + 1;
+	RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, tx_boundary));
+	RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, tx_boundary));
+	RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, tx_boundary));
+	RTWN_CHK(rtwn_write_1(sc, R92C_TRXFF_BNDY, tx_boundary));
+	RTWN_CHK(rtwn_write_1(sc, R92C_TDECTRL + 1, tx_boundary));
+
+	error = rtwn_init_bcnq1_boundary(sc);
+	if (error != 0)
+		return (error);
+
+	/* Set queue to USB pipe mapping. */
+	/* Note: PCIe devices are using some magic number here. */
+	reg = rtwn_get_qmap(sc);
+	RTWN_CHK(rtwn_setbits_2(sc, R92C_TRXDMA_CTRL,
+	    R92C_TRXDMA_CTRL_QMAP_M, reg));
+
+	/* Configure Tx/Rx DMA (PCIe). */
+	rtwn_set_desc_addr(sc);
+
+	/* Set Tx/Rx transfer page boundary. */
+	RTWN_CHK(rtwn_write_2(sc, R92C_TRXFF_BNDY + 2,
+	    sc->rx_dma_size - 1));
+
+	/* Set Tx/Rx transfer page size. */
+	rtwn_set_page_size(sc);
+
+	return (0);
+}
+
+static int
+rtwn_mac_init(struct rtwn_softc *sc)
+{
+	int i, error;
+
+	/* Write MAC initialization values. */
+	for (i = 0; i < sc->mac_size; i++) {
+		error = rtwn_write_1(sc, sc->mac_prog[i].reg,
+		    sc->mac_prog[i].val);
+		if (error != 0)
+			return (error);
+	}
+
+	return (0);
+}
+
+static void
+rtwn_mrr_init(struct rtwn_softc *sc)
+{
+	int i;
+
+	/* Drop rate index by 1 per retry. */
+	for (i = 0; i < R92C_DARFRC_SIZE; i++) {
+		rtwn_write_1(sc, R92C_DARFRC + i, i + 1);
+		rtwn_write_1(sc, R92C_RARFRC + i, i + 1);
+	}
+}
+
+static void
+rtwn_scan_start(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+
+	RTWN_LOCK(sc);
+	/* Pause beaconing. */
+	rtwn_setbits_1(sc, R92C_TXPAUSE, 0, R92C_TX_QUEUE_BCN);
+	/* Receive beacons / probe responses from any BSSID. */
+	if (sc->bcn_vaps == 0)
+		rtwn_set_rx_bssid_all(sc, 1);
+	RTWN_UNLOCK(sc);
+}
+
+static void
+rtwn_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
+{
+	struct rtwn_softc *sc = ss->ss_ic->ic_softc;
+
+	/* Make link LED blink during scan. */
+	RTWN_LOCK(sc);
+	rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink);
+	RTWN_UNLOCK(sc);
+
+	sc->sc_scan_curchan(ss, maxdwell);
+}
+
+static void
+rtwn_scan_end(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+
+	RTWN_LOCK(sc);
+	/* Restore limitations. */
+	if (ic->ic_promisc == 0 && sc->bcn_vaps == 0)
+		rtwn_set_rx_bssid_all(sc, 0);
+
+	/* Restore LED state. */
+	rtwn_set_led(sc, RTWN_LED_LINK, (sc->vaps_running != 0));
+
+	/* Restore basic rates mask. */
+	rtwn_calc_basicrates(sc);
+
+	/* Resume beaconing. */
+	rtwn_setbits_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_BCN, 0);
+	RTWN_UNLOCK(sc);
+}
+
+static void
+rtwn_getradiocaps(struct ieee80211com *ic,
+    int maxchans, int *nchans, struct ieee80211_channel chans[])
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	uint8_t bands[IEEE80211_MODE_BYTES];
+	int i;
+
+	memset(bands, 0, sizeof(bands));
+	setbit(bands, IEEE80211_MODE_11B);
+	setbit(bands, IEEE80211_MODE_11G);
+	setbit(bands, IEEE80211_MODE_11NG);
+	ieee80211_add_channel_list_2ghz(chans, maxchans, nchans,
+	    rtwn_chan_2ghz, nitems(rtwn_chan_2ghz), bands,
+	    !!(ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40));
+
+	/* XXX workaround add_channel_list() limitations */
+	setbit(bands, IEEE80211_MODE_11A);
+	setbit(bands, IEEE80211_MODE_11NA);
+	for (i = 0; i < nitems(sc->chan_num_5ghz); i++) {
+		if (sc->chan_num_5ghz[i] == 0)
+			continue;
+
+		ieee80211_add_channel_list_5ghz(chans, maxchans, nchans,
+		    sc->chan_list_5ghz[i], sc->chan_num_5ghz[i], bands,
+		    !!(ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40));
+	}
+}
+
+static void
+rtwn_update_chw(struct ieee80211com *ic)
+{
+}
+
+static void
+rtwn_set_channel(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct ieee80211_channel *c = ic->ic_curchan;
+
+	RTWN_LOCK(sc);
+	rtwn_set_chan(sc, c);
+	sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq);
+	sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags);
+	sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq);
+	sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags);
+	RTWN_UNLOCK(sc);
+}
+
+static int
+rtwn_wme_update(struct ieee80211com *ic)
+{
+	struct ieee80211_channel *c = ic->ic_curchan;
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct wmeParams *wmep = sc->cap_wmeParams;
+	uint8_t aifs, acm, slottime;
+	int ac;
+
+	/* Prevent possible races. */
+	IEEE80211_LOCK(ic);	/* XXX */
+	RTWN_LOCK(sc);
+	memcpy(wmep, ic->ic_wme.wme_chanParams.cap_wmeParams,
+	    sizeof(sc->cap_wmeParams));
+	RTWN_UNLOCK(sc);
+	IEEE80211_UNLOCK(ic);
+
+	acm = 0;
+	slottime = IEEE80211_GET_SLOTTIME(ic);
+
+	RTWN_LOCK(sc);
+	for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) {
+		/* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */
+		aifs = wmep[ac].wmep_aifsn * slottime +
+		    (IEEE80211_IS_CHAN_5GHZ(c) ?
+			IEEE80211_DUR_OFDM_SIFS : IEEE80211_DUR_SIFS);
+		rtwn_write_4(sc, wme2reg[ac],
+		    SM(R92C_EDCA_PARAM_TXOP, wmep[ac].wmep_txopLimit) |
+		    SM(R92C_EDCA_PARAM_ECWMIN, wmep[ac].wmep_logcwmin) |
+		    SM(R92C_EDCA_PARAM_ECWMAX, wmep[ac].wmep_logcwmax) |
+		    SM(R92C_EDCA_PARAM_AIFS, aifs));
+		if (ac != WME_AC_BE)
+			acm |= wmep[ac].wmep_acm << ac;
+	}
+
+	if (acm != 0)
+		acm |= R92C_ACMHWCTRL_EN;
+	rtwn_setbits_1(sc, R92C_ACMHWCTRL, R92C_ACMHWCTRL_ACM_MASK, acm);
+	RTWN_UNLOCK(sc);
+
+	return 0;
+}
+
+static void
+rtwn_update_slot(struct ieee80211com *ic)
+{
+	rtwn_cmd_sleepable(ic->ic_softc, NULL, 0, rtwn_update_slot_cb);
+}
+
+static void
+rtwn_update_slot_cb(struct rtwn_softc *sc, union sec_param *data)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint8_t slottime;
+
+	slottime = IEEE80211_GET_SLOTTIME(ic);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: setting slot time to %uus\n",
+	    __func__, slottime);
+
+	rtwn_write_1(sc, R92C_SLOT, slottime);
+	rtwn_update_aifs(sc, slottime);
+}
+
+static void
+rtwn_update_aifs(struct rtwn_softc *sc, uint8_t slottime)
+{
+	struct ieee80211_channel *c = sc->sc_ic.ic_curchan;
+	const struct wmeParams *wmep = sc->cap_wmeParams;
+	uint8_t aifs, ac;
+
+	for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) {
+		/* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */
+		aifs = wmep[ac].wmep_aifsn * slottime +
+		    (IEEE80211_IS_CHAN_5GHZ(c) ?
+			IEEE80211_DUR_OFDM_SIFS : IEEE80211_DUR_SIFS);
+		rtwn_write_1(sc, wme2reg[ac], aifs);
+	}
+}
+
+static void
+rtwn_update_promisc(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+
+	RTWN_LOCK(sc);
+	if (sc->sc_flags & RTWN_RUNNING)
+		rtwn_set_promisc(sc);
+	RTWN_UNLOCK(sc);
+}
+
+static void
+rtwn_update_mcast(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+
+	RTWN_LOCK(sc);
+	if (sc->sc_flags & RTWN_RUNNING)
+		rtwn_set_multi(sc);
+	RTWN_UNLOCK(sc);
+}
+
+static int
+rtwn_set_bssid(struct rtwn_softc *sc, const uint8_t *bssid, int id)
+{
+	int error;
+
+	error = rtwn_write_4(sc, R92C_BSSID(id), le32dec(&bssid[0]));
+	if (error != 0)
+		return (error);
+	error = rtwn_write_2(sc, R92C_BSSID(id) + 4, le16dec(&bssid[4]));
+
+	return (error);
+}
+
+static int
+rtwn_set_macaddr(struct rtwn_softc *sc, const uint8_t *addr, int id)
+{
+	int error;
+
+	error = rtwn_write_4(sc, R92C_MACID(id), le32dec(&addr[0]));
+	if (error != 0)
+		return (error);
+	error = rtwn_write_2(sc, R92C_MACID(id) + 4, le16dec(&addr[4]));
+
+	return (error);
+}
+
+static struct ieee80211_node *
+rtwn_node_alloc(struct ieee80211vap *vap,
+    const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	struct rtwn_node *un;
+
+	un = malloc(sizeof (struct rtwn_node), M_80211_NODE,
+	    M_NOWAIT | M_ZERO);
+
+	if (un == NULL)
+		return NULL;
+
+	un->id = RTWN_MACID_UNDEFINED;
+	un->avg_pwdb = -1;
+
+	return &un->ni;
+}
+
+static void
+rtwn_newassoc(struct ieee80211_node *ni, int isnew)
+{
+	struct rtwn_softc *sc = ni->ni_ic->ic_softc;
+	struct rtwn_node *un = RTWN_NODE(ni);
+	int id;
+
+	if (!isnew)
+		return;
+
+	RTWN_NT_LOCK(sc);
+	for (id = 0; id <= sc->macid_limit; id++) {
+		if (id != RTWN_MACID_BC && sc->node_list[id] == NULL) {
+			un->id = id;
+			sc->node_list[id] = ni;
+			break;
+		}
+	}
+	RTWN_NT_UNLOCK(sc);
+
+	if (id > sc->macid_limit) {
+		device_printf(sc->sc_dev, "%s: node table is full\n",
+		    __func__);
+		return;
+	}
+
+#ifndef RTWN_WITHOUT_UCODE
+	/* Notify firmware. */
+	id |= RTWN_MACID_VALID;
+	rtwn_cmd_sleepable(sc, &id, sizeof(id), rtwn_set_media_status);
+#endif
+}
+
+static void
+rtwn_node_free(struct ieee80211_node *ni)
+{
+	struct rtwn_softc *sc = ni->ni_ic->ic_softc;
+	struct rtwn_node *un = RTWN_NODE(ni);
+
+	RTWN_NT_LOCK(sc);
+	if (un->id != RTWN_MACID_UNDEFINED) {
+		sc->node_list[un->id] = NULL;
+#ifndef RTWN_WITHOUT_UCODE
+		rtwn_cmd_sleepable(sc, &un->id, sizeof(un->id),
+		    rtwn_set_media_status);
+#endif
+	}
+	RTWN_NT_UNLOCK(sc);
+
+	sc->sc_node_free(ni);
+}
+
+static void
+rtwn_init_beacon_reg(struct rtwn_softc *sc)
+{
+	rtwn_write_1(sc, R92C_BCN_CTRL(0), R92C_BCN_CTRL_DIS_TSF_UDT0);
+	rtwn_write_1(sc, R92C_BCN_CTRL(1), R92C_BCN_CTRL_DIS_TSF_UDT0);
+	rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404);
+	rtwn_write_1(sc, R92C_DRVERLYINT, 0x05);
+	rtwn_write_1(sc, R92C_BCNDMATIM, 0x02);
+	rtwn_write_2(sc, R92C_BCNTCFG, 0x660f);
+}
+
+static int
+rtwn_init(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	int i, error;
+
+	RTWN_LOCK(sc);
+	if (sc->sc_flags & RTWN_RUNNING) {
+		RTWN_UNLOCK(sc);
+		return (0);
+	}
+	sc->sc_flags |= RTWN_STARTED;
+
+	/* Power on adapter. */
+	error = rtwn_power_on(sc);
+	if (error != 0)
+		goto fail;
+
+#ifndef RTWN_WITHOUT_UCODE
+	/* Load 8051 microcode. */
+	error = rtwn_load_firmware(sc);
+	if (error == 0)
+		sc->sc_flags |= RTWN_FW_LOADED;
+
+	/* Init firmware commands ring. */
+	sc->fwcur = 0;
+#endif
+
+	/* Initialize MAC block. */
+	error = rtwn_mac_init(sc);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: error while initializing MAC block\n", __func__);
+		goto fail;
+	}
+
+	/* Initialize DMA. */
+	error = rtwn_dma_init(sc);
+	if (error != 0)
+		goto fail;
+
+	/* Drop incorrect TX (USB). */
+	rtwn_drop_incorrect_tx(sc);
+
+	/* Set info size in Rx descriptors (in 64-bit words). */
+	rtwn_write_1(sc, R92C_RX_DRVINFO_SZ, R92C_RX_DRVINFO_SZ_DEF);
+
+	/* Init interrupts. */
+	rtwn_init_intr(sc);
+
+	for (i = 0; i < nitems(sc->vaps); i++) {
+		struct rtwn_vap *uvp = sc->vaps[i];
+
+		/* Set initial network type. */
+		rtwn_set_mode(sc, R92C_MSR_NOLINK, i);
+
+		if (uvp == NULL)
+			continue;
+
+		/* Set MAC address. */
+		error = rtwn_set_macaddr(sc, uvp->vap.iv_myaddr, uvp->id);
+		if (error != 0)
+			goto fail;
+	}
+
+	/* Initialize Rx filter. */
+	rtwn_rxfilter_init(sc);
+
+	/* Set short/long retry limits. */
+	rtwn_write_2(sc, R92C_RL,
+	    SM(R92C_RL_SRL, 0x30) | SM(R92C_RL_LRL, 0x30));
+
+	/* Initialize EDCA parameters. */
+	rtwn_init_edca(sc);
+
+	rtwn_setbits_1(sc, R92C_FWHW_TXQ_CTRL, 0,
+	    R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW);
+	/* Set ACK timeout. */
+	rtwn_write_1(sc, R92C_ACKTO, sc->ackto);
+
+	/* Setup aggregation. */
+	/* Tx aggregation. */
+	rtwn_init_tx_agg(sc);
+	rtwn_init_rx_agg(sc);
+
+	/* Initialize beacon parameters. */
+	rtwn_init_beacon_reg(sc);
+
+	/* Init A-MPDU parameters. */
+	rtwn_init_ampdu(sc);
+
+	/* Init MACTXEN / MACRXEN after setting RxFF boundary. */
+	rtwn_setbits_1(sc, R92C_CR, 0, R92C_CR_MACTXEN | R92C_CR_MACRXEN);
+
+	/* Initialize BB/RF blocks. */
+	rtwn_init_bb(sc);
+	rtwn_init_rf(sc);
+
+	/* Initialize wireless band. */
+	rtwn_set_chan(sc, ic->ic_curchan);
+
+	/* Clear per-station keys table. */
+	rtwn_init_cam(sc);
+
+	/* Enable decryption / encryption. */
+	rtwn_init_seccfg(sc);
+
+	/* Install static keys (if any). */
+	for (i = 0; i < nitems(sc->vaps); i++) {
+		if (sc->vaps[i] != NULL) {
+			error = rtwn_init_static_keys(sc, sc->vaps[i]);
+			if (error != 0)
+				goto fail;
+		}
+	}
+
+	/* Initialize antenna selection. */
+	rtwn_init_antsel(sc);
+
+	/* Enable hardware sequence numbering. */
+	rtwn_write_1(sc, R92C_HWSEQ_CTRL, R92C_TX_QUEUE_ALL);
+
+	/* Disable BAR. */
+	rtwn_write_4(sc, R92C_BAR_MODE_CTRL, 0x0201ffff);
+
+	/* NAV limit. */
+	rtwn_write_1(sc, R92C_NAV_UPPER, 0);
+
+	/* Initialize GPIO setting. */
+	rtwn_setbits_1(sc, R92C_GPIO_MUXCFG, R92C_GPIO_MUXCFG_ENBT, 0);
+
+	/* Initialize MRR. */
+	rtwn_mrr_init(sc);
+
+	/* Device-specific post initialization. */
+	rtwn_post_init(sc);
+
+	rtwn_start_xfers(sc);
+
+#ifndef D4054
+	callout_reset(&sc->sc_watchdog_to, hz, rtwn_watchdog, sc);
+#endif
+
+	sc->sc_flags |= RTWN_RUNNING;
+fail:
+	RTWN_UNLOCK(sc);
+
+	return (error);
+}
+
+static void
+rtwn_stop(struct rtwn_softc *sc)
+{
+
+	RTWN_LOCK(sc);
+	if (!(sc->sc_flags & RTWN_STARTED)) {
+		RTWN_UNLOCK(sc);
+		return;
+	}
+
+#ifndef D4054
+	callout_stop(&sc->sc_watchdog_to);
+	sc->sc_tx_timer = 0;
+#endif
+	sc->sc_flags &= ~(RTWN_STARTED | RTWN_RUNNING | RTWN_FW_LOADED);
+	sc->sc_flags &= ~RTWN_TEMP_MEASURED;
+	sc->fwver = 0;
+	sc->thcal_temp = 0;
+	sc->cur_bcnq_id = RTWN_VAP_ID_INVALID;
+
+#ifdef D4054
+	ieee80211_tx_watchdog_stop(&sc->sc_ic);
+#endif
+
+	rtwn_abort_xfers(sc);
+	rtwn_drain_mbufq(sc);
+	rtwn_power_off(sc);
+	rtwn_reset_lists(sc, NULL);
+	RTWN_UNLOCK(sc);
+}
+
+MODULE_VERSION(rtwn, 2);
+MODULE_DEPEND(rtwn, wlan, 1, 1, 1);
+#ifndef RTWN_WITHOUT_UCODE
+MODULE_DEPEND(rtwn, firmware, 1, 1, 1);
+#endif
Index: freebsd/sys/dev/rtwn/if_rtwn_beacon.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,271 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_beacon.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_tx.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+
+static void
+rtwn_reset_beacon_valid(struct rtwn_softc *sc, int id)
+{
+
+	KASSERT (id == 0 || id == 1, ("wrong port id %d\n", id));
+
+	/* XXX cannot be cleared on RTL8188CE */
+	rtwn_setbits_1_shift(sc, sc->bcn_status_reg[id],
+	    R92C_TDECTRL_BCN_VALID, 0, 2);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON,
+	    "%s: 'beacon valid' bit for vap %d was unset\n",
+	    __func__, id);
+}
+
+static int
+rtwn_check_beacon_valid(struct rtwn_softc *sc, int id)
+{
+	uint16_t reg;
+	int ntries;
+
+	if (id == RTWN_VAP_ID_INVALID)
+		return (0);
+
+	reg = sc->bcn_status_reg[id];
+	for (ntries = 0; ntries < 10; ntries++) {
+		if (rtwn_read_4(sc, reg) & R92C_TDECTRL_BCN_VALID) {
+			RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON,
+			    "%s: beacon for vap %d was recognized\n",
+			    __func__, id);
+			break;
+		}
+		rtwn_delay(sc, sc->bcn_check_interval);
+	}
+	if (ntries == 10)
+		return (ETIMEDOUT);
+
+	return (0);
+}
+
+void
+rtwn_switch_bcnq(struct rtwn_softc *sc, int id)
+{
+
+	if (sc->cur_bcnq_id != id) {
+		/* Wait until any previous transmit completes. */
+		(void) rtwn_check_beacon_valid(sc, sc->cur_bcnq_id);
+
+		/* Change current port. */
+		rtwn_beacon_select(sc, id);
+		sc->cur_bcnq_id = id;
+	}
+
+	/* Reset 'beacon valid' bit. */
+	rtwn_reset_beacon_valid(sc, id);
+}
+
+int
+rtwn_setup_beacon(struct rtwn_softc *sc, struct ieee80211_node *ni)
+{
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct mbuf *m;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	if (ni->ni_chan == IEEE80211_CHAN_ANYC)
+		return (EINVAL);
+
+	m = ieee80211_beacon_alloc(ni);
+	if (m == NULL) {
+		device_printf(sc->sc_dev,
+		    "%s: could not allocate beacon frame\n", __func__);
+		return (ENOMEM);
+	}
+
+	if (uvp->bcn_mbuf != NULL) {
+		rtwn_beacon_unload(sc, uvp->id);
+		m_freem(uvp->bcn_mbuf);
+	}
+
+	uvp->bcn_mbuf = m;
+
+	rtwn_beacon_set_rate(sc, &uvp->bcn_desc.txd[0],
+	    IEEE80211_IS_CHAN_5GHZ(ni->ni_chan));
+
+	return (rtwn_tx_beacon_check(sc, uvp));
+}
+
+/*
+ * Push a beacon frame into the chip. Beacon will
+ * be repeated by the chip every R92C_BCN_INTERVAL.
+ */
+static int
+rtwn_tx_beacon(struct rtwn_softc *sc, struct rtwn_vap *uvp)
+{
+	int error;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON,
+	    "%s: sending beacon for vap %d\n", __func__, uvp->id);
+
+	error = rtwn_tx_start(sc, NULL, uvp->bcn_mbuf, &uvp->bcn_desc.txd[0],
+	    IEEE80211_FC0_TYPE_MGT, uvp->id);
+
+	return (error);
+}
+
+void
+rtwn_update_beacon(struct ieee80211vap *vap, int item)
+{
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
+	struct ieee80211_node *ni = vap->iv_bss;
+	int mcast = 0;
+
+	RTWN_LOCK(sc);
+	if (uvp->bcn_mbuf == NULL) {
+		uvp->bcn_mbuf = ieee80211_beacon_alloc(ni);
+		if (uvp->bcn_mbuf == NULL) {
+			device_printf(sc->sc_dev,
+			    "%s: could not allocate beacon frame\n", __func__);
+			RTWN_UNLOCK(sc);
+			return;
+		}
+	}
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON,
+	    "%s: vap id %d, iv_csa_count %d, ic_csa_count %d, item %d\n",
+	    __func__, uvp->id, vap->iv_csa_count, ic->ic_csa_count, item);
+
+	switch (item) {
+	case IEEE80211_BEACON_CSA:
+		if (vap->iv_csa_count != ic->ic_csa_count) {
+			/*
+			 * XXX two APs with different beacon intervals
+			 * are not handled properly.
+			 */
+			/* XXX check TBTT? */
+			taskqueue_enqueue_timeout(taskqueue_thread,
+			    &uvp->tx_beacon_csa,
+			    msecs_to_ticks(ni->ni_intval));
+		}
+		break;
+	case IEEE80211_BEACON_TIM:
+		mcast = 1;	/* XXX */
+		break;
+	default:
+		break;
+	}
+
+	setbit(bo->bo_flags, item);
+
+	rtwn_beacon_update_begin(sc, vap);
+	RTWN_UNLOCK(sc);
+
+	ieee80211_beacon_update(ni, uvp->bcn_mbuf, mcast);
+
+	/* XXX clear manually */
+	clrbit(bo->bo_flags, IEEE80211_BEACON_CSA);
+
+	RTWN_LOCK(sc);
+	rtwn_tx_beacon(sc, uvp);
+	rtwn_beacon_update_end(sc, vap);
+	RTWN_UNLOCK(sc);
+}
+
+void
+rtwn_tx_beacon_csa(void *arg, int npending __unused)
+{
+	struct ieee80211vap *vap = arg;
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct rtwn_vap *rvp = RTWN_VAP(vap);
+
+	KASSERT (rvp->id == 0 || rvp->id == 1,
+	    ("wrong port id %d\n", rvp->id));
+
+	IEEE80211_LOCK(ic);
+	if (ic->ic_flags & IEEE80211_F_CSAPENDING) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON,
+		    "%s: vap id %d, iv_csa_count %d, ic_csa_count %d\n",
+		    __func__, rvp->id, vap->iv_csa_count, ic->ic_csa_count);
+
+		rtwn_update_beacon(vap, IEEE80211_BEACON_CSA);
+	}
+	IEEE80211_UNLOCK(ic);
+
+	(void) rvp;
+}
+
+int
+rtwn_tx_beacon_check(struct rtwn_softc *sc, struct rtwn_vap *uvp)
+{
+	int ntries, error;
+
+	for (ntries = 0; ntries < 5; ntries++) {
+		rtwn_reset_beacon_valid(sc, uvp->id);
+
+		error = rtwn_tx_beacon(sc, uvp);
+		if (error != 0)
+			continue;
+
+		error = rtwn_check_beacon_valid(sc, uvp->id);
+		if (error == 0)
+			break;
+	}
+	if (ntries == 5) {
+		device_printf(sc->sc_dev,
+		    "%s: cannot push beacon into chip, error %d!\n",
+		    __func__, error);
+		return (error);
+	}
+
+	return (0);
+}
Index: freebsd/sys/dev/rtwn/if_rtwn_beacon.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_beacon.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_beacon.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,28 @@
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_BEACON_H
+#define IF_RTWN_BEACON_H
+
+void	rtwn_switch_bcnq(struct rtwn_softc *, int);
+int	rtwn_setup_beacon(struct rtwn_softc *, struct ieee80211_node *);
+void	rtwn_update_beacon(struct ieee80211vap *, int);
+void	rtwn_tx_beacon_csa(void *arg, int);
+int	rtwn_tx_beacon_check(struct rtwn_softc *, struct rtwn_vap *);
+
+#endif	/* IF_RTWN_BEACON_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_calib.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,130 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_calib.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_task.h>
+
+
+static void
+rtwn_temp_calib(struct rtwn_softc *sc)
+{
+	uint8_t temp;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	if (!(sc->sc_flags & RTWN_TEMP_MEASURED)) {
+		/* Start measuring temperature. */
+		RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP,
+		    "%s: start measuring temperature\n", __func__);
+		rtwn_temp_measure(sc);
+		sc->sc_flags |= RTWN_TEMP_MEASURED;
+		return;
+	}
+	sc->sc_flags &= ~RTWN_TEMP_MEASURED;
+
+	/* Read measured temperature. */
+	temp = rtwn_temp_read(sc);
+	if (temp == 0) {	/* Read failed, skip. */
+		RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP,
+		    "%s: temperature read failed, skipping\n", __func__);
+		return;
+	}
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP,
+	    "temperature: previous %u, current %u\n",
+	    sc->thcal_temp, temp);
+
+	/*
+	 * Redo LC/IQ calibration if temperature changed significantly since
+	 * last calibration.
+	 */
+	if (sc->thcal_temp == 0xff) {
+		/* efuse value is absent; do LCK at initial status. */
+		rtwn_lc_calib(sc);
+
+		sc->thcal_temp = temp;
+	} else if (abs(temp - sc->thcal_temp) > sc->temp_delta) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP,
+		    "%s: LC/IQ calib triggered by temp: %u -> %u\n",
+		    __func__, sc->thcal_temp, temp);
+
+		rtwn_lc_calib(sc);
+		rtwn_iq_calib(sc);
+
+		/* Record temperature of last calibration. */
+		sc->thcal_temp = temp;
+	}
+}
+
+static void
+rtwn_calib_cb(struct rtwn_softc *sc, union sec_param *data)
+{
+	/* Do temperature compensation. */
+	rtwn_temp_calib(sc);
+
+#ifndef RTWN_WITHOUT_UCODE
+	if (sc->sc_ratectl == RTWN_RATECTL_FW) {
+		/* Refresh per-node RSSI. */
+		rtwn_set_rssi(sc);
+	}
+#endif
+
+	if (sc->vaps_running > sc->monvaps_running)
+		callout_reset(&sc->sc_calib_to, 2*hz, rtwn_calib_to, sc);
+}
+
+void
+rtwn_calib_to(void *arg)
+{
+	struct rtwn_softc *sc = arg;
+
+	/* Do it in a process context. */
+	rtwn_cmd_sleepable(sc, NULL, 0, rtwn_calib_cb);
+}
Index: freebsd/sys/dev/rtwn/if_rtwn_calib.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_calib.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_calib.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,24 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_CALIB_H
+#define IF_RTWN_CALIB_H
+
+void	rtwn_calib_to(void *);
+
+#endif	/* IF_RTWN_CALIB_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_cam.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_cam.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_cam.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,366 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_cam.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_task.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+
+void
+rtwn_init_cam(struct rtwn_softc *sc)
+{
+	/* Invalidate all CAM entries. */
+	rtwn_write_4(sc, R92C_CAMCMD,
+	    R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR);
+}
+
+static int
+rtwn_cam_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data)
+{
+	int error;
+
+	error = rtwn_write_4(sc, R92C_CAMWRITE, data);
+	if (error != 0)
+		return (error);
+	error = rtwn_write_4(sc, R92C_CAMCMD,
+	    R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE |
+	    SM(R92C_CAMCMD_ADDR, addr));
+
+	return (error);
+}
+
+void
+rtwn_init_seccfg(struct rtwn_softc *sc)
+{
+	uint16_t seccfg;
+
+	/* Select decryption / encryption flags. */
+	seccfg = 0;
+	switch (sc->sc_hwcrypto) {
+	case RTWN_CRYPTO_SW:
+		break;	/* nothing to do */
+	case RTWN_CRYPTO_PAIR:
+		/* NB: TXUCKEY_DEF / RXUCKEY_DEF are required for RTL8192C */
+		seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF |
+		    R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA |
+		    R92C_SECCFG_MC_SRCH_DIS;
+		break;
+	case RTWN_CRYPTO_FULL:
+		seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF |
+		    R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA |
+		    R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF;
+		break;
+	default:
+		KASSERT(0, ("%s: case %d was not handled\n", __func__,
+		    sc->sc_hwcrypto));
+		break;
+	}
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, "%s: seccfg %04X, hwcrypto %d\n",
+	    __func__, seccfg, sc->sc_hwcrypto);
+
+	rtwn_write_2(sc, R92C_SECCFG, seccfg);
+}
+
+int
+rtwn_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
+    ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
+{
+	struct rtwn_softc *sc = vap->iv_ic->ic_softc;
+	int i, start;
+
+	if (&vap->iv_nw_keys[0] <= k &&
+	    k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) {
+#if __FreeBSD_version > 1200018
+		*keyix = ieee80211_crypto_get_key_wepidx(vap, k);
+#else
+		*keyix = k - vap->iv_nw_keys;
+#endif
+		if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL)
+			k->wk_flags |= IEEE80211_KEY_SWCRYPT;
+		else {
+			RTWN_LOCK(sc);
+			if (isset(sc->keys_bmap, *keyix)) {
+				device_printf(sc->sc_dev,
+				    "%s: group key slot %d is already used!\n",
+				    __func__, *keyix);
+				/* XXX recover? */
+				RTWN_UNLOCK(sc);
+				return (0);
+			}
+
+			setbit(sc->keys_bmap, *keyix);
+			RTWN_UNLOCK(sc);
+		}
+
+		goto end;
+	}
+
+	start = sc->cam_entry_limit;
+	switch (sc->sc_hwcrypto) {
+	case RTWN_CRYPTO_SW:
+		k->wk_flags |= IEEE80211_KEY_SWCRYPT;
+		*keyix = 0;
+		goto end;
+	case RTWN_CRYPTO_PAIR:
+		/* all slots for pairwise keys. */
+		start = 0;
+		RTWN_LOCK(sc);
+		if (sc->sc_flags & RTWN_FLAG_CAM_FIXED)
+			start = 4;
+		RTWN_UNLOCK(sc);
+		break;
+	case RTWN_CRYPTO_FULL:
+		/* first 4 - for group keys, others for pairwise. */
+		start = 4;
+		break;
+	default:
+		KASSERT(0, ("%s: case %d was not handled!\n",
+		    __func__, sc->sc_hwcrypto));
+		break;
+	}
+
+	RTWN_LOCK(sc);
+	for (i = start; i < sc->cam_entry_limit; i++) {
+		if (isclr(sc->keys_bmap, i)) {
+			setbit(sc->keys_bmap, i);
+			*keyix = i;
+			break;
+		}
+	}
+	RTWN_UNLOCK(sc);
+	if (i == sc->cam_entry_limit) {
+#if __FreeBSD_version > 1200008
+		/* XXX check and remove keys with the same MAC address */
+		k->wk_flags |= IEEE80211_KEY_SWCRYPT;
+		*keyix = 0;
+#else
+		device_printf(sc->sc_dev,
+		    "%s: no free space in the key table\n", __func__);
+		return (0);
+#endif
+	}
+
+end:
+	*rxkeyix = *keyix;
+	return (1);
+}
+
+static int
+rtwn_key_set_cb0(struct rtwn_softc *sc, const struct ieee80211_key *k)
+{
+	uint8_t algo, keyid;
+	int i, error;
+
+	if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL &&
+	    k->wk_keyix < IEEE80211_WEP_NKID)
+		keyid = k->wk_keyix;
+	else
+		keyid = 0;
+
+	/* Map net80211 cipher to HW crypto algorithm. */
+	switch (k->wk_cipher->ic_cipher) {
+	case IEEE80211_CIPHER_WEP:
+		if (k->wk_keylen < 8)
+			algo = R92C_CAM_ALGO_WEP40;
+		else
+			algo = R92C_CAM_ALGO_WEP104;
+		break;
+	case IEEE80211_CIPHER_TKIP:
+		algo = R92C_CAM_ALGO_TKIP;
+		break;
+	case IEEE80211_CIPHER_AES_CCM:
+		algo = R92C_CAM_ALGO_AES;
+		break;
+	default:
+		device_printf(sc->sc_dev, "%s: unknown cipher %u\n",
+		    __func__, k->wk_cipher->ic_cipher);
+		return (EINVAL);
+	}
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_KEY,
+	    "%s: keyix %u, keyid %u, algo %u/%u, flags %04X, len %u, "
+	    "macaddr %s\n", __func__, k->wk_keyix, keyid,
+	    k->wk_cipher->ic_cipher, algo, k->wk_flags, k->wk_keylen,
+	    ether_sprintf(k->wk_macaddr));
+
+	/* Clear high bits. */
+	rtwn_cam_write(sc, R92C_CAM_CTL6(k->wk_keyix), 0);
+	rtwn_cam_write(sc, R92C_CAM_CTL7(k->wk_keyix), 0);
+
+	/* Write key. */
+	for (i = 0; i < 4; i++) {
+		error = rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i),
+		    le32dec(&k->wk_key[i * 4]));
+		if (error != 0)
+			goto fail;
+	}
+
+	/* Write CTL0 last since that will validate the CAM entry. */
+	error = rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix),
+	    le32dec(&k->wk_macaddr[2]));
+	if (error != 0)
+		goto fail;
+	error = rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix),
+	    SM(R92C_CAM_ALGO, algo) |
+	    SM(R92C_CAM_KEYID, keyid) |
+	    SM(R92C_CAM_MACLO, le16dec(&k->wk_macaddr[0])) |
+	    R92C_CAM_VALID);
+	if (error != 0)
+		goto fail;
+
+	return (0);
+
+fail:
+	device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error);
+	return (error);
+}
+
+static void
+rtwn_key_set_cb(struct rtwn_softc *sc, union sec_param *data)
+{
+	const struct ieee80211_key *k = &data->key;
+
+	(void) rtwn_key_set_cb0(sc, k);
+}
+
+int
+rtwn_init_static_keys(struct rtwn_softc *sc, struct rtwn_vap *rvp)
+{
+	int i, error;
+
+	if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL)
+		return (0);		/* nothing to do */
+
+	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+		const struct ieee80211_key *k = rvp->keys[i];
+		if (k != NULL) {
+			error = rtwn_key_set_cb0(sc, k);
+			if (error != 0)
+				return (error);
+		}
+	}
+
+	return (0);
+}
+
+static void
+rtwn_key_del_cb(struct rtwn_softc *sc, union sec_param *data)
+{
+	struct ieee80211_key *k = &data->key;
+	int i;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_KEY,
+	    "%s: keyix %u, flags %04X, macaddr %s\n", __func__,
+	    k->wk_keyix, k->wk_flags, ether_sprintf(k->wk_macaddr));
+
+	rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 0);
+	rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 0);
+
+	/* Clear key. */
+	for (i = 0; i < 4; i++)
+		rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 0);
+	clrbit(sc->keys_bmap, k->wk_keyix);
+}
+
+static int
+rtwn_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k,
+    int set)
+{
+	struct rtwn_softc *sc = vap->iv_ic->ic_softc;
+
+	if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
+		/* Not for us. */
+		return (1);
+	}
+
+	if (&vap->iv_nw_keys[0] <= k &&
+	    k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) {
+#if __FreeBSD_version <= 1200008
+		struct ieee80211_key *k1 = &vap->iv_nw_keys[k->wk_keyix];
+
+		if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) {
+			k1->wk_flags |= IEEE80211_KEY_SWCRYPT;
+			return (k->wk_cipher->ic_setkey(k1));
+		} else {
+#else
+		if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL) {
+#endif
+			struct rtwn_vap *rvp = RTWN_VAP(vap);
+
+			RTWN_LOCK(sc);
+			rvp->keys[k->wk_keyix] = (set ? k : NULL);
+			if ((sc->sc_flags & RTWN_RUNNING) == 0) {
+				if (!set)
+					clrbit(sc->keys_bmap, k->wk_keyix);
+				RTWN_UNLOCK(sc);
+				return (1);
+			}
+			RTWN_UNLOCK(sc);
+		}
+	}
+
+	return (!rtwn_cmd_sleepable(sc, k, sizeof(*k),
+	    set ? rtwn_key_set_cb : rtwn_key_del_cb));
+}
+
+int
+rtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
+{
+	return (rtwn_process_key(vap, k, 1));
+}
+
+int
+rtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
+{
+	return (rtwn_process_key(vap, k, 0));
+}
Index: freebsd/sys/dev/rtwn/if_rtwn_cam.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_cam.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_cam.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_CAM_H
+#define IF_RTWN_CAM_H
+
+void	rtwn_init_cam(struct rtwn_softc *);
+void	rtwn_init_seccfg(struct rtwn_softc *);
+int	rtwn_key_alloc(struct ieee80211vap *, struct ieee80211_key *,
+	    ieee80211_keyix *, ieee80211_keyix *);
+int	rtwn_key_set(struct ieee80211vap *, const struct ieee80211_key *);
+int	rtwn_init_static_keys(struct rtwn_softc *, struct rtwn_vap *);
+int	rtwn_key_delete(struct ieee80211vap *, const struct ieee80211_key *);
+
+#endif	/* IF_RTWN_CAM_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_debug.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_debug.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_debug.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,60 @@
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_DEBUG_H
+#define IF_RTWN_DEBUG_H
+
+#include <rtems/bsd/local/opt_rtwn.h>
+
+#ifdef RTWN_DEBUG
+enum {
+	RTWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
+	RTWN_DEBUG_XMIT_DESC	= 0x00000002,	/* xmit descriptors */
+	RTWN_DEBUG_RECV		= 0x00000004,	/* basic recv operation */
+	RTWN_DEBUG_RECV_DESC	= 0x00000008,	/* recv descriptors */
+	RTWN_DEBUG_STATE	= 0x00000010,	/* 802.11 state transitions */
+	RTWN_DEBUG_RA		= 0x00000020,	/* f/w rate adaptation setup */
+	RTWN_DEBUG_USB		= 0x00000040,	/* usb requests */
+	RTWN_DEBUG_FIRMWARE	= 0x00000080,	/* firmware(9) loading debug */
+	RTWN_DEBUG_BEACON	= 0x00000100,	/* beacon handling */
+	RTWN_DEBUG_INTR		= 0x00000200,	/* ISR */
+	RTWN_DEBUG_TEMP		= 0x00000400,	/* temperature calibration */
+	RTWN_DEBUG_ROM		= 0x00000800,	/* various ROM info */
+	RTWN_DEBUG_KEY		= 0x00001000,	/* crypto keys management */
+	RTWN_DEBUG_TXPWR	= 0x00002000,	/* dump Tx power values */
+	RTWN_DEBUG_RSSI		= 0x00004000,	/* dump RSSI lookups */
+	RTWN_DEBUG_RESET	= 0x00008000,	/* initialization progress */
+	RTWN_DEBUG_CALIB	= 0x00010000,	/* calibration progress */
+	RTWN_DEBUG_RADAR	= 0x00020000,	/* radar detection status */
+	RTWN_DEBUG_ANY		= 0xffffffff
+};
+
+#define RTWN_DPRINTF(_sc, _m, ...) do {			\
+	if ((_sc)->sc_debug & (_m))				\
+		device_printf((_sc)->sc_dev, __VA_ARGS__);	\
+} while(0)
+
+#else
+#define RTWN_DPRINTF(_sc, _m, ...)	do { (void) _sc; } while (0)
+#endif
+
+#endif	/* IF_RTWN_DEBUG_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_efuse.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_efuse.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_efuse.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,267 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_efuse.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+
+static int
+rtwn_efuse_switch_power(struct rtwn_softc *sc)
+{
+	uint32_t reg;
+	int error;
+
+	error = rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON);
+	if (error != 0)
+		return (error);
+
+	reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
+	if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
+		error = rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+		    reg | R92C_SYS_FUNC_EN_ELDR);
+		if (error != 0)
+			return (error);
+	}
+	reg = rtwn_read_2(sc, R92C_SYS_CLKR);
+	if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
+	    (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
+		error = rtwn_write_2(sc, R92C_SYS_CLKR,
+		    reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
+		if (error != 0)
+			return (error);
+	}
+
+	return (0);
+}
+
+int
+rtwn_efuse_read_next(struct rtwn_softc *sc, uint8_t *val)
+{
+	uint32_t reg;
+	int ntries, error;
+
+	if (sc->next_rom_addr >= sc->efuse_maxlen)
+		return (EFAULT);
+
+	reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
+	reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->next_rom_addr);
+	reg &= ~R92C_EFUSE_CTRL_VALID;
+
+	error = rtwn_write_4(sc, R92C_EFUSE_CTRL, reg);
+	if (error != 0)
+		return (error);
+	/* Wait for read operation to complete. */
+	for (ntries = 0; ntries < 100; ntries++) {
+		reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
+		if (reg & R92C_EFUSE_CTRL_VALID)
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 100) {
+		device_printf(sc->sc_dev,
+		    "could not read efuse byte at address 0x%x\n",
+		    sc->next_rom_addr);
+		return (ETIMEDOUT);
+	}
+
+	*val = MS(reg, R92C_EFUSE_CTRL_DATA);
+	sc->next_rom_addr++;
+
+	return (0);
+}
+
+static int
+rtwn_efuse_read_data(struct rtwn_softc *sc, uint8_t *rom, uint8_t off,
+    uint8_t msk)
+{
+	uint8_t reg;
+	int addr, i, error;
+
+	for (i = 0; i < 4; i++) {
+		if (msk & (1 << i))
+			continue;
+
+		addr = off * 8 + i * 2;
+		if (addr + 1 >= sc->efuse_maplen)
+			return (EFAULT);
+
+		error = rtwn_efuse_read_next(sc, &reg);
+		if (error != 0)
+			return (error);
+		RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n",
+		    addr, reg);
+		rom[addr] = reg;
+
+		error = rtwn_efuse_read_next(sc, &reg);
+		if (error != 0)
+			return (error);
+		RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n",
+		    addr + 1, reg);
+		rom[addr + 1] = reg;
+	}
+
+	return (0);
+}
+
+#ifdef RTWN_DEBUG
+static void
+rtwn_dump_rom_contents(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
+{
+	int i;
+
+	/* Dump ROM contents. */
+	device_printf(sc->sc_dev, "%s:", __func__);
+	for (i = 0; i < size; i++) {
+		if (i % 32 == 0)
+			printf("\n%03X: ", i);
+		else if (i % 4 == 0)
+			printf(" ");
+
+		printf("%02X", rom[i]);
+	}
+	printf("\n");
+}
+#endif
+
+static int
+rtwn_efuse_read(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
+{
+#define RTWN_CHK(res) do {	\
+	if ((error = res) != 0)	\
+		goto end;	\
+} while(0)
+	uint8_t msk, off, reg;
+	int error;
+
+	/* Read full ROM image. */
+	sc->next_rom_addr = 0;
+	memset(rom, 0xff, size);
+
+	RTWN_CHK(rtwn_efuse_read_next(sc, &reg));
+	while (reg != 0xff) {
+		/* check for extended header */
+		if ((sc->sc_flags & RTWN_FLAG_EXT_HDR) &&
+		    (reg & 0x1f) == 0x0f) {
+			off = reg >> 5;
+			RTWN_CHK(rtwn_efuse_read_next(sc, &reg));
+
+			if ((reg & 0x0f) != 0x0f)
+				off = ((reg & 0xf0) >> 1) | off;
+			else
+				continue;
+		} else
+			off = reg >> 4;
+		msk = reg & 0xf;
+
+		RTWN_CHK(rtwn_efuse_read_data(sc, rom, off, msk));
+		RTWN_CHK(rtwn_efuse_read_next(sc, &reg));
+	}
+
+end:
+
+#ifdef RTWN_DEBUG
+	if (sc->sc_debug & RTWN_DEBUG_ROM)
+		rtwn_dump_rom_contents(sc, rom, size);
+#endif
+
+	/* Device-specific. */
+	rtwn_efuse_postread(sc);
+
+	if (error != 0) {
+		device_printf(sc->sc_dev, "%s: error while reading ROM\n",
+		    __func__);
+	}
+
+	return (error);
+#undef RTWN_CHK
+}
+
+static int
+rtwn_efuse_read_prepare(struct rtwn_softc *sc, uint8_t *rom, uint16_t size)
+{
+	int error;
+
+	error = rtwn_efuse_switch_power(sc);
+	if (error != 0)
+		goto fail;
+
+	error = rtwn_efuse_read(sc, rom, size);
+
+fail:
+	rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF);
+
+	return (error);
+}
+
+int
+rtwn_read_rom(struct rtwn_softc *sc)
+{
+	uint8_t *rom;
+	int error;
+
+	rom = malloc(sc->efuse_maplen, M_TEMP, M_WAITOK);
+
+	/* Read full ROM image. */
+	RTWN_LOCK(sc);
+	error = rtwn_efuse_read_prepare(sc, rom, sc->efuse_maplen);
+	RTWN_UNLOCK(sc);
+	if (error != 0)
+		goto fail;
+
+	/* Parse & save data in softc. */
+	rtwn_parse_rom(sc, rom);
+
+fail:
+	free(rom, M_TEMP);
+
+	return (error);
+}
Index: freebsd/sys/dev/rtwn/if_rtwn_efuse.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_efuse.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_efuse.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,25 @@
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_EFUSE_H
+#define IF_RTWN_EFUSE_H
+
+int	rtwn_efuse_read_next(struct rtwn_softc *, uint8_t *);
+int	rtwn_read_rom(struct rtwn_softc *);
+
+#endif	/* IF_RTWN_EFUSE_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_fw.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,226 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+#include <sys/firmware.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_fw.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+
+#ifndef RTWN_WITHOUT_UCODE
+static int
+rtwn_fw_loadpage(struct rtwn_softc *sc, int page, const uint8_t *buf,
+    int len)
+{
+	uint32_t reg;
+	uint16_t off;
+	int mlen, error;
+
+	reg = rtwn_read_4(sc, R92C_MCUFWDL);
+	reg = RW(reg, R92C_MCUFWDL_PAGE, page);
+	rtwn_write_4(sc, R92C_MCUFWDL, reg);
+
+	error = 0;
+	off = R92C_FW_START_ADDR;
+	while (len > 0) {
+		if (len > R92C_FW_MAX_BLOCK_SIZE)
+			mlen = R92C_FW_MAX_BLOCK_SIZE;
+		else if (len > 4)
+			mlen = 4;
+		else
+			mlen = 1;
+		error = rtwn_fw_write_block(sc, buf, off, mlen);
+		if (error != 0)
+			break;
+		off += mlen;
+		buf += mlen;
+		len -= mlen;
+	}
+
+	if (error != 0) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE,
+		    "%s: could not load firmware page %d (offset %u)\n",
+		    __func__, page, off);
+	}
+
+	return (error);
+}
+
+static int
+rtwn_fw_checksum_report(struct rtwn_softc *sc)
+{
+	int ntries;
+
+	for (ntries = 0; ntries < 25; ntries++) {
+		if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT)
+			break;
+		rtwn_delay(sc, 10000);
+	}
+	if (ntries == 25) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE,
+		    "timeout waiting for checksum report\n");
+		return (ETIMEDOUT);
+	}
+
+	return (0);
+}
+
+int
+rtwn_load_firmware(struct rtwn_softc *sc)
+{
+	const struct firmware *fw;
+	const struct r92c_fw_hdr *hdr;
+	const u_char *ptr;
+	size_t len;
+	int ntries, error;
+
+	/* Read firmware image from the filesystem. */
+	RTWN_UNLOCK(sc);
+	fw = firmware_get(sc->fwname);
+	RTWN_LOCK(sc);
+	if (fw == NULL) {
+		device_printf(sc->sc_dev,
+		    "failed loadfirmware of file %s\n", sc->fwname);
+		return (ENOENT);
+	}
+
+	len = fw->datasize;
+	if (len < sizeof(*hdr) || len > sc->fwsize_limit) {
+		device_printf(sc->sc_dev, "wrong firmware size (%zu)\n", len);
+		error = EINVAL;
+		goto fail;
+	}
+	ptr = fw->data;
+	hdr = (const struct r92c_fw_hdr *)ptr;
+	/* Check if there is a valid FW header and skip it. */
+	if ((le16toh(hdr->signature) >> 4) == sc->fwsig) {
+		sc->fwver = le16toh(hdr->version);
+
+		RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE,
+		    "FW V%u.%u %02u-%02u %02u:%02u\n",
+		    le16toh(hdr->version), le16toh(hdr->subversion),
+		    hdr->month, hdr->date, hdr->hour, hdr->minute);
+		ptr += sizeof(*hdr);
+		len -= sizeof(*hdr);
+	}
+
+	if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) {
+		rtwn_write_1(sc, R92C_MCUFWDL, 0);
+		rtwn_fw_reset(sc, RTWN_FW_RESET_DOWNLOAD);
+	}
+
+	/* Enable firmware download. */
+	rtwn_fw_download_enable(sc, 1);
+
+	error = 0;	/* compiler warning */
+	for (ntries = 0; ntries < 3; ntries++) {
+		const u_char *curr_ptr = ptr;
+		const int maxpages = len / R92C_FW_PAGE_SIZE;
+		int page;
+
+		/* Reset the FWDL checksum. */
+		rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_CHKSUM_RPT);
+
+		for (page = 0; page < maxpages; page++) {
+			error = rtwn_fw_loadpage(sc, page, curr_ptr,
+			    R92C_FW_PAGE_SIZE);
+			if (error != 0)
+				break;
+			curr_ptr += R92C_FW_PAGE_SIZE;
+		}
+		if (page != maxpages)
+			continue;
+
+		if (len % R92C_FW_PAGE_SIZE != 0) {
+			error = rtwn_fw_loadpage(sc, page, curr_ptr,
+			    len % R92C_FW_PAGE_SIZE);
+			if (error != 0)
+				continue;
+		}
+
+		/* Wait for checksum report. */
+		error = rtwn_fw_checksum_report(sc);
+		if (error == 0)
+			break;
+	}
+	if (ntries == 3) {
+		device_printf(sc->sc_dev,
+		    "%s: failed to upload firmware %s (error %d)\n",
+		    __func__, sc->fwname, error);
+		goto fail;
+	}
+
+	/* Disable firmware download. */
+	rtwn_fw_download_enable(sc, 0);
+
+	rtwn_setbits_4(sc, R92C_MCUFWDL, R92C_MCUFWDL_WINTINI_RDY,
+	    R92C_MCUFWDL_RDY);
+
+	rtwn_fw_reset(sc, RTWN_FW_RESET_CHECKSUM);
+
+	/* Wait for firmware readiness. */
+	for (ntries = 0; ntries < 20; ntries++) {
+		if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY)
+			break;
+		rtwn_delay(sc, 10000);
+	}
+	if (ntries == 20) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for firmware readiness\n");
+		error = ETIMEDOUT;
+		goto fail;
+	}
+fail:
+	firmware_put(fw, FIRMWARE_UNLOAD);
+	return (error);
+}
+#endif
Index: freebsd/sys/dev/rtwn/if_rtwn_fw.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_fw.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_fw.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_FW_H
+#define IF_RTWN_FW_H
+
+/*
+ * Firmware base address.
+ */
+#define R92C_FW_START_ADDR		0x1000
+#define R92C_FW_PAGE_SIZE		4096
+#define R92C_FW_MAX_BLOCK_SIZE		196
+
+/*
+ * Firmware image header.
+ */
+struct r92c_fw_hdr {
+	/* QWORD0 */
+	uint16_t	signature;
+	uint8_t		category;
+	uint8_t		function;
+	uint16_t	version;
+	uint16_t	subversion;
+	/* QWORD1 */
+	uint8_t		month;
+	uint8_t		date;
+	uint8_t		hour;
+	uint8_t		minute;
+	uint16_t	ramcodesize;
+	uint16_t	reserved2;
+	/* QWORD2 */
+	uint32_t	svnidx;
+	uint32_t	reserved3;
+	/* QWORD3 */
+	uint32_t	reserved4;
+	uint32_t	reserved5;
+} __packed;
+
+
+int		rtwn_load_firmware(struct rtwn_softc *);
+
+#endif	/* IF_RTWN_FW_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_nop.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_nop.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_nop.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_NOP_H
+#define IF_RTWN_NOP_H
+
+static __inline void
+rtwn_nop_softc(struct rtwn_softc *sc)
+{
+}
+
+static __inline int
+rtwn_nop_int_softc(struct rtwn_softc *sc)
+{
+	return (0);
+}
+
+static __inline int
+rtwn_nop_int_softc_mbuf(struct rtwn_softc *sc, struct mbuf *m)
+{
+	return (0);
+}
+
+static __inline void
+rtwn_nop_softc_int(struct rtwn_softc *sc, int id)
+{
+}
+
+static __inline void
+rtwn_nop_softc_uint32(struct rtwn_softc *sc, uint32_t reg)
+{
+}
+
+static __inline void
+rtwn_nop_softc_chan(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+}
+
+static __inline void
+rtwn_nop_softc_vap(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+}
+
+static __inline void
+rtwn_nop_softc_uint8_int(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+}
+
+static __inline void
+rtwn_nop_void_int(void *buf, int is5ghz)
+{
+}
+
+#endif	/* IF_RTWN_NOP_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_ridx.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_ridx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_ridx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,94 @@
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_RIDX_H
+#define IF_RTWN_RIDX_H
+
+/* HW rate indices. */
+#define RTWN_RIDX_CCK1		0
+#define RTWN_RIDX_CCK2		1
+#define RTWN_RIDX_CCK55		2
+#define RTWN_RIDX_CCK11		3
+#define RTWN_RIDX_OFDM6		4
+#define RTWN_RIDX_OFDM9		5
+#define RTWN_RIDX_OFDM12	6
+#define RTWN_RIDX_OFDM18	7
+#define RTWN_RIDX_OFDM24	8
+#define RTWN_RIDX_OFDM36	9
+#define RTWN_RIDX_OFDM48	10
+#define RTWN_RIDX_OFDM54	11
+#define RTWN_RIDX_MCS(i)	(12 + (i))
+
+#define RTWN_RIDX_COUNT		28
+#define RTWN_RIDX_UNKNOWN	(uint8_t)-1
+
+#define RTWN_RATE_IS_CCK(rate)  ((rate) <= RTWN_RIDX_CCK11)
+#define RTWN_RATE_IS_OFDM(rate) \
+	((rate) >= RTWN_RIDX_OFDM6 && (rate) != RTWN_RIDX_UNKNOWN)
+
+
+static const uint8_t ridx2rate[] =
+	{ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
+
+static __inline uint8_t
+rate2ridx(uint8_t rate)
+{
+	if (rate & IEEE80211_RATE_MCS) {
+		/* 11n rates start at idx 12 */
+		return ((rate & 0xf) + 12);
+	}
+	switch (rate) {
+	/* 11g */
+	case 12:	return 4;
+	case 18:	return 5;
+	case 24:	return 6;
+	case 36:	return 7;
+	case 48:	return 8;
+	case 72:	return 9;
+	case 96:	return 10;
+	case 108:	return 11;
+	/* 11b */
+	case 2:		return 0;
+	case 4:		return 1;
+	case 11:	return 2;
+	case 22:	return 3;
+	default:	return RTWN_RIDX_UNKNOWN;
+	}
+}
+
+/* XXX move to net80211 */
+static __inline__ uint8_t
+rtwn_ctl_mcsrate(const struct ieee80211_rate_table *rt, uint8_t ridx)
+{
+	uint8_t cix, rate;
+
+	/* Check if we are using MCS rate. */
+	KASSERT(ridx >= RTWN_RIDX_MCS(0) && ridx != RTWN_RIDX_UNKNOWN,
+	    ("bad mcs rate index %d", ridx));
+
+	rate = (ridx - RTWN_RIDX_MCS(0)) | IEEE80211_RATE_MCS;
+	cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex;
+	KASSERT(cix != (uint8_t)-1, ("rate %d (%d) has no info", rate, ridx));
+	return rt->info[cix].dot11Rate;
+}
+
+#endif	/* IF_RTWN_RIDX_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,466 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_rx.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
+
+
+void
+rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs,
+    const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p,
+    int *maxrate_p, int basic_rates)
+{
+	uint32_t rates;
+	uint8_t ridx;
+	int i, maxrate;
+
+	/* Get rates mask. */
+	rates = 0;
+	maxrate = 0;
+
+	/* This is for 11bg */
+	for (i = 0; i < rs->rs_nrates; i++) {
+		/* Convert 802.11 rate to HW rate index. */
+		ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i]));
+		if (ridx == RTWN_RIDX_UNKNOWN)	/* Unknown rate, skip. */
+			continue;
+		if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) ||
+		    !basic_rates) {
+			rates |= 1 << ridx;
+			if (ridx > maxrate)
+				maxrate = ridx;
+		}
+	}
+
+	/* If we're doing 11n, enable 11n rates */
+	if (rs_ht != NULL && !basic_rates) {
+		for (i = 0; i < rs_ht->rs_nrates; i++) {
+			if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
+				continue;
+			/* 11n rates start at index 12 */
+			ridx = RTWN_RIDX_MCS((rs_ht->rs_rates[i]) & 0xf);
+			rates |= (1 << ridx);
+
+			/* Guard against the rate table being oddly ordered */
+			if (ridx > maxrate)
+				maxrate = ridx;
+		}
+	}
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
+	    "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate);
+
+	if (rates_p != NULL)
+		*rates_p = rates;
+	if (maxrate_p != NULL)
+		*maxrate_p = maxrate;
+}
+
+void
+rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates)
+{
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates);
+
+	rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates);
+}
+
+static void
+rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int rate)
+{
+	int pwdb;
+
+	/* Convert antenna signal to percentage. */
+	if (un->last_rssi <= -100 || un->last_rssi >= 20)
+		pwdb = 0;
+	else if (un->last_rssi >= 0)
+		pwdb = 100;
+	else
+		pwdb = 100 + un->last_rssi;
+	if (RTWN_RATE_IS_CCK(rate)) {
+		/* CCK gain is smaller than OFDM/MCS gain. */
+		pwdb += 6;
+		if (pwdb > 100)
+			pwdb = 100;
+		if (pwdb <= 14)
+			pwdb -= 4;
+		else if (pwdb <= 26)
+			pwdb -= 8;
+		else if (pwdb <= 34)
+			pwdb -= 6;
+		else if (pwdb <= 42)
+			pwdb -= 2;
+	}
+
+	if (un->avg_pwdb == -1)	/* Init. */
+		un->avg_pwdb = pwdb;
+	else if (un->avg_pwdb < pwdb)
+		un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1;
+	else
+		un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI,
+	    "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb);
+}
+
+static int8_t
+rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt)
+{
+	int8_t rssi;
+
+	if (RTWN_RATE_IS_CCK(rate))
+		rssi = rtwn_get_rssi_cck(sc, physt);
+	else	/* OFDM/HT. */
+		rssi = rtwn_get_rssi_ofdm(sc, physt);
+
+	return (rssi);
+}
+
+static uint32_t
+rtwn_get_tsf_low(struct rtwn_softc *sc, int id)
+{
+	return (rtwn_read_4(sc, R92C_TSFTR(id)));
+}
+
+static uint32_t
+rtwn_get_tsf_high(struct rtwn_softc *sc, int id)
+{
+	return (rtwn_read_4(sc, R92C_TSFTR(id) + 4));
+}
+
+static void
+rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id)
+{
+	/* NB: we cannot read it at once. */
+	*buf = rtwn_get_tsf_high(sc, id);
+	*buf <<= 32;
+	*buf += rtwn_get_tsf_low(sc, id);
+}
+
+struct ieee80211_node *
+rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc,
+    int8_t *rssi)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_node *ni;
+	struct ieee80211_frame_min *wh;
+	struct rtwn_node *un;
+	struct r92c_rx_stat *stat;
+	uint32_t rxdw0, rxdw3;
+	int cipher, infosz, pktlen, rate, shift;
+
+	stat = desc;
+	rxdw0 = le32toh(stat->rxdw0);
+	rxdw3 = le32toh(stat->rxdw3);
+
+	cipher = MS(rxdw0, R92C_RXDW0_CIPHER);
+	infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
+	pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+	shift = MS(rxdw0, R92C_RXDW0_SHIFT);
+	rate = MS(rxdw3, R92C_RXDW3_RATE);
+
+	wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz));
+	if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+	    cipher != R92C_CAM_ALGO_NONE)
+		m->m_flags |= M_WEP;
+
+	if (pktlen >= sizeof(*wh))
+		ni = ieee80211_find_rxnode(ic, wh);
+	else
+		ni = NULL;
+	un = RTWN_NODE(ni);
+
+	/* Get RSSI from PHY status descriptor if present. */
+	if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
+		*rssi = rtwn_get_rssi(sc, rate, mtod(m, void *));
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, ridx %d\n",
+		    __func__, *rssi, rate);
+
+		sc->last_rssi = *rssi;
+		if (un != NULL) {
+			un->last_rssi = *rssi;
+
+			/* Update our average RSSI. */
+			rtwn_update_avgrssi(sc, un, rate);
+		}
+	} else
+		*rssi = (un != NULL) ? un->last_rssi : sc->last_rssi;
+
+	if (ieee80211_radiotap_active(ic)) {
+		struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
+		int id = RTWN_VAP_ID_INVALID;
+
+		if (ni != NULL)
+			id = RTWN_VAP(ni->ni_vap)->id;
+		if (id == RTWN_VAP_ID_INVALID)
+			id = 0;
+
+		tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc);
+		tap->wr_tsft = rtwn_get_tsf_high(sc, id);
+		if (le32toh(stat->tsf_low) > rtwn_get_tsf_low(sc, id))
+			tap->wr_tsft--;
+		tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32;
+		tap->wr_tsft += stat->tsf_low;
+
+		/* XXX 20/40? */
+
+		/* Map HW rate index to 802.11 rate. */
+		if (rate < RTWN_RIDX_MCS(0))
+			tap->wr_rate = ridx2rate[rate];
+		else	/* MCS0~15. */
+			tap->wr_rate = IEEE80211_RATE_MCS | (rate - 12);
+
+		tap->wr_dbm_antsignal = *rssi;
+		tap->wr_dbm_antnoise = RTWN_NOISE_FLOOR;
+	}
+
+	/* Drop PHY descriptor. */
+	m_adj(m, infosz + shift);
+
+	return (ni);
+}
+
+void
+rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
+    const struct ieee80211_rx_stats *rxs,
+    int rssi, int nf)
+{
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct rtwn_softc *sc = vap->iv_ic->ic_softc;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	uint64_t ni_tstamp, curr_tstamp;
+
+	uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
+
+	if (vap->iv_state == IEEE80211_S_RUN &&
+	    (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
+	    subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
+		ni_tstamp = le64toh(ni->ni_tstamp.tsf);
+		RTWN_LOCK(sc);
+		rtwn_get_tsf(sc, &curr_tstamp, uvp->id);
+		RTWN_UNLOCK(sc);
+
+		if (ni_tstamp >= curr_tstamp)
+			(void) ieee80211_ibss_merge(ni);
+	}
+}
+
+static uint8_t
+rtwn_get_multi_pos(const uint8_t maddr[])
+{
+	uint64_t mask = 0x00004d101df481b4;
+	uint8_t pos = 0x27;	/* initial value */
+	int i, j;
+
+	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
+		for (j = (i == 0) ? 1 : 0; j < 8; j++)
+			if ((maddr[i] >> j) & 1)
+				pos ^= (mask >> (i * 8 + j - 1));
+
+	pos &= 0x3f;
+
+	return (pos);
+}
+
+void
+rtwn_set_multi(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint32_t mfilt[2];
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	/* general structure was copied from ath(4). */
+	if (ic->ic_allmulti == 0) {
+		struct ieee80211vap *vap;
+		struct ifnet *ifp;
+		struct ifmultiaddr *ifma;
+
+		/*
+		 * Merge multicast addresses to form the hardware filter.
+		 */
+		mfilt[0] = mfilt[1] = 0;
+		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+			ifp = vap->iv_ifp;
+			if_maddr_rlock(ifp);
+			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+				caddr_t dl;
+				uint8_t pos;
+
+				dl = LLADDR((struct sockaddr_dl *)
+				    ifma->ifma_addr);
+				pos = rtwn_get_multi_pos(dl);
+
+				mfilt[pos / 32] |= (1 << (pos % 32));
+			}
+			if_maddr_runlock(ifp);
+		}
+	} else
+		mfilt[0] = mfilt[1] = ~0;
+
+
+	rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]);
+	rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n",
+	    __func__, mfilt[0], mfilt[1]);
+}
+
+static void
+rtwn_rxfilter_update_mgt(struct rtwn_softc *sc)
+{
+	uint16_t filter;
+
+	filter = 0x7f7f;
+	if (sc->bcn_vaps == 0) {	/* STA and/or MONITOR mode vaps */
+		filter &= ~(
+		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) |
+		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) |
+		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ));
+	}
+	if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) {	/* AP vaps only */
+		filter &= ~(
+		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) |
+		    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP));
+	}
+	rtwn_write_2(sc, R92C_RXFLTMAP0, filter);
+}
+
+void
+rtwn_rxfilter_update(struct rtwn_softc *sc)
+{
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	/* Filter for management frames. */
+	rtwn_rxfilter_update_mgt(sc);
+
+	/* Update Rx filter. */
+	rtwn_set_promisc(sc);
+}
+
+void
+rtwn_rxfilter_init(struct rtwn_softc *sc)
+{
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	/* Setup multicast filter. */
+	rtwn_set_multi(sc);
+
+	/* Reject all control frames. */
+	rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
+
+	/* Reject all data frames. */
+	rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000);
+
+	/* Append generic Rx filter bits. */
+	sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM |
+	    R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS |
+	    R92C_RCR_APP_ICV | R92C_RCR_APP_MIC;
+
+	/* Update dynamic Rx filter parts. */
+	rtwn_rxfilter_update(sc);
+}
+
+void
+rtwn_rxfilter_set(struct rtwn_softc *sc)
+{
+	if (!(sc->sc_flags & RTWN_RCR_LOCKED))
+		rtwn_write_4(sc, R92C_RCR, sc->rcr);
+}
+
+void
+rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable)
+{
+
+	if (enable)
+		sc->rcr &= ~R92C_RCR_CBSSID_BCN;
+	else
+		sc->rcr |= R92C_RCR_CBSSID_BCN;
+	rtwn_rxfilter_set(sc);
+}
+
+void
+rtwn_set_promisc(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint32_t mask_all, mask_min;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP;
+	mask_min = R92C_RCR_APM;
+
+	if (sc->bcn_vaps == 0)
+		mask_min |= R92C_RCR_CBSSID_BCN;
+	if (sc->ap_vaps == 0)
+		mask_min |= R92C_RCR_CBSSID_DATA;
+
+	if (ic->ic_promisc == 0 && sc->mon_vaps == 0) {
+		if (sc->bcn_vaps != 0)
+			mask_all |= R92C_RCR_CBSSID_BCN;
+		if (sc->ap_vaps != 0)	/* for Null data frames */
+			mask_all |= R92C_RCR_CBSSID_DATA;
+
+		sc->rcr &= ~mask_all;
+		sc->rcr |= mask_min;
+	} else {
+		sc->rcr &= ~mask_min;
+		sc->rcr |= mask_all;
+	}
+	rtwn_rxfilter_set(sc);
+}
Index: freebsd/sys/dev/rtwn/if_rtwn_rx.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_rx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_rx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_RX_H
+#define IF_RTWN_RX_H
+
+#define	RTWN_NOISE_FLOOR	-95
+
+
+void	rtwn_get_rates(struct rtwn_softc *, const struct ieee80211_rateset *,
+	    const struct ieee80211_htrateset *, uint32_t *, int *, int);
+void	rtwn_set_basicrates(struct rtwn_softc *, uint32_t);
+struct ieee80211_node *	rtwn_rx_common(struct rtwn_softc *, struct mbuf *,
+	    void *, int8_t *);
+void	rtwn_adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
+	    const struct ieee80211_rx_stats *, int, int);
+void	rtwn_set_multi(struct rtwn_softc *);
+void	rtwn_rxfilter_update(struct rtwn_softc *);
+void	rtwn_rxfilter_init(struct rtwn_softc *);
+void	rtwn_rxfilter_set(struct rtwn_softc *);
+void	rtwn_set_rx_bssid_all(struct rtwn_softc *, int);
+void	rtwn_set_promisc(struct rtwn_softc *);
+
+#endif	/* IF_RTWN_RX_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_task.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_task.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_task.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,124 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_task.h>
+
+
+static void
+rtwn_cmdq_cb(void *arg, int pending)
+{
+	struct rtwn_softc *sc = arg;
+	struct rtwn_cmdq *item;
+
+	/*
+	 * Device must be powered on (via rtwn_power_on())
+	 * before any command may be sent.
+	 */
+	RTWN_LOCK(sc);
+	if (!(sc->sc_flags & RTWN_RUNNING)) {
+		RTWN_UNLOCK(sc);
+		return;
+	}
+
+	RTWN_CMDQ_LOCK(sc);
+	while (sc->cmdq[sc->cmdq_first].func != NULL) {
+		item = &sc->cmdq[sc->cmdq_first];
+		sc->cmdq_first = (sc->cmdq_first + 1) % RTWN_CMDQ_SIZE;
+		RTWN_CMDQ_UNLOCK(sc);
+
+		item->func(sc, &item->data);
+
+		RTWN_CMDQ_LOCK(sc);
+		memset(item, 0, sizeof (*item));
+	}
+	RTWN_CMDQ_UNLOCK(sc);
+	RTWN_UNLOCK(sc);
+}
+
+void
+rtwn_cmdq_init(struct rtwn_softc *sc)
+{
+	RTWN_CMDQ_LOCK_INIT(sc);
+	TASK_INIT(&sc->cmdq_task, 0, rtwn_cmdq_cb, sc);
+}
+
+void
+rtwn_cmdq_destroy(struct rtwn_softc *sc)
+{
+	if (RTWN_CMDQ_LOCK_INITIALIZED(sc))
+		RTWN_CMDQ_LOCK_DESTROY(sc);
+}
+
+int
+rtwn_cmd_sleepable(struct rtwn_softc *sc, const void *ptr, size_t len,
+    CMD_FUNC_PROTO)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	KASSERT(len <= sizeof(union sec_param), ("buffer overflow"));
+
+	RTWN_CMDQ_LOCK(sc);
+	if (sc->sc_detached) {
+		RTWN_CMDQ_UNLOCK(sc);
+		return (ESHUTDOWN);
+	}
+
+	if (sc->cmdq[sc->cmdq_last].func != NULL) {
+		device_printf(sc->sc_dev, "%s: cmdq overflow\n", __func__);
+		RTWN_CMDQ_UNLOCK(sc);
+
+		return (EAGAIN);
+	}
+
+	if (ptr != NULL)
+		memcpy(&sc->cmdq[sc->cmdq_last].data, ptr, len);
+	sc->cmdq[sc->cmdq_last].func = func;
+	sc->cmdq_last = (sc->cmdq_last + 1) % RTWN_CMDQ_SIZE;
+	RTWN_CMDQ_UNLOCK(sc);
+
+	ieee80211_runtask(ic, &sc->cmdq_task);
+
+	return (0);
+}
Index: freebsd/sys/dev/rtwn/if_rtwn_task.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_task.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_task.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_TASK_H
+#define IF_RTWN_TASK_H
+
+void	rtwn_cmdq_init(struct rtwn_softc *);
+void	rtwn_cmdq_destroy(struct rtwn_softc *);
+int	rtwn_cmd_sleepable(struct rtwn_softc *, const void *, size_t,
+	    CMD_FUNC_PROTO);
+
+#endif	/* IF_RTWN_TASK_H */
Index: freebsd/sys/dev/rtwn/if_rtwn_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,348 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
+#ifdef	IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_beacon.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_tx.h>
+
+
+void
+rtwn_drain_mbufq(struct rtwn_softc *sc)
+{
+	struct mbuf *m;
+	struct ieee80211_node *ni;
+	RTWN_ASSERT_LOCKED(sc);
+	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
+		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+		m->m_pkthdr.rcvif = NULL;
+		ieee80211_free_node(ni);
+		m_freem(m);
+	}
+}
+
+#ifdef IEEE80211_SUPPORT_SUPERG
+void
+rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	RTWN_UNLOCK(sc);
+	ieee80211_ff_flush_all(ic);
+	RTWN_LOCK(sc);
+}
+#endif
+
+static uint8_t
+rtwn_get_cipher(u_int ic_cipher)
+{
+	uint8_t cipher;
+
+	switch (ic_cipher) {
+	case IEEE80211_CIPHER_NONE:
+		cipher = RTWN_TXDW1_CIPHER_NONE;
+		break;
+	case IEEE80211_CIPHER_WEP:
+	case IEEE80211_CIPHER_TKIP:
+		cipher = RTWN_TXDW1_CIPHER_RC4;
+		break;
+	case IEEE80211_CIPHER_AES_CCM:
+		cipher = RTWN_TXDW1_CIPHER_AES;
+		break;
+	default:
+		KASSERT(0, ("%s: unknown cipher %d\n", __func__,
+		    ic_cipher));
+		return (RTWN_TXDW1_CIPHER_SM4);
+	}
+
+	return (cipher);
+}
+
+static int
+rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m)
+{
+	const struct ieee80211_txparam *tp;
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct ieee80211_key *k = NULL;
+	struct ieee80211_channel *chan;
+	struct ieee80211_frame *wh;
+	struct rtwn_tx_desc_common *txd;
+	struct rtwn_tx_buf buf;
+	uint8_t rate, ridx, type;
+	u_int cipher;
+	int ismcast, maxretry;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	wh = mtod(m, struct ieee80211_frame *);
+	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+
+	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
+		ni->ni_chan : ic->ic_curchan;
+	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
+	maxretry = tp->maxretry;
+
+	/* Choose a TX rate index. */
+	if (type == IEEE80211_FC0_TYPE_MGT)
+		rate = tp->mgmtrate;
+	else if (ismcast)
+		rate = tp->mcastrate;
+	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
+		rate = tp->ucastrate;
+	else if (m->m_flags & M_EAPOL)
+		rate = tp->mgmtrate;
+	else {
+		if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
+			/* XXX pass pktlen */
+			(void) ieee80211_ratectl_rate(ni, NULL, 0);
+			rate = ni->ni_txrate;
+		} else {
+			if (ni->ni_flags & IEEE80211_NODE_HT)
+				rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */
+			else if (ic->ic_curmode != IEEE80211_MODE_11B)
+				rate = ridx2rate[RTWN_RIDX_OFDM36];
+			else
+				rate = ridx2rate[RTWN_RIDX_CCK55];
+		}
+	}
+
+	ridx = rate2ridx(rate);
+
+	cipher = IEEE80211_CIPHER_NONE;
+	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+		k = ieee80211_crypto_encap(ni, m);
+		if (k == NULL) {
+			device_printf(sc->sc_dev,
+			    "ieee80211_crypto_encap returns NULL.\n");
+			return (ENOBUFS);
+		}
+		if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
+			cipher = k->wk_cipher->ic_cipher;
+
+		/* in case packet header moved, reset pointer */
+		wh = mtod(m, struct ieee80211_frame *);
+	}
+
+	/* Fill Tx descriptor. */
+	txd = (struct rtwn_tx_desc_common *)&buf;
+	memset(txd, 0, sc->txdesc_len);
+	txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
+
+	rtwn_fill_tx_desc(sc, ni, m, txd, ridx, maxretry);
+
+	if (ieee80211_radiotap_active_vap(vap)) {
+		struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
+
+		tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
+		if (k != NULL)
+			tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+		ieee80211_radiotap_tx(vap, m);
+	}
+
+	return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
+}
+
+static int
+rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m, const struct ieee80211_bpf_params *params)
+{
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct ieee80211_key *k = NULL;
+	struct ieee80211_frame *wh;
+	struct rtwn_tx_desc_common *txd;
+	struct rtwn_tx_buf buf;
+	uint8_t type;
+	u_int cipher;
+
+	/* Encrypt the frame if need be. */
+	cipher = IEEE80211_CIPHER_NONE;
+	if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
+		/* Retrieve key for TX. */
+		k = ieee80211_crypto_encap(ni, m);
+		if (k == NULL) {
+			device_printf(sc->sc_dev,
+			    "ieee80211_crypto_encap returns NULL.\n");
+			return (ENOBUFS);
+		}
+		if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
+			cipher = k->wk_cipher->ic_cipher;
+	}
+
+	wh = mtod(m, struct ieee80211_frame *);
+	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+	/* Fill Tx descriptor. */
+	txd = (struct rtwn_tx_desc_common *)&buf;
+	memset(txd, 0, sc->txdesc_len);
+	txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
+
+	rtwn_fill_tx_desc_raw(sc, ni, m, txd, params);
+
+	if (ieee80211_radiotap_active_vap(vap)) {
+		struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
+
+		tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
+		if (k != NULL)
+			tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+		ieee80211_radiotap_tx(vap, m);
+	}
+
+	return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
+}
+
+int
+rtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	int error;
+
+	RTWN_LOCK(sc);
+	if ((sc->sc_flags & RTWN_RUNNING) == 0) {
+		RTWN_UNLOCK(sc);
+		return (ENXIO);
+	}
+	error = mbufq_enqueue(&sc->sc_snd, m);
+	if (error) {
+		RTWN_UNLOCK(sc);
+		return (error);
+	}
+	rtwn_start(sc);
+	RTWN_UNLOCK(sc);
+
+	return (0);
+}
+
+void
+rtwn_start(struct rtwn_softc *sc)
+{
+	struct ieee80211_node *ni;
+	struct mbuf *m;
+
+	RTWN_ASSERT_LOCKED(sc);
+	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
+		if (sc->qfullmsk != 0) {
+			mbufq_prepend(&sc->sc_snd, m);
+			break;
+		}
+		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+		m->m_pkthdr.rcvif = NULL;
+
+		RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
+		    "%s: called; m %p, ni %p\n", __func__, m, ni);
+
+		if (rtwn_tx_data(sc, ni, m) != 0) {
+			if_inc_counter(ni->ni_vap->iv_ifp,
+			    IFCOUNTER_OERRORS, 1);
+			m_freem(m);
+#ifdef D4054
+			ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0);
+#endif
+			ieee80211_free_node(ni);
+			break;
+		}
+	}
+}
+
+int
+rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+    const struct ieee80211_bpf_params *params)
+{
+	struct ieee80211com *ic = ni->ni_ic;
+	struct rtwn_softc *sc = ic->ic_softc;
+	int error;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n",
+	    __func__, m, ni);
+
+	/* prevent management frames from being sent if we're not ready */
+	RTWN_LOCK(sc);
+	if (!(sc->sc_flags & RTWN_RUNNING)) {
+		error = ENETDOWN;
+		goto end;
+	}
+
+	if (sc->qfullmsk != 0) {
+		error = ENOBUFS;
+		goto end;
+	}
+
+	if (params == NULL) {
+		/*
+		 * Legacy path; interpret frame contents to decide
+		 * precisely how to send the frame.
+		 */
+		error = rtwn_tx_data(sc, ni, m);
+	} else {
+		/*
+		 * Caller supplied explicit parameters to use in
+		 * sending the frame.
+		 */
+		error = rtwn_tx_raw(sc, ni, m, params);
+	}
+
+end:
+	if (error != 0) {
+		if (m->m_flags & M_TXCB)
+			ieee80211_process_callback(ni, m, 1);
+		m_freem(m);
+	}
+
+	RTWN_UNLOCK(sc);
+
+	return (error);
+}
Index: freebsd/sys/dev/rtwn/if_rtwn_tx.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwn_tx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwn_tx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,31 @@
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_TX_H
+#define IF_RTWN_TX_H
+
+void	rtwn_drain_mbufq(struct rtwn_softc *);
+#ifdef IEEE80211_SUPPORT_SUPERG
+void	rtwn_ff_flush_all(struct rtwn_softc *, union sec_param *);
+#endif
+int	rtwn_transmit(struct ieee80211com *, struct mbuf *);
+void	rtwn_start(struct rtwn_softc *);
+int	rtwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
+	    const struct ieee80211_bpf_params *);
+
+#endif	/* IF_RTWN_TX_H */
Index: freebsd/sys/dev/rtwn/if_rtwnreg.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwnreg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwnreg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#define R92C_MIN_TX_PWR		0x00
+#define R92C_MAX_TX_PWR		0x3f
+
+#define R92C_H2C_NBOX		4
+
+
+/* Common part of Tx descriptor (named only!). */
+struct rtwn_tx_desc_common {
+	uint16_t	pktlen;
+	uint8_t		offset;
+	uint8_t		flags0;
+#define RTWN_FLAGS0_OWN	0x80
+
+	uint32_t	txdw1;
+/* NB: qsel is shared too; however, it looks better at the lower level */
+#define RTWN_TXDW1_CIPHER_M	0x00c00000
+#define RTWN_TXDW1_CIPHER_S	22
+#define RTWN_TXDW1_CIPHER_NONE	0
+#define RTWN_TXDW1_CIPHER_RC4	1
+#define RTWN_TXDW1_CIPHER_SM4	2
+#define RTWN_TXDW1_CIPHER_AES	3
+
+	uint32_t	reserved[5];
+
+	union txdw7_shared {
+		uint16_t	usb_checksum;
+		uint16_t	pci_txbufsize;
+	} txdw7;
+} __packed __attribute__((aligned(4)));
+
+/*
+ * Macros to access subfields in registers.
+ */
+/* Mask and Shift (getter). */
+#define MS(val, field)							\
+	(((val) & field##_M) >> field##_S)
+
+/* Shift and Mask (setter). */
+#define SM(field, val)							\
+	(((val) << field##_S) & field##_M)
+
+/* Rewrite. */
+#define RW(var, field, val)						\
+	(((var) & ~field##_M) | SM(field, val))
+
+
+#define RTWN_MAX_CONDITIONS	3
+
+/*
+ * Structure for MAC initialization values.
+ */
+struct rtwn_mac_prog {
+	uint16_t	reg;
+	uint8_t		val;
+};
+
+/*
+ * Structure for baseband initialization values.
+ */
+struct rtwn_bb_prog {
+	int		count;
+	const uint16_t	*reg;
+	const uint32_t	*val;
+	const uint8_t	cond[RTWN_MAX_CONDITIONS];
+	const struct rtwn_bb_prog *next;
+};
+
+struct rtwn_agc_prog {
+	int		count;
+	const uint32_t	*val;
+	const uint8_t	cond[RTWN_MAX_CONDITIONS];
+	const struct rtwn_agc_prog *next;
+};
+
+/*
+ * Structure for RF initialization values.
+ */
+struct rtwn_rf_prog {
+	int		count;
+	const uint8_t	*reg;
+	const uint32_t	*val;
+	const uint8_t	cond[RTWN_MAX_CONDITIONS];
+	const struct rtwn_rf_prog *next;
+};
+
+
+/* XXX move to net80211. */
+static __inline int
+rtwn_chan2centieee(const struct ieee80211_channel *c)
+{
+	int chan;
+
+	chan = c->ic_ieee;
+	if (c->ic_extieee != 0)
+		chan = (chan + c->ic_extieee) / 2;
+
+	return (chan);
+}
Index: freebsd/sys/dev/rtwn/if_rtwnvar.h
===================================================================
--- freebsd/sys/dev/rtwn/if_rtwnvar.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/if_rtwnvar.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,624 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWNVAR_H
+#define IF_RTWNVAR_H
+
+#include <rtems/bsd/local/opt_rtwn.h>
+
+#define RTWN_TX_DESC_SIZE	64
+
+#define RTWN_TXBUFSZ		(16 * 1024)
+
+#define RTWN_BCN_MAX_SIZE	512
+#define RTWN_CAM_ENTRY_LIMIT	64
+
+#define RTWN_MACID_BC		1	/* Broadcast. */
+#define RTWN_MACID_UNDEFINED	0x7fff
+#define RTWN_MACID_VALID 	0x8000
+#define RTWN_MACID_LIMIT	128
+
+#define RTWN_TX_TIMEOUT		5000	/* ms */
+#define RTWN_MAX_EPOUT		4
+#define RTWN_PORT_COUNT		2
+
+#define RTWN_LED_LINK		0
+#define RTWN_LED_DATA		1
+
+struct rtwn_rx_radiotap_header {
+	struct ieee80211_radiotap_header wr_ihdr;
+	uint64_t	wr_tsft;
+	uint8_t		wr_flags;
+	uint8_t		wr_rate;
+	uint16_t	wr_chan_freq;
+	uint16_t	wr_chan_flags;
+	int8_t		wr_dbm_antsignal;
+	int8_t		wr_dbm_antnoise;
+} __packed __aligned(8);
+
+#define RTWN_RX_RADIOTAP_PRESENT			\
+	(1 << IEEE80211_RADIOTAP_TSFT |			\
+	 1 << IEEE80211_RADIOTAP_FLAGS |		\
+	 1 << IEEE80211_RADIOTAP_RATE |			\
+	 1 << IEEE80211_RADIOTAP_CHANNEL |		\
+	 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL |	\
+	 1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)
+
+struct rtwn_tx_radiotap_header {
+	struct ieee80211_radiotap_header wt_ihdr;
+	uint8_t		wt_flags;
+	uint16_t	wt_chan_freq;
+	uint16_t	wt_chan_flags;
+} __packed __aligned(8);
+
+#define RTWN_TX_RADIOTAP_PRESENT			\
+	(1 << IEEE80211_RADIOTAP_FLAGS |		\
+	 1 << IEEE80211_RADIOTAP_CHANNEL)
+
+struct rtwn_tx_buf {
+	uint8_t		txd[RTWN_TX_DESC_SIZE];
+} __attribute__((aligned(4)));
+
+struct rtwn_softc;
+
+union sec_param {
+	struct ieee80211_key	key;
+	int			macid;
+};
+
+#define CMD_FUNC_PROTO		void (*func)(struct rtwn_softc *, \
+				    union sec_param *)
+
+struct rtwn_cmdq {
+	union sec_param		data;
+	CMD_FUNC_PROTO;
+};
+#define RTWN_CMDQ_SIZE		16
+
+struct rtwn_node {
+	struct ieee80211_node	ni;	/* must be the first */
+	int			id;
+	int8_t			last_rssi;
+	int			avg_pwdb;
+};
+#define RTWN_NODE(ni)		((struct rtwn_node *)(ni))
+
+struct rtwn_vap {
+	struct ieee80211vap	vap;
+	int			id;
+#define RTWN_VAP_ID_INVALID	-1
+	int			curr_mode;
+
+	struct rtwn_tx_buf	bcn_desc;
+	struct mbuf		*bcn_mbuf;
+	struct timeout_task	tx_beacon_csa;
+
+	struct callout		tsf_sync_adhoc;
+	struct task		tsf_sync_adhoc_task;
+
+	const struct ieee80211_key	*keys[IEEE80211_WEP_NKID];
+
+	int			(*newstate)(struct ieee80211vap *,
+				    enum ieee80211_state, int);
+	void			(*recv_mgmt)(struct ieee80211_node *,
+				    struct mbuf *, int,
+				    const struct ieee80211_rx_stats *,
+				    int, int);
+};
+#define	RTWN_VAP(vap)		((struct rtwn_vap *)(vap))
+
+/*
+ * Rx data types.
+ */
+enum {
+	RTWN_RX_DATA,
+	RTWN_RX_TX_REPORT,
+	RTWN_RX_OTHER
+};
+
+/*
+ * Firmware reset reasons.
+ */
+enum {
+	RTWN_FW_RESET_DOWNLOAD,
+	RTWN_FW_RESET_CHECKSUM,
+	RTWN_FW_RESET_SHUTDOWN
+};
+
+/*
+ * Rate control algorithm selection.
+ */
+enum {
+	RTWN_RATECTL_NONE,
+	RTWN_RATECTL_NET80211,
+	RTWN_RATECTL_FW,
+	RTWN_RATECTL_MAX
+};
+
+/*
+ * Control h/w crypto usage.
+ */
+enum {
+	RTWN_CRYPTO_SW,
+	RTWN_CRYPTO_PAIR,
+	RTWN_CRYPTO_FULL,
+	RTWN_CRYPTO_MAX,
+};
+
+struct rtwn_softc {
+	struct ieee80211com	sc_ic;
+	struct mbufq		sc_snd;
+	device_t		sc_dev;
+
+#if 1
+	int			sc_ht40;
+#endif
+	uint32_t		sc_debug;
+	int			sc_hwcrypto;
+	int			sc_ratectl_sysctl;
+	int			sc_ratectl;
+
+	uint8_t			sc_detached;
+	uint8_t			sc_flags;
+/* Device flags */
+#define RTWN_FLAG_CCK_HIPWR	0x01
+#define RTWN_FLAG_EXT_HDR	0x02
+#define RTWN_FLAG_CAM_FIXED	0x04
+/* Driver state */
+#define RTWN_STARTED		0x08
+#define RTWN_RUNNING		0x10
+#define RTWN_FW_LOADED		0x20
+#define RTWN_TEMP_MEASURED	0x40
+#define RTWN_RCR_LOCKED		0x80
+
+#define RTWN_CHIP_HAS_BCNQ1(_sc)	\
+	((_sc)->bcn_status_reg[0] != (_sc)->bcn_status_reg[1])
+
+	void			*sc_priv;
+	const char		*name;
+	int			sc_ant;
+
+	int8_t			last_rssi;
+	uint8_t			thcal_temp;
+	int			cur_bcnq_id;
+
+	int			nvaps;
+	int			ap_vaps;
+	int			bcn_vaps;
+	int			mon_vaps;
+
+	int			vaps_running;
+	int			monvaps_running;
+
+	uint16_t		next_rom_addr;
+	uint8_t			keys_bmap[howmany(RTWN_CAM_ENTRY_LIMIT, NBBY)];
+
+	struct rtwn_vap		*vaps[RTWN_PORT_COUNT];
+	struct ieee80211_node	*node_list[RTWN_MACID_LIMIT];
+	struct mtx		nt_mtx;
+
+	struct callout		sc_calib_to;
+	struct callout		sc_pwrmode_init;
+#ifndef D4054
+	struct callout		sc_watchdog_to;
+	int			sc_tx_timer;
+#endif
+
+	struct mtx		sc_mtx;
+
+	struct rtwn_cmdq	cmdq[RTWN_CMDQ_SIZE];
+	struct mtx		cmdq_mtx;
+	struct task		cmdq_task;
+	uint8_t			cmdq_first;
+	uint8_t			cmdq_last;
+
+	struct wmeParams	cap_wmeParams[WME_NUM_AC];
+
+	struct rtwn_rx_radiotap_header	sc_rxtap;
+	struct rtwn_tx_radiotap_header	sc_txtap;
+
+	int			ntxchains;
+	int			nrxchains;
+
+	int			ledlink;
+	uint8_t			thermal_meter;
+
+	int			sc_tx_n_active;
+	uint8_t			qfullmsk;
+
+	/* Firmware-specific */
+	const char		*fwname;
+	uint16_t		fwver;
+	uint16_t		fwsig;
+	int			fwcur;
+
+	void		(*sc_node_free)(struct ieee80211_node *);
+	void		(*sc_scan_curchan)(struct ieee80211_scan_state *,
+			    unsigned long);
+
+	/* Interface-specific. */
+	int		(*sc_write_1)(struct rtwn_softc *, uint16_t,
+			    uint8_t);
+	int		(*sc_write_2)(struct rtwn_softc *, uint16_t,
+			    uint16_t);
+	int		(*sc_write_4)(struct rtwn_softc *, uint16_t,
+			    uint32_t);
+	uint8_t		(*sc_read_1)(struct rtwn_softc *, uint16_t);
+	uint16_t	(*sc_read_2)(struct rtwn_softc *, uint16_t);
+	uint32_t	(*sc_read_4)(struct rtwn_softc *, uint16_t);
+	/* XXX eliminate */
+	void		(*sc_delay)(struct rtwn_softc *, int);
+	int		(*sc_tx_start)(struct rtwn_softc *,
+			    struct ieee80211_node *, struct mbuf *, uint8_t *,
+			    uint8_t, int);
+	void		(*sc_start_xfers)(struct rtwn_softc *);
+	void		(*sc_reset_lists)(struct rtwn_softc *,
+			    struct ieee80211vap *);
+	void		(*sc_abort_xfers)(struct rtwn_softc *);
+	int		(*sc_fw_write_block)(struct rtwn_softc *,
+			    const uint8_t *, uint16_t, int);
+	uint16_t	(*sc_get_qmap)(struct rtwn_softc *);
+	void		(*sc_set_desc_addr)(struct rtwn_softc *);
+	void		(*sc_drop_incorrect_tx)(struct rtwn_softc *);
+	void		(*sc_beacon_update_begin)(struct rtwn_softc *,
+			    struct ieee80211vap *);
+	void		(*sc_beacon_update_end)(struct rtwn_softc *,
+			    struct ieee80211vap *);
+	void		(*sc_beacon_unload)(struct rtwn_softc *, int);
+
+	/* XXX drop checks for PCIe? */
+	int		bcn_check_interval;
+
+	/* Device-specific. */
+	uint32_t	(*sc_rf_read)(struct rtwn_softc *, int, uint8_t);
+	void		(*sc_rf_write)(struct rtwn_softc *, int, uint8_t,
+			    uint32_t);
+	int		(*sc_check_condition)(struct rtwn_softc *,
+			    const uint8_t[]);
+	void		(*sc_efuse_postread)(struct rtwn_softc *);
+	void		(*sc_parse_rom)(struct rtwn_softc *, uint8_t *);
+	void		(*sc_set_led)(struct rtwn_softc *, int, int);
+	int		(*sc_power_on)(struct rtwn_softc *);
+	void		(*sc_power_off)(struct rtwn_softc *);
+#ifndef RTWN_WITHOUT_UCODE
+	void		(*sc_fw_reset)(struct rtwn_softc *, int);
+	void		(*sc_fw_download_enable)(struct rtwn_softc *, int);
+#endif
+	int		(*sc_set_page_size)(struct rtwn_softc *);
+	void		(*sc_lc_calib)(struct rtwn_softc *);
+	void		(*sc_iq_calib)(struct rtwn_softc *);
+	void		(*sc_read_chipid_vendor)(struct rtwn_softc *,
+			    uint32_t);
+	void		(*sc_adj_devcaps)(struct rtwn_softc *);
+	void		(*sc_vap_preattach)(struct rtwn_softc *,
+			    struct ieee80211vap *);
+	void		(*sc_postattach)(struct rtwn_softc *);
+	void		(*sc_detach_private)(struct rtwn_softc *);
+	void		(*sc_fill_tx_desc)(struct rtwn_softc *,
+			    struct ieee80211_node *, struct mbuf *,
+			    void *, uint8_t, int);
+	void		(*sc_fill_tx_desc_raw)(struct rtwn_softc *,
+			    struct ieee80211_node *, struct mbuf *,
+			    void *, const struct ieee80211_bpf_params *);
+	void		(*sc_fill_tx_desc_null)(struct rtwn_softc *,
+			    void *, int, int, int);
+	void		(*sc_dump_tx_desc)(struct rtwn_softc *, const void *);
+	uint8_t		(*sc_tx_radiotap_flags)(const void *);
+	uint8_t		(*sc_rx_radiotap_flags)(const void *);
+	void		(*sc_beacon_init)(struct rtwn_softc *, void *, int);
+	void		(*sc_beacon_enable)(struct rtwn_softc *, int, int);
+	void		(*sc_beacon_set_rate)(void *, int);
+	void		(*sc_beacon_select)(struct rtwn_softc *, int);
+	void		(*sc_set_chan)(struct rtwn_softc *,
+			    struct ieee80211_channel *);
+	void		(*sc_set_media_status)(struct rtwn_softc *, int);
+#ifndef RTWN_WITHOUT_UCODE
+	int		(*sc_set_rsvd_page)(struct rtwn_softc *, int, int,
+			    int);
+	int		(*sc_set_pwrmode)(struct rtwn_softc *,
+			    struct ieee80211vap *, int);
+	void		(*sc_set_rssi)(struct rtwn_softc *);
+#endif
+	int8_t		(*sc_get_rssi_cck)(struct rtwn_softc *, void *);
+	int8_t		(*sc_get_rssi_ofdm)(struct rtwn_softc *, void *);
+	int		(*sc_classify_intr)(struct rtwn_softc *, void *, int);
+	void		(*sc_handle_tx_report)(struct rtwn_softc *, uint8_t *,
+			    int);
+	void		(*sc_handle_c2h_report)(struct rtwn_softc *,
+			    uint8_t *, int);
+	int		(*sc_check_frame)(struct rtwn_softc *, struct mbuf *);
+	void		(*sc_temp_measure)(struct rtwn_softc *);
+	uint8_t		(*sc_temp_read)(struct rtwn_softc *);
+	void		(*sc_init_tx_agg)(struct rtwn_softc *);
+	void		(*sc_init_rx_agg)(struct rtwn_softc *);
+	void		(*sc_init_intr)(struct rtwn_softc *);
+	void		(*sc_init_ampdu)(struct rtwn_softc *);
+	void		(*sc_init_edca)(struct rtwn_softc *);
+	void		(*sc_init_bb)(struct rtwn_softc *);
+	void		(*sc_init_rf)(struct rtwn_softc *);
+	void		(*sc_init_antsel)(struct rtwn_softc *);
+	void		(*sc_post_init)(struct rtwn_softc *);
+	int		(*sc_init_bcnq1_boundary)(struct rtwn_softc *);
+
+	const uint8_t			*chan_list_5ghz[3];
+	int				chan_num_5ghz[3];
+
+	const struct rtwn_mac_prog	*mac_prog;
+	int				mac_size;
+	const struct rtwn_bb_prog	*bb_prog;
+	int				bb_size;
+	const struct rtwn_agc_prog	*agc_prog;
+	int				agc_size;
+	const struct rtwn_rf_prog	*rf_prog;
+
+	int				page_count;
+	int				pktbuf_count;
+
+	int				ackto;
+
+	int				npubqpages;
+	int				nhqpages;
+	int				nnqpages;
+	int				nlqpages;
+	int				page_size;
+
+	int				txdesc_len;
+	int				efuse_maxlen;
+	int				efuse_maplen;
+
+	uint16_t			rx_dma_size;
+
+	int				macid_limit;
+	int				cam_entry_limit;
+	int				fwsize_limit;
+	int				temp_delta;
+
+	uint16_t			bcn_status_reg[RTWN_PORT_COUNT];
+	uint32_t			rcr;	/* Rx filter */
+};
+MALLOC_DECLARE(M_RTWN_PRIV);
+
+#define	RTWN_LOCK(sc)			mtx_lock(&(sc)->sc_mtx)
+#define	RTWN_UNLOCK(sc)		mtx_unlock(&(sc)->sc_mtx)
+#define	RTWN_ASSERT_LOCKED(sc)		mtx_assert(&(sc)->sc_mtx, MA_OWNED)
+
+#define RTWN_CMDQ_LOCK_INIT(sc) \
+	mtx_init(&(sc)->cmdq_mtx, "cmdq lock", NULL, MTX_DEF)
+#define RTWN_CMDQ_LOCK(sc)		mtx_lock(&(sc)->cmdq_mtx)
+#define RTWN_CMDQ_UNLOCK(sc)		mtx_unlock(&(sc)->cmdq_mtx)
+#define RTWN_CMDQ_LOCK_INITIALIZED(sc)	mtx_initialized(&(sc)->cmdq_mtx)
+#define RTWN_CMDQ_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->cmdq_mtx)
+
+#define RTWN_NT_LOCK_INIT(sc) \
+	mtx_init(&(sc)->nt_mtx, "node table lock", NULL, MTX_DEF)
+#define RTWN_NT_LOCK(sc)		mtx_lock(&(sc)->nt_mtx)
+#define RTWN_NT_UNLOCK(sc)		mtx_unlock(&(sc)->nt_mtx)
+#define RTWN_NT_LOCK_INITIALIZED(sc)	mtx_initialized(&(sc)->nt_mtx)
+#define RTWN_NT_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->nt_mtx)
+
+
+void	rtwn_sysctlattach(struct rtwn_softc *);
+
+int	rtwn_attach(struct rtwn_softc *);
+void	rtwn_detach(struct rtwn_softc *);
+void	rtwn_resume(struct rtwn_softc *);
+void	rtwn_suspend(struct rtwn_softc *);
+
+
+/* Interface-specific. */
+#define rtwn_write_1(_sc, _addr, _val) \
+	(((_sc)->sc_write_1)((_sc), (_addr), (_val)))
+#define rtwn_write_2(_sc, _addr, _val) \
+	(((_sc)->sc_write_2)((_sc), (_addr), (_val)))
+#define rtwn_write_4(_sc, _addr, _val) \
+	(((_sc)->sc_write_4)((_sc), (_addr), (_val)))
+#define rtwn_read_1(_sc, _addr) \
+	(((_sc)->sc_read_1)((_sc), (_addr)))
+#define rtwn_read_2(_sc, _addr) \
+	(((_sc)->sc_read_2)((_sc), (_addr)))
+#define rtwn_read_4(_sc, _addr) \
+	(((_sc)->sc_read_4)((_sc), (_addr)))
+#define rtwn_delay(_sc, _usec) \
+	(((_sc)->sc_delay)((_sc), (_usec)))
+#define rtwn_tx_start(_sc, _ni, _m, _desc, _type, _id) \
+	(((_sc)->sc_tx_start)((_sc), (_ni), (_m), (_desc), (_type), (_id)))
+#define rtwn_start_xfers(_sc) \
+	(((_sc)->sc_start_xfers)((_sc)))
+#define rtwn_reset_lists(_sc, _vap) \
+	(((_sc)->sc_reset_lists)((_sc), (_vap)))
+#define rtwn_abort_xfers(_sc) \
+	(((_sc)->sc_abort_xfers)((_sc)))
+#define rtwn_fw_write_block(_sc, _buf, _reg, _len) \
+	(((_sc)->sc_fw_write_block)((_sc), (_buf), (_reg), (_len)))
+#define rtwn_get_qmap(_sc) \
+	(((_sc)->sc_get_qmap)((_sc)))
+#define rtwn_set_desc_addr(_sc) \
+	(((_sc)->sc_set_desc_addr)((_sc)))
+#define rtwn_drop_incorrect_tx(_sc) \
+	(((_sc)->sc_drop_incorrect_tx)((_sc)))
+#define rtwn_beacon_update_begin(_sc, _vap) \
+	(((_sc)->sc_beacon_update_begin)((_sc), (_vap)))
+#define rtwn_beacon_update_end(_sc, _vap) \
+	(((_sc)->sc_beacon_update_end)((_sc), (_vap)))
+#define rtwn_beacon_unload(_sc, _id) \
+	(((_sc)->sc_beacon_unload)((_sc), (_id)))
+
+/* Aliases. */
+#define	rtwn_bb_write		rtwn_write_4
+#define rtwn_bb_read		rtwn_read_4
+#define rtwn_bb_setbits	rtwn_setbits_4
+
+/* Device-specific. */
+#define rtwn_rf_read(_sc, _chain, _addr) \
+	(((_sc)->sc_rf_read)((_sc), (_chain), (_addr)))
+#define rtwn_rf_write(_sc, _chain, _addr, _val) \
+	(((_sc)->sc_rf_write)((_sc), (_chain), (_addr), (_val)))
+#define rtwn_check_condition(_sc, _cond) \
+	(((_sc)->sc_check_condition)((_sc), (_cond)))
+#define rtwn_efuse_postread(_sc) \
+	(((_sc)->sc_efuse_postread)((_sc)))
+#define rtwn_parse_rom(_sc, _rom) \
+	(((_sc)->sc_parse_rom)((_sc), (_rom)))
+#define rtwn_set_led(_sc, _led, _on) \
+	(((_sc)->sc_set_led)((_sc), (_led), (_on)))
+#define rtwn_get_rssi_cck(_sc, _physt) \
+	(((_sc)->sc_get_rssi_cck)((_sc), (_physt)))
+#define rtwn_get_rssi_ofdm(_sc, _physt) \
+	(((_sc)->sc_get_rssi_ofdm)((_sc), (_physt)))
+#define rtwn_power_on(_sc) \
+	(((_sc)->sc_power_on)((_sc)))
+#define rtwn_power_off(_sc) \
+	(((_sc)->sc_power_off)((_sc)))
+#ifndef RTWN_WITHOUT_UCODE
+#define rtwn_fw_reset(_sc, _reason) \
+	(((_sc)->sc_fw_reset)((_sc), (_reason)))
+#define rtwn_fw_download_enable(_sc, _enable) \
+	(((_sc)->sc_fw_download_enable)((_sc), (_enable)))
+#endif
+#define rtwn_set_page_size(_sc) \
+	(((_sc)->sc_set_page_size)((_sc)))
+#define rtwn_lc_calib(_sc) \
+	(((_sc)->sc_lc_calib)((_sc)))
+#define rtwn_iq_calib(_sc) \
+	(((_sc)->sc_iq_calib)((_sc)))
+#define rtwn_read_chipid_vendor(_sc, _reg) \
+	(((_sc)->sc_read_chipid_vendor)((_sc), (_reg)))
+#define rtwn_adj_devcaps(_sc) \
+	(((_sc)->sc_adj_devcaps)((_sc)))
+#define rtwn_vap_preattach(_sc, _vap) \
+	(((_sc)->sc_vap_preattach)((_sc), (_vap)))
+#define rtwn_postattach(_sc) \
+	(((_sc)->sc_postattach)((_sc)))
+#define rtwn_detach_private(_sc) \
+	(((_sc)->sc_detach_private)((_sc)))
+#define rtwn_fill_tx_desc(_sc, _ni, _m, \
+	    _buf, _ridx, _maxretry) \
+	(((_sc)->sc_fill_tx_desc)((_sc), (_ni), \
+	    (_m), (_buf), (_ridx), (_maxretry)))
+#define rtwn_fill_tx_desc_raw(_sc, _ni, _m, \
+	    _buf, _params) \
+	(((_sc)->sc_fill_tx_desc_raw)((_sc), (_ni), \
+	    (_m), (_buf), (_params)))
+#define rtwn_fill_tx_desc_null(_sc, _buf, _11b, _qos, _id) \
+	(((_sc)->sc_fill_tx_desc_null)((_sc), \
+	    (_buf), (_11b), (_qos), (_id)))
+#define rtwn_dump_tx_desc(_sc, _desc) \
+	(((_sc)->sc_dump_tx_desc)((_sc), (_desc)))
+#define rtwn_tx_radiotap_flags(_sc, _buf) \
+	(((_sc)->sc_tx_radiotap_flags)((_buf)))
+#define rtwn_rx_radiotap_flags(_sc, _buf) \
+	(((_sc)->sc_rx_radiotap_flags)((_buf)))
+#define rtwn_set_chan(_sc, _c) \
+	(((_sc)->sc_set_chan)((_sc), (_c)))
+#ifndef RTWN_WITHOUT_UCODE
+#define rtwn_set_rsvd_page(_sc, _resp, _null, _qos_null) \
+	(((_sc)->sc_set_rsvd_page)((_sc), \
+	    (_resp), (_null), (_qos_null)))
+#define rtwn_set_pwrmode(_sc, _vap, _off) \
+	(((_sc)->sc_set_pwrmode)((_sc), (_vap), (_off)))
+#define rtwn_set_rssi(_sc) \
+	(((_sc)->sc_set_rssi)((_sc)))
+#endif
+#define rtwn_classify_intr(_sc, _buf, _len) \
+	(((_sc)->sc_classify_intr)((_sc), (_buf), (_len)))
+#define rtwn_handle_tx_report(_sc, _buf, _len) \
+	(((_sc)->sc_handle_tx_report)((_sc), (_buf), (_len)))
+#define rtwn_handle_c2h_report(_sc, _buf, _len) \
+	(((_sc)->sc_handle_c2h_report)((_sc), (_buf), (_len)))
+#define rtwn_check_frame(_sc, _m) \
+	(((_sc)->sc_check_frame)((_sc), (_m)))
+#define rtwn_beacon_init(_sc, _buf, _id) \
+	(((_sc)->sc_beacon_init)((_sc), (_buf), (_id)))
+#define rtwn_beacon_enable(_sc, _id, _enable) \
+	(((_sc)->sc_beacon_enable)((_sc), (_id), (_enable)))
+#define rtwn_beacon_set_rate(_sc, _buf, _is5ghz) \
+	(((_sc)->sc_beacon_set_rate)((_buf), (_is5ghz)))
+#define rtwn_beacon_select(_sc, _id) \
+	(((_sc)->sc_beacon_select)((_sc), (_id)))
+#define rtwn_temp_measure(_sc) \
+	(((_sc)->sc_temp_measure)((_sc)))
+#define rtwn_temp_read(_sc) \
+	(((_sc)->sc_temp_read)((_sc)))
+#define rtwn_init_tx_agg(_sc) \
+	(((_sc)->sc_init_tx_agg)((_sc)))
+#define rtwn_init_rx_agg(_sc) \
+	(((_sc)->sc_init_rx_agg)((_sc)))
+#define rtwn_init_intr(_sc) \
+	(((_sc)->sc_init_intr)((_sc)))
+#define rtwn_init_ampdu(_sc) \
+	(((_sc)->sc_init_ampdu)((_sc)))
+#define rtwn_init_edca(_sc) \
+	(((_sc)->sc_init_edca)((_sc)))
+#define rtwn_init_bb(_sc) \
+	(((_sc)->sc_init_bb)((_sc)))
+#define rtwn_init_rf(_sc) \
+	(((_sc)->sc_init_rf)((_sc)))
+#define rtwn_init_antsel(_sc) \
+	(((_sc)->sc_init_antsel)((_sc)))
+#define rtwn_post_init(_sc) \
+	(((_sc)->sc_post_init)((_sc)))
+#define rtwn_init_bcnq1_boundary(_sc) \
+	(((_sc)->sc_init_bcnq1_boundary)((_sc)))
+
+
+/*
+ * Methods to access subfields in registers.
+ */
+static __inline int
+rtwn_setbits_1(struct rtwn_softc *sc, uint16_t addr, uint8_t clr,
+    uint8_t set)
+{
+	return (rtwn_write_1(sc, addr,
+	    (rtwn_read_1(sc, addr) & ~clr) | set));
+}
+
+static __inline int
+rtwn_setbits_1_shift(struct rtwn_softc *sc, uint16_t addr, uint32_t clr,
+    uint32_t set, int shift)
+{
+	return (rtwn_setbits_1(sc, addr + shift, clr >> shift * NBBY,
+	    set >> shift * NBBY));
+}
+
+static __inline int
+rtwn_setbits_2(struct rtwn_softc *sc, uint16_t addr, uint16_t clr,
+    uint16_t set)
+{
+	return (rtwn_write_2(sc, addr,
+	    (rtwn_read_2(sc, addr) & ~clr) | set));
+}
+
+static __inline int
+rtwn_setbits_4(struct rtwn_softc *sc, uint16_t addr, uint32_t clr,
+    uint32_t set)
+{
+	return (rtwn_write_4(sc, addr,
+	    (rtwn_read_4(sc, addr) & ~clr) | set));
+}
+
+static __inline void
+rtwn_rf_setbits(struct rtwn_softc *sc, int chain, uint8_t addr,
+    uint32_t clr, uint32_t set)
+{
+	rtwn_rf_write(sc, chain, addr,
+	    (rtwn_rf_read(sc, chain, addr) & ~clr) | set);
+}
+
+#endif	/* IF_RTWNVAR_H */
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,784 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/sysctl.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+#include <sys/kdb.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_nop.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+
+#include <dev/rtwn/pci/rtwn_pci_attach.h>
+#include <dev/rtwn/pci/rtwn_pci_reg.h>
+#include <dev/rtwn/pci/rtwn_pci_rx.h>
+#include <dev/rtwn/pci/rtwn_pci_tx.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h>
+
+
+static device_probe_t	rtwn_pci_probe;
+static device_attach_t	rtwn_pci_attach;
+static device_detach_t	rtwn_pci_detach;
+static device_shutdown_t rtwn_pci_shutdown;
+static device_suspend_t	rtwn_pci_suspend;
+static device_resume_t	rtwn_pci_resume;
+
+static int	rtwn_pci_alloc_rx_list(struct rtwn_softc *);
+static void	rtwn_pci_reset_rx_list(struct rtwn_softc *);
+static void	rtwn_pci_free_rx_list(struct rtwn_softc *);
+static int	rtwn_pci_alloc_tx_list(struct rtwn_softc *, int);
+static void	rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *, int);
+static void	rtwn_pci_reset_beacon_ring(struct rtwn_softc *, int);
+static void	rtwn_pci_reset_tx_list(struct rtwn_softc *,
+		    struct ieee80211vap *, int);
+static void	rtwn_pci_free_tx_list(struct rtwn_softc *, int);
+static void	rtwn_pci_reset_lists(struct rtwn_softc *,
+		    struct ieee80211vap *);
+static int	rtwn_pci_fw_write_block(struct rtwn_softc *,
+		    const uint8_t *, uint16_t, int);
+static uint16_t	rtwn_pci_get_qmap(struct rtwn_softc *);
+static void	rtwn_pci_set_desc_addr(struct rtwn_softc *);
+static void	rtwn_pci_beacon_update_begin(struct rtwn_softc *,
+		    struct ieee80211vap *);
+static void	rtwn_pci_beacon_update_end(struct rtwn_softc *,
+		    struct ieee80211vap *);
+static void	rtwn_pci_attach_methods(struct rtwn_softc *);
+
+
+static int matched_chip = RTWN_CHIP_MAX_PCI;
+
+static int
+rtwn_pci_probe(device_t dev)
+{
+	const struct rtwn_pci_ident *ident;
+
+	for (ident = rtwn_pci_ident_table; ident->name != NULL; ident++) {
+		if (pci_get_vendor(dev) == ident->vendor &&
+		    pci_get_device(dev) == ident->device) {
+			matched_chip = ident->chip;
+			device_set_desc(dev, ident->name);
+			return (BUS_PROBE_DEFAULT);
+		}
+	}
+	return (ENXIO);
+}
+
+static int
+rtwn_pci_alloc_rx_list(struct rtwn_softc *sc)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_rx_ring *rx_ring = &pc->rx_ring;
+	struct rtwn_rx_data *rx_data;
+	bus_size_t size;
+	int i, error;
+
+	/* Allocate Rx descriptors. */
+	size = sizeof(struct r92ce_rx_stat) * RTWN_PCI_RX_LIST_COUNT;
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    size, 1, size, 0, NULL, NULL, &rx_ring->desc_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create rx desc DMA tag\n");
+		goto fail;
+	}
+
+	error = bus_dmamem_alloc(rx_ring->desc_dmat, (void **)&rx_ring->desc,
+	    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
+	    &rx_ring->desc_map);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not allocate rx desc\n");
+		goto fail;
+	}
+	error = bus_dmamap_load(rx_ring->desc_dmat, rx_ring->desc_map,
+	    rx_ring->desc, size, rtwn_pci_dma_map_addr, &rx_ring->paddr, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not load rx desc DMA map\n");
+		goto fail;
+	}
+	bus_dmamap_sync(rx_ring->desc_dmat, rx_ring->desc_map,
+	    BUS_DMASYNC_PREWRITE);
+
+	/* Create RX buffer DMA tag. */
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL, &rx_ring->data_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create rx buf DMA tag\n");
+		goto fail;
+	}
+
+	/* Allocate Rx buffers. */
+	for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) {
+		rx_data = &rx_ring->rx_data[i];
+		error = bus_dmamap_create(rx_ring->data_dmat, 0, &rx_data->map);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "could not create rx buf DMA map\n");
+			goto fail;
+		}
+
+		rx_data->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
+		    MJUMPAGESIZE);
+		if (rx_data->m == NULL) {
+			device_printf(sc->sc_dev,
+			    "could not allocate rx mbuf\n");
+			error = ENOMEM;
+			goto fail;
+		}
+
+		error = bus_dmamap_load(rx_ring->data_dmat, rx_data->map,
+		    mtod(rx_data->m, void *), MJUMPAGESIZE,
+		    rtwn_pci_dma_map_addr, &rx_data->paddr, BUS_DMA_NOWAIT);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "could not load rx buf DMA map");
+			goto fail;
+		}
+
+		rtwn_pci_setup_rx_desc(pc, &rx_ring->desc[i], rx_data->paddr,
+		    MJUMPAGESIZE, i);
+	}
+	rx_ring->cur = 0;
+
+	return (0);
+
+fail:
+	rtwn_pci_free_rx_list(sc);
+	return (error);
+}
+
+static void
+rtwn_pci_reset_rx_list(struct rtwn_softc *sc)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_rx_ring *rx_ring = &pc->rx_ring;
+	struct rtwn_rx_data *rx_data;
+	int i;
+
+	for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) {
+		rx_data = &rx_ring->rx_data[i];
+		rtwn_pci_setup_rx_desc(pc, &rx_ring->desc[i],
+		    rx_data->paddr, MJUMPAGESIZE, i);
+	}
+	rx_ring->cur = 0;
+}
+
+static void
+rtwn_pci_free_rx_list(struct rtwn_softc *sc)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_rx_ring *rx_ring = &pc->rx_ring;
+	struct rtwn_rx_data *rx_data;
+	int i;
+
+	if (rx_ring->desc_dmat != NULL) {
+		if (rx_ring->desc != NULL) {
+			bus_dmamap_sync(rx_ring->desc_dmat,
+			    rx_ring->desc_map,
+			    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(rx_ring->desc_dmat,
+			    rx_ring->desc_map);
+			bus_dmamem_free(rx_ring->desc_dmat, rx_ring->desc,
+			    rx_ring->desc_map);
+			rx_ring->desc = NULL;
+		}
+		bus_dma_tag_destroy(rx_ring->desc_dmat);
+		rx_ring->desc_dmat = NULL;
+	}
+
+	for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) {
+		rx_data = &rx_ring->rx_data[i];
+
+		if (rx_data->m != NULL) {
+			bus_dmamap_sync(rx_ring->data_dmat,
+			    rx_data->map, BUS_DMASYNC_POSTREAD);
+			bus_dmamap_unload(rx_ring->data_dmat, rx_data->map);
+			m_freem(rx_data->m);
+			rx_data->m = NULL;
+		}
+		bus_dmamap_destroy(rx_ring->data_dmat, rx_data->map);
+		rx_data->map = NULL;
+	}
+	if (rx_ring->data_dmat != NULL) {
+		bus_dma_tag_destroy(rx_ring->data_dmat);
+		rx_ring->data_dmat = NULL;
+	}
+}
+
+static int
+rtwn_pci_alloc_tx_list(struct rtwn_softc *sc, int qid)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid];
+	bus_size_t size;
+	int i, error;
+
+	size = sc->txdesc_len * RTWN_PCI_TX_LIST_COUNT;
+	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, &tx_ring->desc_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create tx ring DMA tag\n");
+		goto fail;
+	}
+
+	error = bus_dmamem_alloc(tx_ring->desc_dmat, &tx_ring->desc,
+	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &tx_ring->desc_map);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "can't map tx ring DMA memory\n");
+		goto fail;
+	}
+	error = bus_dmamap_load(tx_ring->desc_dmat, tx_ring->desc_map,
+	    tx_ring->desc, size, rtwn_pci_dma_map_addr, &tx_ring->paddr,
+	    BUS_DMA_NOWAIT);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not load desc DMA map\n");
+		goto fail;
+	}
+	bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map,
+	    BUS_DMASYNC_PREWRITE);
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL, &tx_ring->data_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create tx buf DMA tag\n");
+		goto fail;
+	}
+
+	for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) {
+		struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i];
+		void *tx_desc = (uint8_t *)tx_ring->desc + sc->txdesc_len * i;
+		uint32_t next_desc_addr = tx_ring->paddr +
+		    sc->txdesc_len * ((i + 1) % RTWN_PCI_TX_LIST_COUNT);
+
+		rtwn_pci_setup_tx_desc(pc, tx_desc, next_desc_addr);
+
+		error = bus_dmamap_create(tx_ring->data_dmat, 0, &tx_data->map);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "could not create tx buf DMA map\n");
+			return (error);
+		}
+		tx_data->m = NULL;
+		tx_data->ni = NULL;
+	}
+	return (0);
+
+fail:
+	rtwn_pci_free_tx_list(sc, qid);
+	return (error);
+}
+
+static void
+rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *sc, int qid)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_tx_ring *ring = &pc->tx_ring[qid];
+	int i;
+
+	for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) {
+		struct rtwn_tx_data *data = &ring->tx_data[i];
+		void *desc = (uint8_t *)ring->desc + sc->txdesc_len * i;
+
+		rtwn_pci_copy_tx_desc(pc, desc, NULL);
+
+		if (data->m != NULL) {
+			bus_dmamap_sync(ring->data_dmat, data->map,
+			    BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(ring->data_dmat, data->map);
+			m_freem(data->m);
+			data->m = NULL;
+		}
+		if (data->ni != NULL) {
+			ieee80211_free_node(data->ni);
+			data->ni = NULL;
+		}
+	}
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+	    BUS_DMASYNC_POSTWRITE);
+
+	sc->qfullmsk &= ~(1 << qid);
+	ring->queued = 0;
+	ring->last = ring->cur = 0;
+}
+
+/*
+ * Clear entry 0 (or 1) in the beacon queue (other are not used).
+ */
+static void
+rtwn_pci_reset_beacon_ring(struct rtwn_softc *sc, int id)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_tx_ring *ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE];
+	struct rtwn_tx_data *data = &ring->tx_data[id];
+	struct rtwn_tx_desc_common *txd = (struct rtwn_tx_desc_common *)
+	    ((uint8_t *)ring->desc + id * sc->txdesc_len);
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD);
+	if (txd->flags0 & RTWN_FLAGS0_OWN) {
+		/* Clear OWN bit. */
+		txd->flags0 &= ~RTWN_FLAGS0_OWN;
+		bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+		    BUS_DMASYNC_PREWRITE);
+
+		/* Unload mbuf. */
+		bus_dmamap_sync(ring->data_dmat, data->map,
+		    BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(ring->data_dmat, data->map);
+	}
+}
+
+/*
+ * Drop stale entries from Tx ring before the vap will be deleted.
+ * In case if vap is NULL just free everything and reset cur / last pointers.
+ */
+static void
+rtwn_pci_reset_tx_list(struct rtwn_softc *sc, struct ieee80211vap *vap,
+    int qid)
+{
+	int i;
+
+	if (vap == NULL) {
+		if (qid != RTWN_PCI_BEACON_QUEUE) {
+			/*
+			 * Device was stopped; just clear all entries.
+			 */
+			rtwn_pci_reset_tx_ring_stopped(sc, qid);
+		} else {
+			for (i = 0; i < RTWN_PORT_COUNT; i++)
+				rtwn_pci_reset_beacon_ring(sc, i);
+		}
+	} else if (qid == RTWN_PCI_BEACON_QUEUE &&
+		   (vap->iv_opmode == IEEE80211_M_HOSTAP ||
+		    vap->iv_opmode == IEEE80211_M_IBSS)) {
+		struct rtwn_vap *uvp = RTWN_VAP(vap);
+
+		rtwn_pci_reset_beacon_ring(sc, uvp->id);
+	} else {
+		struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+		struct rtwn_tx_ring *ring = &pc->tx_ring[qid];
+
+		for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) {
+			struct rtwn_tx_data *data = &ring->tx_data[i];
+			if (data->ni != NULL && data->ni->ni_vap == vap) {
+				/*
+				 * NB: if some vap is still running
+				 * rtwn_pci_tx_done() will free the mbuf;
+				 * otherwise, rtwn_stop() will reset all rings
+				 * after device shutdown.
+				 */
+				ieee80211_free_node(data->ni);
+				data->ni = NULL;
+			}
+		}
+	}
+}
+
+static void
+rtwn_pci_free_tx_list(struct rtwn_softc *sc, int qid)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid];
+	struct rtwn_tx_data *tx_data;
+	int i;
+
+	if (tx_ring->desc_dmat != NULL) {
+		if (tx_ring->desc != NULL) {
+			bus_dmamap_sync(tx_ring->desc_dmat,
+			    tx_ring->desc_map, BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(tx_ring->desc_dmat,
+			    tx_ring->desc_map);
+			bus_dmamem_free(tx_ring->desc_dmat, tx_ring->desc,
+			    tx_ring->desc_map);
+		}
+		bus_dma_tag_destroy(tx_ring->desc_dmat);
+	}
+
+	for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) {
+		tx_data = &tx_ring->tx_data[i];
+
+		if (tx_data->m != NULL) {
+			bus_dmamap_sync(tx_ring->data_dmat, tx_data->map,
+			    BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(tx_ring->data_dmat, tx_data->map);
+			m_freem(tx_data->m);
+			tx_data->m = NULL;
+		}
+	}
+	if (tx_ring->data_dmat != NULL) {
+		bus_dma_tag_destroy(tx_ring->data_dmat);
+		tx_ring->data_dmat = NULL;
+	}
+
+	sc->qfullmsk &= ~(1 << qid);
+	tx_ring->queued = 0;
+	tx_ring->last = tx_ring->cur = 0;
+}
+
+static void
+rtwn_pci_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	int i;
+
+	for (i = 0; i < RTWN_PCI_NTXQUEUES; i++)
+		rtwn_pci_reset_tx_list(sc, vap, i);
+
+	if (vap == NULL) {
+		sc->qfullmsk = 0;
+		rtwn_pci_reset_rx_list(sc);
+	}
+}
+
+static int
+rtwn_pci_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf,
+    uint16_t reg, int mlen)
+{
+	int i;
+
+	for (i = 0; i < mlen; i++)
+		rtwn_pci_write_1(sc, reg++, buf[i]);
+
+	/* NB: cannot fail */
+	return (0);
+}
+
+static uint16_t
+rtwn_pci_get_qmap(struct rtwn_softc *sc)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+
+	KASSERT(pc->pc_qmap != 0, ("%s: qmap is not set!\n", __func__));
+
+	return (pc->pc_qmap);
+}
+
+static void
+rtwn_pci_set_desc_addr(struct rtwn_softc *sc)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, "%s: addresses:\n"
+	    "bk: %08jX, be: %08jX, vi: %08jX, vo: %08jX\n"
+	    "bcn: %08jX, mgt: %08jX, high: %08jX, rx: %08jX\n",
+	    __func__, (uintmax_t)pc->tx_ring[RTWN_PCI_BK_QUEUE].paddr,
+	    (uintmax_t)pc->tx_ring[RTWN_PCI_BE_QUEUE].paddr,
+	    (uintmax_t)pc->tx_ring[RTWN_PCI_VI_QUEUE].paddr,
+	    (uintmax_t)pc->tx_ring[RTWN_PCI_VO_QUEUE].paddr,
+	    (uintmax_t)pc->tx_ring[RTWN_PCI_BEACON_QUEUE].paddr,
+	    (uintmax_t)pc->tx_ring[RTWN_PCI_MGNT_QUEUE].paddr,
+	    (uintmax_t)pc->tx_ring[RTWN_PCI_HIGH_QUEUE].paddr,
+	    (uintmax_t)pc->rx_ring.paddr);
+
+	/* Set Tx Configuration Register. */
+	rtwn_pci_write_4(sc, R92C_TCR, pc->tcr);
+
+	/* Configure Tx DMA. */
+	rtwn_pci_write_4(sc, R92C_BKQ_DESA,
+	    pc->tx_ring[RTWN_PCI_BK_QUEUE].paddr);
+	rtwn_pci_write_4(sc, R92C_BEQ_DESA,
+	    pc->tx_ring[RTWN_PCI_BE_QUEUE].paddr);
+	rtwn_pci_write_4(sc, R92C_VIQ_DESA,
+	    pc->tx_ring[RTWN_PCI_VI_QUEUE].paddr);
+	rtwn_pci_write_4(sc, R92C_VOQ_DESA,
+	    pc->tx_ring[RTWN_PCI_VO_QUEUE].paddr);
+	rtwn_pci_write_4(sc, R92C_BCNQ_DESA,
+	    pc->tx_ring[RTWN_PCI_BEACON_QUEUE].paddr);
+	rtwn_pci_write_4(sc, R92C_MGQ_DESA,
+	    pc->tx_ring[RTWN_PCI_MGNT_QUEUE].paddr);
+	rtwn_pci_write_4(sc, R92C_HQ_DESA,
+	    pc->tx_ring[RTWN_PCI_HIGH_QUEUE].paddr);
+
+	/* Configure Rx DMA. */
+	rtwn_pci_write_4(sc, R92C_RX_DESA, pc->rx_ring.paddr);
+}
+
+static void
+rtwn_pci_beacon_update_begin(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct rtwn_vap *rvp = RTWN_VAP(vap);
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	rtwn_beacon_enable(sc, rvp->id, 0);
+}
+
+static void
+rtwn_pci_beacon_update_end(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct rtwn_vap *rvp = RTWN_VAP(vap);
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	if (rvp->curr_mode != R92C_MSR_NOLINK)
+		rtwn_beacon_enable(sc, rvp->id, 1);
+}
+
+static void
+rtwn_pci_attach_methods(struct rtwn_softc *sc)
+{
+	sc->sc_write_1		= rtwn_pci_write_1;
+	sc->sc_write_2		= rtwn_pci_write_2;
+	sc->sc_write_4		= rtwn_pci_write_4;
+	sc->sc_read_1		= rtwn_pci_read_1;
+	sc->sc_read_2		= rtwn_pci_read_2;
+	sc->sc_read_4		= rtwn_pci_read_4;
+	sc->sc_delay		= rtwn_pci_delay;
+	sc->sc_tx_start		= rtwn_pci_tx_start;
+	sc->sc_reset_lists	= rtwn_pci_reset_lists;
+	sc->sc_abort_xfers	= rtwn_nop_softc;
+	sc->sc_fw_write_block	= rtwn_pci_fw_write_block;
+	sc->sc_get_qmap		= rtwn_pci_get_qmap;
+	sc->sc_set_desc_addr	= rtwn_pci_set_desc_addr;
+	sc->sc_drop_incorrect_tx = rtwn_nop_softc;
+	sc->sc_beacon_update_begin = rtwn_pci_beacon_update_begin;
+	sc->sc_beacon_update_end = rtwn_pci_beacon_update_end;
+	sc->sc_beacon_unload	= rtwn_pci_reset_beacon_ring;
+
+	sc->bcn_check_interval	= 25000;
+}
+
+static int
+rtwn_pci_attach(device_t dev)
+{
+	struct rtwn_pci_softc *pc = device_get_softc(dev);
+	struct rtwn_softc *sc = &pc->pc_sc;
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint32_t lcsr;
+	int cap_off, i, error, rid;
+
+	if (matched_chip >= RTWN_CHIP_MAX_PCI)
+		return (ENXIO);
+
+	/*
+	 * Get the offset of the PCI Express Capability Structure in PCI
+	 * Configuration Space.
+	 */
+	error = pci_find_cap(dev, PCIY_EXPRESS, &cap_off);
+	if (error != 0) {
+		device_printf(dev, "PCIe capability structure not found!\n");
+		return (error);
+	}
+
+	/* Enable bus-mastering. */
+	pci_enable_busmaster(dev);
+
+	rid = PCIR_BAR(2);
+	pc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (pc->mem == NULL) {
+		device_printf(dev, "can't map mem space\n");
+		return (ENOMEM);
+	}
+	pc->pc_st = rman_get_bustag(pc->mem);
+	pc->pc_sh = rman_get_bushandle(pc->mem);
+
+	/* Install interrupt handler. */
+	rid = 1;
+	if (pci_alloc_msi(dev, &rid) == 0)
+		rid = 1;
+	else
+		rid = 0;
+	pc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE |
+	    (rid != 0 ? 0 : RF_SHAREABLE));
+	if (pc->irq == NULL) {
+		device_printf(dev, "can't map interrupt\n");
+		goto detach;
+	}
+
+	/* Disable PCIe Active State Power Management (ASPM). */
+	lcsr = pci_read_config(dev, cap_off + PCIER_LINK_CTL, 4);
+	lcsr &= ~PCIEM_LINK_CTL_ASPMC;
+	pci_write_config(dev, cap_off + PCIER_LINK_CTL, lcsr, 4);
+
+	sc->sc_dev = dev;
+	ic->ic_name = device_get_nameunit(dev);
+
+	/* Need to be initialized early. */
+	rtwn_sysctlattach(sc);
+	mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF);
+
+	rtwn_pci_attach_methods(sc);
+	/* XXX something similar to USB_GET_DRIVER_INFO() */
+	rtwn_pci_attach_private(pc, matched_chip);
+
+	/* Allocate Tx/Rx buffers. */
+	error = rtwn_pci_alloc_rx_list(sc);
+	if (error != 0) {
+		device_printf(dev,
+		    "could not allocate Rx buffers, error %d\n",
+		    error);
+		goto detach;
+	}
+	for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) {
+		error = rtwn_pci_alloc_tx_list(sc, i);
+		if (error != 0) {
+			device_printf(dev,
+			    "could not allocate Tx buffers, error %d\n",
+			    error);
+			goto detach;
+		}
+	}
+
+	/* Generic attach. */
+	error = rtwn_attach(sc);
+	if (error != 0)
+		goto detach;
+
+	/*
+	 * Hook our interrupt after all initialization is complete.
+	 */
+	error = bus_setup_intr(dev, pc->irq, INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL, rtwn_pci_intr, sc, &pc->pc_ih);
+	if (error != 0) {
+		device_printf(dev, "can't establish interrupt, error %d\n",
+		    error);
+		goto detach;
+	}
+
+	return (0);
+
+detach:
+	rtwn_pci_detach(dev);		/* failure */
+	return (ENXIO);
+}
+
+static int
+rtwn_pci_detach(device_t dev)
+{
+	struct rtwn_pci_softc *pc = device_get_softc(dev);
+	struct rtwn_softc *sc = &pc->pc_sc;
+	int i;
+
+	/* Generic detach. */
+	rtwn_detach(sc);
+
+	/* Uninstall interrupt handler. */
+	if (pc->irq != NULL) {
+		bus_teardown_intr(dev, pc->irq, pc->pc_ih);
+		bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(pc->irq),
+		    pc->irq);
+		pci_release_msi(dev);
+	}
+
+	/* Free Tx/Rx buffers. */
+	for (i = 0; i < RTWN_PCI_NTXQUEUES; i++)
+		rtwn_pci_free_tx_list(sc, i);
+	rtwn_pci_free_rx_list(sc);
+
+	if (pc->mem != NULL)
+		bus_release_resource(dev, SYS_RES_MEMORY,
+		    rman_get_rid(pc->mem), pc->mem);
+
+	rtwn_detach_private(sc);
+	mtx_destroy(&sc->sc_mtx);
+
+	return (0);
+}
+
+static int
+rtwn_pci_shutdown(device_t self)
+{
+	struct rtwn_pci_softc *pc = device_get_softc(self);
+
+	ieee80211_stop_all(&pc->pc_sc.sc_ic);
+	return (0);
+}
+
+static int
+rtwn_pci_suspend(device_t self)
+{
+	struct rtwn_pci_softc *pc = device_get_softc(self);
+
+	rtwn_suspend(&pc->pc_sc);
+
+	return (0);
+}
+
+static int
+rtwn_pci_resume(device_t self)
+{
+	struct rtwn_pci_softc *pc = device_get_softc(self);
+
+	rtwn_resume(&pc->pc_sc);
+
+	return (0);
+}
+
+static device_method_t rtwn_pci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		rtwn_pci_probe),
+	DEVMETHOD(device_attach,	rtwn_pci_attach),
+	DEVMETHOD(device_detach,	rtwn_pci_detach),
+	DEVMETHOD(device_shutdown,	rtwn_pci_shutdown),
+	DEVMETHOD(device_suspend,	rtwn_pci_suspend),
+	DEVMETHOD(device_resume,	rtwn_pci_resume),
+
+	DEVMETHOD_END
+};
+
+static driver_t rtwn_pci_driver = {
+	"rtwn",
+	rtwn_pci_methods,
+	sizeof(struct rtwn_pci_softc)
+};
+
+static devclass_t rtwn_pci_devclass;
+
+DRIVER_MODULE(rtwn_pci, pci, rtwn_pci_driver, rtwn_pci_devclass, NULL, NULL);
+MODULE_VERSION(rtwn_pci, 1);
+MODULE_DEPEND(rtwn_pci, pci, 1, 1, 1);
+MODULE_DEPEND(rtwn_pci, wlan, 1, 1, 1);
+MODULE_DEPEND(rtwn_pci, rtwn, 2, 2, 2);
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * $FreeBSD$
+ */
+
+void	r92ce_attach(struct rtwn_pci_softc *);
+
+enum {
+	RTWN_CHIP_RTL8192CE,
+	RTWN_CHIP_MAX_PCI
+};
+
+struct rtwn_pci_ident {
+	uint16_t	vendor;
+	uint16_t	device;
+	const char	*name;
+	int		chip;
+};
+
+static const struct rtwn_pci_ident rtwn_pci_ident_table[] = {
+	{ 0x10ec, 0x8176, "Realtek RTL8188CE", RTWN_CHIP_RTL8192CE },
+	{ 0, 0, NULL, RTWN_CHIP_MAX_PCI }
+};
+
+typedef void	(*chip_pci_attach)(struct rtwn_pci_softc *);
+
+static const chip_pci_attach rtwn_chip_pci_attach[RTWN_CHIP_MAX_PCI] = {
+	[RTWN_CHIP_RTL8192CE] = r92ce_attach
+};
+
+static __inline void
+rtwn_pci_attach_private(struct rtwn_pci_softc *pc, int chip)
+{
+	rtwn_chip_pci_attach[chip](pc);
+}
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,125 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*      $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $     */
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+#include <dev/rtwn/pci/rtwn_pci_reg.h>
+
+
+int
+rtwn_pci_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+
+	bus_space_write_1(pc->pc_st, pc->pc_sh, addr, val);
+
+	return (0);
+}
+
+int
+rtwn_pci_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+
+	val = htole16(val);
+	bus_space_write_2(pc->pc_st, pc->pc_sh, addr, val);
+
+	return (0);
+}
+
+int
+rtwn_pci_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+
+	val = htole32(val);
+	bus_space_write_4(pc->pc_st, pc->pc_sh, addr, val);
+
+	return (0);
+}
+
+uint8_t
+rtwn_pci_read_1(struct rtwn_softc *sc, uint16_t addr)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+
+	return (bus_space_read_1(pc->pc_st, pc->pc_sh, addr));
+}
+
+uint16_t
+rtwn_pci_read_2(struct rtwn_softc *sc, uint16_t addr)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	uint16_t val;
+
+	val = bus_space_read_2(pc->pc_st, pc->pc_sh, addr);
+	return le16toh(val);
+}
+
+uint32_t
+rtwn_pci_read_4(struct rtwn_softc *sc, uint16_t addr)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	uint32_t val;
+
+	val = bus_space_read_4(pc->pc_st, pc->pc_sh, addr);
+	return le32toh(val);
+}
+
+void
+rtwn_pci_delay(struct rtwn_softc *sc, int usec)
+{
+	if (usec < 1000)
+		DELAY(usec);
+	else {
+		(void) mtx_sleep(sc, &sc->sc_mtx, 0, "rtwn_pci",
+		    MAX(msecs_to_ticks(usec / 1000), 1));
+	}
+}
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTWN_PCI_REG_H
+#define RTWN_PCI_REG_H
+
+int		rtwn_pci_write_1(struct rtwn_softc *, uint16_t, uint8_t);
+int		rtwn_pci_write_2(struct rtwn_softc *, uint16_t, uint16_t);
+int		rtwn_pci_write_4(struct rtwn_softc *, uint16_t, uint32_t);
+uint8_t		rtwn_pci_read_1(struct rtwn_softc *, uint16_t);
+uint16_t	rtwn_pci_read_2(struct rtwn_softc *, uint16_t);
+uint32_t	rtwn_pci_read_4(struct rtwn_softc *, uint16_t);
+void		rtwn_pci_delay(struct rtwn_softc *, int);
+
+#endif	/* RTWN_PCI_REG_H */
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,329 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_rx.h>
+#include <dev/rtwn/if_rtwn_task.h>
+#include <dev/rtwn/if_rtwn_tx.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+#include <dev/rtwn/pci/rtwn_pci_rx.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h>
+
+
+void
+rtwn_pci_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs,
+    int error)
+{
+
+	if (error != 0)
+		return;
+	KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs));
+	*(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+void
+rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *pc, struct r92ce_rx_stat *desc,
+    bus_addr_t addr, size_t len, int idx)
+{
+
+	memset(desc, 0, sizeof(*desc));
+	desc->rxdw0 = htole32(SM(R92C_RXDW0_PKTLEN, len) |
+		((idx == RTWN_PCI_RX_LIST_COUNT - 1) ? R92C_RXDW0_EOR : 0));
+	desc->rxbufaddr = htole32(addr);
+	bus_space_barrier(pc->pc_st, pc->pc_sh, 0, pc->pc_mapsize,
+	    BUS_SPACE_BARRIER_WRITE);
+	desc->rxdw0 |= htole32(R92C_RXDW0_OWN);
+}
+
+static void
+rtwn_pci_rx_frame(struct rtwn_softc *sc, struct r92ce_rx_stat *rx_desc,
+    int desc_idx)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_rx_ring *ring = &pc->rx_ring;
+	struct rtwn_rx_data *rx_data = &ring->rx_data[desc_idx];
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_node *ni;
+	uint32_t rxdw0;
+	struct mbuf *m, *m1;
+	int8_t rssi = 0, nf;
+	int infosz, pktlen, shift, error;
+
+	/* Dump Rx descriptor. */
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
+	    "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X, "
+	    "addr: %08X (64: %08X)\n",
+	    __func__, le32toh(rx_desc->rxdw0), le32toh(rx_desc->rxdw1),
+	    le32toh(rx_desc->rxdw2), le32toh(rx_desc->rxdw3),
+	    le32toh(rx_desc->rxdw4), le32toh(rx_desc->tsf_low),
+	    le32toh(rx_desc->rxbufaddr), le32toh(rx_desc->rxbufaddr64));
+
+	rxdw0 = le32toh(rx_desc->rxdw0);
+	if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) {
+		/*
+		 * This should not happen since we setup our Rx filter
+		 * to not receive these frames.
+		 */
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
+		    "%s: RX flags error (%s)\n", __func__,
+		    rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV");
+		goto fail;
+	}
+
+	pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+	if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack) ||
+	    pktlen > MJUMPAGESIZE)) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
+		    "%s: frame is too short/long: %d\n", __func__, pktlen);
+		goto fail;
+	}
+
+	infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
+	shift = MS(rxdw0, R92C_RXDW0_SHIFT);
+
+	m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
+	if (__predict_false(m1 == NULL)) {
+		device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n",
+		    __func__);
+		goto fail;
+	}
+	bus_dmamap_sync(ring->data_dmat, rx_data->map, BUS_DMASYNC_POSTREAD);
+	bus_dmamap_unload(ring->data_dmat, rx_data->map);
+
+	error = bus_dmamap_load(ring->data_dmat, rx_data->map, mtod(m1, void *),
+	    MJUMPAGESIZE, rtwn_pci_dma_map_addr, &rx_data->paddr, 0);
+	if (error != 0) {
+		m_freem(m1);
+
+		error = bus_dmamap_load(ring->data_dmat, rx_data->map,
+		    mtod(rx_data->m, void *), MJUMPAGESIZE,
+		    rtwn_pci_dma_map_addr, &rx_data->paddr, BUS_DMA_NOWAIT);
+		if (error != 0)
+			panic("%s: could not load old RX mbuf",
+			    device_get_name(sc->sc_dev));
+
+		/* Physical address may have changed. */
+		rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr,
+		    MJUMPAGESIZE, desc_idx);
+		goto fail;
+	}
+
+	/* Finalize mbuf. */
+	m = rx_data->m;
+	rx_data->m = m1;
+	m->m_pkthdr.len = m->m_len = pktlen + infosz + shift;
+
+	nf = RTWN_NOISE_FLOOR;
+	ni = rtwn_rx_common(sc, m, rx_desc, &rssi);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
+	    "%s: Rx frame len %d, infosz %d, shift %d, rssi %d\n",
+	    __func__, pktlen, infosz, shift, rssi);
+
+	/* Update RX descriptor. */
+	rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, MJUMPAGESIZE,
+	    desc_idx);
+
+	/* Send the frame to the 802.11 layer. */
+	RTWN_UNLOCK(sc);
+	if (ni != NULL) {
+		(void)ieee80211_input(ni, m, rssi - nf, nf);
+		/* Node is no longer needed. */
+		ieee80211_free_node(ni);
+	} else
+		(void)ieee80211_input_all(ic, m, rssi - nf, nf);
+
+	RTWN_LOCK(sc);
+
+	return;
+
+fail:
+	counter_u64_add(ic->ic_ierrors, 1);
+}
+
+static void
+rtwn_pci_tx_done(struct rtwn_softc *sc, int qid)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_tx_ring *ring = &pc->tx_ring[qid];
+	struct rtwn_tx_desc_common *desc;
+	struct rtwn_tx_data *data;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: qid %d, last %d, cur %d\n",
+	    __func__, qid, ring->last, ring->cur);
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD);
+
+	while(ring->last != ring->cur) {
+		data = &ring->tx_data[ring->last];
+		desc = (struct rtwn_tx_desc_common *)
+		    ((uint8_t *)ring->desc + sc->txdesc_len * ring->last);
+
+		KASSERT(data->m != NULL, ("no mbuf"));
+
+		if (desc->flags0 & RTWN_FLAGS0_OWN)
+			break;
+
+		/* Unmap and free mbuf. */
+		bus_dmamap_sync(ring->data_dmat, data->map,
+		    BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(ring->data_dmat, data->map);
+
+		if (data->ni != NULL) {	/* not a beacon frame */
+			ieee80211_tx_complete(data->ni, data->m, 0);
+
+			data->ni = NULL;
+			ring->queued--;
+			KASSERT(ring->queued >= 0,
+			    ("ring->queued (qid %d) underflow!\n", qid));
+		} else
+			m_freem(data->m);
+
+		data->m = NULL;
+		ring->last = (ring->last + 1) % RTWN_PCI_TX_LIST_COUNT;
+#ifndef D4054
+		if (ring->queued > 0)
+			sc->sc_tx_timer = 5;
+		else
+			sc->sc_tx_timer = 0;
+#endif
+	}
+
+	if ((sc->qfullmsk & (1 << qid)) != 0 &&
+	    ring->queued < (RTWN_PCI_TX_LIST_COUNT - 1)) {
+		sc->qfullmsk &= ~(1 << qid);
+		rtwn_start(sc);
+	}
+
+#ifdef  IEEE80211_SUPPORT_SUPERG
+	/*
+	 * If the TX active queue drops below a certain
+	 * threshold, ensure we age fast-frames out so they're
+	 * transmitted.
+	 */
+	if (sc->sc_ratectl != RTWN_RATECTL_NET80211 && ring->queued <= 1) {
+		/*
+		 * XXX TODO: just make this a callout timer schedule
+		 * so we can flush the FF staging queue if we're
+		 * approaching idle.
+		 */
+		rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
+	}
+#endif
+}
+
+static void
+rtwn_pci_rx_done(struct rtwn_softc *sc)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_rx_ring *ring = &pc->rx_ring;
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD);
+
+	for (;;) {
+		struct r92ce_rx_stat *rx_desc = &ring->desc[ring->cur];
+
+		if (le32toh(rx_desc->rxdw0) & R92C_RXDW0_OWN)
+			break;
+
+		rtwn_pci_rx_frame(sc, rx_desc, ring->cur);
+
+		if (!(sc->sc_flags & RTWN_RUNNING))
+			return;
+
+		ring->cur = (ring->cur + 1) % RTWN_PCI_RX_LIST_COUNT;
+	}
+
+	/* Finished receive; age anything left on the FF queue by a little bump */
+	/*
+	 * XXX TODO: just make this a callout timer schedule so we can
+	 * flush the FF staging queue if we're approaching idle.
+	 */
+#ifdef  IEEE80211_SUPPORT_SUPERG
+	if (!(sc->sc_flags & RTWN_FW_LOADED) ||
+	    sc->sc_ratectl != RTWN_RATECTL_NET80211)
+		rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
+#endif
+}
+
+void
+rtwn_pci_intr(void *arg)
+{
+	struct rtwn_softc *sc = arg;
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	int i, status, tx_rings;
+
+	RTWN_LOCK(sc);
+	status = rtwn_classify_intr(sc, &tx_rings, 0);
+	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: status %08X, tx_rings %08X\n",
+	    __func__, status, tx_rings);
+	if (status == 0 && tx_rings == 0)
+		goto unlock;
+
+	if (status & RTWN_PCI_INTR_RX) {
+		rtwn_pci_rx_done(sc);
+		if (!(sc->sc_flags & RTWN_RUNNING))
+			goto unlock;
+	}
+
+	if (tx_rings != 0)
+		for (i = 0; i < RTWN_PCI_NTXQUEUES; i++)
+			if (tx_rings & (1 << i))
+				rtwn_pci_tx_done(sc, i);
+
+	if (sc->sc_flags & RTWN_RUNNING)
+		rtwn_pci_enable_intr(pc);
+unlock:
+	RTWN_UNLOCK(sc);
+}
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTWN_PCI_RX_H
+#define RTWN_PCI_RX_H
+
+void	rtwn_pci_dma_map_addr(void *, bus_dma_segment_t *, int, int);
+void	rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *,
+	    struct r92ce_rx_stat *, bus_addr_t, size_t, int);
+void	rtwn_pci_intr(void *);
+
+#endif	/* RTWN_PCI_RX_H */
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,274 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+#include <dev/rtwn/pci/rtwn_pci_tx.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
+
+
+static struct mbuf *
+rtwn_mbuf_defrag(struct mbuf *m0, int how)
+{
+	struct mbuf *m = NULL;
+
+	KASSERT(m0->m_flags & M_PKTHDR,
+	    ("M_PKTHDR flag is absent (m %p)!", m0));
+
+	/* NB: we need _exactly_ one mbuf (no less, no more). */
+	if (m0->m_pkthdr.len > MJUMPAGESIZE) {
+		/* XXX MJUM9BYTES? */
+		return (NULL);
+	} else if (m0->m_pkthdr.len > MCLBYTES) {
+		m = m_getjcl(how, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
+		if (m == NULL)
+			return (NULL);
+
+		if (m_dup_pkthdr(m, m0, how) == 0) {
+			m_freem(m);
+			return (NULL);
+		}
+
+		m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
+		m->m_len = m->m_pkthdr.len;
+		m_freem(m0);
+
+		return (m);
+	} else
+		return (m_defrag(m0, how));
+}
+
+static int
+rtwn_pci_tx_start_frame(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m, uint8_t *tx_desc, uint8_t type)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_tx_ring *ring;
+	struct rtwn_tx_data *data;
+	struct rtwn_tx_desc_common *txd;
+	bus_dma_segment_t segs[1];
+	uint8_t qid;
+	int nsegs, error;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	switch (type) {
+	case IEEE80211_FC0_TYPE_CTL:
+	case IEEE80211_FC0_TYPE_MGT:
+		qid = RTWN_PCI_MGNT_QUEUE;
+		break;
+	default:
+		qid = M_WME_GETAC(m);
+		break;
+	}
+
+	ring = &pc->tx_ring[qid];
+	data = &ring->tx_data[ring->cur];
+	if (data->m != NULL) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
+		    "%s: ring #%u is full (m %p)\n", __func__, qid, data->m);
+		return (ENOBUFS);
+	}
+
+	txd = (struct rtwn_tx_desc_common *)
+	    ((uint8_t *)ring->desc + sc->txdesc_len * ring->cur);
+	if (txd->flags0 & RTWN_FLAGS0_OWN) {
+		device_printf(sc->sc_dev,
+		    "%s: OWN bit is set (tx desc %d, ring %u)!\n",
+		    __func__, ring->cur, qid);
+		return (ENOBUFS);
+	}
+
+	/* Copy Tx descriptor. */
+	rtwn_pci_copy_tx_desc(pc, txd, tx_desc);
+	txd->pktlen = htole16(m->m_pkthdr.len);
+	txd->offset = sc->txdesc_len;
+
+	error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs,
+	    &nsegs, BUS_DMA_NOWAIT);
+	if (error != 0 && error != EFBIG) {
+		device_printf(sc->sc_dev, "can't map mbuf (error %d)\n",
+		    error);
+		return (error);
+	}
+	if (error != 0) {
+		struct mbuf *mnew;
+
+		mnew = rtwn_mbuf_defrag(m, M_NOWAIT);
+		if (mnew == NULL) {
+			device_printf(sc->sc_dev, "can't defragment mbuf\n");
+			return (ENOBUFS);
+		}
+		m = mnew;
+
+		error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m,
+		    segs, &nsegs, BUS_DMA_NOWAIT);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "can't map mbuf (error %d)\n", error);
+			if (ni != NULL) {
+				if_inc_counter(ni->ni_vap->iv_ifp,
+				    IFCOUNTER_OERRORS, 1);
+				ieee80211_free_node(ni);
+			}
+			m_freem(m);
+			return (0);	/* XXX */
+		}
+	}
+
+	rtwn_pci_tx_postsetup(pc, txd, segs);
+	txd->flags0 |= RTWN_FLAGS0_OWN;
+
+	/* Dump Tx descriptor. */
+	rtwn_dump_tx_desc(sc, txd);
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+	    BUS_DMASYNC_POSTWRITE);
+	bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE);
+
+	data->m = m;
+	data->ni = ni;
+
+	ring->cur = (ring->cur + 1) % RTWN_PCI_TX_LIST_COUNT;
+
+	ring->queued++;
+	if (ring->queued >= (RTWN_PCI_TX_LIST_COUNT - 1))
+		sc->qfullmsk |= (1 << qid);
+
+#ifndef D4054
+	sc->sc_tx_timer = 5;
+#endif
+
+	/* Kick TX. */
+	rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid));
+
+	return (0);
+}
+
+static int
+rtwn_pci_tx_start_beacon(struct rtwn_softc *sc, struct mbuf *m,
+    uint8_t *tx_desc, int id)
+{
+	struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
+	struct rtwn_tx_ring *ring;
+	struct rtwn_tx_data *data;
+	struct rtwn_tx_desc_common *txd;
+	bus_dma_segment_t segs[1];
+	int nsegs, error, own;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	KASSERT(id == 0 || id == 1, ("bogus vap id %d\n", id));
+
+	ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE];
+	data = &ring->tx_data[id];
+	txd = (struct rtwn_tx_desc_common *)
+	    ((uint8_t *)ring->desc + id * sc->txdesc_len);
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+	    BUS_DMASYNC_POSTREAD);
+	own = !!(txd->flags0 & RTWN_FLAGS0_OWN);
+	error = 0;
+	if (!own || txd->pktlen != htole16(m->m_pkthdr.len)) {
+		if (!own) {
+			/* Copy Tx descriptor. */
+			rtwn_pci_copy_tx_desc(pc, txd, tx_desc);
+			txd->offset = sc->txdesc_len;
+		} else {
+			/* Reload mbuf. */
+			bus_dmamap_unload(ring->data_dmat, data->map);
+		}
+
+		error = bus_dmamap_load_mbuf_sg(ring->data_dmat,
+		    data->map, m, segs, &nsegs, BUS_DMA_NOWAIT);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "can't map beacon (error %d)\n", error);
+			txd->flags0 &= ~RTWN_FLAGS0_OWN;
+			goto end;
+		}
+
+		txd->pktlen = htole16(m->m_pkthdr.len);
+		rtwn_pci_tx_postsetup(pc, txd, segs);
+		txd->flags0 |= RTWN_FLAGS0_OWN;
+end:
+		bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+		    BUS_DMASYNC_PREWRITE);
+	}
+
+	/* Dump Tx descriptor. */
+	rtwn_dump_tx_desc(sc, txd);
+
+	bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
+
+	return (0);
+}
+
+int
+rtwn_pci_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id)
+{
+	int error = 0;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	if (ni == NULL)		/* beacon frame */
+		error = rtwn_pci_tx_start_beacon(sc, m, tx_desc, id);
+	else
+		error = rtwn_pci_tx_start_frame(sc, ni, m, tx_desc, type);
+
+	return (error);
+}
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,25 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTWN_PCI_TX_H
+#define RTWN_PCI_TX_H
+
+int	rtwn_pci_tx_start(struct rtwn_softc *, struct ieee80211_node *,
+	    struct mbuf *, uint8_t *, uint8_t, int);
+
+#endif	/* RTWN_PCI_TX_H */
Index: freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h
===================================================================
--- freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,140 @@
+/*	$OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef RTWN_PCI_VAR_H
+#define RTWN_PCI_VAR_H
+
+#include <dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h>
+
+
+#define RTWN_PCI_RX_LIST_COUNT		256
+#define RTWN_PCI_TX_LIST_COUNT		256
+
+struct rtwn_rx_data {
+	bus_dmamap_t		map;
+	struct mbuf		*m;
+	bus_addr_t		paddr;
+};
+
+struct rtwn_rx_ring {
+	struct r92ce_rx_stat	*desc;
+	bus_addr_t		paddr;
+	bus_dma_tag_t		desc_dmat;
+	bus_dmamap_t		desc_map;
+	bus_dma_tag_t		data_dmat;
+	bus_dma_segment_t	seg;
+	struct rtwn_rx_data	rx_data[RTWN_PCI_RX_LIST_COUNT];
+	int			cur;
+};
+
+struct rtwn_tx_data {
+	bus_dmamap_t		map;
+	struct mbuf		*m;
+	struct ieee80211_node	*ni;
+};
+
+struct rtwn_tx_ring {
+	bus_addr_t		paddr;
+	bus_dma_tag_t		desc_dmat;
+	bus_dmamap_t		desc_map;
+	bus_dma_tag_t		data_dmat;
+	bus_dma_segment_t	seg;
+	void			*desc;
+	struct rtwn_tx_data	tx_data[RTWN_PCI_TX_LIST_COUNT];
+	int			queued;
+	int			cur;
+	int			last;
+};
+
+/*
+ * TX queue indices.
+ */
+enum {
+	RTWN_PCI_BK_QUEUE,
+	RTWN_PCI_BE_QUEUE,
+	RTWN_PCI_VI_QUEUE,
+	RTWN_PCI_VO_QUEUE,
+	RTWN_PCI_BEACON_QUEUE,
+	RTWN_PCI_TXCMD_QUEUE,
+	RTWN_PCI_MGNT_QUEUE,
+	RTWN_PCI_HIGH_QUEUE,
+	RTWN_PCI_HCCA_QUEUE,
+	RTWN_PCI_NTXQUEUES
+};
+
+/*
+ * Interrupt events.
+ */
+enum {
+	RTWN_PCI_INTR_RX_ERROR		= 0x00000001,
+	RTWN_PCI_INTR_RX_OVERFLOW	= 0x00000002,
+	RTWN_PCI_INTR_RX_DESC_UNAVAIL	= 0x00000004,
+	RTWN_PCI_INTR_RX_DONE		= 0x00000008,
+	RTWN_PCI_INTR_TX_ERROR		= 0x00000010,
+	RTWN_PCI_INTR_TX_OVERFLOW	= 0x00000020,
+	RTWN_PCI_INTR_TX_REPORT		= 0x00000040,
+	RTWN_PCI_INTR_PS_TIMEOUT	= 0x00000080
+};
+
+/* Shortcuts */
+/* Vendor driver treats RX errors like ROK... */
+#define RTWN_PCI_INTR_RX \
+	(RTWN_PCI_INTR_RX_OVERFLOW | RTWN_PCI_INTR_RX_DESC_UNAVAIL | \
+	 RTWN_PCI_INTR_RX_DONE)
+
+
+struct rtwn_pci_softc {
+	struct rtwn_softc	pc_sc;		/* must be the first */
+
+	struct resource		*irq;
+	struct resource		*mem;
+	bus_space_tag_t		pc_st;
+	bus_space_handle_t	pc_sh;
+	void			*pc_ih;
+	bus_size_t		pc_mapsize;
+
+	struct rtwn_rx_ring	rx_ring;
+	struct rtwn_tx_ring	tx_ring[RTWN_PCI_NTXQUEUES];
+
+	/* must be set by the driver. */
+	uint16_t		pc_qmap;
+	uint32_t		tcr;
+
+	void			(*pc_setup_tx_desc)(struct rtwn_pci_softc *,
+				    void *, uint32_t);
+	void			(*pc_tx_postsetup)(struct rtwn_pci_softc *,
+				    void *, bus_dma_segment_t *);
+	void			(*pc_copy_tx_desc)(void *, const void *);
+	void			(*pc_enable_intr)(struct rtwn_pci_softc *);
+};
+#define RTWN_PCI_SOFTC(sc)	((struct rtwn_pci_softc *)(sc))
+
+#define rtwn_pci_setup_tx_desc(_pc, _desc, _addr) \
+	(((_pc)->pc_setup_tx_desc)((_pc), (_desc), (_addr)))
+#define rtwn_pci_tx_postsetup(_pc, _txd, _segs) \
+	(((_pc)->pc_tx_postsetup)((_pc), (_txd), (_segs)))
+#define rtwn_pci_copy_tx_desc(_pc, _dest, _src) \
+	(((_pc)->pc_copy_tx_desc)((_dest), (_src)))
+#define rtwn_pci_enable_intr(_pc) \
+	(((_pc)->pc_enable_intr)((_pc)))
+
+#endif	/* RTWN_PCI_VAR_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef RTL8188E_H
+#define RTL8188E_H
+
+/*
+ * Global definitions.
+ */
+#define R88E_PUBQ_NPAGES	142
+#define R88E_TXPKTBUF_COUNT	177
+#define R88E_TX_PAGE_COUNT	169
+
+#define R88E_MACID_MAX		63
+#define R88E_RX_DMA_BUFFER_SIZE	0x2400
+
+#define R88E_INTR_MSG_LEN	60
+
+#define R88E_CALIB_THRESHOLD	4
+
+
+/*
+ * Function declarations.
+ */
+/* r88e_beacon.c */
+void	r88e_beacon_enable(struct rtwn_softc *, int, int);
+
+/* r88e_calib.c */
+void	r88e_iq_calib(struct rtwn_softc *);
+void	r88e_temp_measure(struct rtwn_softc *);
+uint8_t	r88e_temp_read(struct rtwn_softc *);
+
+/* r88e_chan.c */
+void	r88e_get_txpower(struct rtwn_softc *, int,
+	    struct ieee80211_channel *, uint16_t[]);
+void	r88e_set_bw20(struct rtwn_softc *, uint8_t);
+void	r88e_set_gain(struct rtwn_softc *, uint8_t);
+
+/* r88e_fw.c */
+#ifndef RTWN_WITHOUT_UCODE
+int	r88e_fw_cmd(struct rtwn_softc *, uint8_t, const void *, int);
+void	r88e_fw_reset(struct rtwn_softc *, int);
+void	r88e_fw_download_enable(struct rtwn_softc *, int);
+#endif
+void	r88e_macid_enable_link(struct rtwn_softc *, int, int);
+void	r88e_set_media_status(struct rtwn_softc *, int);
+#ifndef RTWN_WITHOUT_UCODE
+int	r88e_set_rsvd_page(struct rtwn_softc *, int, int, int);
+int	r88e_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, int);
+#endif
+
+/* r88e_init.c */
+void	r88e_init_bb(struct rtwn_softc *);
+void	r88e_init_rf(struct rtwn_softc *);
+int	r88e_power_on(struct rtwn_softc *);
+
+/* r88e_led.c */
+void	r88e_set_led(struct rtwn_softc *, int, int);
+
+/* r88e_rf.c */
+void	r88e_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t);
+
+/* r88e_rom.c */
+void	r88e_parse_rom(struct rtwn_softc *, uint8_t *);
+
+/* r88e_rx.c */
+void	r88e_ratectl_tx_complete(struct rtwn_softc *, uint8_t *, int);
+void	r88e_handle_c2h_report(struct rtwn_softc *, uint8_t *, int);
+int8_t	r88e_get_rssi_cck(struct rtwn_softc *, void *);
+int8_t	r88e_get_rssi_ofdm(struct rtwn_softc *, void *);
+
+/* r88e_tx.c */
+void	r88e_tx_enable_ampdu(void *, int);
+void	r88e_tx_setup_hwseq(void *);
+void	r88e_tx_setup_macid(void *, int);
+
+#endif	/* RTL8188E_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,64 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+
+
+void
+r88e_beacon_enable(struct rtwn_softc *sc, int id, int enable)
+{
+
+	if (enable) {
+		rtwn_setbits_1(sc, R92C_MBID_NUM, 0, R88E_MBID_TXBCN_RPT(id));
+		rtwn_setbits_1(sc, R92C_BCN_CTRL(id),
+		    0, R92C_BCN_CTRL_EN_BCN);
+	} else {
+		rtwn_setbits_1(sc, R92C_MBID_NUM, R88E_MBID_TXBCN_RPT(id), 0);
+		rtwn_setbits_1(sc, R92C_BCN_CTRL(id),
+		    R92C_BCN_CTRL_EN_BCN, 0);
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,69 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+
+
+void
+r88e_iq_calib(struct rtwn_softc *sc)
+{
+	/* XXX TODO */
+}
+
+void
+r88e_temp_measure(struct rtwn_softc *sc)
+{
+	rtwn_rf_write(sc, 0, R88E_RF_T_METER, R88E_RF_T_METER_START);
+}
+
+uint8_t
+r88e_temp_read(struct rtwn_softc *sc)
+{
+	return (MS(rtwn_rf_read(sc, 0, R88E_RF_T_METER),
+	    R88E_RF_T_METER_VAL));
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,169 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_priv.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+
+
+static int
+r88e_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	uint8_t chan;
+	int group;
+
+	chan = rtwn_chan2centieee(c);
+	if (IEEE80211_IS_CHAN_2GHZ(c)) {
+		if (chan <= 2)			group = 0;
+		else if (chan <= 5)		group = 1;
+		else if (chan <= 8)		group = 2;
+		else if (chan <= 11)		group = 3;
+		else if (chan <= 13)		group = 4;
+		else if (chan <= 14)		group = 5;
+		else {
+			KASSERT(0, ("wrong 2GHz channel %d!\n", chan));
+			return (-1);
+		}
+	} else {
+		KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags));
+		return (-1);
+	}
+
+	return (group);
+}
+
+void
+r88e_get_txpower(struct rtwn_softc *sc, int chain,
+    struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT])
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	const struct rtwn_r88e_txpwr *rt = rs->rs_txpwr;
+	const struct rtwn_r88e_txagc *base = rs->rs_txagc;
+	uint16_t cckpow, ofdmpow, bw20pow, htpow;
+	int max_mcs, ridx, group;
+
+	/* Determine channel group. */
+	group = r88e_get_power_group(sc, c);
+	if (group == -1) {	/* shouldn't happen */
+		device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__);
+		return;
+	}
+
+	/* XXX net80211 regulatory */
+
+	max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1);
+	KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n"));
+
+	memset(power, 0, max_mcs * sizeof(power[0]));
+	if (rs->regulatory == 0) {
+		for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
+			power[ridx] = base->pwr[0][ridx];
+	}
+	for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_COUNT; ridx++) {
+		if (rs->regulatory == 3)
+			power[ridx] = base->pwr[0][ridx];
+		else if (rs->regulatory == 1) {
+			if (!IEEE80211_IS_CHAN_HT40(c))
+				power[ridx] = base->pwr[group][ridx];
+		} else if (rs->regulatory != 2)
+			power[ridx] = base->pwr[0][ridx];
+	}
+
+	/* Compute per-CCK rate Tx power. */
+	cckpow = rt->cck_tx_pwr[group];
+	for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
+		power[ridx] += cckpow;
+
+	htpow = rt->ht40_tx_pwr[group];
+
+	/* Compute per-OFDM rate Tx power. */
+	ofdmpow = htpow + rt->ofdm_tx_pwr_diff;
+	for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++)
+		power[ridx] += ofdmpow;
+
+	bw20pow = htpow + rt->bw20_tx_pwr_diff;
+	for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++)
+		power[ridx] += bw20pow;
+
+	/* Apply max limit. */
+	for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) {
+		if (power[ridx] > R92C_MAX_TX_PWR)
+			power[ridx] = R92C_MAX_TX_PWR;
+	}
+}
+
+void
+r88e_set_bw20(struct rtwn_softc *sc, uint8_t chan)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ);
+
+	rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0);
+	rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0);
+
+	/* Select 20MHz bandwidth. */
+	rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+	    (rs->rf_chnlbw[0] & ~0xfff) | chan | R88E_RF_CHNLBW_BW20);
+}
+
+void
+r88e_set_gain(struct rtwn_softc *sc, uint8_t gain)
+{
+
+	rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0),
+	    R92C_OFDM0_AGCCORE1_GAIN_M, gain);
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,227 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+#include <dev/rtwn/rtl8188e/r88e_fw_cmd.h>
+
+
+#ifndef RTWN_WITHOUT_UCODE
+int
+r88e_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len)
+{
+	struct r88e_fw_cmd cmd;
+	int ntries, error;
+
+	if (!(sc->sc_flags & RTWN_FW_LOADED)) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware "
+		    "was not loaded; command (id %d) will be discarded\n",
+		    __func__, id);
+		return (0);
+	}
+
+	/* Wait for current FW box to be empty. */
+	for (ntries = 0; ntries < 50; ntries++) {
+		if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
+			break;
+		rtwn_delay(sc, 2000);
+	}
+	if (ntries == 100) {
+		device_printf(sc->sc_dev,
+		    "could not send firmware command\n");
+		return (ETIMEDOUT);
+	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.id = id;
+	KASSERT(len <= sizeof(cmd.msg),
+	    ("%s: firmware command too long (%d > %zu)\n",
+	    __func__, len, sizeof(cmd.msg)));
+	memcpy(cmd.msg, buf, len);
+
+	/* Write the first word last since that will trigger the FW. */
+	if (len > 3) {
+		error = rtwn_write_4(sc, R88E_HMEBOX_EXT(sc->fwcur),
+		    *(uint32_t *)((uint8_t *)&cmd + 4));
+		if (error != 0)
+			return (error);
+	}
+	error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *(uint32_t *)&cmd);
+	if (error != 0)
+		return (error);
+
+	sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
+
+	return (0);
+}
+
+void
+r88e_fw_reset(struct rtwn_softc *sc, int reason)
+{
+	uint16_t reg;
+
+	reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
+	rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
+	rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN);
+}
+
+void
+r88e_fw_download_enable(struct rtwn_softc *sc, int enable)
+{
+	if (enable) {
+		/* MCU firmware download enable. */
+		rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN);
+		/* 8051 reset. */
+		rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN,
+		    0, 2);
+	} else {
+		/* MCU download disable. */
+		rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0);
+		/* Reserved for f/w extension. */
+		rtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
+	}
+}
+#endif
+
+void
+r88e_macid_enable_link(struct rtwn_softc *sc, int id, int enable)
+{
+	uint32_t reg;
+
+	reg = R88E_MACID_NO_LINK;
+	if (id > 32)
+		reg += 4;
+
+	if (enable)
+		rtwn_setbits_4(sc, reg, 1 << (id % 32), 0);
+	else
+		rtwn_setbits_4(sc, reg, 0, 1 << (id % 32));
+
+	/* XXX max macid for tx reports */
+}
+
+void
+r88e_set_media_status(struct rtwn_softc *sc, int macid)
+{
+	struct r88e_fw_cmd_msrrpt status;
+
+	if (macid & RTWN_MACID_VALID)
+		status.msrb0 = R88E_MSRRPT_B0_ASSOC;
+	else
+		status.msrb0 = R88E_MSRRPT_B0_DISASSOC;
+	status.macid = (macid & ~RTWN_MACID_VALID);
+
+	r88e_macid_enable_link(sc, status.macid,
+	    (macid & RTWN_MACID_VALID) != 0);
+
+#ifndef RTWN_WITHOUT_UCODE
+	if (r88e_fw_cmd(sc, R88E_CMD_MSR_RPT, &status, sizeof(status)) != 0) {
+		device_printf(sc->sc_dev, "%s: cannot change media status!\n",
+		    __func__);
+	}
+#endif
+}
+
+#ifndef RTWN_WITHOUT_UCODE
+int
+r88e_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null,
+    int qos_null)
+{
+	struct r88e_fw_cmd_rsvdpage rsvd;
+
+	rsvd.probe_resp = probe_resp;
+	rsvd.ps_poll = 0;
+	rsvd.null_data = null;
+	rsvd.null_data_qos = qos_null;
+	rsvd.null_data_qos_bt = 0;
+	return (r88e_fw_cmd(sc, R88E_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd)));
+}
+
+int
+r88e_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap,
+    int off)
+{
+	struct r88e_fw_cmd_pwrmode mode;
+	int error;
+
+	if (off && vap->iv_state == IEEE80211_S_RUN &&
+	    (vap->iv_flags & IEEE80211_F_PMGTON)) {
+		mode.mode = R88E_PWRMODE_LEG;
+		/*
+		 * TODO: switch to RFOFF state
+		 * (something is missing here - Rx stops with it).
+		 */
+#ifdef RTWN_TODO
+		mode.pwr_state = R88E_PWRMODE_STATE_RFOFF;
+#else
+		mode.pwr_state = R88E_PWRMODE_STATE_RFON;
+#endif
+	} else {
+		mode.mode = R88E_PWRMODE_CAM;
+		mode.pwr_state = R88E_PWRMODE_STATE_ALLON;
+	}
+	mode.pwrb1 =
+	    SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) |
+	    SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN);
+	/* XXX ignored */
+	mode.bcn_pass = 0;
+	mode.queue_uapsd = 0;
+	error = r88e_fw_cmd(sc, R88E_CMD_SET_PWRMODE, &mode, sizeof(mode));
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: CMD_SET_PWRMODE was not sent, error %d\n",
+		    __func__, error);
+	}
+
+	return (error);
+}
+#endif
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2015 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R88E_FW_CMD_H
+#define R88E_FW_CMD_H
+
+/*
+ * Host to firmware commands.
+ */
+struct r88e_fw_cmd {
+	uint8_t id;
+#define R88E_CMD_RSVD_PAGE		0x00
+#define R88E_CMD_MSR_RPT		0x01
+#define R88E_CMD_SET_PWRMODE		0x20
+
+	uint8_t msg[7];
+} __packed __attribute__((aligned(4)));
+
+/* Structure for R88E_CMD_RSVD_PAGE. */
+struct r88e_fw_cmd_rsvdpage {
+	uint8_t		probe_resp;
+	uint8_t		ps_poll;
+	uint8_t		null_data;
+	uint8_t		null_data_qos;
+	uint8_t		null_data_qos_bt;
+} __packed;
+
+/* Structure for R88E_CMD_MSR_RPT. */
+struct r88e_fw_cmd_msrrpt {
+	uint8_t		msrb0;
+#define R88E_MSRRPT_B0_DISASSOC		0x00
+#define R88E_MSRRPT_B0_ASSOC		0x01
+
+	uint8_t		macid;
+} __packed;
+
+/* Structure for R88E_CMD_SET_PWRMODE. */
+struct r88e_fw_cmd_pwrmode {
+	uint8_t		mode;
+#define R88E_PWRMODE_CAM		0
+#define R88E_PWRMODE_LEG		1
+#define R88E_PWRMODE_UAPSD		2
+
+	uint8_t		pwrb1;
+#define R88E_PWRMODE_B1_RLBM_M		0x0f
+#define R88E_PWRMODE_B1_RLBM_S		0
+#define R88E_PWRMODE_B1_MODE_MIN	0
+#define R88E_PWRMODE_B1_MODE_MAX	1
+#define R88E_PWRMODE_B1_MODE_DTIM	2
+
+#define R88E_PWRMODE_B1_SMART_PS_M	0xf0
+#define R88E_PWRMODE_B1_SMART_PS_S	4
+#define R88E_PWRMODE_B1_LEG_PSPOLL0	0
+#define R88E_PWRMODE_B1_LEG_PSPOLL1	1
+#define R88E_PWRMODE_B1_LEG_NULLDATA	2
+#define R88E_PWRMODE_B1_WMM_PSPOLL	0
+#define R88E_PWRMODE_B1_WMM_NULLDATA	1
+
+	uint8_t		bcn_pass;
+	uint8_t		queue_uapsd;
+	uint8_t		pwr_state;
+#define R88E_PWRMODE_STATE_RFOFF	0x00
+#define R88E_PWRMODE_STATE_RFON		0x04
+#define R88E_PWRMODE_STATE_ALLON	0x0c
+} __packed;
+
+#endif	/* R88E_FW_CMD_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,160 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+
+
+static void
+r88e_crystalcap_write(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	uint32_t reg;
+	uint8_t val;
+
+	val = rs->crystalcap & 0x3f;
+	reg = rtwn_bb_read(sc, R92C_AFE_XTAL_CTRL);
+	rtwn_bb_write(sc, R92C_AFE_XTAL_CTRL,
+	    RW(reg, R92C_AFE_XTAL_CTRL_ADDR, val | val << 6));
+}
+
+void
+r88e_init_bb(struct rtwn_softc *sc)
+{
+
+	/* Enable BB and RF. */
+	rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0,
+	    R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
+	    R92C_SYS_FUNC_EN_DIO_RF);
+
+	rtwn_write_1(sc, R92C_RF_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
+	rtwn_write_1(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD |
+	    R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB);
+
+	r92c_init_bb_common(sc);
+
+	rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553422);
+	rtwn_delay(sc, 1);
+	rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420);
+	rtwn_delay(sc, 1);
+
+	r88e_crystalcap_write(sc);
+}
+
+int
+r88e_power_on(struct rtwn_softc *sc)
+{
+#define RTWN_CHK(res) do {	\
+	if (res != 0)		\
+		return (EIO);	\
+} while(0)
+	int ntries;
+
+	/* Wait for power ready bit. */
+	for (ntries = 0; ntries < 5000; ntries++) {
+		if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST)
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 5000) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for chip power up\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Reset BB. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST, 0));
+
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0, 0x80));
+
+	/* Disable HWPDN. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_APDM_HPDN, 0, 1));
+
+	/* Disable WL suspend. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1));
+
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    0, R92C_APS_FSMCO_APFM_ONMAC, 1));
+	for (ntries = 0; ntries < 5000; ntries++) {
+		if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
+		    R92C_APS_FSMCO_APFM_ONMAC))
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 5000)
+		return (ETIMEDOUT);
+
+	/* Enable LDO normal mode. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_LPLDO_CTRL,
+	    R92C_LPLDO_CTRL_SLEEP, 0));
+
+	/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+	RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0));
+	RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN |
+	    R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN |
+	    R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN |
+	    ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) |
+	    R92C_CR_CALTMR_EN));
+
+	return (0);
+#undef RTWN_CHK
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,70 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+
+
+void
+r88e_set_led(struct rtwn_softc *sc, int led, int on)
+{
+
+	if (led == RTWN_LED_LINK) {
+		if (!on) {
+			rtwn_setbits_1(sc, R92C_LEDCFG2, 0x6f,
+			    R92C_LEDCFG0_DIS);
+			rtwn_setbits_1(sc, R92C_MAC_PINMUX_CFG, 0x01, 0);
+		} else
+			rtwn_setbits_1(sc, R92C_LEDCFG2, 0x0f, 0x60);
+		sc->ledlink = on;	/* Save LED state. */
+	}
+
+	/* XXX led #1? */
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,273 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R88E_PRIV_H
+#define R88E_PRIV_H
+
+#include <dev/rtwn/rtl8188e/r88e_rom_defs.h>
+
+/*
+ * Parsed Tx power (diff) values.
+ */
+struct rtwn_r88e_txpwr {
+	uint8_t		cck_tx_pwr[R88E_GROUP_2G];
+	uint8_t		ht40_tx_pwr[R88E_GROUP_2G - 1];
+	int8_t		ofdm_tx_pwr_diff;
+	int8_t		bw20_tx_pwr_diff;
+};
+
+
+/*
+ * MAC initialization values.
+ */
+static const struct rtwn_mac_prog rtl8188eu_mac[] = {
+	{ 0x026, 0x41 }, { 0x027, 0x35 }, { 0x040, 0x00 }, { 0x428, 0x0a },
+	{ 0x429, 0x10 }, { 0x430, 0x00 }, { 0x431, 0x01 }, { 0x432, 0x02 },
+	{ 0x433, 0x04 }, { 0x434, 0x05 }, { 0x435, 0x06 }, { 0x436, 0x07 },
+	{ 0x437, 0x08 }, { 0x438, 0x00 }, { 0x439, 0x00 }, { 0x43a, 0x01 },
+	{ 0x43b, 0x02 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, { 0x43e, 0x06 },
+	{ 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, { 0x442, 0x00 },
+	{ 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, { 0x447, 0x00 },
+	{ 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, { 0x45b, 0xb9 },
+	{ 0x460, 0x66 }, { 0x461, 0x66 }, { 0x480, 0x08 }, { 0x4c8, 0xff },
+	{ 0x4c9, 0x08 }, { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 },
+	{ 0x4d3, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, { 0x502, 0x2f },
+	{ 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, { 0x506, 0x5e },
+	{ 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, { 0x50a, 0x5e },
+	{ 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, { 0x50e, 0x00 },
+	{ 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, { 0x516, 0x0a },
+	{ 0x525, 0x4f }, { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 },
+	{ 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a },
+	{ 0x620, 0xff }, { 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff },
+	{ 0x624, 0xff }, { 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff },
+	{ 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e },
+	{ 0x63f, 0x0e }, { 0x640, 0x40 }, { 0x66e, 0x05 }, { 0x700, 0x21 },
+	{ 0x701, 0x43 }, { 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 },
+	{ 0x709, 0x43 }, { 0x70a, 0x65 }, { 0x70b, 0x87 }
+};
+
+/*
+ * Baseband initialization values.
+ */
+static const uint16_t rtl8188eu_bb_regs[] = {
+	0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x81c,
+	0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c,
+	0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c,
+	0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c,
+	0x880, 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c,
+	0x900, 0x904, 0x908, 0x90c, 0x910, 0x914, 0xa00, 0xa04,
+	0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24,
+	0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xb2c,
+	0xc00, 0xc04, 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c,
+	0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c,
+	0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, 0xc5c,
+	0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c,
+	0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, 0xc98, 0xc9c,
+	0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, 0xcbc,
+	0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc,
+	0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c,
+	0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c,
+	0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c,
+	0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00,
+	0xe04, 0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30,
+	0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50,
+	0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74,
+	0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4,
+	0xed8, 0xedc, 0xee0, 0xee8, 0xeec, 0xf14, 0xf4c, 0xf00
+};
+
+static const uint32_t rtl8188eu_bb_vals[] = {
+	0x80040000, 0x00000003, 0x0000fc00, 0x0000000a, 0x10001331,
+	0x020c3d10, 0x02200385, 0x00000000, 0x01000100, 0x00390204,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00010000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x569a11a9, 0x01000014, 0x66f60110,
+	0x061f0649, 0x00000000, 0x27272700, 0x07000760, 0x25004000,
+	0x00000808, 0x00000000, 0xb0000c1c, 0x00000001, 0x00000000,
+	0xccc000c0, 0x00000800, 0xfffffffe, 0x40302010, 0x00706050,
+	0x00000000, 0x00000023, 0x00000000, 0x81121111, 0x00000002,
+	0x00000201, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e7f120f,
+	0x9500bb78, 0x1114d028, 0x00881117, 0x89140f00, 0x1a1b0000,
+	0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+	0x00000900, 0x225b0606, 0x218075b1, 0x80000000, 0x48071d40,
+	0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, 0x40000100,
+	0x08800000, 0x40000100, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x69e9ac47, 0x469652af, 0x49795994, 0x0a97971c,
+	0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, 0x69553420,
+	0x43bc0094, 0x00013169, 0x00250492, 0x00000000, 0x7112848b,
+	0x47c00bff, 0x00000036, 0x2c7f000d, 0x020610db, 0x0000001f,
+	0x00b91612, 0x390000e4, 0x20f60000, 0x40000100, 0x20200000,
+	0x00091521, 0x00000000, 0x00121820, 0x00007f7f, 0x00000000,
+	0x000300a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x28000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x64b22427, 0x00766932,
+	0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, 0x00000740,
+	0x00020401, 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43,
+	0x7a8f5b6f, 0xcc979975, 0x00000000, 0x80608000, 0x00000000,
+	0x00127353, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x6437140a, 0x00000000, 0x00000282, 0x30032064, 0x4653de68,
+	0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220,
+	0x000e3c24, 0x2d2d2d2d, 0x2d2d2d2d, 0x0390272d, 0x2d2d2d2d,
+	0x2d2d2d2d, 0x2d2d2d2d, 0x2d2d2d2d, 0x00000000, 0x1000dc1f,
+	0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, 0x01004800,
+	0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102,
+	0x28160d05, 0x00000008, 0x001b25a4, 0x00c00014, 0x00c00014,
+	0x01000014, 0x01000014, 0x01000014, 0x01000014, 0x00c00014,
+	0x01000014, 0x00c00014, 0x00c00014, 0x00c00014, 0x00c00014,
+	0x00000014, 0x00000014, 0x21555448, 0x01c00014, 0x00000003,
+	0x00000000, 0x00000300
+};
+
+static const struct rtwn_bb_prog rtl8188eu_bb[] = {
+	{
+		nitems(rtl8188eu_bb_regs),
+		rtl8188eu_bb_regs,
+		rtl8188eu_bb_vals,
+		{ 0 },
+		NULL
+	}
+};
+
+static const uint32_t rtl8188eu_agc_vals[] = {
+	0xfb000001, 0xfb010001, 0xfb020001, 0xfb030001, 0xfb040001,
+	0xfb050001, 0xfa060001, 0xf9070001, 0xf8080001, 0xf7090001,
+	0xf60a0001, 0xf50b0001, 0xf40c0001, 0xf30d0001, 0xf20e0001,
+	0xf10f0001, 0xf0100001, 0xef110001, 0xee120001, 0xed130001,
+	0xec140001, 0xeb150001, 0xea160001, 0xe9170001, 0xe8180001,
+	0xe7190001, 0xe61a0001, 0xe51b0001, 0xe41c0001, 0xe31d0001,
+	0xe21e0001, 0xe11f0001, 0x8a200001, 0x89210001, 0x88220001,
+	0x87230001, 0x86240001, 0x85250001, 0x84260001, 0x83270001,
+	0x82280001, 0x6b290001, 0x6a2a0001, 0x692b0001, 0x682c0001,
+	0x672d0001, 0x662e0001, 0x652f0001, 0x64300001, 0x63310001,
+	0x62320001, 0x61330001, 0x46340001, 0x45350001, 0x44360001,
+	0x43370001, 0x42380001, 0x41390001, 0x403a0001, 0x403b0001,
+	0x403c0001, 0x403d0001, 0x403e0001, 0x403f0001, 0xfb400001,
+	0xfb410001, 0xfb420001, 0xfb430001, 0xfb440001, 0xfb450001,
+	0xfb460001, 0xfb470001, 0xfb480001, 0xfa490001, 0xf94a0001,
+	0xf84B0001, 0xf74c0001, 0xf64d0001, 0xf54e0001, 0xf44f0001,
+	0xf3500001, 0xf2510001, 0xf1520001, 0xf0530001, 0xef540001,
+	0xee550001, 0xed560001, 0xec570001, 0xeb580001, 0xea590001,
+	0xe95a0001, 0xe85b0001, 0xe75c0001, 0xe65d0001, 0xe55e0001,
+	0xe45f0001, 0xe3600001, 0xe2610001, 0xc3620001, 0xc2630001,
+	0xc1640001, 0x8b650001, 0x8a660001, 0x89670001, 0x88680001,
+	0x87690001, 0x866a0001, 0x856b0001, 0x846c0001, 0x676d0001,
+	0x666e0001, 0x656f0001, 0x64700001, 0x63710001, 0x62720001,
+	0x61730001, 0x60740001, 0x46750001, 0x45760001, 0x44770001,
+	0x43780001, 0x42790001, 0x417a0001, 0x407b0001, 0x407c0001,
+	0x407d0001, 0x407e0001, 0x407f0001
+};
+
+static const struct rtwn_agc_prog rtl8188eu_agc[] = {
+	{
+		nitems(rtl8188eu_agc_vals),
+		rtl8188eu_agc_vals,
+		{ 0 },
+		NULL
+	}
+};
+
+/*
+ * RF initialization values.
+ */
+static const uint8_t rtl8188eu_rf_regs[] = {
+	0x00, 0x08, 0x18, 0x19, 0x1e, 0x1f, 0x2f, 0x3f, 0x42, 0x57,
+	0x58, 0x67, 0x83, 0xb0, 0xb1, 0xb2, 0xb4, 0xb6, 0xb7, 0xb8,
+	0xb9, 0xba, 0xbb, 0xbf, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+	0xc8, 0xc9, 0xca, 0xdf, 0xef, 0x51, 0x52, 0x53, 0x56,
+	0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xb6, 0x18, 0x5a,
+	0x19, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+	0x34, 0x34, 0x00, 0x84, 0x86, 0x87, 0x8e, 0x8f, 0xef, 0x3b,
+	0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+	0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0x00, 0x18, 0xfe, 0xfe,
+	0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00
+};
+
+static const uint32_t rtl8188eu_rf_vals[] = {
+	0x30000, 0x84000, 0x00407, 0x00012, 0x80009, 0x00880, 0x1a060,
+	0x00000, 0x060c0, 0xd0000, 0xbe180, 0x01552, 0x00000, 0xff8fc,
+	0x54400, 0xccc19, 0x43003, 0x4953e, 0x1c718, 0x060ff, 0x80001,
+	0x40000, 0x00400, 0xc0000, 0x02400, 0x00009, 0x40c91, 0x99999,
+	0x000a3, 0x88820, 0x76c06, 0x00000, 0x80000, 0x00180, 0x001a0,
+	0x6b27d, 0x7e49d, 0x00073, 0x51ff3, 0x00086, 0x00186,
+	0x00286, 0x01c25, 0x09c25, 0x11c25, 0x19c25, 0x48538, 0x00c07,
+	0x4bd00, 0x739d0, 0x0adf3, 0x09df0, 0x08ded, 0x07dea, 0x06de7,
+	0x054ee, 0x044eb, 0x034e8, 0x0246b, 0x01468, 0x0006d, 0x30159,
+	0x68200, 0x000ce, 0x48a00, 0x65540, 0x88000, 0x020a0, 0xf02b0,
+	0xef7b0, 0xd4fb0, 0xcf060, 0xb0090, 0xa0080, 0x90080, 0x8f780,
+	0x722b0, 0x6f7b0, 0x54fb0, 0x4f060, 0x30090, 0x20080, 0x10080,
+	0x0f780, 0x000a0, 0x10159, 0x0f407, 0x0c350, 0x0c350, 0x80003,
+	0x0c350, 0x0c350, 0x00001, 0x80000, 0x33e60
+};
+
+static const struct rtwn_rf_prog rtl8188eu_rf[] = {
+	{
+		nitems(rtl8188eu_rf_regs),
+		rtl8188eu_rf_regs,
+		rtl8188eu_rf_vals,
+		{ 0 },
+		NULL
+	},
+	{ 0, NULL, NULL, { 0 }, NULL }
+};
+
+
+struct rtwn_r88e_txagc {
+	uint8_t	pwr[R88E_GROUP_2G][20];	/* RTWN_RIDX_MCS(7) + 1 */
+};
+
+/*
+ * Per RF chain/group/rate Tx gain values.
+ */
+static const struct rtwn_r88e_txagc r88e_txagc[] = {
+	{ {	/* Chain 0. */
+	{	/* Group 0. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	},
+	{	/* Group 1. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	},
+	{	/* Group 2. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	},
+	{	/* Group 3. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	},
+	{	/* Group 4. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	},
+	{	/* Group 5. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	}
+	} }
+};
+
+#endif	/* R88E_PRIV_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R88E_REG_H
+#define R88E_REG_H
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+/*
+ * MAC registers.
+ */
+/* System Configuration. */
+#define R88E_BB_PAD_CTRL		0x064
+#define R88E_HIMR			0x0b0
+#define R88E_HISR			0x0b4
+#define R88E_HIMRE			0x0b8
+#define R88E_HISRE			0x0bc
+/* MAC General Configuration. */
+#define R88E_32K_CTRL			0x194
+#define R88E_HMEBOX_EXT(idx)		(0x1f0 + (idx) * 4)
+/* Protocol Configuration. */
+#define R88E_TXPKTBUF_BCNQ1_BDNY	0x457
+#define R88E_MACID_NO_LINK		0x484
+#define R88E_TX_RPT_CTRL		0x4ec
+#define R88E_TX_RPT_MACID_MAX		0x4ed
+#define R88E_TX_RPT_TIME		0x4f0
+#define R88E_SCH_TXCMD			0x5f8
+
+
+/* Bits for R88E_HIMR. */
+#define R88E_HIMR_CPWM			0x00000100
+#define R88E_HIMR_CPWM2			0x00000200
+#define R88E_HIMR_TBDER			0x04000000
+#define R88E_HIMR_PSTIMEOUT		0x20000000
+
+/* Bits for R88E_HIMRE.*/
+#define R88E_HIMRE_RXFOVW		0x00000100
+#define R88E_HIMRE_TXFOVW		0x00000200
+#define R88E_HIMRE_RXERR		0x00000400
+#define R88E_HIMRE_TXERR		0x00000800
+
+/* Bits for R88E_TX_RPT_CTRL. */
+#define R88E_TX_RPT1_ENA		0x01
+#define R88E_TX_RPT2_ENA		0x02
+
+/* Bits for R92C_MBID_NUM. */
+#define R88E_MBID_TXBCN_RPT(id)		(0x08 << (id))
+
+/* Bits for R92C_SECCFG. */
+#define R88E_SECCFG_CHK_KEYID	0x0100
+
+
+/*
+ * Baseband registers.
+ */
+/* Bits for R92C_LSSI_PARAM(i). */
+#define R88E_LSSI_PARAM_ADDR_M	0x0ff00000
+#define R88E_LSSI_PARAM_ADDR_S	20
+
+
+/*
+ * RF (6052) registers.
+ */
+#define R88E_RF_T_METER		0x42
+
+/* Bits for R92C_RF_CHNLBW. */
+#define R88E_RF_CHNLBW_BW20	0x00c00
+
+/* Bits for R88E_RF_T_METER. */
+#define R88E_RF_T_METER_VAL_M	0x0fc00
+#define R88E_RF_T_METER_VAL_S	10
+#define R88E_RF_T_METER_START	0x30000
+
+#endif	/* R88E_REG_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,62 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+
+
+void
+r88e_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val)
+{
+	rtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
+	    SM(R88E_LSSI_PARAM_ADDR, addr) |
+	    SM(R92C_LSSI_PARAM_DATA, val));
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,87 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_priv.h>
+#include <dev/rtwn/rtl8188e/r88e_rom_image.h>
+
+
+void
+r88e_parse_rom(struct rtwn_softc *sc, uint8_t *buf)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	struct rtwn_r88e_txpwr *rt = rs->rs_txpwr;
+	struct r88e_rom *rom = (struct r88e_rom *)buf;
+	int i;
+
+	rt->bw20_tx_pwr_diff = RTWN_SIGN4TO8(MS(rom->tx_pwr_diff, HIGH_PART));
+	rt->ofdm_tx_pwr_diff = RTWN_SIGN4TO8(MS(rom->tx_pwr_diff, LOW_PART));
+	for (i = 0; i < nitems(rom->cck_tx_pwr); i++)
+		rt->cck_tx_pwr[i] = rom->cck_tx_pwr[i];
+	for (i = 0; i < nitems(rom->ht40_tx_pwr); i++)
+		rt->ht40_tx_pwr[i] = rom->ht40_tx_pwr[i];
+
+	rs->crystalcap = RTWN_GET_ROM_VAR(rom->crystalcap,
+	    R88E_ROM_CRYSTALCAP_DEF);
+	rs->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY);
+	rs->board_type =
+	    MS(RTWN_GET_ROM_VAR(rom->rf_board_opt, R92C_BOARD_TYPE_DONGLE),
+		R92C_ROM_RF1_BOARD_TYPE);
+	RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type %d\n",
+	    __func__,rs->regulatory);
+
+	sc->thermal_meter = rom->thermal_meter;
+	IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr);
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R88E_ROM_DEFS_H
+#define R88E_ROM_DEFS_H
+
+#include <dev/rtwn/rtl8192c/r92c_rom_defs.h>
+
+#define R88E_GROUP_2G		6
+
+#define R88E_EFUSE_MAX_LEN	512
+#define R88E_EFUSE_MAP_LEN	512
+
+#endif	/* R88E_ROM_DEFS_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R88E_ROM_IMAGE_H
+#define R88E_ROM_IMAGE_H
+
+#include <dev/rtwn/rtl8188e/r88e_rom_defs.h>
+
+/*
+ * RTL8188EU ROM image.
+ */
+struct r88e_rom {
+	uint8_t		reserved1[16];
+	uint8_t		cck_tx_pwr[R88E_GROUP_2G];
+	uint8_t		ht40_tx_pwr[R88E_GROUP_2G - 1];
+	uint8_t		tx_pwr_diff;
+	uint8_t		reserved2[156];
+	uint8_t		channel_plan;
+	uint8_t		crystalcap;
+#define R88E_ROM_CRYSTALCAP_DEF		0x20
+
+	uint8_t		thermal_meter;
+	uint8_t		reserved3[6];
+	uint8_t		rf_board_opt;
+	uint8_t		rf_feature_opt;
+	uint8_t		rf_bt_opt;
+	uint8_t		version;
+	uint8_t		customer_id;
+	uint8_t		reserved4[3];
+	uint8_t		rf_ant_opt;
+	uint8_t		reserved5[6];
+	uint16_t	vid;
+	uint16_t	pid;
+	uint8_t		usb_opt;
+	uint8_t		reserved6[2];
+	uint8_t		macaddr[IEEE80211_ADDR_LEN];
+	uint8_t		reserved7[2];
+	uint8_t		string[33];	/* "realtek 802.11n NIC" */
+	uint8_t		reserved8[256];
+} __packed;
+
+_Static_assert(sizeof(struct r88e_rom) == R88E_EFUSE_MAP_LEN,
+    "R88E_EFUSE_MAP_LEN must be equal to sizeof(struct r88e_rom)!");
+
+#endif	/* R88E_ROM_IMAGE_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,213 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_rx_desc.h>
+
+
+void
+r88e_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+#if __FreeBSD_version >= 1200012
+	struct ieee80211_ratectl_tx_status txs;
+#endif
+	struct r88e_tx_rpt_ccx *rpt;
+	struct ieee80211_node *ni;
+	uint8_t macid;
+	int ntries;
+
+	/* Skip Rx descriptor. */
+	buf += sizeof(struct r92c_rx_stat);
+	len -= sizeof(struct r92c_rx_stat);
+
+	rpt = (struct r88e_tx_rpt_ccx *)buf;
+	if (len != sizeof(*rpt)) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
+		    "%s: wrong report size (%d, must be %zu)\n",
+		    __func__, len, sizeof(*rpt));
+		return;
+	}
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
+	    "%s: ccx report dump: 0: %02X, 1: %02X, 2: %02X, queue time: "
+	    "low %02X, high %02X, final ridx: %02X, 6: %02X, 7: %02X\n",
+	    __func__, rpt->rptb0, rpt->rptb1, rpt->rptb2, rpt->queue_time_low,
+	    rpt->queue_time_high, rpt->final_rate, rpt->rptb6, rpt->rptb7);
+
+	macid = MS(rpt->rptb1, R88E_RPTB1_MACID);
+	if (macid > sc->macid_limit) {
+		device_printf(sc->sc_dev,
+		    "macid %u is too big; increase MACID_MAX limit\n",
+		    macid);
+		return;
+	}
+
+	ntries = MS(rpt->rptb2, R88E_RPTB2_RETRY_CNT);
+
+	ni = sc->node_list[macid];
+	if (ni != NULL) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
+		    "%s sent (%d retries)\n", __func__, macid,
+		    (rpt->rptb1 & R88E_RPTB1_PKT_OK) ? "" : " not",
+		    ntries);
+
+#if __FreeBSD_version >= 1200012
+		txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY |
+			    IEEE80211_RATECTL_STATUS_FINAL_RATE;
+		txs.long_retries = ntries;
+		if (rpt->final_rate > RTWN_RIDX_OFDM54) {	/* MCS */
+			txs.final_rate =
+			    (rpt->final_rate - 12) | IEEE80211_RATE_MCS;
+		} else
+			txs.final_rate = ridx2rate[rpt->final_rate];
+		if (rpt->rptb1 & R88E_RPTB1_PKT_OK)
+			txs.status = IEEE80211_RATECTL_TX_SUCCESS;
+		else if (rpt->rptb2 & R88E_RPTB2_RETRY_OVER)
+			txs.status = IEEE80211_RATECTL_TX_FAIL_LONG;
+		else if (rpt->rptb2 & R88E_RPTB2_LIFE_EXPIRE)
+			txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
+		else
+			txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
+		ieee80211_ratectl_tx_complete(ni, &txs);
+#else
+		struct ieee80211vap *vap = ni->ni_vap;
+		if (rpt->rptb1 & R88E_RPTB1_PKT_OK) {
+			ieee80211_ratectl_tx_complete(vap, ni,
+			    IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
+		} else {
+			ieee80211_ratectl_tx_complete(vap, ni,
+			    IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
+		}
+#endif
+	} else {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n",
+		    __func__, macid);
+	}
+}
+
+void
+r88e_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+
+	/* Skip Rx descriptor. */
+	buf += sizeof(struct r92c_rx_stat);
+	len -= sizeof(struct r92c_rx_stat);
+
+	if (len != R88E_INTR_MSG_LEN) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
+		    "%s: wrong interrupt message size (%d, must be %d)\n",
+		    __func__, len, R88E_INTR_MSG_LEN);
+		return;
+	}
+
+	/* XXX TODO */
+}
+
+int8_t
+r88e_get_rssi_cck(struct rtwn_softc *sc, void *physt)
+{
+	struct r88e_rx_phystat *phy = (struct r88e_rx_phystat *)physt;
+	int8_t lna_idx, vga_idx, rssi;
+
+	lna_idx = (phy->agc_rpt & 0xe0) >> 5;
+	vga_idx = (phy->agc_rpt & 0x1f);
+	rssi = 6 - 2 * vga_idx;
+
+	switch (lna_idx) {
+	case 7:
+		if (vga_idx > 27)
+			rssi = -100 + 6;
+		else
+			rssi += -100 + 2 * 27;
+		break;
+	case 6:
+		rssi += -48 + 2 * 2;
+		break;
+	case 5:
+		rssi += -42 + 2 * 7;
+		break;
+	case 4:
+		rssi += -36 + 2 * 7;
+		break;
+	case 3:
+		rssi += -24 + 2 * 7;
+		break;
+	case 2:
+		rssi += -6 + 2 * 5;
+		if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR)
+			rssi -= 6;
+		break;
+	case 1:
+		rssi += 8;
+		break;
+	case 0:
+		rssi += 14;
+		break;
+	}
+
+	return (rssi);
+}
+
+int8_t
+r88e_get_rssi_ofdm(struct rtwn_softc *sc, void *physt)
+{
+	struct r88e_rx_phystat *phy = (struct r88e_rx_phystat *)physt;
+	int rssi;
+
+	/* Get average RSSI. */
+	rssi = ((phy->sig_qual >> 1) & 0x7f) - 110;
+
+	return (rssi);
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R88E_RX_DESC_H
+#define R88E_RX_DESC_H
+
+#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
+
+/* Rx MAC descriptor defines (chip-specific). */
+/* Rx dword 3 */
+#define R88E_RXDW3_RPT_M	0x0000c000
+#define R88E_RXDW3_RPT_S	14
+#define R88E_RXDW3_RPT_RX	0
+#define R88E_RXDW3_RPT_TX1	1
+#define R88E_RXDW3_RPT_TX2	2
+#define R88E_RXDW3_RPT_HIS	3
+
+/* Rx PHY descriptor. */
+struct r88e_rx_phystat {
+	uint8_t		path_agc[2];
+	uint8_t		chan;
+	uint8_t		reserved1;
+	uint8_t		sig_qual;
+	uint8_t		agc_rpt;
+	uint8_t		rpt_b;
+	uint8_t		reserved2;
+	uint8_t		noise_power;
+	uint8_t		path_cfotail[2];
+	uint8_t		pcts_mask[2];
+	uint8_t		stream_rxevm[2];
+	uint8_t		path_rxsnr[2];
+	uint8_t		noise_power_db_lsb;
+	uint8_t		reserved3[3];
+	uint8_t		stream_csi[2];
+	uint8_t		stream_target_csi[2];
+	uint8_t		sig_evm;
+} __packed;
+
+/* Tx report (type 1). */
+struct r88e_tx_rpt_ccx {
+	uint8_t		rptb0;
+#define R88E_RPTB6_PKT_NUM_M	0x0e
+#define R88E_RPTB6_PKT_NUM_S	1
+#define R88E_RPTB0_INT_CCX	0x80
+
+	uint8_t		rptb1;
+#define R88E_RPTB1_MACID_M	0x3f
+#define R88E_RPTB1_MACID_S	0
+#define R88E_RPTB1_PKT_OK	0x40
+#define R88E_RPTB1_BMC		0x80
+
+	uint8_t		rptb2;
+#define R88E_RPTB2_RETRY_CNT_M	0x3f
+#define R88E_RPTB2_RETRY_CNT_S	0
+#define R88E_RPTB2_LIFE_EXPIRE	0x40
+#define R88E_RPTB2_RETRY_OVER	0x80
+
+	uint8_t		queue_time_low;
+	uint8_t		queue_time_high;
+	uint8_t		final_rate;
+	uint8_t		rptb6;
+#define R88E_RPTB6_QSEL_M	0xf0
+#define R88E_RPTB6_QSEL_S	4
+
+	uint8_t		rptb7;
+} __packed;
+
+/* Interrupt message format. */
+/* XXX recheck */
+struct r88e_intr_msg {
+	uint8_t		c2h_id;
+	uint8_t		c2h_seq;
+	uint8_t		c2h_evt;
+	uint8_t		reserved1[13];
+	uint8_t		cpwm1;
+	uint8_t		reserved2[3];
+	uint8_t		cpwm2;
+	uint8_t		reserved3[27];
+	uint32_t	hisr;
+	uint32_t	hisr_ex;
+};
+
+#endif	/* R88E_RX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,81 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+#include <dev/rtwn/rtl8188e/r88e_tx_desc.h>
+
+
+void
+r88e_tx_enable_ampdu(void *buf, int enable)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	if (enable)
+		txd->txdw2 |= htole32(R88E_TXDW2_AGGEN);
+	else
+		txd->txdw2 |= htole32(R88E_TXDW2_AGGBK);
+}
+
+void
+r88e_tx_setup_hwseq(void *buf)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	txd->txdseq |= htole16(R88E_TXDSEQ_HWSEQ_EN);
+}
+
+void
+r88e_tx_setup_macid(void *buf, int id)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, id));
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R88E_TX_DESC_H
+#define R88E_TX_DESC_H
+
+#include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
+
+/* Tx MAC descriptor defines (chip-specific). */
+/* Tx dword 1. */
+#define R88E_TXDW1_MACID_M	0x0000003f
+#define R88E_TXDW1_MACID_S	0
+
+/* Tx dword 2. */
+#define R88E_TXDW2_AGGEN	0x00001000
+#define R88E_TXDW2_AGGBK	0x00010000
+
+/* Tx dword 3. */
+#define R88E_TXDSEQ_HWSEQ_EN	0x8000
+
+#endif	/* R88E_TX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef RTL8188EU_H
+#define RTL8188EU_H
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+
+
+/*
+ * Function declarations.
+ */
+/* r88eu_init.c */
+void	r88eu_power_off(struct rtwn_softc *);
+void	r88eu_init_intr(struct rtwn_softc *);
+void	r88eu_init_rx_agg(struct rtwn_softc *);
+void	r88eu_post_init(struct rtwn_softc *);
+
+/* r88eu_rx.c */
+int	r88eu_classify_intr(struct rtwn_softc *, void *, int);
+
+#endif	/* RTL8188EU_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,218 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_nop.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu.h>
+#include <dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h>
+
+#include <dev/rtwn/rtl8188e/r88e_priv.h>
+
+#include <dev/rtwn/rtl8188e/usb/r88eu.h>
+
+
+static struct rtwn_r88e_txpwr r88e_txpwr;
+
+void	r88eu_attach(struct rtwn_usb_softc *);
+
+static void
+r88e_postattach(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	rs->rs_scan_start = ic->ic_scan_start;
+	ic->ic_scan_start = r92c_scan_start;
+	rs->rs_scan_end = ic->ic_scan_end;
+	ic->ic_scan_end = r92c_scan_end;
+}
+
+static void
+r88eu_attach_private(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs;
+
+	rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO);
+
+	rs->rs_txpwr			= &r88e_txpwr;
+	rs->rs_txagc			= &r88e_txagc;
+
+	rs->rs_set_bw20			= r88e_set_bw20;
+	rs->rs_get_txpower		= r88e_get_txpower;
+	rs->rs_set_gain			= r88e_set_gain;
+	rs->rs_tx_enable_ampdu		= r88e_tx_enable_ampdu;
+	rs->rs_tx_setup_hwseq		= r88e_tx_setup_hwseq;
+	rs->rs_tx_setup_macid		= r88e_tx_setup_macid;
+	rs->rs_set_name			= rtwn_nop_softc;	/* not used */
+
+	rs->rf_read_delay[0]		= 10;
+	rs->rf_read_delay[1]		= 100;
+	rs->rf_read_delay[2]		= 10;
+
+	sc->sc_priv = rs;
+}
+
+static void
+r88eu_adj_devcaps(struct rtwn_softc *sc)
+{
+	/* XXX TODO? */
+}
+
+void
+r88eu_attach(struct rtwn_usb_softc *uc)
+{
+	struct rtwn_softc *sc		= &uc->uc_sc;
+
+	/* USB part. */
+	uc->uc_align_rx			= r92cu_align_rx;
+	uc->tx_agg_desc_num		= 6;
+
+	/* Common part. */
+	sc->sc_flags			= RTWN_FLAG_EXT_HDR;
+
+	sc->sc_set_chan			= r92c_set_chan;
+	sc->sc_fill_tx_desc		= r92c_fill_tx_desc;
+	sc->sc_fill_tx_desc_raw 	= r92c_fill_tx_desc_raw;
+	sc->sc_fill_tx_desc_null	= r92c_fill_tx_desc_null;
+	sc->sc_dump_tx_desc		= r92cu_dump_tx_desc;
+	sc->sc_tx_radiotap_flags	= r92c_tx_radiotap_flags;
+	sc->sc_rx_radiotap_flags	= r92c_rx_radiotap_flags;
+	sc->sc_get_rssi_cck		= r88e_get_rssi_cck;
+	sc->sc_get_rssi_ofdm		= r88e_get_rssi_ofdm;
+	sc->sc_classify_intr		= r88eu_classify_intr;
+	sc->sc_handle_tx_report		= r88e_ratectl_tx_complete;
+	sc->sc_handle_c2h_report	= r88e_handle_c2h_report;
+	sc->sc_check_frame		= rtwn_nop_int_softc_mbuf;
+	sc->sc_rf_read			= r92c_rf_read;
+	sc->sc_rf_write			= r88e_rf_write;
+	sc->sc_check_condition		= r92c_check_condition;
+	sc->sc_efuse_postread		= rtwn_nop_softc;
+	sc->sc_parse_rom		= r88e_parse_rom;
+	sc->sc_set_led			= r88e_set_led;
+	sc->sc_power_on			= r88e_power_on;
+	sc->sc_power_off		= r88eu_power_off;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_fw_reset			= r88e_fw_reset;
+	sc->sc_fw_download_enable	= r88e_fw_download_enable;
+#endif
+	sc->sc_set_page_size		= r92c_set_page_size;
+	sc->sc_lc_calib			= r92c_lc_calib;
+	sc->sc_iq_calib			= r88e_iq_calib;	/* XXX TODO */
+	sc->sc_read_chipid_vendor	= rtwn_nop_softc_uint32;
+	sc->sc_adj_devcaps		= r88eu_adj_devcaps;
+	sc->sc_vap_preattach		= rtwn_nop_softc_vap;
+	sc->sc_postattach		= r88e_postattach;
+	sc->sc_detach_private		= r92c_detach_private;
+	sc->sc_set_media_status		= r88e_set_media_status;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_set_rsvd_page		= r88e_set_rsvd_page;
+	sc->sc_set_pwrmode		= r88e_set_pwrmode;
+	sc->sc_set_rssi			= rtwn_nop_softc;	/* XXX TODO? */
+#endif
+	sc->sc_beacon_init		= r92c_beacon_init;
+	sc->sc_beacon_enable		= r88e_beacon_enable;
+	sc->sc_beacon_set_rate		= rtwn_nop_void_int;
+	sc->sc_beacon_select		= rtwn_nop_softc_int;
+	sc->sc_temp_measure		= r88e_temp_measure;
+	sc->sc_temp_read		= r88e_temp_read;
+	sc->sc_init_tx_agg		= r92cu_init_tx_agg;
+	sc->sc_init_rx_agg		= r88eu_init_rx_agg;
+	sc->sc_init_ampdu		= rtwn_nop_softc;
+	sc->sc_init_intr		= r88eu_init_intr;
+	sc->sc_init_edca		= r92c_init_edca;
+	sc->sc_init_bb			= r88e_init_bb;
+	sc->sc_init_rf			= r92c_init_rf;
+	sc->sc_init_antsel		= rtwn_nop_softc;
+	sc->sc_post_init		= r88eu_post_init;
+	sc->sc_init_bcnq1_boundary	= rtwn_nop_int_softc;
+
+	sc->mac_prog			= &rtl8188eu_mac[0];
+	sc->mac_size			= nitems(rtl8188eu_mac);
+	sc->bb_prog			= &rtl8188eu_bb[0];
+	sc->bb_size			= nitems(rtl8188eu_bb);
+	sc->agc_prog			= &rtl8188eu_agc[0];
+	sc->agc_size			= nitems(rtl8188eu_agc);
+	sc->rf_prog			= &rtl8188eu_rf[0];
+
+	sc->name			= "RTL8188EU";
+	sc->fwname			= "rtwn-rtl8188eufw";
+	sc->fwsig			= 0x88e;
+
+	sc->page_count			= R88E_TX_PAGE_COUNT;
+	sc->pktbuf_count		= R88E_TXPKTBUF_COUNT;
+
+	sc->ackto			= 0x40;
+	sc->npubqpages			= R88E_PUBQ_NPAGES;
+	sc->page_size			= R92C_TX_PAGE_SIZE;
+
+	sc->txdesc_len			= sizeof(struct r92cu_tx_desc);
+	sc->efuse_maxlen		= R88E_EFUSE_MAX_LEN;
+	sc->efuse_maplen		= R88E_EFUSE_MAP_LEN;
+	sc->rx_dma_size			= R88E_RX_DMA_BUFFER_SIZE;
+
+	sc->macid_limit			= R88E_MACID_MAX + 1;
+	sc->cam_entry_limit		= R92C_CAM_ENTRY_COUNT;
+	sc->fwsize_limit		= R92C_MAX_FW_SIZE;
+	sc->temp_delta			= R88E_CALIB_THRESHOLD;
+
+	sc->bcn_status_reg[0]		= R92C_TDECTRL;
+	sc->bcn_status_reg[1]		= R92C_TDECTRL;
+	sc->rcr				= 0;
+
+	sc->ntxchains			= 1;
+	sc->nrxchains			= 1;
+
+	r88eu_attach_private(sc);
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,226 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8188e/usb/r88eu.h>
+#include <dev/rtwn/rtl8188e/usb/r88eu_reg.h>
+
+
+void
+r88eu_power_off(struct rtwn_softc *sc)
+{
+	uint8_t reg;
+	int error, ntries;
+
+	/* Disable any kind of TX reports. */
+	error = rtwn_setbits_1(sc, R88E_TX_RPT_CTRL,
+	    R88E_TX_RPT1_ENA | R88E_TX_RPT2_ENA, 0);
+	if (error == ENXIO)	/* hardware gone */
+		return;
+
+	/* Stop Rx. */
+	rtwn_write_1(sc, R92C_CR, 0);
+
+	/* Move card to Low Power State. */
+	/* Block all Tx queues. */
+	rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
+
+	for (ntries = 0; ntries < 10; ntries++) {
+		/* Should be zero if no packet is transmitting. */
+		if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0)
+			break;
+
+		rtwn_delay(sc, 5000);
+	}
+	if (ntries == 10) {
+		device_printf(sc->sc_dev, "%s: failed to block Tx queues\n",
+		    __func__);
+		return;
+	}
+
+	/* CCK and OFDM are disabled, and clock are gated. */
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0);
+
+	rtwn_delay(sc, 1);
+
+	/* Reset MAC TRX */
+	rtwn_write_1(sc, R92C_CR,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
+	    R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN |
+	    R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN);
+
+	/* check if removed later */
+	rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1);
+
+	/* Respond TxOK to scheduler */
+	rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, 0x20);
+
+	/* If firmware in ram code, do reset. */
+#ifndef RTWN_WITHOUT_UCODE
+	if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY)
+		r88e_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN);
+#endif
+
+	/* Reset MCU ready status. */
+	rtwn_write_1(sc, R92C_MCUFWDL, 0);
+
+	/* Disable 32k. */
+	rtwn_setbits_1(sc, R88E_32K_CTRL, 0x01, 0);
+
+	/* Move card to Disabled state. */
+	/* Turn off RF. */
+	rtwn_write_1(sc, R92C_RF_CTRL, 0);
+
+	/* LDO Sleep mode. */
+	rtwn_setbits_1(sc, R92C_LPLDO_CTRL, 0, R92C_LPLDO_CTRL_SLEEP);
+
+	/* Turn off MAC by HW state machine */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0,
+	    R92C_APS_FSMCO_APFM_OFF, 1);
+
+	for (ntries = 0; ntries < 10; ntries++) {
+		/* Wait until it will be disabled. */
+		if ((rtwn_read_2(sc, R92C_APS_FSMCO) &
+		    R92C_APS_FSMCO_APFM_OFF) == 0)
+			break;
+
+		rtwn_delay(sc, 5000);
+	}
+	if (ntries == 10) {
+		device_printf(sc->sc_dev, "%s: could not turn off MAC\n",
+		    __func__);
+		return;
+	}
+
+	/* schmit trigger */
+	rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0, 0x80);
+
+	/* Enable WL suspend. */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_PCIE, R92C_APS_FSMCO_AFSM_HSUS, 1);
+
+	/* Enable bandgap mbias in suspend. */
+	rtwn_write_1(sc, R92C_APS_FSMCO + 3, 0);
+
+	/* Clear SIC_EN register. */
+	rtwn_setbits_1(sc, R92C_GPIO_MUXCFG + 1, 0x10, 0);
+
+	/* Set USB suspend enable local register */
+	rtwn_setbits_1(sc, R92C_USB_SUSPEND, 0, 0x10);
+
+	/* Reset MCU IO Wrapper. */
+	reg = rtwn_read_1(sc, R92C_RSV_CTRL + 1);
+	rtwn_write_1(sc, R92C_RSV_CTRL + 1, reg & ~0x08);
+	rtwn_write_1(sc, R92C_RSV_CTRL + 1, reg | 0x08);
+
+	/* marked as 'For Power Consumption' code. */
+	rtwn_write_1(sc, R92C_GPIO_OUT, rtwn_read_1(sc, R92C_GPIO_IN));
+	rtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff);
+
+	rtwn_write_1(sc, R92C_GPIO_IO_SEL,
+	    rtwn_read_1(sc, R92C_GPIO_IO_SEL) << 4);
+	rtwn_setbits_1(sc, R92C_GPIO_MOD, 0, 0x0f);
+
+	/* Set LNA, TRSW, EX_PA Pin to output mode. */
+	rtwn_write_4(sc, R88E_BB_PAD_CTRL, 0x00080808);
+}
+
+void
+r88eu_init_intr(struct rtwn_softc *sc)
+{
+	/* TODO: adjust */
+	rtwn_write_4(sc, R88E_HISR, 0xffffffff);
+	rtwn_write_4(sc, R88E_HIMR, R88E_HIMR_CPWM | R88E_HIMR_CPWM2 |
+	    R88E_HIMR_TBDER | R88E_HIMR_PSTIMEOUT);
+	rtwn_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW |
+	    R88E_HIMRE_TXFOVW | R88E_HIMRE_RXERR | R88E_HIMRE_TXERR);
+	rtwn_setbits_1(sc, R92C_USB_SPECIAL_OPTION, 0,
+	    R92C_USB_SPECIAL_OPTION_INT_BULK_SEL);
+}
+
+void
+r88eu_init_rx_agg(struct rtwn_softc *sc)
+{
+	/* XXX merge? */
+	rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0,
+	    R92C_TRXDMA_CTRL_RXDMA_AGG_EN);
+	/* XXX dehardcode */
+	rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48);
+	rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 4);
+}
+
+void
+r88eu_post_init(struct rtwn_softc *sc)
+{
+
+	/* Enable per-packet TX report. */
+	rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, 0, R88E_TX_RPT1_ENA);
+
+	/* Disable Tx if MACID is not associated. */
+	rtwn_write_4(sc, R88E_MACID_NO_LINK, 0xffffffff);
+	rtwn_write_4(sc, R88E_MACID_NO_LINK + 4, 0xffffffff);
+	r88e_macid_enable_link(sc, RTWN_MACID_BC, 1);
+
+	/* Perform LO and IQ calibrations. */
+	r88e_iq_calib(sc);
+	/* Perform LC calibration. */
+	r92c_lc_calib(sc);
+
+	rtwn_write_1(sc, R92C_USB_HRPWM, 0);
+
+	if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) {
+		/* No support (yet?) for f/w rate adaptation. */
+		sc->sc_ratectl = RTWN_RATECTL_NET80211;
+	} else
+		sc->sc_ratectl = sc->sc_ratectl_sysctl;
+}
Index: freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R88EU_REG_H
+#define R88EU_REG_H
+
+#include <dev/rtwn/rtl8192c/usb/r92cu_reg.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+
+#endif	/* R88EU_REG_H */
Index: freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,76 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8188e/r88e_rx_desc.h>
+
+#include <dev/rtwn/rtl8188e/usb/r88eu.h>
+
+
+int
+r88eu_classify_intr(struct rtwn_softc *sc, void *buf, int len)
+{
+	struct r92c_rx_stat *stat = buf;
+	int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT);
+
+	switch (report_sel) {
+	case R88E_RXDW3_RPT_RX:
+		return (RTWN_RX_DATA);
+	case R88E_RXDW3_RPT_TX1:	/* per-packet Tx report */
+	case R88E_RXDW3_RPT_TX2:	/* periodical Tx report */
+		return (RTWN_RX_TX_REPORT);
+	case R88E_RXDW3_RPT_HIS:
+		return (RTWN_RX_OTHER);
+	default:			/* shut up the compiler */
+		return (RTWN_RX_DATA);
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,74 @@
+/*	$OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef RTL8192CE_H
+#define RTL8192CE_H
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+
+
+/*
+ * Global definitions.
+ */
+#define R92CE_PUBQ_NPAGES	176
+#define R92CE_HPQ_NPAGES	41
+#define R92CE_LPQ_NPAGES	28
+#define R92CE_TX_PAGE_COUNT	\
+	(R92CE_PUBQ_NPAGES + R92CE_HPQ_NPAGES + R92CE_LPQ_NPAGES)
+
+
+/*
+ * Function declarations.
+ */
+/* r92ce_calib.c */
+void	r92ce_iq_calib(struct rtwn_softc *);
+
+/* r92ce_fw.c */
+#ifndef RTWN_WITHOUT_UCODE
+void	r92ce_fw_reset(struct rtwn_softc *, int);
+#endif
+
+/* r92ce_init.c */
+void	r92ce_init_intr(struct rtwn_softc *);
+void	r92ce_init_edca(struct rtwn_softc *);
+void	r92ce_init_bb(struct rtwn_softc *);
+int	r92ce_power_on(struct rtwn_softc *);
+void	r92ce_power_off(struct rtwn_softc *);
+void	r92ce_init_ampdu(struct rtwn_softc *);
+void	r92ce_post_init(struct rtwn_softc *);
+
+/* r92ce_led.c */
+void	r92ce_set_led(struct rtwn_softc *, int, int);
+
+/* r92ce_rx.c */
+int	r92ce_classify_intr(struct rtwn_softc *, void *, int);
+void	r92ce_enable_intr(struct rtwn_pci_softc *);
+void	r92ce_start_xfers(struct rtwn_softc *);
+
+/* r92ce_tx.c */
+void	r92ce_setup_tx_desc(struct rtwn_pci_softc *, void *, uint32_t);
+void	r92ce_tx_postsetup(struct rtwn_pci_softc *, void *,
+	    bus_dma_segment_t[]);
+void	r92ce_copy_tx_desc(void *, const void *);
+void	r92ce_dump_tx_desc(struct rtwn_softc *, const void *);
+
+#endif	/* RTL8192CE_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,265 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_nop.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_priv.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h>
+
+
+static struct rtwn_r92c_txpwr r92c_txpwr;
+
+void	r92ce_attach(struct rtwn_pci_softc *);
+
+static void
+r92ce_postattach(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	if (!(rs->chip & R92C_CHIP_92C) &&
+	    rs->board_type == R92C_BOARD_TYPE_HIGHPA)
+		rs->rs_txagc = &rtl8188ru_txagc[0];
+	else
+		rs->rs_txagc = &rtl8192cu_txagc[0];
+
+	if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) ==
+	    R92C_CHIP_UMC_A_CUT)
+		sc->fwname = "rtwn-rtl8192cfwE";
+	else
+		sc->fwname = "rtwn-rtl8192cfwE_B";
+	sc->fwsig = 0x88c;
+
+	rs->rs_scan_start = ic->ic_scan_start;
+	ic->ic_scan_start = r92c_scan_start;
+	rs->rs_scan_end = ic->ic_scan_end;
+	ic->ic_scan_end = r92c_scan_end;
+}
+
+static void
+r92ce_set_name(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	if (rs->chip & R92C_CHIP_92C)
+		sc->name = "RTL8192CE";
+	else
+		sc->name = "RTL8188CE";
+}
+
+static void
+r92ce_attach_private(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs;
+
+	rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO);
+
+	rs->rs_txpwr			= &r92c_txpwr;
+
+	rs->rs_set_bw20			= r92c_set_bw20;
+	rs->rs_get_txpower		= r92c_get_txpower;
+	rs->rs_set_gain			= r92c_set_gain;
+	rs->rs_tx_enable_ampdu		= r92c_tx_enable_ampdu;
+	rs->rs_tx_setup_hwseq		= r92c_tx_setup_hwseq;
+	rs->rs_tx_setup_macid		= r92c_tx_setup_macid;
+	rs->rs_set_name			= r92ce_set_name;
+
+	/* XXX TODO: test with net80211 ratectl! */
+#ifndef RTWN_WITHOUT_UCODE
+	rs->rs_c2h_timeout		= hz;
+
+	callout_init_mtx(&rs->rs_c2h_report, &sc->sc_mtx, 0);
+#endif
+
+	rs->rf_read_delay[0]		= 1000;
+	rs->rf_read_delay[1]		= 1000;
+	rs->rf_read_delay[2]		= 1000;
+
+	sc->sc_priv = rs;
+}
+
+static void
+r92ce_adj_devcaps(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	/*
+	 * XXX do NOT enable PMGT until RSVD_PAGE command
+	 * will not be tested / fixed + HRPWM register must be set too.
+	 */
+	ic->ic_caps &= ~IEEE80211_C_PMGT;
+}
+
+void
+r92ce_attach(struct rtwn_pci_softc *pc)
+{
+	struct rtwn_softc *sc		= &pc->pc_sc;
+
+	/* PCIe part. */
+	pc->pc_setup_tx_desc		= r92ce_setup_tx_desc;
+	pc->pc_tx_postsetup		= r92ce_tx_postsetup;
+	pc->pc_copy_tx_desc		= r92ce_copy_tx_desc;
+	pc->pc_enable_intr		= r92ce_enable_intr;
+
+	pc->pc_qmap			= 0xf771;
+	pc->tcr				=
+	    R92C_TCR_CFENDFORM | (1 << 12) | (1 << 13);
+
+	/* Common part. */
+	/* RTL8192C* cannot use pairwise keys from first 4 slots */
+	sc->sc_flags			= RTWN_FLAG_CAM_FIXED;
+
+	sc->sc_start_xfers		= r92ce_start_xfers;
+	sc->sc_set_chan			= r92c_set_chan;
+	sc->sc_fill_tx_desc		= r92c_fill_tx_desc;
+	sc->sc_fill_tx_desc_raw		= r92c_fill_tx_desc_raw;
+	sc->sc_fill_tx_desc_null	= r92c_fill_tx_desc_null; /* XXX recheck */
+	sc->sc_dump_tx_desc		= r92ce_dump_tx_desc;
+	sc->sc_tx_radiotap_flags	= r92c_tx_radiotap_flags;
+	sc->sc_rx_radiotap_flags	= r92c_rx_radiotap_flags;
+	sc->sc_get_rssi_cck		= r92c_get_rssi_cck;
+	sc->sc_get_rssi_ofdm		= r92c_get_rssi_ofdm;
+	sc->sc_classify_intr		= r92ce_classify_intr;
+	sc->sc_handle_tx_report		= rtwn_nop_softc_uint8_int;
+	sc->sc_handle_c2h_report	= rtwn_nop_softc_uint8_int;
+	sc->sc_check_frame		= rtwn_nop_int_softc_mbuf;
+	sc->sc_rf_read			= r92c_rf_read;
+	sc->sc_rf_write			= r92c_rf_write;
+	sc->sc_check_condition		= r92c_check_condition;
+	sc->sc_efuse_postread		= r92c_efuse_postread;
+	sc->sc_parse_rom		= r92c_parse_rom;
+	sc->sc_set_led			= r92ce_set_led;
+	sc->sc_power_on			= r92ce_power_on;
+	sc->sc_power_off		= r92ce_power_off;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_fw_reset			= r92ce_fw_reset;
+	sc->sc_fw_download_enable	= r92c_fw_download_enable;
+#endif
+	sc->sc_set_page_size		= r92c_set_page_size;
+	sc->sc_lc_calib			= r92c_lc_calib;
+	sc->sc_iq_calib			= r92ce_iq_calib;
+	sc->sc_read_chipid_vendor	= r92c_read_chipid_vendor;
+	sc->sc_adj_devcaps		= r92ce_adj_devcaps;
+	sc->sc_vap_preattach		= rtwn_nop_softc_vap;
+	sc->sc_postattach		= r92ce_postattach;
+	sc->sc_detach_private		= r92c_detach_private;
+	sc->sc_set_media_status		= r92c_joinbss_rpt;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_set_rsvd_page		= r92c_set_rsvd_page;
+	sc->sc_set_pwrmode		= r92c_set_pwrmode;
+	sc->sc_set_rssi			= r92c_set_rssi;
+#endif
+	sc->sc_beacon_init		= r92c_beacon_init;
+	sc->sc_beacon_enable		= r92c_beacon_enable;
+	sc->sc_beacon_set_rate		= rtwn_nop_void_int;
+	sc->sc_beacon_select		= rtwn_nop_softc_int;
+	sc->sc_temp_measure		= r92c_temp_measure;
+	sc->sc_temp_read		= r92c_temp_read;
+	sc->sc_init_tx_agg		= rtwn_nop_softc;
+	sc->sc_init_rx_agg		= rtwn_nop_softc;
+	sc->sc_init_ampdu		= r92ce_init_ampdu;
+	sc->sc_init_intr		= r92ce_init_intr;
+	sc->sc_init_edca		= r92ce_init_edca;
+	sc->sc_init_bb			= r92ce_init_bb;
+	sc->sc_init_rf			= r92c_init_rf;
+	sc->sc_init_antsel		= rtwn_nop_softc;
+	sc->sc_post_init		= r92ce_post_init;
+	sc->sc_init_bcnq1_boundary	= rtwn_nop_int_softc;
+
+	sc->mac_prog			= &rtl8192ce_mac[0];
+	sc->mac_size			= nitems(rtl8192ce_mac);
+	sc->bb_prog			= &rtl8192ce_bb[0];
+	sc->bb_size			= nitems(rtl8192ce_bb);
+	sc->agc_prog			= &rtl8192ce_agc[0];
+	sc->agc_size			= nitems(rtl8192ce_agc);
+	sc->rf_prog			= &rtl8192c_rf[0];
+
+	sc->page_count			= R92CE_TX_PAGE_COUNT;
+	sc->pktbuf_count		= R92C_TXPKTBUF_COUNT;
+
+	sc->ackto			= 0x40;
+	sc->npubqpages			= R92CE_PUBQ_NPAGES;
+	sc->nhqpages			= R92CE_HPQ_NPAGES;
+	sc->nnqpages			= 0;
+	sc->nlqpages			= R92CE_LPQ_NPAGES;
+	sc->page_size			= R92C_TX_PAGE_SIZE;
+
+	sc->txdesc_len			= sizeof(struct r92ce_tx_desc);
+	sc->efuse_maxlen		= R92C_EFUSE_MAX_LEN;
+	sc->efuse_maplen		= R92C_EFUSE_MAP_LEN;
+	sc->rx_dma_size			= R92C_RX_DMA_BUFFER_SIZE;
+
+	sc->macid_limit			= R92C_MACID_MAX + 1;
+	sc->cam_entry_limit		= R92C_CAM_ENTRY_COUNT;
+	sc->fwsize_limit		= R92C_MAX_FW_SIZE;
+	sc->temp_delta			= R92C_CALIB_THRESHOLD;
+
+	sc->bcn_status_reg[0]		= R92C_TDECTRL;
+	/*
+	 * TODO: some additional setup is required
+	 * to maintain few beacons at the same time.
+	 *
+	 * XXX BCNQ1 mechanism is not needed here; move it to the USB module.
+	 */
+	sc->bcn_status_reg[1]		= R92C_TDECTRL;
+	sc->rcr				= 0;
+
+	r92ce_attach_private(sc);
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,388 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
+
+
+/* Registers to save and restore during IQ calibration. */
+struct r92ce_iq_cal_reg_vals {
+	uint32_t	adda[16];
+	uint8_t		txpause;
+	uint8_t		bcn_ctrl[2];
+	uint32_t	gpio_muxcfg;
+	uint32_t	ofdm0_trxpathena;
+	uint32_t	ofdm0_trmuxpar;
+	uint32_t	fpga0_rfifacesw1;
+};
+
+/* XXX 92CU? */
+static int
+r92ce_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2],
+    uint16_t rx[2])
+{
+	uint32_t status;
+	int offset = chain * 0x20;
+
+	if (chain == 0) {	/* IQ calibration for chain 0. */
+		/* IQ calibration settings for chain 0. */
+		rtwn_bb_write(sc, 0xe30, 0x10008c1f);
+		rtwn_bb_write(sc, 0xe34, 0x10008c1f);
+		rtwn_bb_write(sc, 0xe38, 0x82140102);
+
+		if (sc->ntxchains > 1) {
+			rtwn_bb_write(sc, 0xe3c, 0x28160202);	/* 2T */
+			/* IQ calibration settings for chain 1. */
+			rtwn_bb_write(sc, 0xe50, 0x10008c22);
+			rtwn_bb_write(sc, 0xe54, 0x10008c22);
+			rtwn_bb_write(sc, 0xe58, 0x82140102);
+			rtwn_bb_write(sc, 0xe5c, 0x28160202);
+		} else
+			rtwn_bb_write(sc, 0xe3c, 0x28160502);	/* 1T */
+
+		/* LO calibration settings. */
+		rtwn_bb_write(sc, 0xe4c, 0x001028d1);
+		/* We're doing LO and IQ calibration in one shot. */
+		rtwn_bb_write(sc, 0xe48, 0xf9000000);
+		rtwn_bb_write(sc, 0xe48, 0xf8000000);
+
+	} else {		/* IQ calibration for chain 1. */
+		/* We're doing LO and IQ calibration in one shot. */
+		rtwn_bb_write(sc, 0xe60, 0x00000002);
+		rtwn_bb_write(sc, 0xe60, 0x00000000);
+	}
+
+	/* Give LO and IQ calibrations the time to complete. */
+	rtwn_delay(sc, 1000);
+
+	/* Read IQ calibration status. */
+	status = rtwn_bb_read(sc, 0xeac);
+
+	if (status & (1 << (28 + chain * 3)))
+		return (0);	/* Tx failed. */
+	/* Read Tx IQ calibration results. */
+	tx[0] = (rtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff;
+	tx[1] = (rtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff;
+	if (tx[0] == 0x142 || tx[1] == 0x042)
+		return (0);	/* Tx failed. */
+
+	if (status & (1 << (27 + chain * 3)))
+		return (1);	/* Rx failed. */
+	/* Read Rx IQ calibration results. */
+	rx[0] = (rtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff;
+	rx[1] = (rtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff;
+	if (rx[0] == 0x132 || rx[1] == 0x036)
+		return (1);	/* Rx failed. */
+
+	return (3);	/* Both Tx and Rx succeeded. */
+}
+
+static void
+r92ce_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2],
+    uint16_t rx[2][2], struct r92ce_iq_cal_reg_vals *vals)
+{
+	/* Registers to save and restore during IQ calibration. */
+	static const uint16_t reg_adda[16] = {
+		0x85c, 0xe6c, 0xe70, 0xe74,
+		0xe78, 0xe7c, 0xe80, 0xe84,
+		0xe88, 0xe8c, 0xed0, 0xed4,
+		0xed8, 0xedc, 0xee0, 0xeec
+	};
+	int i, chain;
+	uint32_t hssi_param1;
+
+	if (n == 0) {
+		for (i = 0; i < nitems(reg_adda); i++)
+			vals->adda[i] = rtwn_bb_read(sc, reg_adda[i]);
+
+		vals->txpause = rtwn_read_1(sc, R92C_TXPAUSE);
+		vals->bcn_ctrl[0] = rtwn_read_1(sc, R92C_BCN_CTRL(0));
+		vals->bcn_ctrl[1] = rtwn_read_1(sc, R92C_BCN_CTRL(1));
+		vals->gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG);
+	}
+
+	if (sc->ntxchains == 1) {
+		rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0);
+		for (i = 1; i < nitems(reg_adda); i++)
+			rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0);
+	} else {
+		for (i = 0; i < nitems(reg_adda); i++)
+			rtwn_bb_write(sc, reg_adda[i], 0x04db25a4);
+	}
+
+	hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0));
+	if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
+		rtwn_bb_write(sc, R92C_HSSI_PARAM1(0),
+		    hssi_param1 | R92C_HSSI_PARAM1_PI);
+		rtwn_bb_write(sc, R92C_HSSI_PARAM1(1),
+		    hssi_param1 | R92C_HSSI_PARAM1_PI);
+	}
+
+	if (n == 0) {
+		vals->ofdm0_trxpathena =
+		    rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
+		vals->ofdm0_trmuxpar = rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR);
+		vals->fpga0_rfifacesw1 =
+		    rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1));
+	}
+
+	rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600);
+	rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4);
+	rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000);
+	if (sc->ntxchains > 1) {
+		rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
+		rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000);
+	}
+
+	rtwn_write_1(sc, R92C_TXPAUSE,
+	    R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH);
+	rtwn_write_1(sc, R92C_BCN_CTRL(0),
+	    vals->bcn_ctrl[0] & ~R92C_BCN_CTRL_EN_BCN);
+	rtwn_write_1(sc, R92C_BCN_CTRL(1),
+	    vals->bcn_ctrl[1] & ~R92C_BCN_CTRL_EN_BCN);
+	rtwn_write_1(sc, R92C_GPIO_MUXCFG,
+	    vals->gpio_muxcfg & ~R92C_GPIO_MUXCFG_ENBT);
+
+	rtwn_bb_write(sc, 0x0b68, 0x00080000);
+	if (sc->ntxchains > 1)
+		rtwn_bb_write(sc, 0x0b6c, 0x00080000);
+
+	rtwn_bb_write(sc, 0x0e28, 0x80800000);
+	rtwn_bb_write(sc, 0x0e40, 0x01007c00);
+	rtwn_bb_write(sc, 0x0e44, 0x01004800);
+
+	rtwn_bb_write(sc, 0x0b68, 0x00080000);
+
+	for (chain = 0; chain < sc->ntxchains; chain++) {
+		if (chain > 0) {
+			/* Put chain 0 on standby. */
+			rtwn_bb_write(sc, 0x0e28, 0x00);
+			rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
+			rtwn_bb_write(sc, 0x0e28, 0x80800000);
+
+			/* Enable chain 1. */
+			for (i = 0; i < nitems(reg_adda); i++)
+				rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4);
+		}
+
+		/* Run IQ calibration twice. */
+		for (i = 0; i < 2; i++) {
+			int ret;
+
+			ret = r92ce_iq_calib_chain(sc, chain,
+			    tx[chain], rx[chain]);
+			if (ret == 0) {
+				RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
+				    "%s: chain %d: Tx failed.\n",
+				    __func__, chain);
+				tx[chain][0] = 0xff;
+				tx[chain][1] = 0xff;
+				rx[chain][0] = 0xff;
+				rx[chain][1] = 0xff;
+			} else if (ret == 1) {
+				RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
+				    "%s: chain %d: Rx failed.\n",
+				    __func__, chain);
+				rx[chain][0] = 0xff;
+				rx[chain][1] = 0xff;
+			} else if (ret == 3) {
+				RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
+				    "%s: chain %d: Both Tx and Rx "
+				    "succeeded.\n", __func__, chain);
+			}
+		}
+
+		RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
+		    "%s: results for run %d chain %d: tx[0] 0x%x, "
+		    "tx[1] 0x%x, rx[0] 0x%x, rx[1] 0x%x\n", __func__, n, chain,
+		    tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1]);
+	}
+
+	rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA,
+	    vals->ofdm0_trxpathena);
+	rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1),
+	    vals->fpga0_rfifacesw1);
+	rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, vals->ofdm0_trmuxpar);
+
+	rtwn_bb_write(sc, 0x0e28, 0x00);
+	rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3);
+	if (sc->ntxchains > 1)
+		rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3);
+
+	if (n != 0) {
+		if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
+			rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1);
+			rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1);
+		}
+
+		for (i = 0; i < nitems(reg_adda); i++)
+			rtwn_bb_write(sc, reg_adda[i], vals->adda[i]);
+
+		rtwn_write_1(sc, R92C_TXPAUSE, vals->txpause);
+		rtwn_write_1(sc, R92C_BCN_CTRL(0), vals->bcn_ctrl[0]);
+		rtwn_write_1(sc, R92C_BCN_CTRL(1), vals->bcn_ctrl[1]);
+		rtwn_write_4(sc, R92C_GPIO_MUXCFG, vals->gpio_muxcfg);
+	}
+}
+
+#define RTWN_IQ_CAL_MAX_TOLERANCE 5
+static int
+r92ce_iq_calib_compare_results(struct rtwn_softc *sc, uint16_t tx1[2][2],
+    uint16_t rx1[2][2], uint16_t tx2[2][2], uint16_t rx2[2][2])
+{
+	int chain, i, tx_ok[2], rx_ok[2];
+
+	tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0;
+	for (chain = 0; chain < sc->ntxchains; chain++) {
+		for (i = 0; i < 2; i++)	{
+			if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff ||
+			    rx1[chain][i] == 0xff || rx2[chain][i] == 0xff)
+				continue;
+
+			tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <=
+			    RTWN_IQ_CAL_MAX_TOLERANCE);
+
+			rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <=
+			    RTWN_IQ_CAL_MAX_TOLERANCE);
+		}
+	}
+
+	if (sc->ntxchains > 1)
+		return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]);
+	else
+		return (tx_ok[0] && rx_ok[0]);
+}
+#undef RTWN_IQ_CAL_MAX_TOLERANCE
+
+static void
+r92ce_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2],
+    uint16_t rx[2], int chain)
+{
+	uint32_t reg, val, x;
+	long y, tx_c;
+
+	if (tx[0] == 0xff || tx[1] == 0xff)
+		return;
+
+	reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain));
+	val = ((reg >> 22) & 0x3ff);
+	x = tx[0];
+	if (x & 0x00000200)
+		x |= 0xfffffc00;
+	reg = (((x * val) >> 8) & 0x3ff);
+	rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(chain), 0x3ff, reg);
+	rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x80000000,
+	    ((x * val) & 0x80) << 24);
+
+	y = tx[1];
+	if (y & 0x00000200)
+		y |= 0xfffffc00;
+	tx_c = (y * val) >> 8;
+	rtwn_bb_setbits(sc, R92C_OFDM0_TXAFE(chain), 0xf0000000,
+	    (tx_c & 0x3c0) << 22);
+	rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(chain), 0x003f0000,
+	    (tx_c & 0x3f) << 16);
+	rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x20000000,
+	    ((y * val) & 0x80) << 22);
+
+	if (rx[0] == 0xff || rx[1] == 0xff)
+		return;
+
+	rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(chain), 0x3ff,
+	    rx[0] & 0x3ff);
+	rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(chain), 0xfc00,
+	    (rx[1] & 0x3f) << 10);
+
+	if (chain == 0) {
+		rtwn_bb_setbits(sc, R92C_OFDM0_RXIQEXTANTA, 0xf0000000,
+		    (rx[1] & 0x3c0) << 22);
+	} else {
+		rtwn_bb_setbits(sc, R92C_OFDM0_AGCRSSITABLE, 0xf000,
+		    (rx[1] & 0x3c0) << 6);
+	}
+}
+
+#define RTWN_IQ_CAL_NRUN	3
+void
+r92ce_iq_calib(struct rtwn_softc *sc)
+{
+	struct r92ce_iq_cal_reg_vals vals;
+	uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2];
+	int n, valid;
+
+	valid = 0;
+	for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) {
+		r92ce_iq_calib_run(sc, n, tx[n], rx[n], &vals);
+
+		if (n == 0)
+			continue;
+
+		/* Valid results remain stable after consecutive runs. */
+		valid = r92ce_iq_calib_compare_results(sc, tx[n - 1],
+		    rx[n - 1], tx[n], rx[n]);
+		if (valid)
+			break;
+	}
+
+	if (valid) {
+		r92ce_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0);
+		if (sc->ntxchains > 1)
+			r92ce_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1);
+	}
+}
+#undef RTWN_IQ_CAL_NRUN
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,77 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce.h>
+
+
+#ifndef RTWN_WITHOUT_UCODE
+void
+r92ce_fw_reset(struct rtwn_softc *sc, int reason)
+{
+
+	if (reason == RTWN_FW_RESET_CHECKSUM)
+		return;
+
+	r92c_fw_reset(sc, reason);
+
+	/*
+	 * We must sleep for one second to let the firmware settle.
+	 * Accessing registers too early will hang the whole system.
+	 */
+	if (reason == RTWN_FW_RESET_DOWNLOAD)
+		rtwn_delay(sc, 1000 * 1000);
+}
+#endif
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,325 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
+
+
+void
+r92ce_init_intr(struct rtwn_softc *sc)
+{
+	/* Disable interrupts. */
+	rtwn_write_4(sc, R92C_HISR, 0x00000000);
+	rtwn_write_4(sc, R92C_HIMR, 0x00000000);
+}
+
+void
+r92ce_init_edca(struct rtwn_softc *sc)
+{
+	/* SIFS */
+	rtwn_write_2(sc, R92C_SPEC_SIFS, 0x1010);
+	rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x1010);
+	rtwn_write_2(sc, R92C_SIFS_CCK, 0x1010);
+	rtwn_write_2(sc, R92C_SIFS_OFDM, 0x0e0e);
+	/* TXOP */
+	rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b);
+	rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f);
+	rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4322);
+	rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3222);
+}
+
+void
+r92ce_init_bb(struct rtwn_softc *sc)
+{
+
+	/* Enable BB and RF. */
+	rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0,
+	    R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
+	    R92C_SYS_FUNC_EN_DIO_RF);
+
+	rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83);
+
+	rtwn_write_1(sc, R92C_RF_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
+
+	rtwn_write_1(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA |
+	    R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST |
+	    R92C_SYS_FUNC_EN_BBRSTB);
+
+	rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80);
+
+	rtwn_setbits_4(sc, R92C_LEDCFG0, 0, 0x00800000);
+
+	r92c_init_bb_common(sc);
+}
+
+int
+r92ce_power_on(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	uint32_t reg;
+	int ntries;
+
+	/* Wait for autoload done bit. */
+	for (ntries = 0; ntries < 1000; ntries++) {
+		if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN)
+			break;
+		DELAY(5);
+	}
+	if (ntries == 1000) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for chip autoload\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Unlock ISO/CLK/Power control register. */
+	rtwn_write_1(sc, R92C_RSV_CTRL, 0);
+
+	if (rs->board_type != R92C_BOARD_TYPE_DONGLE) {
+		/* bt coex */
+		rtwn_setbits_4(sc, R92C_APS_FSMCO, 0,
+		    R92C_APS_FSMCO_SOP_ABG |
+		    R92C_APS_FSMCO_SOP_AMB |
+		    R92C_APS_FSMCO_XOP_BTCK);
+	}
+
+	/* Move SPS into PWM mode. */
+	rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b);
+
+	/* Set low byte to 0x0f, leave others unchanged. */
+	rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0f);
+
+	/* TODO: check if we need this for 8188CE */
+	if (rs->board_type != R92C_BOARD_TYPE_DONGLE) {
+		/* bt coex */
+		/* XXX magic from linux */
+		rtwn_setbits_4(sc, R92C_AFE_XTAL_CTRL, 0x024800, 0);
+	}
+
+	rtwn_setbits_2(sc, R92C_SYS_ISO_CTRL, 0xff00,
+	    R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR);
+
+	DELAY(200);
+
+	/* TODO: linux does additional btcoex stuff here */
+
+	/* Auto enable WLAN. */
+	rtwn_setbits_2(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_ONMAC);
+	for (ntries = 0; ntries < 1000; ntries++) {
+		if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
+		    R92C_APS_FSMCO_APFM_ONMAC))
+			break;
+		DELAY(5);
+	}
+	if (ntries == 1000) {
+		device_printf(sc->sc_dev, "timeout waiting for MAC auto ON\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Enable radio, GPIO and LED functions. */
+	rtwn_write_2(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_PCIE |
+	    R92C_APS_FSMCO_PDN_EN |
+	    R92C_APS_FSMCO_PFM_ALDN);
+	/* Release RF digital isolation. */
+	rtwn_setbits_2(sc, R92C_SYS_ISO_CTRL, R92C_SYS_ISO_CTRL_DIOR, 0);
+
+	if (rs->chip & R92C_CHIP_92C)
+		rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77);
+	else
+		rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22);
+
+	rtwn_write_4(sc, R92C_INT_MIG, 0);
+
+	if (rs->board_type != R92C_BOARD_TYPE_DONGLE) {
+		/* bt coex */
+		/* XXX magic from linux */
+		rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0x02, 0);
+	}
+
+	rtwn_setbits_1(sc, R92C_GPIO_MUXCFG, R92C_GPIO_MUXCFG_RFKILL, 0);
+
+	reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL);
+	if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) {
+		device_printf(sc->sc_dev,
+		    "radio is disabled by hardware switch\n");
+		/* XXX how driver will know when radio will be enabled? */
+		return (EPERM);
+	}
+
+	/* Initialize MAC. */
+	rtwn_setbits_1(sc, R92C_APSD_CTRL, R92C_APSD_CTRL_OFF, 0);
+	for (ntries = 0; ntries < 200; ntries++) {
+		if (!(rtwn_read_1(sc, R92C_APSD_CTRL) &
+		    R92C_APSD_CTRL_OFF_STATUS))
+			break;
+		DELAY(500);
+	}
+	if (ntries == 200) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for MAC initialization\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+	rtwn_setbits_2(sc, R92C_CR, 0,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
+	    R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
+	    R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
+	    ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0));
+
+	rtwn_write_4(sc, R92C_MCUTST_1, 0x0);
+
+	return (0);
+}
+
+void
+r92ce_power_off(struct rtwn_softc *sc)
+{
+#ifndef RTWN_WITHOUT_UCODE
+	struct r92c_softc *rs = sc->sc_priv;
+
+	/* Deinit C2H event handler. */
+	callout_stop(&rs->rs_c2h_report);
+	rs->rs_c2h_paused = 0;
+	rs->rs_c2h_pending = 0;
+	rs->rs_c2h_timeout = hz;
+#endif
+
+	/* Stop hardware. */
+	/* Disable interrupts. */
+	rtwn_write_4(sc, R92C_HISR, 0);
+	rtwn_write_4(sc, R92C_HIMR, 0);
+
+	/* Stop hardware. */
+	rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
+
+	/* Turn off RF. */
+	rtwn_write_1(sc, R92C_RF_CTRL, 0);
+
+	/* Reset BB state machine */
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0, R92C_SYS_FUNC_EN_BB_GLB_RST);
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0);
+
+	/* Disable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+	rtwn_setbits_2(sc, R92C_CR,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
+	    R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
+	    R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
+	    R92C_CR_ENSEC,
+	    0);
+
+	/* If firmware in ram code, do reset. */
+#ifndef RTWN_WITHOUT_UCODE
+	if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
+		r92ce_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN);
+#endif
+
+	/* TODO: linux does additional btcoex stuff here */
+	rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0x80); /* linux magic number */
+	rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); /* ditto */
+	rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0e); /* different with btcoex */
+	rtwn_write_1(sc, R92C_RSV_CTRL, 0x0e);
+	rtwn_write_1(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_PDN_EN);
+}
+
+void
+r92ce_init_ampdu(struct rtwn_softc *sc)
+{
+
+	/* Setup AMPDU aggregation. */
+	rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631);	/* MCS7~0 */
+	rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16);
+}
+
+void
+r92ce_post_init(struct rtwn_softc *sc)
+{
+	rtwn_write_2(sc, R92C_FWHW_TXQ_CTRL,
+	    0x1f00 | R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW);
+
+	rtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff);
+
+	/* Perform LO and IQ calibrations. */
+	r92ce_iq_calib(sc);
+	/* Perform LC calibration. */
+	r92c_lc_calib(sc);
+
+	r92c_pa_bias_init(sc);
+
+	/* Fix for lower temperature. */
+	rtwn_write_1(sc, 0x15, 0xe9);
+
+#ifndef RTWN_WITHOUT_UCODE
+	if (sc->sc_flags & RTWN_FW_LOADED) {
+		struct r92c_softc *rs = sc->sc_priv;
+
+		if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) {
+			/* XXX TODO: fix (see comment in r92cu_init.c) */
+			sc->sc_ratectl = RTWN_RATECTL_NET80211;
+		} else
+			sc->sc_ratectl = sc->sc_ratectl_sysctl;
+
+		/* Start C2H event handling. */
+		callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout,
+		    r92c_handle_c2h_report, sc);
+	} else
+#endif
+		sc->sc_ratectl = RTWN_RATECTL_NONE;
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,69 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
+
+void
+r92ce_set_led(struct rtwn_softc *sc, int led, int on)
+{
+
+	if (led == RTWN_LED_LINK) {
+		rtwn_setbits_1(sc, R92C_LEDCFG2, 0x0f,
+		    on ? R92C_LEDCFG2_EN : R92C_LEDCFG2_DIS);
+		sc->ledlink = on;	/* Save LED state. */
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,182 @@
+/*	$OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef R92CE_PRIV_H
+#define R92CE_PRIV_H
+
+#include <dev/rtwn/rtl8192c/r92c_priv.h>
+
+
+/*
+ * MAC initialization values.
+ */
+static const struct rtwn_mac_prog rtl8192ce_mac[] = {
+	{ 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 },
+	{ 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 },
+	{ 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 },
+	{ 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 },
+	{ 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 },
+	{ 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f },
+	{ 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 },
+	{ 0x45b, 0xb9 }, { 0x460, 0x88 }, { 0x461, 0x88 }, { 0x462, 0x06 },
+	{ 0x463, 0x03 }, { 0x4c8, 0x04 }, { 0x4c9, 0x08 }, { 0x4cc, 0x02 },
+	{ 0x4cd, 0x28 }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 },
+	{ 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 },
+	{ 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 },
+	{ 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 },
+	{ 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a },
+	{ 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 },
+	{ 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x20 }, { 0x547, 0x00 },
+	{ 0x559, 0x02 }, { 0x55a, 0x02 }, { 0x55d, 0xff }, { 0x605, 0x30 },
+	{ 0x608, 0x0e }, { 0x609, 0x2a }, { 0x652, 0x20 }, { 0x63c, 0x0a },
+	{ 0x63d, 0x0e }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 },
+	{ 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 },
+	{ 0x70b, 0x87 }
+};
+
+
+/*
+ * Baseband initialization values.
+ */
+static const uint16_t rtl8192ce_bb_regs0[] = {
+	0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818,
+	0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c,
+	0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860,
+	0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884,
+	0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908,
+	0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c,
+	0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04
+}, rtl8192ce_bb_regs1[] = {
+	0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28,
+	0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c,
+	0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70,
+	0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94,
+	0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8,
+	0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc,
+	0xce0, 0xce4, 0xce8, 0xcec, 0xd00
+};
+
+static const uint32_t rtl8192ce_bb_vals0_2t[] = {
+	0x0011800f, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00,
+	0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+	0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727,
+	0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000,
+	0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a,
+	0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27,
+	0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070,
+	0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe,
+	0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+	0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+	0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+	0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+	0x48071d40, 0x03a05633
+}, rtl8192ce_bb_vals0_1t[] = {
+	0x0011800f, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00,
+	0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+	0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a,
+	0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200,
+	0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070,
+	0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe,
+	0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+	0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+	0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+	0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+	0x48071d40, 0x03a05611
+}, rtl8192ce_bb_vals1[] = {
+	0x000000e4, 0x6c6c6c6c, 0x08800000, 0x40000100, 0x08800000,
+	0x40000100, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x69e9ac44, 0x469652cf, 0x49795994, 0x0a97971c, 0x1f7c403f,
+	0x000100b7, 0xec020107, 0x007f037f, 0x69543420, 0x43bc0094,
+	0x69543420, 0x433c0094, 0x00000000, 0x5116848b, 0x47c00bff,
+	0x00000036, 0x2c7f000d, 0x018610db, 0x0000001f, 0x00b91612,
+	0x40000100, 0x20f60000, 0x40000100, 0x20200000, 0x00121820,
+	0x00000000, 0x00121820, 0x00007f7f, 0x00000000, 0x00000080,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x28000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x64b22427, 0x00766932, 0x00222222,
+	0x00000000, 0x37644302, 0x2f97d40c, 0x00080740
+}, rtl8192ce_bb_vals4_1t[] = {
+	0x00000010, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0,
+	0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0,
+	0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0,
+	0x001b25a0, 0x6b1b25a0, 0x00000003, 0x00000000, 0x00000300
+};
+
+static const struct rtwn_bb_prog rtl8192ce_bb[] = {
+	{
+		nitems(rtl8192ce_bb_regs0),
+		rtl8192ce_bb_regs0,
+		rtl8192ce_bb_vals0_2t,
+		{ R92C_COND_RTL8192C },
+		&(const struct rtwn_bb_prog){
+			nitems(rtl8192ce_bb_regs0),
+			rtl8192ce_bb_regs0,
+			rtl8192ce_bb_vals0_1t,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8192ce_bb_regs1),
+		rtl8192ce_bb_regs1,
+		rtl8192ce_bb_vals1,
+		{ 0 },
+		NULL
+	},
+	{
+		nitems(rtl8192c_bb_regs3),
+		rtl8192c_bb_regs3,
+		rtl8192c_bb_vals3_92ce_92cu,
+		{ R92C_COND_RTL8192C },
+		&(const struct rtwn_bb_prog){
+			nitems(rtl8192c_bb_regs3),
+			rtl8192c_bb_regs3,
+			rtl8192c_bb_vals3_88cu_88ru,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8192c_bb_regs4),
+		rtl8192c_bb_regs4,
+		rtl8192c_bb_vals4,
+		{ 0 },
+		NULL
+	},
+	{
+		nitems(rtl8192c_bb_regs5),
+		rtl8192c_bb_regs5,
+		rtl8192c_bb_vals5_92ce_92cu,
+		{ R92C_COND_RTL8192C },
+		&(const struct rtwn_bb_prog){
+			nitems(rtl8192c_bb_regs5),
+			rtl8192c_bb_regs5,
+			rtl8192ce_bb_vals4_1t,
+			{ 0 },
+			NULL
+		}
+	}
+};
+
+#endif	/* R92CE_PRIV_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,103 @@
+/*	$OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef R92CE_REG_H
+#define R92CE_REG_H
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+/*
+ * MAC registers.
+ */
+/* System Configuration. */
+#define R92C_PCIE_MIO_INTF		0x0e4
+#define R92C_PCIE_MIO_INTD		0x0e8
+/* PCIe Configuration. */
+#define R92C_PCIE_CTRL_REG		0x300
+#define R92C_INT_MIG			0x304
+#define R92C_BCNQ_DESA			0x308
+#define R92C_HQ_DESA			0x310
+#define R92C_MGQ_DESA			0x318
+#define R92C_VOQ_DESA			0x320
+#define R92C_VIQ_DESA			0x328
+#define R92C_BEQ_DESA			0x330
+#define R92C_BKQ_DESA			0x338
+#define R92C_RX_DESA			0x340
+#define R92C_DBI			0x348
+#define R92C_MDIO			0x354
+#define R92C_DBG_SEL			0x360
+#define R92C_PCIE_HRPWM			0x361
+#define R92C_PCIE_HCPWM			0x363
+#define R92C_UART_CTRL			0x364
+#define R92C_UART_TX_DES		0x370
+#define R92C_UART_RX_DES		0x378
+
+
+/* Bits for R92C_GPIO_MUXCFG. */
+#define R92C_GPIO_MUXCFG_RFKILL		0x0008
+
+/* Bits for R92C_GPIO_IO_SEL. */
+#define R92C_GPIO_IO_SEL_RFKILL		0x0008
+
+/* Bits for R92C_LEDCFG2. */
+#define R92C_LEDCFG2_EN			0x60
+#define R92C_LEDCFG2_DIS		0x68
+
+/* Bits for R92C_HIMR. */
+#define R92C_IMR_ROK		0x00000001	/* receive DMA OK */
+#define R92C_IMR_VODOK		0x00000002	/* AC_VO DMA OK */
+#define R92C_IMR_VIDOK		0x00000004	/* AC_VI DMA OK */
+#define R92C_IMR_BEDOK		0x00000008	/* AC_BE DMA OK */
+#define R92C_IMR_BKDOK		0x00000010	/* AC_BK DMA OK */
+#define R92C_IMR_TXBDER		0x00000020	/* beacon transmit error */
+#define R92C_IMR_MGNTDOK	0x00000040	/* management queue DMA OK */
+#define R92C_IMR_TBDOK		0x00000080	/* beacon transmit OK */
+#define R92C_IMR_HIGHDOK	0x00000100	/* high queue DMA OK */
+#define R92C_IMR_BDOK		0x00000200	/* beacon queue DMA OK */
+#define R92C_IMR_ATIMEND	0x00000400	/* ATIM window end interrupt */
+#define R92C_IMR_RDU		0x00000800	/* Rx descriptor unavailable */
+#define R92C_IMR_RXFOVW		0x00001000	/* receive FIFO overflow */
+#define R92C_IMR_BCNINT		0x00002000	/* beacon DMA interrupt 0 */
+#define R92C_IMR_PSTIMEOUT	0x00004000	/* powersave timeout */
+#define R92C_IMR_TXFOVW		0x00008000	/* transmit FIFO overflow */
+#define R92C_IMR_TIMEOUT1	0x00010000	/* timeout interrupt 1 */
+#define R92C_IMR_TIMEOUT2	0x00020000	/* timeout interrupt 2 */
+#define R92C_IMR_BCNDOK1	0x00040000	/* beacon queue DMA OK (1) */
+#define R92C_IMR_BCNDOK2	0x00080000	/* beacon queue DMA OK (2) */
+#define R92C_IMR_BCNDOK3	0x00100000	/* beacon queue DMA OK (3) */
+#define R92C_IMR_BCNDOK4	0x00200000	/* beacon queue DMA OK (4) */
+#define R92C_IMR_BCNDOK5	0x00400000	/* beacon queue DMA OK (5) */
+#define R92C_IMR_BCNDOK6	0x00800000	/* beacon queue DMA OK (6) */
+#define R92C_IMR_BCNDOK7	0x01000000	/* beacon queue DMA OK (7) */
+#define R92C_IMR_BCNDOK8	0x02000000	/* beacon queue DMA OK (8) */
+#define R92C_IMR_BCNDMAINT1	0x04000000	/* beacon DMA interrupt 1 */
+#define R92C_IMR_BCNDMAINT2	0x08000000	/* beacon DMA interrupt 2 */
+#define R92C_IMR_BCNDMAINT3	0x10000000	/* beacon DMA interrupt 3 */
+#define R92C_IMR_BCNDMAINT4	0x20000000	/* beacon DMA interrupt 4 */
+#define R92C_IMR_BCNDMAINT5	0x40000000	/* beacon DMA interrupt 5 */
+#define R92C_IMR_BCNDMAINT6	0x80000000	/* beacon DMA interrupt 6 */
+
+/* Shortcut. */
+#define R92C_IBSS_INT_MASK	\
+	(R92C_IMR_BCNINT | R92C_IMR_TBDOK | R92C_IMR_TBDER)
+
+#endif	/* R92CE_REG_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,134 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
+
+
+int
+r92ce_classify_intr(struct rtwn_softc *sc, void *arg, int len __unused)
+{
+	uint32_t status;
+	int *rings = arg;
+	int ret;
+
+	*rings = 0;
+	status = rtwn_read_4(sc, R92C_HISR);
+	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: HISR %08X, HISRE %04X\n",
+	    __func__, status, rtwn_read_2(sc, R92C_HISRE));
+	if (status == 0 || status == 0xffffffff)
+		return (0);
+
+	/* Disable interrupts. */
+	rtwn_write_4(sc, R92C_HIMR, 0);
+
+	/* Ack interrupts. */
+	rtwn_write_4(sc, R92C_HISR, status);
+
+	if (status & R92C_IMR_BDOK)
+		*rings |= (1 << RTWN_PCI_BEACON_QUEUE);
+	if (status & R92C_IMR_HIGHDOK)
+		*rings |= (1 << RTWN_PCI_HIGH_QUEUE);
+	if (status & R92C_IMR_MGNTDOK)
+		*rings |= (1 << RTWN_PCI_MGNT_QUEUE);
+	if (status & R92C_IMR_BKDOK)
+		*rings |= (1 << RTWN_PCI_BK_QUEUE);
+	if (status & R92C_IMR_BEDOK)
+		*rings |= (1 << RTWN_PCI_BE_QUEUE);
+	if (status & R92C_IMR_VIDOK)
+		*rings |= (1 << RTWN_PCI_VI_QUEUE);
+	if (status & R92C_IMR_VODOK)
+		*rings |= (1 << RTWN_PCI_VO_QUEUE);
+
+	ret = 0;
+	if (status & R92C_IMR_RXFOVW)
+		ret |= RTWN_PCI_INTR_RX_OVERFLOW;
+	if (status & R92C_IMR_RDU)
+		ret |= RTWN_PCI_INTR_RX_DESC_UNAVAIL;
+	if (status & R92C_IMR_ROK)
+		ret |= RTWN_PCI_INTR_RX_DONE;
+	if (status & R92C_IMR_TXFOVW)
+		ret |= RTWN_PCI_INTR_TX_OVERFLOW;
+	if (status & R92C_IMR_PSTIMEOUT)
+		ret |= RTWN_PCI_INTR_PS_TIMEOUT;
+
+	return (ret);
+}
+
+#define R92C_INT_ENABLE (R92C_IMR_ROK | R92C_IMR_VODOK | R92C_IMR_VIDOK | \
+			R92C_IMR_BEDOK | R92C_IMR_BKDOK | R92C_IMR_MGNTDOK | \
+			R92C_IMR_HIGHDOK | R92C_IMR_BDOK | R92C_IMR_RDU | \
+			R92C_IMR_RXFOVW)
+void
+r92ce_enable_intr(struct rtwn_pci_softc *pc)
+{
+	struct rtwn_softc *sc = &pc->pc_sc;
+
+	/* Enable interrupts. */
+	rtwn_write_4(sc, R92C_HIMR, R92C_INT_ENABLE);
+}
+
+void
+r92ce_start_xfers(struct rtwn_softc *sc)
+{
+	/* Clear pending interrupts. */
+	rtwn_write_4(sc, R92C_HISR, 0xffffffff);
+
+	/* Enable interrupts. */
+	rtwn_write_4(sc, R92C_HIMR, R92C_INT_ENABLE);
+}
+#undef R92C_INT_ENABLE
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,41 @@
+/*	$OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef R92CE_RX_DESC_H
+#define R92CE_RX_DESC_H
+
+#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
+
+/* Rx MAC descriptor (PCIe). */
+struct r92ce_rx_stat {
+	uint32_t	rxdw0;
+	uint32_t	rxdw1;
+	uint32_t	rxdw2;
+	uint32_t	rxdw3;
+	uint32_t	rxdw4;
+	uint32_t	tsf_low;
+
+	uint32_t	rxbufaddr;
+	uint32_t	rxbufaddr64;
+} __packed __attribute__((aligned(4)));
+
+#endif	/* R92CE_RX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,117 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/pci/rtwn_pci_var.h>
+
+#include <dev/rtwn/rtl8192c/pci/r92ce.h>
+#include <dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h>
+
+
+void
+r92ce_setup_tx_desc(struct rtwn_pci_softc *pc, void *desc,
+    uint32_t next_desc_addr)
+{
+	struct r92ce_tx_desc *txd = desc;
+
+	/* setup tx desc */
+	txd->nextdescaddr = htole32(next_desc_addr);
+}
+
+void
+r92ce_tx_postsetup(struct rtwn_pci_softc *pc, void *desc,
+    bus_dma_segment_t segs[])
+{
+	struct r92ce_tx_desc *txd = desc;
+
+	txd->txbufaddr = htole32(segs[0].ds_addr);
+	txd->txbufsize = txd->pktlen;
+	bus_space_barrier(pc->pc_st, pc->pc_sh, 0, pc->pc_mapsize,
+	    BUS_SPACE_BARRIER_WRITE);
+}
+
+void
+r92ce_copy_tx_desc(void *dest, const void *src)
+{
+	struct r92ce_tx_desc *txd = dest;
+	size_t len = sizeof(struct r92c_tx_desc) +
+	    sizeof(txd->txbufsize) + sizeof(txd->pad);
+
+	if (src != NULL)
+		memcpy(dest, src, len);
+	else
+		memset(dest, 0, len);
+}
+
+void
+r92ce_dump_tx_desc(struct rtwn_softc *sc, const void *desc)
+{
+#ifdef RTWN_DEBUG
+	const struct r92ce_tx_desc *txd = desc;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC,
+	    "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %04X "
+	    "(seq %04X), 4 %08X, 5 %08X, 6 %08X, size %04X, pad %04X, "
+	    "addr: %08X (64: %08X), next: %08X (64: %08X), "
+	    "rsvd: %08X %08X %08X %08X\n",
+	    __func__, le16toh(txd->pktlen), txd->offset, txd->flags0,
+	    le32toh(txd->txdw1), le32toh(txd->txdw2), le16toh(txd->txdw3),
+	    le16toh(txd->txdseq), le32toh(txd->txdw4), le32toh(txd->txdw5),
+	    le32toh(txd->txdw6), le16toh(txd->txbufsize), le16toh(txd->pad),
+	    le32toh(txd->txbufaddr), le32toh(txd->txbufaddr64),
+	    le32toh(txd->nextdescaddr), le32toh(txd->nextdescaddr64),
+	    le32toh(txd->reserved[0]), le32toh(txd->reserved[1]),
+	    le32toh(txd->reserved[2]), le32toh(txd->reserved[3]));
+#endif
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,55 @@
+/*	$OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef R92CE_TX_DESC_H
+#define R92CE_TX_DESC_H
+
+#include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
+
+/* Tx MAC descriptor (PCIe). */
+struct r92ce_tx_desc {
+	uint16_t 	pktlen;
+	uint8_t		offset;
+	uint8_t		flags0;
+
+	uint32_t	txdw1;
+	uint32_t	txdw2;
+	uint16_t	txdw3;
+	uint16_t	txdseq;
+
+	uint32_t	txdw4;
+	uint32_t	txdw5;
+	uint32_t	txdw6;
+
+	uint16_t	txbufsize;
+	uint16_t	pad;
+
+	uint32_t	txbufaddr;
+	uint32_t	txbufaddr64;
+
+	uint32_t	nextdescaddr;
+	uint32_t	nextdescaddr64;
+
+	uint32_t	reserved[4];
+} __packed __attribute__((aligned(4)));
+
+#endif	/* R92CE_TX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef RTL8192C_H
+#define RTL8192C_H
+
+/*
+ * Global definitions.
+ */
+#define R92C_TXPKTBUF_COUNT	256
+
+#define R92C_TX_PAGE_SIZE	128
+#define R92C_RX_DMA_BUFFER_SIZE	0x2800
+
+#define R92C_MAX_FW_SIZE	0x4000
+#define R92C_MACID_MAX		31
+#define R92C_CAM_ENTRY_COUNT	32
+
+#define R92C_CALIB_THRESHOLD	2
+
+
+/*
+ * Function declarations.
+ */
+/* r92c_attach.c */
+void	r92c_detach_private(struct rtwn_softc *);
+void	r92c_read_chipid_vendor(struct rtwn_softc *, uint32_t);
+
+/* r92c_beacon.c */
+void	r92c_beacon_init(struct rtwn_softc *, void *, int);
+void	r92c_beacon_enable(struct rtwn_softc *, int, int);
+
+/* r92c_calib.c */
+void	r92c_iq_calib(struct rtwn_softc *);
+void	r92c_lc_calib(struct rtwn_softc *);
+void	r92c_temp_measure(struct rtwn_softc *);
+uint8_t	r92c_temp_read(struct rtwn_softc *);
+
+/* r92c_chan.c */
+void	r92c_get_txpower(struct rtwn_softc *, int,
+	    struct ieee80211_channel *, uint16_t[]);
+void	r92c_set_bw20(struct rtwn_softc *, uint8_t);
+void	r92c_set_chan(struct rtwn_softc *, struct ieee80211_channel *);
+void	r92c_set_gain(struct rtwn_softc *, uint8_t);
+void	r92c_scan_start(struct ieee80211com *);
+void	r92c_scan_end(struct ieee80211com *);
+
+/* r92c_fw.c */
+#ifndef RTWN_WITHOUT_UCODE
+void	r92c_fw_reset(struct rtwn_softc *, int);
+void	r92c_fw_download_enable(struct rtwn_softc *, int);
+#endif
+void	r92c_joinbss_rpt(struct rtwn_softc *, int);
+#ifndef RTWN_WITHOUT_UCODE
+int	r92c_set_rsvd_page(struct rtwn_softc *, int, int, int);
+int	r92c_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, int);
+void	r92c_set_rssi(struct rtwn_softc *);
+void	r92c_handle_c2h_report(void *);
+#endif
+
+/* r92c_init.c */
+int	r92c_check_condition(struct rtwn_softc *, const uint8_t[]);
+int	r92c_set_page_size(struct rtwn_softc *);
+void	r92c_init_bb_common(struct rtwn_softc *);
+int	r92c_init_rf_chain(struct rtwn_softc *,
+	    const struct rtwn_rf_prog *, int);
+void	r92c_init_rf(struct rtwn_softc *);
+void	r92c_init_edca(struct rtwn_softc *);
+void	r92c_init_ampdu(struct rtwn_softc *);
+void	r92c_init_antsel(struct rtwn_softc *);
+void	r92c_pa_bias_init(struct rtwn_softc *);
+
+/* r92c_rf.c */
+uint32_t	r92c_rf_read(struct rtwn_softc *, int, uint8_t);
+void		r92c_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t);
+
+/* r92c_rom.c */
+void	r92c_efuse_postread(struct rtwn_softc *);
+void	r92c_parse_rom(struct rtwn_softc *, uint8_t *);
+
+/* r92c_rx.c */
+int8_t	r92c_get_rssi_cck(struct rtwn_softc *, void *);
+int8_t	r92c_get_rssi_ofdm(struct rtwn_softc *, void *);
+uint8_t	r92c_rx_radiotap_flags(const void *);
+
+/* r92c_tx.c */
+void	r92c_tx_enable_ampdu(void *, int);
+void	r92c_tx_setup_hwseq(void *);
+void	r92c_tx_setup_macid(void *, int);
+void	r92c_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *,
+	    struct mbuf *, void *, uint8_t, int);
+void	r92c_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *,
+	    struct mbuf *, void *, const struct ieee80211_bpf_params *);
+void	r92c_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int);
+uint8_t	r92c_tx_radiotap_flags(const void *);
+
+#endif	/* RTL8192C_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,82 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+
+void
+r92c_detach_private(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	free(rs, M_RTWN_PRIV);
+}
+
+void
+r92c_read_chipid_vendor(struct rtwn_softc *sc, uint32_t reg_sys_cfg)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	if (reg_sys_cfg & R92C_SYS_CFG_TYPE_92C) {
+		rs->chip |= R92C_CHIP_92C;
+		/* Check if it is a castrated 8192C. */
+		if (MS(rtwn_read_4(sc, R92C_HPON_FSM),
+		    R92C_HPON_FSM_CHIP_BONDING_ID) ==
+		    R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R)
+			rs->chip |= R92C_CHIP_92C_1T2R;
+	}
+	if (reg_sys_cfg & R92C_SYS_CFG_VENDOR_UMC) {
+		if (MS(reg_sys_cfg, R92C_SYS_CFG_CHIP_VER_RTL) == 0)
+			rs->chip |= R92C_CHIP_UMC_A_CUT;
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,88 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwnreg.h>
+
+#include <dev/rtwn/if_rtwn_ridx.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+#include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
+
+
+void
+r92c_beacon_init(struct rtwn_softc *sc, void *buf, int id)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	/*
+	 * NB: there is no need to setup HWSEQ_EN bit;
+	 * QSEL_BEACON already implies it.
+	 */
+	txd->flags0 |= R92C_FLAGS0_BMCAST | R92C_FLAGS0_FSG | R92C_FLAGS0_LSG;
+	txd->txdw1 |= htole32(
+	    SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BEACON) |
+	    SM(R92C_TXDW1_RAID, R92C_RAID_11B));
+
+	rtwn_r92c_tx_setup_macid(sc, buf, id);
+	txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
+	txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id));
+	txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id));
+	txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, RTWN_RIDX_CCK1));
+}
+
+void
+r92c_beacon_enable(struct rtwn_softc *sc, int id, int enable)
+{
+
+	if (enable) {
+		rtwn_setbits_1(sc, R92C_BCN_CTRL(id),
+		    0, R92C_BCN_CTRL_EN_BCN);
+	} else {
+		rtwn_setbits_1(sc, R92C_BCN_CTRL(id),
+		    R92C_BCN_CTRL_EN_BCN, 0);
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,115 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+
+void
+r92c_iq_calib(struct rtwn_softc *sc)
+{
+	/* XXX TODO */
+}
+
+void
+r92c_lc_calib(struct rtwn_softc *sc)
+{
+	uint32_t rf_ac[2];
+	uint8_t txmode;
+	int i;
+
+	txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3);
+	if ((txmode & 0x70) != 0) {
+		/* Disable all continuous Tx. */
+		rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70);
+
+		/* Set RF mode to standby mode. */
+		for (i = 0; i < sc->nrxchains; i++) {
+			rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC);
+			rtwn_rf_write(sc, i, R92C_RF_AC,
+			    RW(rf_ac[i], R92C_RF_AC_MODE,
+				R92C_RF_AC_MODE_STANDBY));
+		}
+	} else {
+		/* Block all Tx queues. */
+		rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
+	}
+	/* Start calibration. */
+	rtwn_rf_setbits(sc, 0, R92C_RF_CHNLBW, 0, R92C_RF_CHNLBW_LCSTART);
+
+	/* Give calibration the time to complete. */
+	rtwn_delay(sc, 100000);	/* 100ms */
+
+	/* Restore configuration. */
+	if ((txmode & 0x70) != 0) {
+		/* Restore Tx mode. */
+		rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode);
+		/* Restore RF mode. */
+		for (i = 0; i < sc->nrxchains; i++)
+			rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]);
+	} else {
+		/* Unblock all Tx queues. */
+		rtwn_write_1(sc, R92C_TXPAUSE, 0x00);
+	}
+}
+
+void
+r92c_temp_measure(struct rtwn_softc *sc)
+{
+	rtwn_rf_write(sc, 0, R92C_RF_T_METER, R92C_RF_T_METER_START);
+}
+
+uint8_t
+r92c_temp_read(struct rtwn_softc *sc)
+{
+	return (MS(rtwn_rf_read(sc, 0, R92C_RF_T_METER),
+	    R92C_RF_T_METER_VAL));
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,353 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_priv.h>
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+
+static int
+r92c_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	uint8_t chan;
+	int group;
+
+	chan = rtwn_chan2centieee(c);
+	if (IEEE80211_IS_CHAN_2GHZ(c)) {
+		if (chan <= 3)			group = 0;
+		else if (chan <= 9)		group = 1;
+		else if (chan <= 14)		group = 2;
+		else {
+			KASSERT(0, ("wrong 2GHz channel %d!\n", chan));
+			return (-1);
+		}
+	} else {
+		KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags));
+		return (-1);
+	}
+
+	return (group);
+}
+
+/* XXX recheck */
+void
+r92c_get_txpower(struct rtwn_softc *sc, int chain,
+    struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT])
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	struct rtwn_r92c_txpwr *rt = rs->rs_txpwr;
+	const struct rtwn_r92c_txagc *base = rs->rs_txagc;
+	uint8_t ofdmpow, htpow, diff, max;
+	int max_mcs, ridx, group;
+
+	/* Determine channel group. */
+	group = r92c_get_power_group(sc, c);
+	if (group == -1) {	/* shouldn't happen */
+		device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__);
+		return;
+	}
+
+	/* XXX net80211 regulatory */
+
+	max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1);
+	KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n"));
+
+	memset(power, 0, max_mcs * sizeof(power[0]));
+	if (rs->regulatory == 0) {
+		for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
+			power[ridx] = base[chain].pwr[0][ridx];
+	}
+	for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_COUNT; ridx++) {
+		if (rs->regulatory == 3) {
+			power[ridx] = base[chain].pwr[0][ridx];
+			/* Apply vendor limits. */
+			if (IEEE80211_IS_CHAN_HT40(c))
+				max = rt->ht40_max_pwr[chain][group];
+			else
+				max = rt->ht20_max_pwr[chain][group];
+			if (power[ridx] > max)
+				power[ridx] = max;
+		} else if (rs->regulatory == 1) {
+			if (!IEEE80211_IS_CHAN_HT40(c))
+				power[ridx] = base[chain].pwr[group][ridx];
+		} else if (rs->regulatory != 2)
+			power[ridx] = base[chain].pwr[0][ridx];
+	}
+
+	/* Compute per-CCK rate Tx power. */
+	for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
+		power[ridx] += rt->cck_tx_pwr[chain][group];
+
+	htpow = rt->ht40_1s_tx_pwr[chain][group];
+	if (sc->ntxchains > 1) {
+		/* Apply reduction for 2 spatial streams. */
+		diff = rt->ht40_2s_tx_pwr_diff[chain][group];
+		htpow = (htpow > diff) ? htpow - diff : 0;
+	}
+
+	/* Compute per-OFDM rate Tx power. */
+	diff = rt->ofdm_tx_pwr_diff[chain][group];
+	ofdmpow = htpow + diff;	/* HT->OFDM correction. */
+	for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++)
+		power[ridx] += ofdmpow;
+
+	/* Compute per-MCS Tx power. */
+	if (!IEEE80211_IS_CHAN_HT40(c)) {
+		diff = rt->ht20_tx_pwr_diff[chain][group];
+		htpow += diff;	/* HT40->HT20 correction. */
+	}
+	for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++)
+		power[ridx] += htpow;
+
+	/* Apply max limit. */
+	for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) {
+		if (power[ridx] > R92C_MAX_TX_PWR)
+			power[ridx] = R92C_MAX_TX_PWR;
+	}
+}
+
+static void
+r92c_write_txpower(struct rtwn_softc *sc, int chain,
+    uint16_t power[RTWN_RIDX_COUNT])
+{
+	uint32_t reg;
+
+	/* Write per-CCK rate Tx power. */
+	if (chain == 0) {
+		reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32);
+		reg = RW(reg, R92C_TXAGC_A_CCK1,  power[RTWN_RIDX_CCK1]);
+		rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg);
+		reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
+		reg = RW(reg, R92C_TXAGC_A_CCK2,  power[RTWN_RIDX_CCK2]);
+		reg = RW(reg, R92C_TXAGC_A_CCK55, power[RTWN_RIDX_CCK55]);
+		reg = RW(reg, R92C_TXAGC_A_CCK11, power[RTWN_RIDX_CCK11]);
+		rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
+	} else {
+		reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32);
+		reg = RW(reg, R92C_TXAGC_B_CCK1,  power[RTWN_RIDX_CCK1]);
+		reg = RW(reg, R92C_TXAGC_B_CCK2,  power[RTWN_RIDX_CCK2]);
+		reg = RW(reg, R92C_TXAGC_B_CCK55, power[RTWN_RIDX_CCK55]);
+		rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg);
+		reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
+		reg = RW(reg, R92C_TXAGC_B_CCK11, power[RTWN_RIDX_CCK11]);
+		rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
+	}
+	/* Write per-OFDM rate Tx power. */
+	rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain),
+	    SM(R92C_TXAGC_RATE06, power[RTWN_RIDX_OFDM6]) |
+	    SM(R92C_TXAGC_RATE09, power[RTWN_RIDX_OFDM9]) |
+	    SM(R92C_TXAGC_RATE12, power[RTWN_RIDX_OFDM12]) |
+	    SM(R92C_TXAGC_RATE18, power[RTWN_RIDX_OFDM18]));
+	rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain),
+	    SM(R92C_TXAGC_RATE24, power[RTWN_RIDX_OFDM24]) |
+	    SM(R92C_TXAGC_RATE36, power[RTWN_RIDX_OFDM36]) |
+	    SM(R92C_TXAGC_RATE48, power[RTWN_RIDX_OFDM48]) |
+	    SM(R92C_TXAGC_RATE54, power[RTWN_RIDX_OFDM54]));
+	/* Write per-MCS Tx power. */
+	rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain),
+	    SM(R92C_TXAGC_MCS00,  power[RTWN_RIDX_MCS(0)]) |
+	    SM(R92C_TXAGC_MCS01,  power[RTWN_RIDX_MCS(1)]) |
+	    SM(R92C_TXAGC_MCS02,  power[RTWN_RIDX_MCS(2)]) |
+	    SM(R92C_TXAGC_MCS03,  power[RTWN_RIDX_MCS(3)]));
+	rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain),
+	    SM(R92C_TXAGC_MCS04,  power[RTWN_RIDX_MCS(4)]) |
+	    SM(R92C_TXAGC_MCS05,  power[RTWN_RIDX_MCS(5)]) |
+	    SM(R92C_TXAGC_MCS06,  power[RTWN_RIDX_MCS(6)]) |
+	    SM(R92C_TXAGC_MCS07,  power[RTWN_RIDX_MCS(7)]));
+	if (sc->ntxchains >= 2) {
+		rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain),
+		    SM(R92C_TXAGC_MCS08,  power[RTWN_RIDX_MCS(8)]) |
+		    SM(R92C_TXAGC_MCS09,  power[RTWN_RIDX_MCS(9)]) |
+		    SM(R92C_TXAGC_MCS10,  power[RTWN_RIDX_MCS(10)]) |
+		    SM(R92C_TXAGC_MCS11,  power[RTWN_RIDX_MCS(11)]));
+		rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain),
+		    SM(R92C_TXAGC_MCS12,  power[RTWN_RIDX_MCS(12)]) |
+		    SM(R92C_TXAGC_MCS13,  power[RTWN_RIDX_MCS(13)]) |
+		    SM(R92C_TXAGC_MCS14,  power[RTWN_RIDX_MCS(14)]) |
+		    SM(R92C_TXAGC_MCS15,  power[RTWN_RIDX_MCS(15)]));
+	}
+}
+
+static void
+r92c_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	uint16_t power[RTWN_RIDX_COUNT];
+	int i;
+
+	for (i = 0; i < sc->ntxchains; i++) {
+		/* Compute per-rate Tx power values. */
+		rtwn_r92c_get_txpower(sc, i, c, power);
+#ifdef RTWN_DEBUG
+		if (sc->sc_debug & RTWN_DEBUG_TXPWR) {
+			int ridx;
+
+			/* Dump per-rate Tx power values. */
+			printf("Tx power for chain %d:\n", i);
+			for (ridx = RTWN_RIDX_CCK1;
+			     ridx < RTWN_RIDX_COUNT;
+			     ridx++)
+				printf("Rate %d = %u\n", ridx, power[ridx]);
+		}
+#endif
+		/* Write per-rate Tx power values to hardware. */
+		r92c_write_txpower(sc, i, power);
+	}
+}
+
+static void
+r92c_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	rtwn_setbits_1(sc, R92C_BWOPMODE, R92C_BWOPMODE_20MHZ, 0);
+	rtwn_setbits_1(sc, R92C_RRSR + 2, 0x6f, (prichlo ? 1 : 2) << 5);
+
+	rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_40MHZ);
+	rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, 0, R92C_RFMOD_40MHZ);
+
+	/* Set CCK side band. */
+	rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10,
+	    (prichlo ? 0 : 1) << 4);
+
+	rtwn_bb_setbits(sc, R92C_OFDM1_LSTF, 0x0c00,
+	    (prichlo ? 1 : 2) << 10);
+
+	rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2,
+	    R92C_FPGA0_ANAPARAM2_CBW20, 0);
+
+	rtwn_bb_setbits(sc, 0x818, 0x0c000000, (prichlo ? 2 : 1) << 26);
+
+	/* Select 40MHz bandwidth. */
+	rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+	    (rs->rf_chnlbw[0] & ~0xfff) | chan);
+}
+
+void
+r92c_set_bw20(struct rtwn_softc *sc, uint8_t chan)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ);
+
+	rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0);
+	rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0);
+
+	rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, 0,
+	    R92C_FPGA0_ANAPARAM2_CBW20);
+
+	/* Select 20MHz bandwidth. */
+	rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+	    (rs->rf_chnlbw[0] & ~0xfff) | chan | R92C_RF_CHNLBW_BW20);
+}
+
+void
+r92c_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	u_int chan;
+	int i;
+
+	chan = rtwn_chan2centieee(c);
+
+	/* Set Tx power for this new channel. */
+	r92c_set_txpower(sc, c);
+
+	for (i = 0; i < sc->nrxchains; i++) {
+		rtwn_rf_write(sc, i, R92C_RF_CHNLBW,
+		    RW(rs->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan));
+	}
+	if (IEEE80211_IS_CHAN_HT40(c))
+		r92c_set_bw40(sc, chan, IEEE80211_IS_CHAN_HT40U(c));
+	else
+		rtwn_r92c_set_bw20(sc, chan);
+}
+
+void
+r92c_set_gain(struct rtwn_softc *sc, uint8_t gain)
+{
+
+	rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0),
+	    R92C_OFDM0_AGCCORE1_GAIN_M, gain);
+	rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(1),
+	    R92C_OFDM0_AGCCORE1_GAIN_M, gain);
+}
+
+void
+r92c_scan_start(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct r92c_softc *rs = sc->sc_priv;
+
+	RTWN_LOCK(sc);
+	/* Set gain for scanning. */
+	rtwn_r92c_set_gain(sc, 0x20);
+	RTWN_UNLOCK(sc);
+
+	rs->rs_scan_start(ic);
+}
+
+void
+r92c_scan_end(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct r92c_softc *rs = sc->sc_priv;
+
+	RTWN_LOCK(sc);
+	/* Set gain under link. */
+	rtwn_r92c_set_gain(sc, 0x32);
+	RTWN_UNLOCK(sc);
+
+	rs->rs_scan_end(ic);
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,522 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_rx.h>
+#include <dev/rtwn/if_rtwn_task.h>
+#include <dev/rtwn/if_rtwn_tx.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+#include <dev/rtwn/rtl8192c/r92c_fw_cmd.h>
+#include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
+
+
+#ifndef RTWN_WITHOUT_UCODE
+static int
+r92c_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len)
+{
+	struct r92c_fw_cmd cmd;
+	int ntries, error;
+
+	KASSERT(len <= sizeof(cmd.msg),
+	    ("%s: firmware command too long (%d > %zu)\n",
+	    __func__, len, sizeof(cmd.msg)));
+
+	if (!(sc->sc_flags & RTWN_FW_LOADED)) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware "
+		    "was not loaded; command (id %u) will be discarded\n",
+		    __func__, id);
+		return (0);
+	}
+
+	/* Wait for current FW box to be empty. */
+	for (ntries = 0; ntries < 50; ntries++) {
+		if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
+			break;
+		rtwn_delay(sc, 2000);
+	}
+	if (ntries == 100) {
+		device_printf(sc->sc_dev,
+		    "could not send firmware command\n");
+		return (ETIMEDOUT);
+	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.id = id;
+	if (len > 3) {
+		/* Ext command: [id : byte2 : byte3 : byte4 : byte0 : byte1] */
+		cmd.id |= R92C_CMD_FLAG_EXT;
+		memcpy(cmd.msg, (const uint8_t *)buf + 2, len - 2);
+		memcpy(cmd.msg + 3, buf, 2);
+	} else
+		memcpy(cmd.msg, buf, len);
+
+	/* Write the first word last since that will trigger the FW. */
+	if (len > 3) {
+		error = rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur),
+		    *(uint16_t *)((uint8_t *)&cmd + 4));
+		if (error != 0)
+			return (error);
+	}
+	error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur),
+	    *(uint32_t *)&cmd);
+	if (error != 0)
+		return (error);
+
+	sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
+
+	return (0);
+}
+
+void
+r92c_fw_reset(struct rtwn_softc *sc, int reason)
+{
+	int ntries;
+
+	if (reason == RTWN_FW_RESET_CHECKSUM)
+		return;
+
+	/* Tell 8051 to reset itself. */
+	rtwn_write_1(sc, R92C_HMETFR + 3, 0x20);
+
+	/* Wait until 8051 resets by itself. */
+	for (ntries = 0; ntries < 100; ntries++) {
+		if ((rtwn_read_2(sc, R92C_SYS_FUNC_EN) &
+		    R92C_SYS_FUNC_EN_CPUEN) == 0)
+			return;
+		rtwn_delay(sc, 50);
+	}
+	/* Force 8051 reset. */
+	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_CPUEN, 0, 1);
+}
+
+void
+r92c_fw_download_enable(struct rtwn_softc *sc, int enable)
+{
+	if (enable) {
+		/* 8051 enable. */
+		rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, 0,
+		    R92C_SYS_FUNC_EN_CPUEN, 1);
+		/* MCU firmware download enable. */
+		rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN);
+		/* 8051 reset. */
+		rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN,
+		    0, 2);
+	} else {
+		/* MCU download disable. */
+		rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0);
+		/* Reserved for f/w extension. */
+		rtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
+	}
+}
+#endif
+
+/*
+ * Initialize firmware rate adaptation.
+ */
+#ifndef RTWN_WITHOUT_UCODE
+static int
+r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates,
+    int maxrate)
+{
+	struct r92c_fw_cmd_macid_cfg cmd;
+	uint8_t mode;
+	int error = 0;
+
+	/* XXX should be called directly from iv_newstate() for MACID_BC */
+	/* XXX joinbss, not send_ra_cmd() */
+#ifdef RTWN_TODO
+	/* NB: group addressed frames are done at 11bg rates for now */
+	if (ic->ic_curmode == IEEE80211_MODE_11B)
+		mode = R92C_RAID_11B;
+	else
+		mode = R92C_RAID_11BG;
+	/* XXX misleading 'mode' value here for unicast frames */
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
+	    "%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__,
+	    mode, rates, basicrates);
+
+	/* Set rates mask for group addressed frames. */
+	cmd.macid = RTWN_MACID_BC | R92C_CMD_MACID_VALID;
+	cmd.mask = htole32(mode << 28 | basicrates);
+	error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "could not set RA mask for broadcast station\n");
+		return (error);
+	}
+#endif
+
+	/* Set rates mask for unicast frames. */
+	if (maxrate >= RTWN_RIDX_MCS(0))
+		mode = R92C_RAID_11GN;
+	else if (maxrate >= RTWN_RIDX_OFDM6)
+		mode = R92C_RAID_11BG;
+	else
+		mode = R92C_RAID_11B;
+	cmd.macid = macid | R92C_CMD_MACID_VALID;
+	cmd.mask = htole32(mode << 28 | rates);
+	error = r92c_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not set RA mask for %d station\n",
+		    __func__, macid);
+		return (error);
+	}
+
+	return (0);
+}
+#endif
+
+static void
+r92c_init_ra(struct rtwn_softc *sc, int macid)
+{
+	struct ieee80211_htrateset *rs_ht;
+	struct ieee80211_node *ni;
+	uint32_t rates;
+	int maxrate;
+
+	RTWN_NT_LOCK(sc);
+	if (sc->node_list[macid] == NULL) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: macid %d, ni is NULL\n",
+		    __func__, macid);
+		RTWN_NT_UNLOCK(sc);
+		return;
+	}
+
+	ni = ieee80211_ref_node(sc->node_list[macid]);
+	if (ni->ni_flags & IEEE80211_NODE_HT)
+		rs_ht = &ni->ni_htrates;
+	else
+		rs_ht = NULL;
+	/* XXX MACID_BC */
+	rtwn_get_rates(sc, &ni->ni_rates, rs_ht, &rates, &maxrate, 0);
+	RTWN_NT_UNLOCK(sc);
+
+#ifndef RTWN_WITHOUT_UCODE
+	if (sc->sc_ratectl == RTWN_RATECTL_FW) {
+		r92c_send_ra_cmd(sc, macid, rates, maxrate);
+	}
+#endif
+
+	rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), maxrate);
+
+	ieee80211_free_node(ni);
+}
+
+void
+r92c_joinbss_rpt(struct rtwn_softc *sc, int macid)
+{
+#ifndef RTWN_WITHOUT_UCODE
+	struct r92c_softc *rs = sc->sc_priv;
+	struct ieee80211vap *vap;
+	struct r92c_fw_cmd_joinbss_rpt cmd;
+
+	if (sc->vaps[0] == NULL)	/* XXX fix */
+		goto end;
+
+	vap = &sc->vaps[0]->vap;
+	if ((vap->iv_state == IEEE80211_S_RUN) ^
+	    !(rs->rs_flags & R92C_FLAG_ASSOCIATED))
+		goto end;
+
+	if (rs->rs_flags & R92C_FLAG_ASSOCIATED) {
+		cmd.mstatus = R92C_MSTATUS_DISASSOC;
+		rs->rs_flags &= ~R92C_FLAG_ASSOCIATED;
+	} else {
+		cmd.mstatus = R92C_MSTATUS_ASSOC;
+		rs->rs_flags |= R92C_FLAG_ASSOCIATED;
+	}
+
+	if (r92c_fw_cmd(sc, R92C_CMD_JOINBSS_RPT, &cmd, sizeof(cmd)) != 0) {
+		device_printf(sc->sc_dev, "%s: cannot change media status!\n",
+		    __func__);
+	}
+
+end:
+#endif
+
+	/* TODO: init rates for RTWN_MACID_BC. */
+	if (macid & RTWN_MACID_VALID)
+		r92c_init_ra(sc, macid & ~RTWN_MACID_VALID);
+}
+
+#ifndef RTWN_WITHOUT_UCODE
+int
+r92c_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null,
+    int qos_null)
+{
+	struct r92c_fw_cmd_rsvdpage rsvd;
+
+	rsvd.probe_resp = probe_resp;
+	rsvd.ps_poll = 0;
+	rsvd.null_data = null;
+
+	return (r92c_fw_cmd(sc, R92C_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd)));
+}
+
+int
+r92c_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap,
+    int off)
+{
+	struct r92c_fw_cmd_pwrmode mode;
+	int error;
+
+	/* XXX dm_RF_saving */
+
+	if (off && vap->iv_state == IEEE80211_S_RUN &&
+	    (vap->iv_flags & IEEE80211_F_PMGTON))
+		mode.mode = R92C_PWRMODE_MIN;
+	else
+		mode.mode = R92C_PWRMODE_CAM;
+	mode.smart_ps = R92C_PWRMODE_SMARTPS_NULLDATA;
+	mode.bcn_pass = 1;	/* XXX */
+	error = r92c_fw_cmd(sc, R92C_CMD_SET_PWRMODE, &mode, sizeof(mode));
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: CMD_SET_PWRMODE was not sent, error %d\n",
+		    __func__, error);
+	}
+
+	return (error);
+}
+
+void
+r92c_set_rssi(struct rtwn_softc *sc)
+{
+	struct ieee80211_node *ni;
+	struct rtwn_node *rn;
+	struct r92c_fw_cmd_rssi cmd;
+	int i;
+
+	cmd.reserved = 0;
+
+	RTWN_NT_LOCK(sc);
+	for (i = 0; i < sc->macid_limit; i++) {
+		/* XXX optimize? */
+		ni = sc->node_list[i];
+		if (ni == NULL)
+			continue;
+
+		rn = RTWN_NODE(ni);
+		cmd.macid = i;
+		cmd.pwdb = rn->avg_pwdb;
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI,
+		    "%s: sending RSSI command (macid %d, rssi %d)\n",
+		    __func__, i, rn->avg_pwdb);
+
+		RTWN_NT_UNLOCK(sc);
+		r92c_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd));
+		RTWN_NT_LOCK(sc);
+	}
+	RTWN_NT_UNLOCK(sc);
+}
+
+static void
+r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+#if __FreeBSD_version >= 1200012
+	struct ieee80211_ratectl_tx_status txs;
+#endif
+	struct r92c_c2h_tx_rpt *rpt;
+	struct ieee80211_node *ni;
+	uint8_t macid;
+	int ntries;
+
+	if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
+		/* shouldn't happen */
+		device_printf(sc->sc_dev, "%s called while ratectl = %d!\n",
+		    __func__, sc->sc_ratectl);
+		return;
+	}
+
+	rpt = (struct r92c_c2h_tx_rpt *)buf;
+	if (len != sizeof(*rpt)) {
+		device_printf(sc->sc_dev,
+		    "%s: wrong report size (%d, must be %zu)\n",
+		    __func__, len, sizeof(*rpt));
+		return;
+	}
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
+	    "%s: ccx report dump: 0: %02X, 1: %02X, queue time: "
+	    "low %02X, high %02X, 4: %02X, 5: %02X, 6: %02X, 7: %02X\n",
+	    __func__, rpt->rptb0, rpt->rptb1, rpt->queue_time_low,
+	    rpt->queue_time_high, rpt->rptb4, rpt->rptb5, rpt->rptb6,
+	    rpt->rptb7);
+
+	macid = MS(rpt->rptb5, R92C_RPTB5_MACID);
+	if (macid > sc->macid_limit) {
+		device_printf(sc->sc_dev,
+		    "macid %u is too big; increase MACID_MAX limit\n",
+		    macid);
+		return;
+	}
+
+	ntries = MS(rpt->rptb0, R92C_RPTB0_RETRY_CNT);
+
+	RTWN_NT_LOCK(sc);
+	ni = sc->node_list[macid];
+	if (ni != NULL) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
+		    "%s sent (%d retries)\n", __func__, macid,
+		    (rpt->rptb7 & R92C_RPTB7_PKT_OK) ? "" : " not",
+		    ntries);
+
+#if __FreeBSD_version >= 1200012
+		txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY;
+		txs.long_retries = ntries;
+		if (rpt->rptb7 & R92C_RPTB7_PKT_OK)
+			txs.status = IEEE80211_RATECTL_TX_SUCCESS;
+		else if (rpt->rptb6 & R92C_RPTB6_RETRY_OVER)
+			txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; /* XXX */
+		else if (rpt->rptb6 & R92C_RPTB6_LIFE_EXPIRE)
+			txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
+		else
+			txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
+		ieee80211_ratectl_tx_complete(ni, &txs);
+#else
+		struct ieee80211vap *vap = ni->ni_vap;
+		if (rpt->rptb7 & R92C_RPTB7_PKT_OK) {
+			ieee80211_ratectl_tx_complete(vap, ni,
+			    IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
+		} else {
+			ieee80211_ratectl_tx_complete(vap, ni,
+			    IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
+		}
+#endif
+	} else {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n",
+		    __func__, macid);
+	}
+	RTWN_NT_UNLOCK(sc);
+
+#ifdef IEEE80211_SUPPORT_SUPERG
+	if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
+		rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
+#endif
+}
+
+static void
+r92c_handle_c2h_task(struct rtwn_softc *sc, union sec_param *data)
+{
+	const uint16_t off = R92C_C2H_EVT_MSG + sizeof(struct r92c_c2h_evt);
+	struct r92c_softc *rs = sc->sc_priv;
+	uint16_t buf[R92C_C2H_MSG_MAX_LEN / 2 + 1];
+	uint8_t id, len, status;
+	int i;
+
+	/* Do not reschedule the task if device is not running. */
+	if (!(sc->sc_flags & RTWN_RUNNING))
+		return;
+
+	/* Read current status. */
+	status = rtwn_read_1(sc, R92C_C2H_EVT_CLEAR);
+	if (status == R92C_C2H_EVT_HOST_CLOSE)
+		goto end;	/* nothing to do */
+	else if (status == R92C_C2H_EVT_FW_CLOSE) {
+		len = rtwn_read_1(sc, R92C_C2H_EVT_MSG);
+		id = MS(len, R92C_C2H_EVTB0_ID);
+		len = MS(len, R92C_C2H_EVTB0_LEN);
+
+		memset(buf, 0, sizeof(buf));
+		/* Try to optimize event reads. */
+		for (i = 0; i < len; i += 2)
+			buf[i / 2] = rtwn_read_2(sc, off + i);
+		KASSERT(i < sizeof(buf), ("%s: buffer overrun (%d >= %zu)!",
+		    __func__, i, sizeof(buf)));
+
+		switch (id) {
+		case R92C_C2H_EVT_TX_REPORT:
+			r92c_ratectl_tx_complete(sc, (uint8_t *)buf, len);
+			break;
+		default:
+			device_printf(sc->sc_dev,
+			    "%s: C2H report %u (len %u) was not handled\n",
+			    __func__, id, len);
+			break;
+		}
+	}
+
+	/* Prepare for next event. */
+	rtwn_write_1(sc, R92C_C2H_EVT_CLEAR, R92C_C2H_EVT_HOST_CLOSE);
+
+end:
+	/* Adjust timeout for next call. */
+	if (rs->rs_c2h_pending != 0) {
+		rs->rs_c2h_pending = 0;
+		rs->rs_c2h_paused = 0;
+	} else
+		rs->rs_c2h_paused++;
+
+	if (rs->rs_c2h_paused > R92C_TX_PAUSED_THRESHOLD)
+		rs->rs_c2h_timeout = hz;
+	else
+		rs->rs_c2h_timeout = MAX(hz / 100, 1);
+
+	/* Reschedule the task. */
+	callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout,
+	    r92c_handle_c2h_report, sc);
+}
+
+void
+r92c_handle_c2h_report(void *arg)
+{
+	struct rtwn_softc *sc = arg;
+
+	rtwn_cmd_sleepable(sc, NULL, 0, r92c_handle_c2h_task);
+}
+
+#endif	/* RTWN_WITHOUT_UCODE */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92C_FW_CMD_H
+#define R92C_FW_CMD_H
+
+/*
+ * Host to firmware commands.
+ */
+struct r92c_fw_cmd {
+	uint8_t	id;
+#define R92C_CMD_SET_PWRMODE		1
+#define R92C_CMD_JOINBSS_RPT		2
+#define R92C_CMD_RSVD_PAGE		3
+#define R92C_CMD_RSSI_SETTING		5
+#define R92C_CMD_MACID_CONFIG		6
+
+#define R92C_CMD_FLAG_EXT		0x80
+
+	uint8_t	msg[5];
+} __packed __attribute__((aligned(4)));
+
+/* Structure for R92C_CMD_JOINBSS_RPT. */
+struct r92c_fw_cmd_joinbss_rpt {
+	uint8_t	mstatus;
+#define R92C_MSTATUS_DISASSOC		0x00
+#define R92C_MSTATUS_ASSOC		0x01
+} __packed;
+
+/* Structure for R92C_CMD_SET_PWRMODE. */
+struct r92c_fw_cmd_pwrmode {
+	uint8_t	mode;
+#define R92C_PWRMODE_CAM	0
+#define R92C_PWRMODE_MIN	1
+#define R92C_PWRMODE_MAX	2
+#define R92C_PWRMODE_DTIM	3
+#define R92C_PWRMODE_UAPSD_WMM	5
+#define R92C_PWRMODE_UAPSD	6
+#define R92C_PWRMODE_IBSS	7
+
+	uint8_t	smart_ps;
+/* XXX undocumented */
+#define R92C_PWRMODE_SMARTPS_NULLDATA	2
+
+	uint8_t	bcn_pass;	/* unit: beacon interval */
+} __packed;
+
+/* Structure for R92C_CMD_RSVD_PAGE. */
+struct r92c_fw_cmd_rsvdpage {
+	uint8_t probe_resp;
+	uint8_t ps_poll;
+	uint8_t null_data;
+} __packed;
+
+/* Structure for R92C_CMD_RSSI_SETTING. */
+struct r92c_fw_cmd_rssi {
+	uint8_t	macid;
+	uint8_t	reserved;
+	uint8_t	pwdb;
+} __packed;
+
+/* Structure for R92C_CMD_MACID_CONFIG. */
+struct r92c_fw_cmd_macid_cfg {
+	uint32_t	mask;
+	uint8_t		macid;
+#define R92C_CMD_MACID_VALID	0x80
+} __packed;
+
+/*
+ * C2H event structure.
+ */
+/* Bigger value is used to prevent buffer overrun. */
+#define R92C_C2H_MSG_MAX_LEN		16
+
+struct r92c_c2h_evt {
+	uint8_t		evtb0;
+#define R92C_C2H_EVTB0_ID_M		0x0f
+#define R92C_C2H_EVTB0_ID_S		0
+#define R92C_C2H_EVTB0_LEN_M		0xf0
+#define R92C_C2H_EVTB0_LEN_S		4
+
+	uint8_t		seq;
+
+	/* Followed by payload (see below). */
+} __packed;
+
+/*
+ * C2H event types.
+ */
+#define R92C_C2H_EVT_DEBUG		0
+#define R92C_C2H_EVT_TX_REPORT		3
+#define R92C_C2H_EVT_EXT_RA_RPT		6
+
+/* Structure for R92C_C2H_EVT_TX_REPORT event. */
+struct r92c_c2h_tx_rpt {
+	uint8_t		rptb0;
+#define R92C_RPTB0_RETRY_CNT_M		0x3f
+#define R92C_RPTB0_RETRY_CNT_S		0
+
+	uint8_t		rptb1;		/* XXX junk */
+#define R92C_RPTB1_RTS_RETRY_CNT_M	0x3f
+#define R92C_RPTB1_RTS_RETRY_CNT_S	0
+
+	uint8_t		queue_time_low;
+	uint8_t		queue_time_high;
+	uint8_t		rptb4;
+#define R92C_RPTB4_MISSED_PKT_NUM_M	0x1f
+#define R92C_RPTB4_MISSED_PKT_NUM_S	0
+
+	uint8_t		rptb5;
+#define R92C_RPTB5_MACID_M		0x1f
+#define R92C_RPTB5_MACID_S		0
+#define R92C_RPTB5_DES1_FRAGSSN_M	0xe0
+#define R92C_RPTB5_DES1_FRAGSSN_S	5
+
+	uint8_t		rptb6;
+#define R92C_RPTB6_RPT_PKT_NUM_M	0x1f
+#define R92C_RPTB6_RPT_PKT_NUM_S	0
+#define R92C_RPTB6_PKT_DROP		0x20
+#define R92C_RPTB6_LIFE_EXPIRE		0x40
+#define R92C_RPTB6_RETRY_OVER		0x80
+
+	uint8_t		rptb7;
+#define R92C_RPTB7_EDCA_M		0x0f
+#define R92C_RPTB7_EDCA_S		0
+#define R92C_RPTB7_BMC			0x20
+#define R92C_RPTB7_PKT_OK		0x40
+#define R92C_RPTB7_INT_CCX		0x80
+} __packed;
+
+#endif	/* R92C_FW_CMD_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,319 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_priv.h>
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+
+int
+r92c_check_condition(struct rtwn_softc *sc, const uint8_t cond[])
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	uint8_t mask;
+	int i;
+
+	if (cond[0] == 0)
+		return (1);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+	    "%s: condition byte 0: %02X; chip %02X, board %02X\n",
+	    __func__, cond[0], rs->chip, rs->board_type);
+
+	if (!(rs->chip & R92C_CHIP_92C)) {
+		if (rs->board_type == R92C_BOARD_TYPE_HIGHPA)
+			mask = R92C_COND_RTL8188RU;
+		else if (rs->board_type == R92C_BOARD_TYPE_MINICARD)
+			mask = R92C_COND_RTL8188CE;
+		else
+			mask = R92C_COND_RTL8188CU;
+	} else {
+		if (rs->board_type == R92C_BOARD_TYPE_MINICARD)
+			mask = R92C_COND_RTL8192CE;
+		else
+			mask = R92C_COND_RTL8192CU;
+	}
+
+	for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++)
+		if ((cond[i] & mask) == mask)
+			return (1);
+
+	return (0);
+}
+
+int
+r92c_set_page_size(struct rtwn_softc *sc)
+{
+	return (rtwn_write_1(sc, R92C_PBP, SM(R92C_PBP_PSRX, R92C_PBP_128) |
+	    SM(R92C_PBP_PSTX, R92C_PBP_128)) == 0);
+}
+
+void
+r92c_init_bb_common(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	int i, j;
+
+	/* Write BB initialization values. */
+	for (i = 0; i < sc->bb_size; i++) {
+		const struct rtwn_bb_prog *bb_prog = &sc->bb_prog[i];
+
+		while (!rtwn_check_condition(sc, bb_prog->cond)) {
+			KASSERT(bb_prog->next != NULL,
+			    ("%s: wrong condition value (i %d)\n",
+			    __func__, i));
+			bb_prog = bb_prog->next;
+		}
+
+		for (j = 0; j < bb_prog->count; j++) {
+			RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+			    "BB: reg 0x%03x, val 0x%08x\n",
+			    bb_prog->reg[j], bb_prog->val[j]);
+
+			rtwn_bb_write(sc, bb_prog->reg[j], bb_prog->val[j]);
+			rtwn_delay(sc, 1);
+		}
+	}
+
+	if (rs->chip & R92C_CHIP_92C_1T2R) {
+		/* 8192C 1T only configuration. */
+		rtwn_bb_setbits(sc, R92C_FPGA0_TXINFO, 0x03, 0x02);
+		rtwn_bb_setbits(sc, R92C_FPGA1_TXINFO, 0x300033, 0x200022);
+		rtwn_bb_setbits(sc, R92C_CCK0_AFESETTING, 0xff000000,
+		    0x45000000);
+		rtwn_bb_setbits(sc, R92C_OFDM0_TRXPATHENA, 0xff, 0x23);
+		rtwn_bb_setbits(sc, R92C_OFDM0_AGCPARAM1, 0x30, 0x10);
+
+		rtwn_bb_setbits(sc, 0xe74, 0x0c000000, 0x08000000);
+		rtwn_bb_setbits(sc, 0xe78, 0x0c000000, 0x08000000);
+		rtwn_bb_setbits(sc, 0xe7c, 0x0c000000, 0x08000000);
+		rtwn_bb_setbits(sc, 0xe80, 0x0c000000, 0x08000000);
+		rtwn_bb_setbits(sc, 0xe88, 0x0c000000, 0x08000000);
+	}
+
+	/* Write AGC values. */
+	for (i = 0; i < sc->agc_size; i++) {
+		const struct rtwn_agc_prog *agc_prog = &sc->agc_prog[i];
+
+		while (!rtwn_check_condition(sc, agc_prog->cond)) {
+			KASSERT(agc_prog->next != NULL,
+			    ("%s: wrong condition value (2) (i %d)\n",
+			    __func__, i));
+			agc_prog = agc_prog->next;
+		}
+
+		for (j = 0; j < agc_prog->count; j++) {
+			RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+			    "AGC: val 0x%08x\n", agc_prog->val[j]);
+
+			rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE,
+			    agc_prog->val[j]);
+			rtwn_delay(sc, 1);
+		}
+	}
+
+	if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & R92C_HSSI_PARAM2_CCK_HIPWR)
+		sc->sc_flags |= RTWN_FLAG_CCK_HIPWR;
+}
+
+int
+r92c_init_rf_chain(struct rtwn_softc *sc,
+    const struct rtwn_rf_prog *rf_prog, int chain)
+{
+	int i, j;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, "%s: chain %d\n",
+	    __func__, chain);
+
+	for (i = 0; rf_prog[i].reg != NULL; i++) {
+		const struct rtwn_rf_prog *prog = &rf_prog[i];
+
+		while (!rtwn_check_condition(sc, prog->cond)) {
+			KASSERT(prog->next != NULL,
+			    ("%s: wrong condition value (i %d)\n",
+			    __func__, i));
+			prog = prog->next;
+		}
+
+		for (j = 0; j < prog->count; j++) {
+			RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+			    "RF: reg 0x%02x, val 0x%05x\n",
+			    prog->reg[j], prog->val[j]);
+
+			/*
+			 * These are fake RF registers offsets that
+			 * indicate a delay is required.
+			 */
+			/* NB: we are using 'value' to store required delay. */
+			if (prog->reg[j] > 0xf8) {
+				rtwn_delay(sc, prog->val[j]);
+				continue;
+			}
+
+			rtwn_rf_write(sc, chain, prog->reg[j], prog->val[j]);
+			rtwn_delay(sc, 1);
+		}
+	}
+
+	return (i);
+}
+
+void
+r92c_init_rf(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	uint32_t reg, type;
+	int i, chain, idx, off;
+
+	for (chain = 0, i = 0; chain < sc->nrxchains; chain++, i++) {
+		/* Save RF_ENV control type. */
+		idx = chain / 2;
+		off = (chain % 2) * 16;
+		reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
+		type = (reg >> off) & 0x10;
+
+		/* Set RF_ENV enable. */
+		rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(chain),
+		    0, 0x100000);
+		rtwn_delay(sc, 1);
+		/* Set RF_ENV output high. */
+		rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(chain),
+		    0, 0x10);
+		rtwn_delay(sc, 1);
+		/* Set address and data lengths of RF registers. */
+		rtwn_bb_setbits(sc, R92C_HSSI_PARAM2(chain),
+		    R92C_HSSI_PARAM2_ADDR_LENGTH, 0);
+		rtwn_delay(sc, 1);
+		rtwn_bb_setbits(sc, R92C_HSSI_PARAM2(chain),
+		    R92C_HSSI_PARAM2_DATA_LENGTH, 0);
+		rtwn_delay(sc, 1);
+
+		/* Write RF initialization values for this chain. */
+		i += r92c_init_rf_chain(sc, &sc->rf_prog[i], chain);
+
+		/* Restore RF_ENV control type. */
+		rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACESW(idx),
+		    0x10 << off, type << off);
+
+		/* Cache RF register CHNLBW. */
+		rs->rf_chnlbw[chain] = rtwn_rf_read(sc, chain,
+		    R92C_RF_CHNLBW);
+	}
+
+	if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) ==
+	    R92C_CHIP_UMC_A_CUT) {
+		rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255);
+		rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00);
+	}
+
+	/* Turn CCK and OFDM blocks on. */
+	rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_CCK_EN);
+	rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_OFDM_EN);
+}
+
+void
+r92c_init_edca(struct rtwn_softc *sc)
+{
+	/* SIFS */
+	rtwn_write_2(sc, R92C_SPEC_SIFS, 0x100a);
+	rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x100a);
+	rtwn_write_2(sc, R92C_SIFS_CCK, 0x100a);
+	rtwn_write_2(sc, R92C_SIFS_OFDM, 0x100a);
+	/* TXOP */
+	rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b);
+	rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f);
+	rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005ea324);
+	rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002fa226);
+}
+
+void
+r92c_init_ampdu(struct rtwn_softc *sc)
+{
+
+	/* Setup AMPDU aggregation. */
+	rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631);	/* MCS7~0 */
+	rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16);
+	rtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x0708);
+}
+
+void
+r92c_init_antsel(struct rtwn_softc *sc)
+{
+	uint32_t reg;
+
+	if (sc->ntxchains != 1 || sc->nrxchains != 1)
+		return;
+
+	rtwn_setbits_1(sc, R92C_LEDCFG2, 0, 0x80);
+	rtwn_bb_setbits(sc, R92C_FPGA0_RFPARAM(0), 0, 0x2000);
+	reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(0));
+	sc->sc_ant = MS(reg, R92C_FPGA0_RFIFACEOE0_ANT);	/* XXX */
+}
+
+void
+r92c_pa_bias_init(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	int i;
+
+	for (i = 0; i < sc->nrxchains; i++) {
+		if (rs->pa_setting & (1 << i))
+			continue;
+		r92c_rf_write(sc, i, R92C_RF_IPA, 0x0f406);
+		r92c_rf_write(sc, i, R92C_RF_IPA, 0x4f406);
+		r92c_rf_write(sc, i, R92C_RF_IPA, 0x8f406);
+		r92c_rf_write(sc, i, R92C_RF_IPA, 0xcf406);
+	}
+	if (!(rs->pa_setting & 0x10))
+		rtwn_setbits_1(sc, 0x16, 0xf0, 0x90);
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,408 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92C_PRIV_H
+#define R92C_PRIV_H
+
+#include <dev/rtwn/rtl8192c/r92c_rom_defs.h>
+
+/*
+ * Parsed Tx power (diff) values.
+ */
+struct rtwn_r92c_txpwr {
+	uint8_t		cck_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G];
+	uint8_t		ht40_1s_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G];
+	int8_t		ht40_2s_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G];
+	int8_t		ht20_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G];
+	int8_t		ofdm_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G];
+	int8_t		ht40_max_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G];
+	int8_t		ht20_max_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G];
+};
+
+
+/*
+ * Baseband initialization values (shared parts).
+ */
+#define R92C_COND_RTL8188CE	0x01
+#define R92C_COND_RTL8188CU	0x02
+#define R92C_COND_RTL8188RU	0x04
+#define R92C_COND_RTL8192CE	0x08
+#define R92C_COND_RTL8192CU	0x10
+
+/* Shortcut. */
+#define R92C_COND_RTL8192C	(R92C_COND_RTL8192CE | R92C_COND_RTL8192CU)
+
+static const uint16_t rtl8192c_bb_regs3[] = {
+	0xd04
+}, rtl8192c_bb_regs4[] = {
+	0xd08, 0xd0c, 0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38,
+	0xd3c, 0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c,
+	0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04,
+	0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38,
+	0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c
+}, rtl8192c_bb_regs5[] = {
+	0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84,
+	0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xf14,
+	0xf4c, 0xf00
+};
+
+static const uint32_t rtl8192c_bb_vals3_88cu_88ru[] = {
+	0x00020401
+}, rtl8192c_bb_vals3_92ce_92cu[] = {
+	0x00020403
+}, rtl8192c_bb_vals4[] = {
+	0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43, 0x7a8f5b6b,
+	0xcc979975, 0x00000000, 0x80608000, 0x00000000, 0x00027293,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6437140a,
+	0x00000000, 0x00000000, 0x30032064, 0x4653de68, 0x04518a3c,
+	0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, 0x000e3c24,
+	0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, 0x2a2a2a2a, 0x2a2a2a2a,
+	0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, 0x1000dc1f, 0x10008c1f,
+	0x02140102, 0x681604c2, 0x01007c00, 0x01004800, 0xfb000000,
+	0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x28160d05
+},rtl8192c_bb_vals5_92ce_92cu[] = {
+	0x00000010, 0x001b25a4, 0x63db25a4, 0x63db25a4, 0x0c1b25a4,
+	0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x63db25a4, 0x0c1b25a4,
+	0x63db25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, 0x001b25a4,
+	0x001b25a4, 0x6fdb25a4, 0x00000003, 0x00000000, 0x00000300
+};
+
+/*
+ * RTL8192CU and RTL8192CE-VAU.
+ */
+
+static const uint32_t rtl8192ce_agc_vals[] = {
+	0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001,
+	0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001,
+	0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001,
+	0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001,
+	0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001,
+	0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001,
+	0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001,
+	0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001,
+	0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001,
+	0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001,
+	0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001,
+	0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001,
+	0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001,
+	0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001,
+	0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001,
+	0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001,
+	0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001,
+	0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001,
+	0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001,
+	0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001,
+	0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001,
+	0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001,
+	0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001,
+	0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001,
+	0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001,
+	0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e,
+	0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e,
+	0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e,
+	0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e,
+	0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e,
+	0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e,
+	0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e
+};
+
+static const struct rtwn_agc_prog rtl8192ce_agc[] = {
+	{
+		nitems(rtl8192ce_agc_vals),
+		rtl8192ce_agc_vals,
+		{ 0 },
+		NULL
+	}
+};
+
+
+/*
+ * RF initialization values.
+ */
+static const uint8_t rtl8192c_rf0_regs0[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+	0x0f, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21
+}, rtl8192c_rf0_regs1[] = {
+	0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28
+}, rtl8192c_rf0_regs2[] = {
+	0x29, 0x2a, 0x2b, 0x2a, 0x2b, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b,
+	0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a,
+	0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c,
+	0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b,
+	0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b,
+	0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x10, 0x11, 0x10, 0x11,
+	0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11
+}, rtl8192c_rf0_regs3[] = {
+	0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+	0x13, 0x13, 0x13, 0x13
+}, rtl8192c_rf0_regs4[] = {
+	0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15
+}, rtl8192c_rf0_regs5[] = {
+	0x16, 0x16, 0x16, 0x16, 0x00, 0x18, 0xfe, 0xfe, 0x1f, 0xfe, 0xfe,
+	0x1e, 0x1f, 0x00
+};
+
+static const uint32_t rtl8192c_rf0_vals0_88ce_88cu_92ce[] = {
+	0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1,
+	0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255,
+	0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000
+}, rtl8192c_rf0_vals0_88ru[] = {
+	0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb0,
+	0x54867, 0x8992e, 0x0e529, 0x39ce7, 0x00451, 0x00000, 0x00255,
+	0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000
+}, rtl8192c_rf0_vals1_88ru[] = {
+	0x0083c, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x977c0
+}, rtl8192c_rf0_vals1_88ce[] = {
+	0x00000, 0x01558, 0x00060, 0x00483, 0x4f200, 0xec7d9, 0x577c0
+}, rtl8192c_rf0_vals1_88cu_92ce[] = {
+	0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0
+}, rtl8192c_rf0_vals2[] = {
+	0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808,
+	0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003,
+	0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d,
+	0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333,
+	0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a,
+	0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a,
+	0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d,
+	0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333,
+	0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f,
+	0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500,
+	0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100
+}, rtl8192c_rf0_vals3_88ru[] = {
+	0xd8000, 0x90000, 0x51000, 0x12000, 0x28fb4, 0x24fa8, 0x207a4,
+	0x1c798, 0x183a4, 0x14398, 0x101a4, 0x0c198, 0x080a4, 0x04098,
+	0x00014
+}, rtl8192c_rf0_vals3_92ce[] = {
+	0x32000, 0x71000, 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab,
+	0x1c49f, 0x18493, 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8,
+	0x0001c
+}, rtl8192c_rf0_vals3_88cu_88ce[] = {
+	0x32000, 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab,
+	0x1c49f, 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac,
+	0x00020
+}, rtl8192c_rf0_vals4_92ce_88ce[] = {
+	0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424,
+	0xcf424
+}, rtl8192c_rf0_vals4_88cu_88ru[] = {
+	0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405,
+	0xcf405
+}, rtl8192c_rf0_vals5[] = {
+	0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, 0x0c350,
+	0x0c350, 0x80003, 0x0c350, 0x0c350, 0x44457, 0x80000, 0x30159
+};
+
+static const struct rtwn_rf_prog rtl8192c_rf[] = {
+	/* RF chain 0 */
+	/* RTL8188RU. */
+	{
+		nitems(rtl8192c_rf0_regs0),
+		rtl8192c_rf0_regs0,
+		rtl8192c_rf0_vals0_88ru,
+		{ R92C_COND_RTL8188RU },
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8192c_rf0_regs0),
+			rtl8192c_rf0_regs0,
+			rtl8192c_rf0_vals0_88ce_88cu_92ce,
+			{ 0 },
+			NULL
+		}
+	},
+	/* RTL8188RU. */
+	{
+		nitems(rtl8192c_rf0_regs1),
+		rtl8192c_rf0_regs1,
+		rtl8192c_rf0_vals1_88ru,
+		{ R92C_COND_RTL8188RU },
+		/* RTL8188CE. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8192c_rf0_regs1),
+			rtl8192c_rf0_regs1,
+			rtl8192c_rf0_vals1_88ce,
+			{ R92C_COND_RTL8188CE },
+			/* Others. */
+			&(const struct rtwn_rf_prog){
+				nitems(rtl8192c_rf0_regs1),
+				rtl8192c_rf0_regs1,
+				rtl8192c_rf0_vals1_88cu_92ce,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	{
+		nitems(rtl8192c_rf0_regs2),
+		rtl8192c_rf0_regs2,
+		rtl8192c_rf0_vals2,
+		{ 0 },
+		NULL
+	},
+	/* RTL8188RU. */
+	{
+		nitems(rtl8192c_rf0_regs3),
+		rtl8192c_rf0_regs3,
+		rtl8192c_rf0_vals3_88ru,
+		{ R92C_COND_RTL8188RU },
+		/* RTL8192C. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8192c_rf0_regs3),
+			rtl8192c_rf0_regs3,
+			rtl8192c_rf0_vals3_92ce,
+			{ R92C_COND_RTL8192C },
+			/* Others. */
+			&(struct rtwn_rf_prog){
+				nitems(rtl8192c_rf0_regs3),
+				rtl8192c_rf0_regs3,
+				rtl8192c_rf0_vals3_88cu_88ce,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	/* RTL8188CE / RTL8192C. */
+	{
+		nitems(rtl8192c_rf0_regs4),
+		rtl8192c_rf0_regs4,
+		rtl8192c_rf0_vals4_92ce_88ce,
+		{ R92C_COND_RTL8188CE | R92C_COND_RTL8192C },
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8192c_rf0_regs4),
+			rtl8192c_rf0_regs4,
+			rtl8192c_rf0_vals4_88cu_88ru,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8192c_rf0_regs5),
+		rtl8192c_rf0_regs5,
+		rtl8192c_rf0_vals5,
+		{ 0 },
+		NULL
+	},
+	{ 0, NULL, NULL, { 0 }, NULL },
+	/* RF chain 1 (RTL8192C). */
+	{
+		12,				/* 0x00 - 0x0f */
+		rtl8192c_rf0_regs0,
+		rtl8192c_rf0_vals0_88ce_88cu_92ce,
+		{ 0 },
+		NULL
+	},
+	{
+		nitems(rtl8192c_rf0_regs3),	/* 0x12 - 0x13 */
+		rtl8192c_rf0_regs3,
+		rtl8192c_rf0_vals3_92ce,
+		{ 0 },
+		NULL
+	},
+	{
+		nitems(rtl8192c_rf0_regs4),	/* 0x14 - 0x15 */
+		rtl8192c_rf0_regs4,
+		rtl8192c_rf0_vals4_92ce_88ce,
+		{ 0 },
+		NULL
+	},
+	{
+		4,				/* 0x16 */
+		rtl8192c_rf0_regs5,
+		rtl8192c_rf0_vals5,
+		{ 0 },
+		NULL
+	},
+	{ 0, NULL, NULL, { 0 }, NULL }
+};
+
+
+struct rtwn_r92c_txagc {
+	uint8_t	pwr[R92C_GROUP_2G][28];	/* RTWN_RIDX_MCS(15) + 1 */
+};
+
+/*
+ * Per RF chain/group/rate Tx gain values.
+ */
+static const struct rtwn_r92c_txagc rtl8192cu_txagc[] = {
+	{ {	/* Chain 0. */
+	{	/* Group 0. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02,	/* OFDM6~54. */
+	0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02,	/* MCS0~7. */
+	0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02	/* MCS8~15. */
+	},
+	{	/* Group 1. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	/* MCS8~15. */
+	},
+	{	/* Group 2. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	/* MCS8~15. */
+	}
+	} },
+	{ {	/* Chain 1. */
+	{	/* Group 0. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	/* MCS8~15. */
+	},
+	{	/* Group 1. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	/* MCS8~15. */
+	},
+	{	/* Group 2. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	/* MCS8~15. */
+	}
+	} }
+};
+
+static const struct rtwn_r92c_txagc rtl8188ru_txagc[] = {
+	{ {	/* Chain 0. */
+	{	/* Group 0. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x08, 0x08, 0x08, 0x06, 0x06, 0x04, 0x04, 0x00,	/* OFDM6~54. */
+	0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00,	/* MCS0~7. */
+	0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00	/* MCS8~15. */
+	},
+	{	/* Group 1. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	/* MCS8~15. */
+	},
+	{	/* Group 2. */
+	0x00, 0x00, 0x00, 0x00,				/* CCK1~11. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* OFDM6~54. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* MCS0~7. */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	/* MCS8~15. */
+	}
+	} }
+};
+
+#endif	/* R92C_PRIV_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,855 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92C_REG_H
+#define R92C_REG_H
+
+/*
+ * MAC registers.
+ */
+/* System Configuration. */
+#define R92C_SYS_ISO_CTRL		0x000
+#define R92C_SYS_FUNC_EN		0x002
+#define R92C_APS_FSMCO			0x004
+#define R92C_SYS_CLKR			0x008
+#define R92C_AFE_MISC			0x010
+#define R92C_SPS0_CTRL			0x011
+#define R92C_SPS_OCP_CFG		0x018
+#define R92C_RSV_CTRL			0x01c
+#define R92C_RF_CTRL			0x01f
+#define R92C_LDOA15_CTRL		0x020
+#define R92C_LDOV12D_CTRL		0x021
+#define R92C_LDOHCI12_CTRL		0x022
+#define R92C_LPLDO_CTRL			0x023
+#define R92C_AFE_XTAL_CTRL		0x024
+#define R92C_AFE_PLL_CTRL		0x028
+#define R92C_APE_PLL_CTRL_EXT		0x02c
+#define R92C_MAC_PHY_CTRL		R92C_APE_PLL_CTRL_EXT
+#define R92C_EFUSE_CTRL			0x030
+#define R92C_EFUSE_TEST			0x034
+#define R92C_PWR_DATA			0x038
+#define R92C_CAL_TIMER			0x03c
+#define R92C_ACLK_MON			0x03e
+#define R92C_GPIO_MUXCFG		0x040
+#define R92C_GPIO_IO_SEL		0x042
+#define R92C_MAC_PINMUX_CFG		0x043
+#define R92C_GPIO_PIN_CTRL		0x044
+#define R92C_GPIO_IN			0x044
+#define R92C_GPIO_OUT			0x045
+#define R92C_GPIO_IOSEL			0x046
+#define R92C_GPIO_MOD			0x047
+#define R92C_GPIO_INTM			0x048
+#define R92C_LEDCFG0			0x04c
+#define R92C_LEDCFG1			0x04d
+#define R92C_LEDCFG2			0x04e
+#define R92C_LEDCFG3			0x04f
+#define R92C_FSIMR			0x050
+#define R92C_FSISR			0x054
+#define R92C_HSIMR			0x058
+#define R92C_HSISR			0x05c
+#define R92C_MULTI_FUNC_CTRL		0x068
+#define R92C_MCUFWDL			0x080
+#define R92C_HMEBOX_EXT(idx)		(0x088 + (idx) * 2)
+#define R92C_EFUSE_ACCESS		0x0cf
+#define R92C_BIST_SCAN			0x0d0
+#define R92C_BIST_RPT			0x0d4
+#define R92C_BIST_ROM_RPT		0x0d8
+#define R92C_HPON_FSM			0x0ec
+#define R92C_SYS_CFG			0x0f0
+#define R92C_TYPE_ID			0x0fc
+/* MAC General Configuration. */
+#define R92C_CR				0x100
+#define R92C_MSR			0x102
+#define R92C_PBP			0x104
+#define R92C_TRXDMA_CTRL		0x10c
+#define R92C_TRXFF_BNDY			0x114
+#define R92C_TRXFF_STATUS		0x118
+#define R92C_RXFF_PTR			0x11c
+#define R92C_HIMR			0x120
+#define R92C_HISR			0x124
+#define R92C_HIMRE			0x128
+#define R92C_HISRE			0x12c
+#define R92C_CPWM			0x12f
+#define R92C_FWIMR			0x130
+#define R92C_FWISR			0x134
+#define R92C_PKTBUF_DBG_CTRL		0x140
+#define R92C_PKTBUF_DBG_DATA_L		0x144
+#define R92C_PKTBUF_DBG_DATA_H		0x148
+#define R92C_TC0_CTRL(i)		(0x150 + (i) * 4)
+#define R92C_TCUNIT_BASE		0x164
+#define R92C_MBIST_START		0x174
+#define R92C_MBIST_DONE			0x178
+#define R92C_MBIST_FAIL			0x17c
+#define R92C_C2H_EVT_MSG		0x1a0
+#define R92C_C2H_EVT_CLEAR		0x1af
+#define R92C_C2H_EVT_MSG_TEST		0x1b8
+#define R92C_MCUTST_1			0x1c0
+#define R92C_FMETHR			0x1c8
+#define R92C_HMETFR			0x1cc
+#define R92C_HMEBOX(idx)		(0x1d0 + (idx) * 4)
+#define R92C_LLT_INIT			0x1e0
+#define R92C_BB_ACCESS_CTRL		0x1e8
+#define R92C_BB_ACCESS_DATA		0x1ec
+/* Tx DMA Configuration. */
+#define R92C_RQPN			0x200
+#define R92C_FIFOPAGE			0x204
+#define R92C_TDECTRL			0x208
+#define R92C_TXDMA_OFFSET_CHK		0x20c
+#define R92C_TXDMA_STATUS		0x210
+#define R92C_RQPN_NPQ			0x214
+/* Rx DMA Configuration. */
+#define R92C_RXDMA_AGG_PG_TH		0x280
+#define R92C_RXPKT_NUM			0x284
+#define R92C_RXDMA_STATUS		0x288
+/* Protocol Configuration. */
+#define R92C_VOQ_INFORMATION		0x400
+#define R92C_VIQ_INFORMATION		0x404
+#define R92C_BEQ_INFORMATION		0x408
+#define R92C_BKQ_INFORMATION		0x40c
+#define R92C_MGQ_INFORMATION		0x410
+#define R92C_HGQ_INFORMATION		0x414
+#define R92C_BCNQ_INFORMATION		0x418
+#define R92C_CPU_MGQ_INFORMATION	0x41c
+#define R92C_FWHW_TXQ_CTRL		0x420
+#define R92C_HWSEQ_CTRL			0x423
+#define R92C_TXPKTBUF_BCNQ_BDNY		0x424
+#define R92C_TXPKTBUF_MGQ_BDNY		0x425
+#define R92C_SPEC_SIFS			0x428
+#define R92C_RL				0x42a
+#define R92C_DARFRC			0x430
+#define R92C_RARFRC			0x438
+#define R92C_RRSR			0x440
+#define R92C_ARFR(i)			(0x444 + (i) * 4)
+#define R92C_AGGLEN_LMT			0x458
+#define R92C_AMPDU_MIN_SPACE		0x45c
+#define R92C_TXPKTBUF_WMAC_LBK_BF_HD	0x45d
+#define R92C_FAST_EDCA_CTRL		0x460
+#define R92C_RD_RESP_PKT_TH		0x463
+#define R92C_INIRTS_RATE_SEL		0x480
+#define R92C_INIDATA_RATE_SEL(macid)	(0x484 + (macid))
+#define R92C_QUEUE_CTRL			0x4c6
+#define R92C_MAX_AGGR_NUM		0x4ca
+#define R92C_BAR_MODE_CTRL		0x4cc
+/* EDCA Configuration. */
+#define R92C_EDCA_VO_PARAM		0x500
+#define R92C_EDCA_VI_PARAM		0x504
+#define R92C_EDCA_BE_PARAM		0x508
+#define R92C_EDCA_BK_PARAM		0x50c
+#define R92C_BCNTCFG			0x510
+#define R92C_PIFS			0x512
+#define R92C_RDG_PIFS			0x513
+#define R92C_SIFS_CCK			0x514
+#define R92C_SIFS_OFDM			0x516
+#define R92C_AGGR_BREAK_TIME		0x51a
+#define R92C_SLOT			0x51b
+#define R92C_TX_PTCL_CTRL		0x520
+#define R92C_TXPAUSE			0x522
+#define R92C_DIS_TXREQ_CLR		0x523
+#define R92C_RD_CTRL			0x524
+#define R92C_TBTT_PROHIBIT		0x540
+#define R92C_RD_NAV_NXT			0x544
+#define R92C_NAV_PROT_LEN		0x546
+#define R92C_BCN_CTRL(id)		((id) + 0x550)
+/* WARNING: R92C_USTIME_TSF == 0x55c, not 0x551 */
+#define R92C_MBID_NUM			0x552
+#define R92C_DUAL_TSF_RST		0x553
+#define R92C_BCN_INTERVAL(id)		(0x554 + (id) * 2)
+#define R92C_DRVERLYINT			0x558
+#define R92C_BCNDMATIM			0x559
+#define R92C_ATIMWND			0x55a
+#define R92C_USTIME_TSF			0x55c
+#define R92C_BCN_MAX_ERR		0x55d
+#define R92C_RXTSF_OFFSET_CCK		0x55e
+#define R92C_RXTSF_OFFSET_OFDM		0x55f
+#define R92C_TSFTR(i)			(0x560 + (i) * 8)
+#define R92C_PSTIMER			0x580
+#define R92C_TIMER0			0x584
+#define R92C_TIMER1			0x588
+#define R92C_ACMHWCTRL			0x5c0
+#define R92C_ACMRSTCTRL			0x5c1
+#define R92C_ACMAVG			0x5c2
+#define R92C_VO_ADMTIME			0x5c4
+#define R92C_VI_ADMTIME			0x5c6
+#define R92C_BE_ADMTIME			0x5c8
+#define R92C_EDCA_RANDOM_GEN		0x5cc
+#define R92C_SCH_TXCMD			0x5d0
+/* WMAC Configuration. */
+#define R92C_APSD_CTRL			0x600
+#define R92C_BWOPMODE			0x603
+#define R92C_TCR			0x604
+#define R92C_RCR			0x608
+#define R92C_RX_PKT_LIMIT		0x60c
+#define R92C_RX_DRVINFO_SZ		0x60f
+#define R92C_MACID0			0x610
+#define R92C_BSSID0			0x618
+#define R92C_MAR			0x620
+#define R92C_USTIME_EDCA		0x638
+#define R92C_MAC_SPEC_SIFS		0x63a
+#define R92C_R2T_SIFS			0x63c
+#define R92C_T2T_SIFS			0x63e
+#define R92C_ACKTO			0x640
+#define R92C_NAV_UPPER			0x652
+#define R92C_WMAC_TRXPTCL_CTL		0x668
+#define R92C_CAMCMD			0x670
+#define R92C_CAMWRITE			0x674
+#define R92C_CAMREAD			0x678
+#define R92C_CAMDBG			0x67c
+#define R92C_SECCFG			0x680
+#define R92C_RXFLTMAP0			0x6a0
+#define R92C_RXFLTMAP1			0x6a2
+#define R92C_RXFLTMAP2			0x6a4
+#define R92C_BCN_PSR_RPT		0x6a8
+#define R92C_MACID1			0x700
+#define R92C_BSSID1			0x708
+
+
+#define R92C_MACID(id)			((id) == 0 ? R92C_MACID0 : R92C_MACID1)
+#define R92C_BSSID(id)			((id) == 0 ? R92C_BSSID0 : R92C_BSSID1)
+
+/* Bits for R92C_SYS_ISO_CTRL. */
+#define R92C_SYS_ISO_CTRL_MD2PP		0x0001
+#define R92C_SYS_ISO_CTRL_UA2USB	0x0002
+#define R92C_SYS_ISO_CTRL_UD2CORE	0x0004
+#define R92C_SYS_ISO_CTRL_PA2PCIE	0x0008
+#define R92C_SYS_ISO_CTRL_PD2CORE	0x0010
+#define R92C_SYS_ISO_CTRL_IP2MAC	0x0020
+#define R92C_SYS_ISO_CTRL_DIOP		0x0040
+#define R92C_SYS_ISO_CTRL_DIOE		0x0080
+#define R92C_SYS_ISO_CTRL_EB2CORE	0x0100
+#define R92C_SYS_ISO_CTRL_DIOR		0x0200
+#define R92C_SYS_ISO_CTRL_PWC_EV25V	0x4000
+#define R92C_SYS_ISO_CTRL_PWC_EV12V	0x8000
+
+/* Bits for R92C_SYS_FUNC_EN. */
+#define R92C_SYS_FUNC_EN_BBRSTB		0x0001
+#define R92C_SYS_FUNC_EN_BB_GLB_RST	0x0002
+#define R92C_SYS_FUNC_EN_USBA		0x0004
+#define R92C_SYS_FUNC_EN_UPLL		0x0008
+#define R92C_SYS_FUNC_EN_USBD		0x0010
+#define R92C_SYS_FUNC_EN_DIO_PCIE	0x0020
+#define R92C_SYS_FUNC_EN_PCIEA		0x0040
+#define R92C_SYS_FUNC_EN_PPLL		0x0080
+#define R92C_SYS_FUNC_EN_PCIED		0x0100
+#define R92C_SYS_FUNC_EN_DIOE		0x0200
+#define R92C_SYS_FUNC_EN_CPUEN		0x0400
+#define R92C_SYS_FUNC_EN_DCORE		0x0800
+#define R92C_SYS_FUNC_EN_ELDR		0x1000
+#define R92C_SYS_FUNC_EN_DIO_RF		0x2000
+#define R92C_SYS_FUNC_EN_HWPDN		0x4000
+#define R92C_SYS_FUNC_EN_MREGEN		0x8000
+
+/* Bits for R92C_APS_FSMCO. */
+#define R92C_APS_FSMCO_PFM_LDALL	0x00000001
+#define R92C_APS_FSMCO_PFM_ALDN		0x00000002
+#define R92C_APS_FSMCO_PFM_LDKP		0x00000004
+#define R92C_APS_FSMCO_PFM_WOWL		0x00000008
+#define R92C_APS_FSMCO_PDN_EN		0x00000010
+#define R92C_APS_FSMCO_PDN_PL		0x00000020
+#define R92C_APS_FSMCO_APFM_ONMAC	0x00000100
+#define R92C_APS_FSMCO_APFM_OFF		0x00000200
+#define R92C_APS_FSMCO_APFM_RSM		0x00000400
+#define R92C_APS_FSMCO_AFSM_HSUS	0x00000800
+#define R92C_APS_FSMCO_AFSM_PCIE	0x00001000
+#define R92C_APS_FSMCO_APDM_MAC		0x00002000
+#define R92C_APS_FSMCO_APDM_HOST	0x00004000
+#define R92C_APS_FSMCO_APDM_HPDN	0x00008000
+#define R92C_APS_FSMCO_RDY_MACON	0x00010000
+#define R92C_APS_FSMCO_SUS_HOST		0x00020000
+#define R92C_APS_FSMCO_ROP_ALD		0x00100000
+#define R92C_APS_FSMCO_ROP_PWR		0x00200000
+#define R92C_APS_FSMCO_ROP_SPS		0x00400000
+#define R92C_APS_FSMCO_SOP_MRST		0x02000000
+#define R92C_APS_FSMCO_SOP_FUSE		0x04000000
+#define R92C_APS_FSMCO_SOP_ABG		0x08000000
+#define R92C_APS_FSMCO_SOP_AMB		0x10000000
+#define R92C_APS_FSMCO_SOP_RCK		0x20000000
+#define R92C_APS_FSMCO_SOP_A8M		0x40000000
+#define R92C_APS_FSMCO_XOP_BTCK		0x80000000
+
+/* Bits for R92C_SYS_CLKR. */
+#define R92C_SYS_CLKR_ANAD16V_EN	0x00000001
+#define R92C_SYS_CLKR_ANA8M		0x00000002
+#define R92C_SYS_CLKR_MACSLP		0x00000010
+#define R92C_SYS_CLKR_LOADER_EN		0x00000020
+#define R92C_SYS_CLKR_80M_SSC_DIS	0x00000080
+#define R92C_SYS_CLKR_80M_SSC_EN_HO	0x00000100
+#define R92C_SYS_CLKR_PHY_SSC_RSTB	0x00000200
+#define R92C_SYS_CLKR_SEC_EN		0x00000400
+#define R92C_SYS_CLKR_MAC_EN		0x00000800
+#define R92C_SYS_CLKR_SYS_EN		0x00001000
+#define R92C_SYS_CLKR_RING_EN		0x00002000
+
+/* Bits for R92C_RF_CTRL. */
+#define R92C_RF_CTRL_EN		0x01
+#define R92C_RF_CTRL_RSTB	0x02
+#define R92C_RF_CTRL_SDMRSTB	0x04
+
+/* Bits for R92C_LDOA15_CTRL. */
+#define R92C_LDOA15_CTRL_EN		0x01
+#define R92C_LDOA15_CTRL_STBY		0x02
+#define R92C_LDOA15_CTRL_OBUF		0x04
+#define R92C_LDOA15_CTRL_REG_VOS	0x08
+
+/* Bits for R92C_LDOV12D_CTRL. */
+#define R92C_LDOV12D_CTRL_LDV12_EN	0x01
+
+/* Bits for R92C_LPLDO_CTRL. */
+#define R92C_LPLDO_CTRL_SLEEP		0x10
+
+/* Bits for R92C_AFE_XTAL_CTRL. */
+#define R92C_AFE_XTAL_CTRL_ADDR_M	0x007ff800
+#define R92C_AFE_XTAL_CTRL_ADDR_S	11
+
+/* Bits for R92C_AFE_PLL_CTRL. */
+#define R92C_AFE_PLL_CTRL_EN		0x0001
+#define R92C_AFE_PLL_CTRL_320_EN	0x0002
+#define R92C_AFE_PLL_CTRL_FREF_SEL	0x0004
+#define R92C_AFE_PLL_CTRL_EDGE_SEL	0x0008
+#define R92C_AFE_PLL_CTRL_WDOGB		0x0010
+#define R92C_AFE_PLL_CTRL_LPFEN		0x0020
+
+/* Bits for R92C_EFUSE_CTRL. */
+#define R92C_EFUSE_CTRL_DATA_M	0x000000ff
+#define R92C_EFUSE_CTRL_DATA_S	0
+#define R92C_EFUSE_CTRL_ADDR_M	0x0003ff00
+#define R92C_EFUSE_CTRL_ADDR_S	8
+#define R92C_EFUSE_CTRL_VALID	0x80000000
+
+/* Bits for R92C_GPIO_MUXCFG. */
+#define R92C_GPIO_MUXCFG_ENBT	0x0020
+
+/* Bits for R92C_LEDCFG0. */
+#define R92C_LEDCFG0_DIS	0x08
+
+/* Bits for R92C_MULTI_FUNC_CTRL. */
+#define R92C_MULTI_BT_FUNC_EN	0x00040000
+
+/* Bits for R92C_MCUFWDL. */
+#define R92C_MCUFWDL_EN			0x00000001
+#define R92C_MCUFWDL_RDY		0x00000002
+#define R92C_MCUFWDL_CHKSUM_RPT		0x00000004
+#define R92C_MCUFWDL_MACINI_RDY		0x00000008
+#define R92C_MCUFWDL_BBINI_RDY		0x00000010
+#define R92C_MCUFWDL_RFINI_RDY		0x00000020
+#define R92C_MCUFWDL_WINTINI_RDY	0x00000040
+#define R92C_MCUFWDL_RAM_DL_SEL		0x00000080	/* 1: RAM, 0: ROM */
+#define R92C_MCUFWDL_PAGE_M		0x00070000
+#define R92C_MCUFWDL_PAGE_S		16
+#define R92C_MCUFWDL_ROM_DLEN		0x00080000
+#define R92C_MCUFWDL_CPRST		0x00800000
+
+/* Bits for R92C_EFUSE_ACCESS. */
+#define R92C_EFUSE_ACCESS_OFF		0x00
+#define R92C_EFUSE_ACCESS_ON		0x69
+
+/* Bits for R92C_HPON_FSM. */
+#define R92C_HPON_FSM_CHIP_BONDING_ID_S		22
+#define R92C_HPON_FSM_CHIP_BONDING_ID_M		0x00c00000
+#define R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R	1
+
+/* Bits for R92C_SYS_CFG. */
+#define R92C_SYS_CFG_XCLK_VLD		0x00000001
+#define R92C_SYS_CFG_ACLK_VLD		0x00000002
+#define R92C_SYS_CFG_UCLK_VLD		0x00000004
+#define R92C_SYS_CFG_PCLK_VLD		0x00000008
+#define R92C_SYS_CFG_PCIRSTB		0x00000010
+#define R92C_SYS_CFG_V15_VLD		0x00000020
+#define R92C_SYS_CFG_TRP_B15V_EN	0x00000080
+#define R92C_SYS_CFG_SIC_IDLE		0x00000100
+#define R92C_SYS_CFG_BD_MAC2		0x00000200
+#define R92C_SYS_CFG_BD_MAC1		0x00000400
+#define R92C_SYS_CFG_IC_MACPHY_MODE	0x00000800
+#define R92C_SYS_CFG_CHIP_VER_RTL_M	0x0000f000
+#define R92C_SYS_CFG_CHIP_VER_RTL_S	12
+#define R92C_SYS_CFG_BT_FUNC		0x00010000
+#define R92C_SYS_CFG_VENDOR_UMC		0x00080000
+#define R92C_SYS_CFG_PAD_HWPD_IDN	0x00400000
+#define R92C_SYS_CFG_TRP_VAUX_EN	0x00800000
+#define R92C_SYS_CFG_TRP_BT_EN		0x01000000
+#define R92C_SYS_CFG_BD_PKG_SEL		0x02000000
+#define R92C_SYS_CFG_BD_HCI_SEL		0x04000000
+#define R92C_SYS_CFG_TYPE_92C		0x08000000
+
+/* Bits for R92C_CR. */
+#define R92C_CR_HCI_TXDMA_EN	0x0001
+#define R92C_CR_HCI_RXDMA_EN	0x0002
+#define R92C_CR_TXDMA_EN	0x0004
+#define R92C_CR_RXDMA_EN	0x0008
+#define R92C_CR_PROTOCOL_EN	0x0010
+#define R92C_CR_SCHEDULE_EN	0x0020
+#define R92C_CR_MACTXEN		0x0040
+#define R92C_CR_MACRXEN		0x0080
+#define R92C_CR_ENSWBCN		0x0100
+#define R92C_CR_ENSEC		0x0200
+#define R92C_CR_CALTMR_EN	0x0400
+
+/* Bits for R92C_MSR. */
+#define R92C_MSR_NOLINK		0x00
+#define R92C_MSR_ADHOC		0x01
+#define R92C_MSR_INFRA		0x02
+#define R92C_MSR_AP		0x03
+#define R92C_MSR_MASK		(R92C_MSR_AP)
+
+/* Bits for R92C_PBP. */
+#define R92C_PBP_PSRX_M		0x0f
+#define R92C_PBP_PSRX_S		0
+#define R92C_PBP_PSTX_M		0xf0
+#define R92C_PBP_PSTX_S		4
+#define R92C_PBP_64		0
+#define R92C_PBP_128		1
+#define R92C_PBP_256		2
+#define R92C_PBP_512		3
+#define R92C_PBP_1024		4
+
+/* Bits for R92C_TRXDMA_CTRL. */
+#define R92C_TRXDMA_CTRL_RXDMA_AGG_EN		0x0004
+#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_M	0x0030
+#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_S	4
+#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_M	0x00c0
+#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_S	6
+#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_M	0x0300
+#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_S	8
+#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_M	0x0c00
+#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_S	10
+#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_M	0x3000
+#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_S	12
+#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_M	0xc000
+#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_S	14
+#define R92C_TRXDMA_CTRL_QUEUE_LOW		1
+#define R92C_TRXDMA_CTRL_QUEUE_NORMAL		2
+#define R92C_TRXDMA_CTRL_QUEUE_HIGH		3
+#define R92C_TRXDMA_CTRL_QMAP_M			0xfff0
+/* Shortcuts. */
+#define R92C_TRXDMA_CTRL_QMAP_3EP		0xf5b0
+#define R92C_TRXDMA_CTRL_QMAP_HQ_LQ		0xf5f0
+#define R92C_TRXDMA_CTRL_QMAP_HQ_NQ		0xfaf0
+#define R92C_TRXDMA_CTRL_QMAP_LQ		0x5550
+#define R92C_TRXDMA_CTRL_QMAP_NQ		0xaaa0
+#define R92C_TRXDMA_CTRL_QMAP_HQ		0xfff0
+
+/* Bits for R92C_C2H_EVT_CLEAR. */
+#define R92C_C2H_EVT_HOST_CLOSE		0x00
+#define R92C_C2H_EVT_FW_CLOSE		0xff
+
+/* Bits for R92C_LLT_INIT. */
+#define R92C_LLT_INIT_DATA_M		0x000000ff
+#define R92C_LLT_INIT_DATA_S		0
+#define R92C_LLT_INIT_ADDR_M		0x0000ff00
+#define R92C_LLT_INIT_ADDR_S		8
+#define R92C_LLT_INIT_OP_M		0xc0000000
+#define R92C_LLT_INIT_OP_S		30
+#define R92C_LLT_INIT_OP_NO_ACTIVE	0
+#define R92C_LLT_INIT_OP_WRITE		1
+
+/* Bits for R92C_RQPN. */
+#define R92C_RQPN_HPQ_M		0x000000ff
+#define R92C_RQPN_HPQ_S		0
+#define R92C_RQPN_LPQ_M		0x0000ff00
+#define R92C_RQPN_LPQ_S		8
+#define R92C_RQPN_PUBQ_M	0x00ff0000
+#define R92C_RQPN_PUBQ_S	16
+#define R92C_RQPN_LD		0x80000000
+
+/* Bits for R92C_TDECTRL. */
+#define R92C_TDECTRL_BLK_DESC_NUM_M	0x000000f0
+#define R92C_TDECTRL_BLK_DESC_NUM_S	4
+#define R92C_TDECTRL_BCN_VALID		0x00010000
+
+/* Bits for R92C_TXDMA_OFFSET_CHK. */
+#define R92C_TXDMA_OFFSET_DROP_DATA_EN	0x00000200
+
+/* Bits for R92C_FWHW_TXQ_CTRL. */
+#define R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW	0x80
+#define R92C_FWHW_TXQ_CTRL_REAL_BEACON	0x400000
+
+/* Bits for R92C_SPEC_SIFS. */
+#define R92C_SPEC_SIFS_CCK_M	0x00ff
+#define R92C_SPEC_SIFS_CCK_S	0
+#define R92C_SPEC_SIFS_OFDM_M	0xff00
+#define R92C_SPEC_SIFS_OFDM_S	8
+
+/* Bits for R92C_RL. */
+#define R92C_RL_LRL_M		0x003f
+#define R92C_RL_LRL_S		0
+#define R92C_RL_SRL_M		0x3f00
+#define R92C_RL_SRL_S		8
+
+/* Size of R92C_DARFRC. */
+#define R92C_DARFRC_SIZE	8
+
+/* Bits for R92C_RRSR. */
+#define R92C_RRSR_RATE_BITMAP_M		0x000fffff
+#define R92C_RRSR_RATE_BITMAP_S		0
+#define R92C_RRSR_RATE_CCK_ONLY_1M	0xffff1
+#define R92C_RRSR_RATE_ALL		0xfffff
+#define R92C_RRSR_RSC_LOWSUBCHNL	0x00200000
+#define R92C_RRSR_RSC_UPSUBCHNL		0x00400000
+#define R92C_RRSR_SHORT			0x00800000
+
+/* Bits for R92C_EDCA_XX_PARAM. */
+#define R92C_EDCA_PARAM_AIFS_M		0x000000ff
+#define R92C_EDCA_PARAM_AIFS_S		0
+#define R92C_EDCA_PARAM_ECWMIN_M	0x00000f00
+#define R92C_EDCA_PARAM_ECWMIN_S	8
+#define R92C_EDCA_PARAM_ECWMAX_M	0x0000f000
+#define R92C_EDCA_PARAM_ECWMAX_S	12
+#define R92C_EDCA_PARAM_TXOP_M		0xffff0000
+#define R92C_EDCA_PARAM_TXOP_S		16
+
+/* Bits for R92C_HWSEQ_CTRL / R92C_TXPAUSE. */
+#define R92C_TX_QUEUE_VO		0x01
+#define R92C_TX_QUEUE_VI		0x02
+#define R92C_TX_QUEUE_BE		0x04
+#define R92C_TX_QUEUE_BK		0x08
+#define R92C_TX_QUEUE_MGT		0x10
+#define R92C_TX_QUEUE_HIGH		0x20
+#define R92C_TX_QUEUE_BCN		0x40
+
+/* Shortcuts. */
+#define R92C_TX_QUEUE_AC			\
+	(R92C_TX_QUEUE_VO | R92C_TX_QUEUE_VI |	\
+	 R92C_TX_QUEUE_BE | R92C_TX_QUEUE_BK)
+
+#define R92C_TX_QUEUE_ALL			\
+	(R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT |	\
+	 R92C_TX_QUEUE_HIGH | R92C_TX_QUEUE_BCN | 0x80)	/* XXX */
+
+/* Bits for R92C_BCN_CTRL. */
+#define R92C_BCN_CTRL_EN_MBSSID		0x02
+#define R92C_BCN_CTRL_TXBCN_RPT		0x04
+#define R92C_BCN_CTRL_EN_BCN		0x08
+#define R92C_BCN_CTRL_DIS_TSF_UDT0	0x10
+
+/* Bits for R92C_DUAL_TSF_RST. */
+#define R92C_DUAL_TSF_RESET(id)		(0x01 << (id))
+#define R92C_DUAL_TSF_RST_TXOK		0x20
+
+/* Bits for R92C_ACMHWCTRL. */
+#define R92C_ACMHWCTRL_EN		0x01
+#define R92C_ACMHWCTRL_BE		0x02
+#define R92C_ACMHWCTRL_VI		0x04
+#define R92C_ACMHWCTRL_VO		0x08
+#define R92C_ACMHWCTRL_ACM_MASK		0x0f
+
+/* Bits for R92C_APSD_CTRL. */
+#define R92C_APSD_CTRL_OFF		0x40
+#define R92C_APSD_CTRL_OFF_STATUS	0x80
+
+/* Bits for R92C_BWOPMODE. */
+#define R92C_BWOPMODE_11J	0x01
+#define R92C_BWOPMODE_5G	0x02
+#define R92C_BWOPMODE_20MHZ	0x04
+
+/* Bits for R92C_TCR. */
+#define R92C_TCR_TSFRST		0x00000001
+#define R92C_TCR_DIS_GCLK	0x00000002
+#define R92C_TCR_PAD_SEL	0x00000004
+#define R92C_TCR_PWR_ST		0x00000040
+#define R92C_TCR_PWRBIT_OW_EN	0x00000080
+#define R92C_TCR_ACRC		0x00000100
+#define R92C_TCR_CFENDFORM	0x00000200
+#define R92C_TCR_ICV		0x00000400
+
+/* Bits for R92C_RCR. */
+#define R92C_RCR_AAP		0x00000001
+#define R92C_RCR_APM		0x00000002
+#define R92C_RCR_AM		0x00000004
+#define R92C_RCR_AB		0x00000008
+#define R92C_RCR_ADD3		0x00000010
+#define R92C_RCR_APWRMGT	0x00000020
+#define R92C_RCR_CBSSID_DATA	0x00000040
+#define R92C_RCR_CBSSID_BCN	0x00000080
+#define R92C_RCR_ACRC32		0x00000100
+#define R92C_RCR_AICV		0x00000200
+#define R92C_RCR_ADF		0x00000800
+#define R92C_RCR_ACF		0x00001000
+#define R92C_RCR_AMF		0x00002000
+#define R92C_RCR_HTC_LOC_CTRL	0x00004000
+#define R92C_RCR_MFBEN		0x00400000
+#define R92C_RCR_LSIGEN		0x00800000
+#define R92C_RCR_ENMBID		0x01000000
+#define R92C_RCR_APP_BA_SSN	0x08000000
+#define R92C_RCR_APP_PHYSTS	0x10000000
+#define R92C_RCR_APP_ICV	0x20000000
+#define R92C_RCR_APP_MIC	0x40000000
+#define R92C_RCR_APPFCS		0x80000000
+
+/* Bits for R92C_RX_DRVINFO_SZ. */
+#define R92C_RX_DRVINFO_SZ_DEF	4	/* XXX other values will not work */
+
+/* Bits for R92C_WMAC_TRXPTCL_CTL. */
+#define R92C_WMAC_TRXPTCL_SHPRE	0x00020000
+
+/* Bits for R92C_CAMCMD. */
+#define R92C_CAMCMD_ADDR_M	0x0000ffff
+#define R92C_CAMCMD_ADDR_S	0
+#define R92C_CAMCMD_WRITE	0x00010000
+#define R92C_CAMCMD_CLR		0x40000000
+#define R92C_CAMCMD_POLLING	0x80000000
+
+
+/*
+ * CAM entries.
+ */
+#define R92C_CAM_CTL0(entry)	((entry) * 8 + 0)
+#define R92C_CAM_CTL1(entry)	((entry) * 8 + 1)
+#define R92C_CAM_KEY(entry, i)	((entry) * 8 + 2 + (i))
+#define R92C_CAM_CTL6(entry)	((entry) * 8 + 6)
+#define R92C_CAM_CTL7(entry)	((entry) * 8 + 7)
+
+/* Bits for R92C_CAM_CTL0(i). */
+#define R92C_CAM_KEYID_M	0x00000003
+#define R92C_CAM_KEYID_S	0
+#define R92C_CAM_ALGO_M		0x0000001c
+#define R92C_CAM_ALGO_S		2
+#define R92C_CAM_ALGO_NONE	0
+#define R92C_CAM_ALGO_WEP40	1
+#define R92C_CAM_ALGO_TKIP	2
+#define R92C_CAM_ALGO_AES	4
+#define R92C_CAM_ALGO_WEP104	5
+#define R92C_CAM_VALID		0x00008000
+#define R92C_CAM_MACLO_M	0xffff0000
+#define R92C_CAM_MACLO_S	16
+
+/* Bits for R92C_SECCFG. */
+#define R92C_SECCFG_TXUCKEY_DEF	0x0001
+#define R92C_SECCFG_RXUCKEY_DEF	0x0002
+#define R92C_SECCFG_TXENC_ENA	0x0004
+#define R92C_SECCFG_RXDEC_ENA	0x0008
+#define R92C_SECCFG_CMP_A2	0x0010
+#define R92C_SECCFG_MC_SRCH_DIS	0x0020
+#define R92C_SECCFG_TXBCKEY_DEF	0x0040
+#define R92C_SECCFG_RXBCKEY_DEF	0x0080
+
+/* Bits for R92C_RXFLTMAP*. */
+#define R92C_RXFLTMAP_SUBTYPE(subtype)	\
+	(1 << ((subtype) >> IEEE80211_FC0_SUBTYPE_SHIFT))
+
+
+/*
+ * Baseband registers.
+ */
+#define R92C_FPGA0_RFMOD		0x800
+#define R92C_FPGA0_TXINFO		0x804
+#define R92C_HSSI_PARAM1(chain)		(0x820 + (chain) * 8)
+#define R92C_HSSI_PARAM2(chain)		(0x824 + (chain) * 8)
+#define R92C_TXAGC_RATE18_06(i)		(((i) == 0) ? 0xe00 : 0x830)
+#define R92C_TXAGC_RATE54_24(i)		(((i) == 0) ? 0xe04 : 0x834)
+#define R92C_TXAGC_A_CCK1_MCS32		0xe08
+#define R92C_TXAGC_B_CCK1_55_MCS32	0x838
+#define R92C_TXAGC_B_CCK11_A_CCK2_11	0x86c
+#define R92C_TXAGC_MCS03_MCS00(i)	(((i) == 0) ? 0xe10 : 0x83c)
+#define R92C_TXAGC_MCS07_MCS04(i)	(((i) == 0) ? 0xe14 : 0x848)
+#define R92C_TXAGC_MCS11_MCS08(i)	(((i) == 0) ? 0xe18 : 0x84c)
+#define R92C_TXAGC_MCS15_MCS12(i)	(((i) == 0) ? 0xe1c : 0x868)
+#define R92C_LSSI_PARAM(chain)		(0x840 + (chain) * 4)
+#define R92C_FPGA0_RFIFACEOE(chain)	(0x860 + (chain) * 4)
+#define R92C_FPGA0_RFIFACESW(idx)	(0x870 + (idx) * 4)
+#define R92C_FPGA0_RFPARAM(idx)		(0x878 + (idx) * 4)
+#define R92C_FPGA0_ANAPARAM2		0x884
+#define R92C_LSSI_READBACK(chain)	(0x8a0 + (chain) * 4)
+#define R92C_HSPI_READBACK(chain)	(0x8b8 + (chain) * 4)
+#define R92C_FPGA1_RFMOD		0x900
+#define R92C_FPGA1_TXINFO		0x90c
+#define R92C_CCK0_SYSTEM		0xa00
+#define R92C_CCK0_AFESETTING		0xa04
+#define R92C_OFDM0_TRXPATHENA		0xc04
+#define R92C_OFDM0_TRMUXPAR		0xc08
+#define R92C_OFDM0_RXIQIMBALANCE(chain)	(0xc14 + (chain) * 8)
+#define R92C_OFDM0_ECCATHRESHOLD	0xc4c
+#define R92C_OFDM0_AGCCORE1(chain)	(0xc50 + (chain) * 8)
+#define R92C_OFDM0_AGCPARAM1		0xc70
+#define R92C_OFDM0_AGCRSSITABLE		0xc78
+#define R92C_OFDM0_TXIQIMBALANCE(chain)	(0xc80 + (chain) * 8)
+#define R92C_OFDM0_TXAFE(chain)		(0xc94 + (chain) * 8)
+#define R92C_OFDM0_RXIQEXTANTA		0xca0
+#define R92C_OFDM1_LSTF			0xd00
+
+/* Bits for R92C_FPGA[01]_RFMOD. */
+#define R92C_RFMOD_40MHZ	0x00000001
+#define R92C_RFMOD_JAPAN	0x00000002
+#define R92C_RFMOD_CCK_TXSC	0x00000030
+#define R92C_RFMOD_CCK_EN	0x01000000
+#define R92C_RFMOD_OFDM_EN	0x02000000
+
+/* Bits for R92C_HSSI_PARAM1(i). */
+#define R92C_HSSI_PARAM1_PI	0x00000100
+
+/* Bits for R92C_HSSI_PARAM2(i). */
+#define R92C_HSSI_PARAM2_CCK_HIPWR	0x00000200
+#define R92C_HSSI_PARAM2_ADDR_LENGTH	0x00000400
+#define R92C_HSSI_PARAM2_DATA_LENGTH	0x00000800
+#define R92C_HSSI_PARAM2_READ_ADDR_M	0x7f800000
+#define R92C_HSSI_PARAM2_READ_ADDR_S	23
+#define R92C_HSSI_PARAM2_READ_EDGE	0x80000000
+
+/* Bits for R92C_TXAGC_A_CCK1_MCS32. */
+#define R92C_TXAGC_A_CCK1_M	0x0000ff00
+#define R92C_TXAGC_A_CCK1_S	8
+
+/* Bits for R92C_TXAGC_B_CCK11_A_CCK2_11. */
+#define R92C_TXAGC_B_CCK11_M	0x000000ff
+#define R92C_TXAGC_B_CCK11_S	0
+#define R92C_TXAGC_A_CCK2_M	0x0000ff00
+#define R92C_TXAGC_A_CCK2_S	8
+#define R92C_TXAGC_A_CCK55_M	0x00ff0000
+#define R92C_TXAGC_A_CCK55_S	16
+#define R92C_TXAGC_A_CCK11_M	0xff000000
+#define R92C_TXAGC_A_CCK11_S	24
+
+/* Bits for R92C_TXAGC_B_CCK1_55_MCS32. */
+#define R92C_TXAGC_B_CCK1_M	0x0000ff00
+#define R92C_TXAGC_B_CCK1_S	8
+#define R92C_TXAGC_B_CCK2_M	0x00ff0000
+#define R92C_TXAGC_B_CCK2_S	16
+#define R92C_TXAGC_B_CCK55_M	0xff000000
+#define R92C_TXAGC_B_CCK55_S	24
+
+/* Bits for R92C_TXAGC_RATE18_06(x). */
+#define R92C_TXAGC_RATE06_M	0x000000ff
+#define R92C_TXAGC_RATE06_S	0
+#define R92C_TXAGC_RATE09_M	0x0000ff00
+#define R92C_TXAGC_RATE09_S	8
+#define R92C_TXAGC_RATE12_M	0x00ff0000
+#define R92C_TXAGC_RATE12_S	16
+#define R92C_TXAGC_RATE18_M	0xff000000
+#define R92C_TXAGC_RATE18_S	24
+
+/* Bits for R92C_TXAGC_RATE54_24(x). */
+#define R92C_TXAGC_RATE24_M	0x000000ff
+#define R92C_TXAGC_RATE24_S	0
+#define R92C_TXAGC_RATE36_M	0x0000ff00
+#define R92C_TXAGC_RATE36_S	8
+#define R92C_TXAGC_RATE48_M	0x00ff0000
+#define R92C_TXAGC_RATE48_S	16
+#define R92C_TXAGC_RATE54_M	0xff000000
+#define R92C_TXAGC_RATE54_S	24
+
+/* Bits for R92C_TXAGC_MCS03_MCS00(x). */
+#define R92C_TXAGC_MCS00_M	0x000000ff
+#define R92C_TXAGC_MCS00_S	0
+#define R92C_TXAGC_MCS01_M	0x0000ff00
+#define R92C_TXAGC_MCS01_S	8
+#define R92C_TXAGC_MCS02_M	0x00ff0000
+#define R92C_TXAGC_MCS02_S	16
+#define R92C_TXAGC_MCS03_M	0xff000000
+#define R92C_TXAGC_MCS03_S	24
+
+/* Bits for R92C_TXAGC_MCS07_MCS04(x). */
+#define R92C_TXAGC_MCS04_M	0x000000ff
+#define R92C_TXAGC_MCS04_S	0
+#define R92C_TXAGC_MCS05_M	0x0000ff00
+#define R92C_TXAGC_MCS05_S	8
+#define R92C_TXAGC_MCS06_M	0x00ff0000
+#define R92C_TXAGC_MCS06_S	16
+#define R92C_TXAGC_MCS07_M	0xff000000
+#define R92C_TXAGC_MCS07_S	24
+
+/* Bits for R92C_TXAGC_MCS11_MCS08(x). */
+#define R92C_TXAGC_MCS08_M	0x000000ff
+#define R92C_TXAGC_MCS08_S	0
+#define R92C_TXAGC_MCS09_M	0x0000ff00
+#define R92C_TXAGC_MCS09_S	8
+#define R92C_TXAGC_MCS10_M	0x00ff0000
+#define R92C_TXAGC_MCS10_S	16
+#define R92C_TXAGC_MCS11_M	0xff000000
+#define R92C_TXAGC_MCS11_S	24
+
+/* Bits for R92C_TXAGC_MCS15_MCS12(x). */
+#define R92C_TXAGC_MCS12_M	0x000000ff
+#define R92C_TXAGC_MCS12_S	0
+#define R92C_TXAGC_MCS13_M	0x0000ff00
+#define R92C_TXAGC_MCS13_S	8
+#define R92C_TXAGC_MCS14_M	0x00ff0000
+#define R92C_TXAGC_MCS14_S	16
+#define R92C_TXAGC_MCS15_M	0xff000000
+#define R92C_TXAGC_MCS15_S	24
+
+/* Bits for R92C_LSSI_PARAM(i). */
+#define R92C_LSSI_PARAM_DATA_M	0x000fffff
+#define R92C_LSSI_PARAM_DATA_S	0
+#define R92C_LSSI_PARAM_ADDR_M	0x03f00000
+#define R92C_LSSI_PARAM_ADDR_S	20
+
+/* Bits for R92C_FPGA0_RFIFACEOE(0). */
+#define R92C_FPGA0_RFIFACEOE0_ANT_M	0x00000300
+#define R92C_FPGA0_RFIFACEOE0_ANT_S	8
+
+/* Bits for R92C_FPGA0_ANAPARAM2. */
+#define R92C_FPGA0_ANAPARAM2_CBW20	0x00000400
+
+/* Bits for R92C_LSSI_READBACK(i). */
+#define R92C_LSSI_READBACK_DATA_M	0x000fffff
+#define R92C_LSSI_READBACK_DATA_S	0
+
+/* Bits for R92C_OFDM0_AGCCORE1(i). */
+#define R92C_OFDM0_AGCCORE1_GAIN_M	0x0000007f
+#define R92C_OFDM0_AGCCORE1_GAIN_S	0
+
+
+/*
+ * RF (6052) registers.
+ */
+#define R92C_RF_AC		0x00
+#define R92C_RF_IQADJ_G(i)	(0x01 + (i))
+#define R92C_RF_POW_TRSW	0x05
+#define R92C_RF_GAIN_RX		0x06
+#define R92C_RF_GAIN_TX		0x07
+#define R92C_RF_TXM_IDAC	0x08
+#define R92C_RF_BS_IQGEN	0x0f
+#define R92C_RF_MODE1		0x10
+#define R92C_RF_MODE2		0x11
+#define R92C_RF_RX_AGC_HP	0x12
+#define R92C_RF_TX_AGC		0x13
+#define R92C_RF_BIAS		0x14
+#define R92C_RF_IPA		0x15
+#define R92C_RF_POW_ABILITY	0x17
+#define R92C_RF_CHNLBW		0x18
+#define R92C_RF_RX_G1		0x1a
+#define R92C_RF_RX_G2		0x1b
+#define R92C_RF_RX_BB2		0x1c
+#define R92C_RF_RX_BB1		0x1d
+#define R92C_RF_RCK1		0x1e
+#define R92C_RF_RCK2		0x1f
+#define R92C_RF_TX_G(i)		(0x20 + (i))
+#define R92C_RF_TX_BB1		0x23
+#define R92C_RF_T_METER		0x24
+#define R92C_RF_SYN_G(i)	(0x25 + (i))
+#define R92C_RF_RCK_OS		0x30
+#define R92C_RF_TXPA_G(i)	(0x31 + (i))
+
+/* Bits for R92C_RF_AC. */
+#define R92C_RF_AC_MODE_M	0x70000
+#define R92C_RF_AC_MODE_S	16
+#define R92C_RF_AC_MODE_STANDBY	1
+
+/* Bits for R92C_RF_CHNLBW. */
+#define R92C_RF_CHNLBW_CHNL_M	0x003ff
+#define R92C_RF_CHNLBW_CHNL_S	0
+#define R92C_RF_CHNLBW_BW20	0x00400
+#define R92C_RF_CHNLBW_LCSTART	0x08000
+
+/* Bits for R92C_RF_T_METER. */
+#define R92C_RF_T_METER_START	0x60
+#define R92C_RF_T_METER_VAL_M	0x1f
+#define R92C_RF_T_METER_VAL_S	0
+
+#endif	/* R92C_REG_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,95 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+#include <dev/rtwn/rtl8192c/r92c_rom_defs.h>
+
+
+uint32_t
+r92c_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	uint32_t reg[R92C_MAX_CHAINS], val;
+
+	reg[0] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(0));
+	if (chain != 0)
+		reg[chain] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(chain));
+
+	rtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
+	    reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE);
+	rtwn_delay(sc, rs->rf_read_delay[0]);
+
+	rtwn_bb_write(sc, R92C_HSSI_PARAM2(chain),
+	    RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) |
+	    R92C_HSSI_PARAM2_READ_EDGE);
+	rtwn_delay(sc, rs->rf_read_delay[1]);
+
+	rtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
+	    reg[0] | R92C_HSSI_PARAM2_READ_EDGE);
+	rtwn_delay(sc, rs->rf_read_delay[2]);
+
+	if (rtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI)
+		val = rtwn_bb_read(sc, R92C_HSPI_READBACK(chain));
+	else
+		val = rtwn_bb_read(sc, R92C_LSSI_READBACK(chain));
+	return (MS(val, R92C_LSSI_READBACK_DATA));
+}
+
+void
+r92c_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr,
+    uint32_t val)
+{
+	rtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
+	    SM(R92C_LSSI_PARAM_ADDR, addr) |
+	    SM(R92C_LSSI_PARAM_DATA, val));
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,141 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_efuse.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_priv.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+#include <dev/rtwn/rtl8192c/r92c_rom_image.h>
+
+
+static void
+r92c_set_chains(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	if (rs->chip & R92C_CHIP_92C) {
+		sc->ntxchains = (rs->chip & R92C_CHIP_92C_1T2R) ? 1 : 2;
+		sc->nrxchains = 2;
+	} else {
+		sc->ntxchains = 1;
+		sc->nrxchains = 1;
+	}
+}
+
+void
+r92c_efuse_postread(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	/* XXX Weird but this is what the vendor driver does. */
+	sc->next_rom_addr = 0x1fa;
+	(void) rtwn_efuse_read_next(sc, &rs->pa_setting);
+	RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: PA setting=0x%x\n", __func__,
+	    rs->pa_setting);
+}
+
+void
+r92c_parse_rom(struct rtwn_softc *sc, uint8_t *buf)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	struct rtwn_r92c_txpwr *rt = rs->rs_txpwr;
+	struct r92c_rom *rom = (struct r92c_rom *)buf;
+	int i, j;
+
+	rs->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE);
+	rs->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY);
+	RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type=%d\n",
+	    __func__, rs->regulatory);
+
+	/* Need to be set before postinit() (but after preinit()). */
+	rtwn_r92c_set_name(sc);
+	r92c_set_chains(sc);
+
+	for (j = 0; j < R92C_GROUP_2G; j++) {
+		for (i = 0; i < sc->ntxchains; i++) {
+			rt->cck_tx_pwr[i][j] = rom->cck_tx_pwr[i][j];
+			rt->ht40_1s_tx_pwr[i][j] = rom->ht40_1s_tx_pwr[i][j];
+		}
+
+		rt->ht40_2s_tx_pwr_diff[0][j] =
+		    MS(rom->ht40_2s_tx_pwr_diff[j], LOW_PART);
+		rt->ht20_tx_pwr_diff[0][j] =
+		    RTWN_SIGN4TO8(MS(rom->ht20_tx_pwr_diff[j],
+			LOW_PART));
+		rt->ofdm_tx_pwr_diff[0][j] =
+		    MS(rom->ofdm_tx_pwr_diff[j], LOW_PART);
+		rt->ht40_max_pwr[0][j] =
+		    MS(rom->ht40_max_pwr[j], LOW_PART);
+		rt->ht20_max_pwr[0][j] =
+		    MS(rom->ht20_max_pwr[j], LOW_PART);
+
+		if (sc->ntxchains > 1) {
+			rt->ht40_2s_tx_pwr_diff[1][j] =
+			    MS(rom->ht40_2s_tx_pwr_diff[j], HIGH_PART);
+			rt->ht20_tx_pwr_diff[1][j] =
+			    RTWN_SIGN4TO8(MS(rom->ht20_tx_pwr_diff[j],
+				HIGH_PART));
+			rt->ofdm_tx_pwr_diff[1][j] =
+			    MS(rom->ofdm_tx_pwr_diff[j], HIGH_PART);
+			rt->ht40_max_pwr[1][j] =
+			    MS(rom->ht40_max_pwr[j], HIGH_PART);
+			rt->ht20_max_pwr[1][j] =
+			    MS(rom->ht20_max_pwr[j], HIGH_PART);
+		}
+	}
+
+	sc->thermal_meter = MS(rom->thermal_meter, R92C_ROM_THERMAL_METER);
+	if (sc->thermal_meter == R92C_ROM_THERMAL_METER_M)
+		sc->thermal_meter = 0xff;
+	IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr);
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92C_ROM_DEFS_H
+#define R92C_ROM_DEFS_H
+
+#define R92C_MAX_CHAINS			2
+#define R92C_GROUP_2G			3
+
+#define R92C_EFUSE_MAX_LEN		512
+#define R92C_EFUSE_MAP_LEN		128
+
+/*
+ * Some generic rom parsing macros.
+ */
+#define RTWN_GET_ROM_VAR(var, def)	(((var) != 0xff) ? (var) : (def))
+#define RTWN_SIGN4TO8(val)		(((val) & 0x08) ? (val) | 0xf0 : (val))
+
+#define LOW_PART_M	0x0f
+#define LOW_PART_S	0
+#define HIGH_PART_M	0xf0
+#define HIGH_PART_S	4
+
+/* Bits for rf_board_opt (rf_opt1) field. */
+#define R92C_ROM_RF1_REGULATORY_M	0x07
+#define R92C_ROM_RF1_REGULATORY_S	0
+#define R92C_ROM_RF1_BOARD_TYPE_M	0xe0
+#define R92C_ROM_RF1_BOARD_TYPE_S	5
+
+/* Generic board types. */
+#define R92C_BOARD_TYPE_DONGLE		0
+#define R92C_BOARD_TYPE_HIGHPA		1
+#define R92C_BOARD_TYPE_MINICARD	2
+#define R92C_BOARD_TYPE_SOLO		3
+#define R92C_BOARD_TYPE_COMBO		4
+
+/* Bits for channel_plan field. */
+#define R92C_CHANNEL_PLAN_BY_HW		0x80
+
+#endif	/* R92C_ROM_DEFS_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92C_ROM_IMAGE_H
+#define R92C_ROM_IMAGE_H
+
+#include <dev/rtwn/rtl8192c/r92c_rom_defs.h>
+
+/*
+ * RTL8192CU ROM image.
+ */
+struct r92c_rom {
+	uint16_t	id;		/* 0x8192 */
+	uint8_t		reserved1[5];
+	uint8_t		dbg_sel;
+	uint16_t	reserved2;
+	uint16_t	vid;
+	uint16_t	pid;
+	uint8_t		usb_opt;
+	uint8_t		ep_setting;
+	uint16_t	reserved3;
+	uint8_t		usb_phy;
+	uint8_t		reserved4[3];
+	uint8_t		macaddr[IEEE80211_ADDR_LEN];
+	uint8_t		string[61];	/* "Realtek" */
+	uint8_t		subcustomer_id;
+	uint8_t		cck_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G];
+	uint8_t		ht40_1s_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G];
+	uint8_t		ht40_2s_tx_pwr_diff[R92C_GROUP_2G];
+	uint8_t		ht20_tx_pwr_diff[R92C_GROUP_2G];
+	uint8_t		ofdm_tx_pwr_diff[R92C_GROUP_2G];
+	uint8_t		ht40_max_pwr[R92C_GROUP_2G];
+	uint8_t		ht20_max_pwr[R92C_GROUP_2G];
+	uint8_t		xtal_calib;
+	uint8_t		tssi[R92C_MAX_CHAINS];
+	uint8_t		thermal_meter;
+#define R92C_ROM_THERMAL_METER_M	0x1f
+#define R92C_ROM_THERMAL_METER_S	0
+
+	uint8_t		rf_opt1;
+	uint8_t		rf_opt2;
+	uint8_t		rf_opt3;
+	uint8_t		rf_opt4;
+	uint8_t		channel_plan;
+#define R92C_CHANNEL_PLAN_BY_HW		0x80
+
+	uint8_t		version;
+	uint8_t		customer_id;
+} __packed;
+
+_Static_assert(sizeof(struct r92c_rom) == R92C_EFUSE_MAP_LEN,
+    "R92C_EFUSE_MAP_LEN must be equal to sizeof(struct r92c_rom)!");
+
+#endif	/* R92C_ROM_IMAGE_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,104 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
+
+
+int8_t
+r92c_get_rssi_cck(struct rtwn_softc *sc, void *physt)
+{
+	static const int8_t cckoff[] = { 16, -12, -26, -46 };
+	struct r92c_rx_cck *cck = (struct r92c_rx_cck *)physt;
+	uint8_t rpt;
+	int8_t rssi;
+
+	if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) {
+		rpt = (cck->agc_rpt >> 5) & 0x03;
+		rssi = (cck->agc_rpt & 0x1f) << 1;
+	} else {
+		rpt = (cck->agc_rpt >> 6) & 0x03;
+		rssi = cck->agc_rpt & 0x3e;
+	}
+	rssi = cckoff[rpt] - rssi;
+
+	return (rssi);
+}
+
+int8_t
+r92c_get_rssi_ofdm(struct rtwn_softc *sc, void *physt)
+{
+	struct r92c_rx_phystat *phy = (struct r92c_rx_phystat *)physt;
+	int rssi;
+
+	/* Get average RSSI. */
+	rssi = ((phy->pwdb_all >> 1) & 0x7f) - 110;
+
+	return (rssi);
+}
+
+uint8_t
+r92c_rx_radiotap_flags(const void *buf)
+{
+	const struct r92c_rx_stat *stat = buf;
+	uint8_t flags, rate;
+
+	if (!(stat->rxdw3 & htole32(R92C_RXDW3_SPLCP)))
+		return (0);
+
+	rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE);
+	if (RTWN_RATE_IS_CCK(rate))
+		flags = IEEE80211_RADIOTAP_F_SHORTPRE;
+	else
+		flags = IEEE80211_RADIOTAP_F_SHORTGI;
+	return (flags);
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92C_RX_DESC_H
+#define R92C_RX_DESC_H
+
+/* Rx MAC descriptor (common parts / USB). */
+struct r92c_rx_stat {
+	uint32_t	rxdw0;
+#define R92C_RXDW0_PKTLEN_M	0x00003fff
+#define R92C_RXDW0_PKTLEN_S	0
+#define R92C_RXDW0_CRCERR	0x00004000
+#define R92C_RXDW0_ICVERR	0x00008000
+#define R92C_RXDW0_INFOSZ_M	0x000f0000
+#define R92C_RXDW0_INFOSZ_S	16
+#define R92C_RXDW0_CIPHER_M	0x00700000
+#define R92C_RXDW0_CIPHER_S	20
+#define R92C_RXDW0_QOS		0x00800000
+#define R92C_RXDW0_SHIFT_M	0x03000000
+#define R92C_RXDW0_SHIFT_S	24
+#define R92C_RXDW0_PHYST	0x04000000
+#define R92C_RXDW0_SWDEC	0x08000000
+#define R92C_RXDW0_LS		0x10000000
+#define R92C_RXDW0_FS		0x20000000
+#define R92C_RXDW0_EOR		0x40000000
+#define R92C_RXDW0_OWN		0x80000000
+
+	uint32_t	rxdw1;
+#define R92C_RXDW1_MACID_M	0x0000001f
+#define R92C_RXDW1_MACID_S	0
+#define R92C_RXDW1_MC		0x40000000
+#define R92C_RXDW1_BC		0x80000000
+
+	uint32_t	rxdw2;
+	uint32_t	rxdw3;
+#define R92C_RXDW3_RATE_M	0x0000003f
+#define R92C_RXDW3_RATE_S	0
+#define R92C_RXDW3_HT		0x00000040
+#define R92C_RXDW3_SPLCP	0x00000100
+#define R92C_RXDW3_HT40		0x00000200
+#define R92C_RXDW3_HTC		0x00000400
+
+	uint32_t	rxdw4;
+	uint32_t	tsf_low;
+} __packed __attribute__((aligned(4)));
+
+/* Rx PHY CCK descriptor. */
+struct r92c_rx_cck {
+	uint8_t		adc_pwdb[4];
+	uint8_t		sq_rpt;
+	uint8_t		agc_rpt;
+} __packed;
+
+/* Rx PHY descriptor. */
+struct r92c_rx_phystat {
+	uint8_t		trsw_gain[4];
+	uint8_t		pwdb_all;
+	uint8_t		cfosho[4];
+	uint8_t		cfotail[4];
+	uint8_t		rxevm[2];
+	uint8_t		rxsnr[4];
+	uint8_t		pdsnr[2];
+	uint8_t		csi_current[2];
+	uint8_t		csi_target[2];
+	uint8_t		sigevm;
+	uint8_t		max_ex_pwr;
+	uint8_t		phy_byte28;
+#define R92C_PHY_BYTE28_ANTSEL		0x01
+#define R92C_PHY_BYTE28_ANTSEL_B	0x02
+#define R92C_PHY_BYTE28_ANT_TRAIN_EN	0x04
+#define R92C_PHY_BYTE28_IDLE_LONG	0x08
+#define R92C_PHY_BYTE28_RXSC_M		0x30
+#define R92C_PHY_BYTE28_RXSC_S		4
+#define R92C_PHY_BYTE28_SGI_EN		0x40
+#define R92C_PHY_BYTE28_EX_INTF_FLG	0x80
+} __packed;
+
+#endif	/* R92C_RX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,438 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_tx.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+#include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
+
+
+static int
+r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	if (IEEE80211_IS_CHAN_HT40U(c))
+		return (R92C_TXDW4_SCO_SCA);
+	else
+		return (R92C_TXDW4_SCO_SCB);
+}
+
+static void
+r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
+	    IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
+		int extc_offset;
+
+		extc_offset = r92c_tx_get_sco(sc, ni->ni_chan);
+		txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40);
+		txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset));
+	}
+}
+
+static void
+r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd,
+    enum ieee80211_protmode mode, uint8_t ridx)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint8_t rate;
+
+	switch (mode) {
+	case IEEE80211_PROT_CTSONLY:
+		txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF);
+		break;
+	case IEEE80211_PROT_RTSCTS:
+		txd->txdw4 |= htole32(R92C_TXDW4_RTSEN);
+		break;
+	default:
+		break;
+	}
+
+	if (mode == IEEE80211_PROT_CTSONLY ||
+	    mode == IEEE80211_PROT_RTSCTS) {
+		if (ridx >= RTWN_RIDX_MCS(0))
+			rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx);
+		else
+			rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]);
+		ridx = rate2ridx(rate);
+
+		txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx));
+		/* RTS rate fallback limit (max). */
+		txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf));
+
+		if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
+		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+			txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT);
+	}
+}
+
+static void
+r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd,
+    struct ieee80211_node *ni, int ismcast)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct ieee80211_channel *chan;
+	enum ieee80211_phymode mode;
+	uint8_t raid;
+
+	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
+		ni->ni_chan : ic->ic_curchan;
+	mode = ieee80211_chan2mode(chan);
+
+	/* NB: group addressed frames are done at 11bg rates for now */
+	if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) {
+		switch (mode) {
+		case IEEE80211_MODE_11B:
+		case IEEE80211_MODE_11G:
+			break;
+		case IEEE80211_MODE_11NG:
+			mode = IEEE80211_MODE_11G;
+			break;
+		default:
+			device_printf(sc->sc_dev, "unknown mode(1) %d!\n",
+			    ic->ic_curmode);
+			return;
+		}
+	}
+
+	switch (mode) {
+	case IEEE80211_MODE_11B:
+		raid = R92C_RAID_11B;
+		break;
+	case IEEE80211_MODE_11G:
+		if (vap->iv_flags & IEEE80211_F_PUREG)
+			raid = R92C_RAID_11G;
+		else
+			raid = R92C_RAID_11BG;
+		break;
+	case IEEE80211_MODE_11NG:
+		if (vap->iv_flags_ht & IEEE80211_FHT_PUREN)
+			raid = R92C_RAID_11N;
+		else
+			raid = R92C_RAID_11BGN;
+		break;
+	default:
+		device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode);
+		return;
+	}
+
+	txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid));
+}
+
+/* XXX move to device-independent layer */
+static void
+r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+	struct ieee80211vap *vap = ni->ni_vap;
+
+	if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) &&	/* HT20 */
+	    (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20))
+		txd->txdw5 |= htole32(R92C_TXDW5_SGI);
+	else if (ni->ni_chan != IEEE80211_CHAN_ANYC &&		/* HT40 */
+	    IEEE80211_IS_CHAN_HT40(ni->ni_chan) &&
+	    (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
+	    (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40))
+		txd->txdw5 |= htole32(R92C_TXDW5_SGI);
+}
+
+void
+r92c_tx_enable_ampdu(void *buf, int enable)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	if (enable)
+		txd->txdw1 |= htole32(R92C_TXDW1_AGGEN);
+	else
+		txd->txdw1 |= htole32(R92C_TXDW1_AGGBK);
+}
+
+void
+r92c_tx_setup_hwseq(void *buf)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN);
+}
+
+void
+r92c_tx_setup_macid(void *buf, int id)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id));
+}
+
+void
+r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m, void *buf, uint8_t ridx, int maxretry)
+{
+#ifndef RTWN_WITHOUT_UCODE
+	struct r92c_softc *rs = sc->sc_priv;
+#endif
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211_frame *wh;
+	struct r92c_tx_desc *txd;
+	enum ieee80211_protmode prot;
+	uint8_t type, tid, qos, qsel;
+	int hasqos, ismcast, macid;
+
+	wh = mtod(m, struct ieee80211_frame *);
+	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+	hasqos = IEEE80211_QOS_HAS_SEQ(wh);
+	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+
+	/* Select TX ring for this frame. */
+	if (hasqos) {
+		qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
+		tid = qos & IEEE80211_QOS_TID;
+	} else {
+		qos = 0;
+		tid = 0;
+	}
+
+	/* Fill Tx descriptor. */
+	txd = (struct r92c_tx_desc *)buf;
+	txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG;
+	if (ismcast)
+		txd->flags0 |= R92C_FLAGS0_BMCAST;
+
+	if (!ismcast) {
+		/* Unicast frame, check if an ACK is expected. */
+		if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) !=
+		    IEEE80211_QOS_ACKPOLICY_NOACK) {
+			txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA);
+			txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT,
+			    maxretry));
+		}
+
+		struct rtwn_node *un = RTWN_NODE(ni);
+		macid = un->id;
+
+		if (type == IEEE80211_FC0_TYPE_DATA) {
+			qsel = tid % RTWN_MAX_TID;
+
+			rtwn_r92c_tx_enable_ampdu(sc, buf,
+			    (m->m_flags & M_AMPDU_MPDU) != 0);
+			if (m->m_flags & M_AMPDU_MPDU) {
+				txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN,
+				    vap->iv_ampdu_density));
+				txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG,
+				    0x1f));	/* XXX */
+			}
+			if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
+				txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT);
+				sc->sc_tx_n_active++;
+#ifndef RTWN_WITHOUT_UCODE
+				rs->rs_c2h_pending++;
+#endif
+			}
+
+			if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
+			    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+				txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE);
+
+			prot = IEEE80211_PROT_NONE;
+			if (ridx >= RTWN_RIDX_MCS(0)) {
+				r92c_tx_set_ht40(sc, txd, ni);
+				r92c_tx_set_sgi(sc, txd, ni);
+				prot = ic->ic_htprotmode;
+			} else if (ic->ic_flags & IEEE80211_F_USEPROT)
+				prot = ic->ic_protmode;
+
+			/* XXX fix last comparison for A-MSDU (in net80211) */
+			/* XXX A-MPDU? */
+			if (m->m_pkthdr.len + IEEE80211_CRC_LEN >
+			    vap->iv_rtsthreshold &&
+			    vap->iv_rtsthreshold != IEEE80211_RTS_MAX)
+				prot = IEEE80211_PROT_RTSCTS;
+
+			/* NB: checks for ht40 / short bits (set above). */
+			if (prot != IEEE80211_PROT_NONE)
+				r92c_tx_protection(sc, txd, prot, ridx);
+		} else	/* IEEE80211_FC0_TYPE_MGT */
+			qsel = R92C_TXDW1_QSEL_MGNT;
+	} else {
+		macid = RTWN_MACID_BC;
+		qsel = R92C_TXDW1_QSEL_MGNT;
+	}
+
+	txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel));
+
+	rtwn_r92c_tx_setup_macid(sc, txd, macid);
+	txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
+	/* Data rate fallback limit (max). */
+	txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f));
+	txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id));
+	r92c_tx_raid(sc, txd, ni, ismcast);
+
+	/* Force this rate if needed. */
+	if (sc->sc_ratectl != RTWN_RATECTL_FW)
+		txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
+
+	if (!hasqos) {
+		/* Use HW sequence numbering for non-QoS frames. */
+		rtwn_r92c_tx_setup_hwseq(sc, txd);
+		txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id));
+	} else {
+		uint16_t seqno;
+
+		if (m->m_flags & M_AMPDU_MPDU) {
+			seqno = ni->ni_txseqs[tid];
+			/* NB: clear Fragment Number field. */
+			*(uint16_t *)wh->i_seq = 0;
+			ni->ni_txseqs[tid]++;
+		} else
+			seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE;
+
+		/* Set sequence number. */
+		txd->txdseq = htole16(seqno);
+	}
+}
+
+void
+r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params)
+{
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211_frame *wh;
+	struct r92c_tx_desc *txd;
+	uint8_t ridx;
+	int ismcast;
+
+	/* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */
+
+	wh = mtod(m, struct ieee80211_frame *);
+	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+	ridx = rate2ridx(params->ibp_rate0);
+
+	/* Fill Tx descriptor. */
+	txd = (struct r92c_tx_desc *)buf;
+	txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG;
+	if (ismcast)
+		txd->flags0 |= R92C_FLAGS0_BMCAST;
+
+	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) {
+		txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA);
+		txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT,
+		    params->ibp_try0));
+	}
+	if (params->ibp_flags & IEEE80211_BPF_RTS)
+		r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx);
+	if (params->ibp_flags & IEEE80211_BPF_CTS)
+		r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx);
+
+	rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC);
+	txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
+
+	/* Set TX rate index. */
+	txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
+	txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f));
+	txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id));
+	txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
+	r92c_tx_raid(sc, txd, ni, ismcast);
+
+	if (!IEEE80211_QOS_HAS_SEQ(wh)) {
+		/* Use HW sequence numbering for non-QoS frames. */
+		rtwn_r92c_tx_setup_hwseq(sc, txd);
+		txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id));
+	} else {
+		/* Set sequence number. */
+		txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE);
+	}
+}
+
+void
+r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b,
+    int qos, int id)
+{
+	struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
+
+	txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN;
+	txd->txdw1 = htole32(
+	    SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
+
+	txd->txdw4 = htole32(R92C_TXDW4_DRVRATE);
+	txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id));
+	if (is11b) {
+		txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE,
+		    RTWN_RIDX_CCK1));
+	} else {
+		txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE,
+		    RTWN_RIDX_OFDM6));
+	}
+
+	if (!qos) {
+		rtwn_r92c_tx_setup_hwseq(sc, txd);
+		txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id));
+	}
+}
+
+uint8_t
+r92c_tx_radiotap_flags(const void *buf)
+{
+	const struct r92c_tx_desc *txd = buf;
+	uint8_t flags;
+
+	flags = 0;
+	if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE))
+		flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+	if (txd->txdw5 & htole32(R92C_TXDW5_SGI))
+		flags |= IEEE80211_RADIOTAP_F_SHORTGI;
+	return (flags);
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92C_TX_DESC_H
+#define R92C_TX_DESC_H
+
+/* Tx MAC descriptor (common part). */
+struct r92c_tx_desc {
+	uint16_t 	pktlen;
+	uint8_t		offset;
+	uint8_t		flags0;
+#define R92C_FLAGS0_BMCAST	0x01
+#define R92C_FLAGS0_LSG		0x04
+#define R92C_FLAGS0_FSG		0x08
+#define R92C_FLAGS0_OWN		0x80
+
+	uint32_t	txdw1;
+#define R92C_TXDW1_MACID_M	0x0000001f
+#define R92C_TXDW1_MACID_S	0
+#define R92C_TXDW1_AGGEN	0x00000020
+#define R92C_TXDW1_AGGBK	0x00000040
+
+#define R92C_TXDW1_QSEL_M	0x00001f00
+#define R92C_TXDW1_QSEL_S	8
+
+#define R92C_TXDW1_QSEL_BE	0x00	/* or 0x03 */
+#define R92C_TXDW1_QSEL_BK	0x01	/* or 0x02 */
+#define R92C_TXDW1_QSEL_VI	0x04	/* or 0x05 */
+#define R92C_TXDW1_QSEL_VO	0x06	/* or 0x07 */
+#define RTWN_MAX_TID		8
+
+#define R92C_TXDW1_QSEL_BEACON	0x10
+#define R92C_TXDW1_QSEL_MGNT	0x12
+
+#define R92C_TXDW1_RAID_M	0x000f0000
+#define R92C_TXDW1_RAID_S	16
+#define R92C_TXDW1_CIPHER_M	0x00c00000
+#define R92C_TXDW1_CIPHER_S	22
+#define R92C_TXDW1_CIPHER_NONE	0
+#define R92C_TXDW1_CIPHER_RC4	1
+#define R92C_TXDW1_CIPHER_AES	3
+#define R92C_TXDW1_PKTOFF_M	0x7c000000
+#define R92C_TXDW1_PKTOFF_S	26
+
+	uint32_t	txdw2;
+#define R92C_TXDW2_CCX_RPT	0x00080000
+#define R92C_TXDW2_AMPDU_DEN_M	0x00700000
+#define R92C_TXDW2_AMPDU_DEN_S	20
+
+	uint16_t	txdw3;
+	uint16_t	txdseq;
+
+	uint32_t	txdw4;
+#define R92C_TXDW4_RTSRATE_M	0x0000003f
+#define R92C_TXDW4_RTSRATE_S	0
+#define R92C_TXDW4_SEQ_SEL_M	0x00000040
+#define R92C_TXDW4_SEQ_SEL_S	6
+#define R92C_TXDW4_HWSEQ_EN	0x00000080
+#define R92C_TXDW4_DRVRATE	0x00000100
+#define R92C_TXDW4_CTS2SELF	0x00000800
+#define R92C_TXDW4_RTSEN	0x00001000
+#define R92C_TXDW4_HWRTSEN	0x00002000
+#define R92C_TXDW4_PORT_ID_M	0x00004000
+#define R92C_TXDW4_PORT_ID_S	14
+#define R92C_TXDW4_DATA_SCO_M	0x00300000
+#define R92C_TXDW4_DATA_SCO_S	20
+#define R92C_TXDW4_SCO_SCA	1
+#define R92C_TXDW4_SCO_SCB	2
+#define R92C_TXDW4_DATA_SHPRE	0x01000000
+#define R92C_TXDW4_DATA_BW40	0x02000000
+#define R92C_TXDW4_RTS_SHORT	0x04000000
+#define R92C_TXDW4_RTS_BW40	0x08000000
+#define R92C_TXDW4_RTS_SCO_M	0x30000000
+#define R92C_TXDW4_RTS_SCO_S	28
+
+	uint32_t	txdw5;
+#define R92C_TXDW5_DATARATE_M		0x0000003f
+#define R92C_TXDW5_DATARATE_S		0
+#define R92C_TXDW5_SGI			0x00000040
+#define R92C_TXDW5_DATARATE_FB_LMT_M	0x00001f00
+#define R92C_TXDW5_DATARATE_FB_LMT_S	8
+#define R92C_TXDW5_RTSRATE_FB_LMT_M	0x0001e000
+#define R92C_TXDW5_RTSRATE_FB_LMT_S	13
+#define R92C_TXDW5_RTY_LMT_ENA		0x00020000
+#define R92C_TXDW5_RTY_LMT_M		0x00fc0000
+#define R92C_TXDW5_RTY_LMT_S		18
+#define R92C_TXDW5_AGGNUM_M		0xff000000
+#define R92C_TXDW5_AGGNUM_S		24
+
+	uint32_t	txdw6;
+#define R92C_TXDW6_MAX_AGG_M		0x0000f800
+#define R92C_TXDW6_MAX_AGG_S		11
+} __packed __attribute__((aligned(4)));
+
+
+/* Rate adaptation modes. */
+#define R92C_RAID_11BGN		0
+#define R92C_RAID_11GN		1
+#define R92C_RAID_11BN		2
+#define R92C_RAID_11N		3
+#define R92C_RAID_11BG		4
+#define R92C_RAID_11G		5	/* "pure" 11g */
+#define R92C_RAID_11B		6
+
+#endif	/* R92C_TX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92C_VAR_H
+#define R92C_VAR_H
+
+#include <dev/rtwn/rtl8192c/r92c_rom_defs.h>
+
+struct r92c_softc {
+	uint8_t		rs_flags;
+#define R92C_FLAG_ASSOCIATED	0x01
+
+	uint8_t		chip;
+#define R92C_CHIP_92C		0x01
+#define R92C_CHIP_92C_1T2R	0x02
+#define R92C_CHIP_UMC_A_CUT	0x04
+
+#ifndef RTWN_WITHOUT_UCODE
+	struct callout	rs_c2h_report;
+	int		rs_c2h_timeout;
+	int		rs_c2h_pending;
+	int		rs_c2h_paused;
+#endif
+#define R92C_TX_PAUSED_THRESHOLD	20
+
+	void		*rs_txpwr;
+	const void	*rs_txagc;
+
+	uint8_t		board_type;
+	uint8_t		regulatory;
+	uint8_t		crystalcap;
+	uint8_t		pa_setting;
+
+	void		(*rs_scan_start)(struct ieee80211com *);
+	void		(*rs_scan_end)(struct ieee80211com *);
+
+	void		(*rs_set_bw20)(struct rtwn_softc *, uint8_t);
+	void		(*rs_get_txpower)(struct rtwn_softc *, int,
+			    struct ieee80211_channel *, uint16_t[]);
+	void		(*rs_set_gain)(struct rtwn_softc *, uint8_t);
+	void		(*rs_tx_enable_ampdu)(void *, int);
+	void		(*rs_tx_setup_hwseq)(void *);
+	void		(*rs_tx_setup_macid)(void *, int);
+	void		(*rs_set_name)(struct rtwn_softc *);
+
+	int		rf_read_delay[3];
+	uint32_t	rf_chnlbw[R92C_MAX_CHAINS];
+};
+#define R92C_SOFTC(_sc)	((struct r92c_softc *)((_sc)->sc_priv))
+
+#define rtwn_r92c_set_bw20(_sc, _chan) \
+	((R92C_SOFTC(_sc)->rs_set_bw20)((_sc), (_chan)))
+#define rtwn_r92c_get_txpower(_sc, _chain, _c, _power) \
+	((R92C_SOFTC(_sc)->rs_get_txpower)((_sc), (_chain), (_c), (_power)))
+#define rtwn_r92c_set_gain(_sc, _gain) \
+	((R92C_SOFTC(_sc)->rs_set_gain)((_sc), (_gain)))
+#define rtwn_r92c_tx_enable_ampdu(_sc, _buf, _enable) \
+	((R92C_SOFTC(_sc)->rs_tx_enable_ampdu)((_buf), (_enable)))
+#define rtwn_r92c_tx_setup_hwseq(_sc, _buf) \
+	((R92C_SOFTC(_sc)->rs_tx_setup_hwseq)((_buf)))
+#define rtwn_r92c_tx_setup_macid(_sc, _buf, _id) \
+	((R92C_SOFTC(_sc)->rs_tx_setup_macid)((_buf), (_id)))
+#define rtwn_r92c_set_name(_sc) \
+	((R92C_SOFTC(_sc)->rs_set_name)((_sc)))
+
+#endif	/* R92C_VAR_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef RTL8192CU_H
+#define RTL8192CU_H
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+
+
+/*
+ * Global definitions.
+ */
+#define R92CU_PUBQ_NPAGES	231
+#define R92CU_TX_PAGE_COUNT	248
+
+
+/*
+ * Function declarations.
+ */
+/* r92cu_init.c */
+void	r92cu_init_bb(struct rtwn_softc *);
+int	r92cu_power_on(struct rtwn_softc *);
+void	r92cu_power_off(struct rtwn_softc *);
+void	r92cu_init_intr(struct rtwn_softc *);
+void	r92cu_init_tx_agg(struct rtwn_softc *);
+void	r92cu_init_rx_agg(struct rtwn_softc *);
+void	r92cu_post_init(struct rtwn_softc *);
+
+/* r92cu_led.c */
+void	r92cu_set_led(struct rtwn_softc *, int, int);
+
+/* r92cu_rx.c */
+int	r92cu_classify_intr(struct rtwn_softc *, void *, int);
+int	r92cu_align_rx(int, int);
+
+/* r92cu_tx.c */
+void	r92cu_dump_tx_desc(struct rtwn_softc *, const void *);
+
+#endif	/* RTL8192CU_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,247 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_nop.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu.h>
+#include <dev/rtwn/rtl8192c/usb/r92cu_priv.h>
+#include <dev/rtwn/rtl8192c/usb/r92cu_reg.h>
+#include <dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h>
+
+
+static struct rtwn_r92c_txpwr r92c_txpwr;
+
+void	r92cu_attach(struct rtwn_usb_softc *);
+
+static void
+r92cu_postattach(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	if (!(rs->chip & R92C_CHIP_92C) &&
+	    rs->board_type == R92C_BOARD_TYPE_HIGHPA) {
+		sc->agc_prog = &rtl8188ru_agc[0];
+		sc->agc_size = nitems(rtl8188ru_agc);
+		rs->rs_txagc = &rtl8188ru_txagc[0];
+	} else {
+		sc->agc_prog = &rtl8192ce_agc[0];
+		sc->agc_size = nitems(rtl8192ce_agc);
+		rs->rs_txagc = &rtl8192cu_txagc[0];
+	}
+
+	if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) ==
+		    R92C_CHIP_UMC_A_CUT) {
+		sc->fwname = "rtwn-rtl8192cfwU";
+	} else {
+		sc->fwname = "rtwn-rtl8192cfwT";
+	}
+	sc->fwsig = 0x88c;
+
+	rs->rs_scan_start = ic->ic_scan_start;
+	ic->ic_scan_start = r92c_scan_start;
+	rs->rs_scan_end = ic->ic_scan_end;
+	ic->ic_scan_end = r92c_scan_end;
+}
+
+static void
+r92cu_set_name(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs = sc->sc_priv;
+
+	if (!(rs->chip & R92C_CHIP_92C)) {
+		if (rs->board_type == R92C_BOARD_TYPE_HIGHPA)
+			sc->name = "RTL8188RU";
+		else if (rs->board_type == R92C_BOARD_TYPE_MINICARD)
+			sc->name = "RTL8188CU-VAU";
+		else
+			sc->name = "RTL8188CUS";
+	} else
+		sc->name = "RTL8192CU";
+}
+
+static void
+r92cu_attach_private(struct rtwn_softc *sc)
+{
+	struct r92c_softc *rs;
+
+	rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO);
+
+	rs->rs_txpwr			= &r92c_txpwr;
+
+	rs->rs_set_bw20			= r92c_set_bw20;
+	rs->rs_get_txpower		= r92c_get_txpower;
+	rs->rs_set_gain			= r92c_set_gain;
+	rs->rs_tx_enable_ampdu		= r92c_tx_enable_ampdu;
+	rs->rs_tx_setup_hwseq		= r92c_tx_setup_hwseq;
+	rs->rs_tx_setup_macid		= r92c_tx_setup_macid;
+	rs->rs_set_name			= r92cu_set_name;
+
+#ifndef RTWN_WITHOUT_UCODE
+	rs->rs_c2h_timeout		= hz;
+
+	callout_init_mtx(&rs->rs_c2h_report, &sc->sc_mtx, 0);
+#endif
+
+	rs->rf_read_delay[0]		= 10;
+	rs->rf_read_delay[1]		= 100;
+	rs->rf_read_delay[2]		= 10;
+
+	sc->sc_priv = rs;
+}
+
+static void
+r92cu_adj_devcaps(struct rtwn_softc *sc)
+{
+	/* XXX Currently broken / incomplete. */
+	sc->sc_ic.ic_caps &= ~IEEE80211_C_PMGT;
+}
+
+void
+r92cu_attach(struct rtwn_usb_softc *uc)
+{
+	struct rtwn_softc *sc		= &uc->uc_sc;
+
+	/* USB part. */
+	uc->uc_align_rx			= r92cu_align_rx;
+	uc->tx_agg_desc_num		= 6;
+
+	/* Common part. */
+	sc->sc_flags			= RTWN_FLAG_CAM_FIXED;
+
+	sc->sc_set_chan			= r92c_set_chan;
+	sc->sc_fill_tx_desc		= r92c_fill_tx_desc;
+	sc->sc_fill_tx_desc_raw 	= r92c_fill_tx_desc_raw;
+	sc->sc_fill_tx_desc_null	= r92c_fill_tx_desc_null;
+	sc->sc_dump_tx_desc		= r92cu_dump_tx_desc;
+	sc->sc_tx_radiotap_flags	= r92c_tx_radiotap_flags;
+	sc->sc_rx_radiotap_flags	= r92c_rx_radiotap_flags;
+	sc->sc_get_rssi_cck		= r92c_get_rssi_cck;
+	sc->sc_get_rssi_ofdm		= r92c_get_rssi_ofdm;
+	sc->sc_classify_intr		= r92cu_classify_intr;
+	sc->sc_handle_tx_report		= rtwn_nop_softc_uint8_int;
+	sc->sc_handle_c2h_report	= rtwn_nop_softc_uint8_int;
+	sc->sc_check_frame		= rtwn_nop_int_softc_mbuf;
+	sc->sc_rf_read			= r92c_rf_read;
+	sc->sc_rf_write			= r92c_rf_write;
+	sc->sc_check_condition		= r92c_check_condition;
+	sc->sc_efuse_postread		= r92c_efuse_postread;
+	sc->sc_parse_rom		= r92c_parse_rom;
+	sc->sc_set_led			= r92cu_set_led;
+	sc->sc_power_on			= r92cu_power_on;
+	sc->sc_power_off		= r92cu_power_off;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_fw_reset			= r92c_fw_reset;
+	sc->sc_fw_download_enable	= r92c_fw_download_enable;
+#endif
+	sc->sc_set_page_size		= r92c_set_page_size;
+	sc->sc_lc_calib			= r92c_lc_calib;
+	sc->sc_iq_calib			= r92c_iq_calib;	/* XXX TODO */
+	sc->sc_read_chipid_vendor	= r92c_read_chipid_vendor;
+	sc->sc_adj_devcaps		= r92cu_adj_devcaps;
+	sc->sc_vap_preattach		= rtwn_nop_softc_vap;
+	sc->sc_postattach		= r92cu_postattach;
+	sc->sc_detach_private		= r92c_detach_private;
+	sc->sc_set_media_status		= r92c_joinbss_rpt;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_set_rsvd_page		= r92c_set_rsvd_page;
+	sc->sc_set_pwrmode		= r92c_set_pwrmode;
+	sc->sc_set_rssi			= r92c_set_rssi;
+#endif
+	sc->sc_beacon_init		= r92c_beacon_init;
+	sc->sc_beacon_enable		= r92c_beacon_enable;
+	sc->sc_beacon_set_rate		= rtwn_nop_void_int;
+	sc->sc_beacon_select		= rtwn_nop_softc_int;
+	sc->sc_temp_measure		= r92c_temp_measure;
+	sc->sc_temp_read		= r92c_temp_read;
+	sc->sc_init_tx_agg		= r92cu_init_tx_agg;
+	sc->sc_init_rx_agg		= r92cu_init_rx_agg;
+	sc->sc_init_ampdu		= r92c_init_ampdu;
+	sc->sc_init_intr		= r92cu_init_intr;
+	sc->sc_init_edca		= r92c_init_edca;
+	sc->sc_init_bb			= r92cu_init_bb;
+	sc->sc_init_rf			= r92c_init_rf;
+	sc->sc_init_antsel		= r92c_init_antsel;
+	sc->sc_post_init		= r92cu_post_init;
+	sc->sc_init_bcnq1_boundary	= rtwn_nop_int_softc;
+
+	sc->mac_prog			= &rtl8192cu_mac[0];
+	sc->mac_size			= nitems(rtl8192cu_mac);
+	sc->bb_prog			= &rtl8192cu_bb[0];
+	sc->bb_size			= nitems(rtl8192cu_bb);
+	sc->rf_prog			= &rtl8192c_rf[0];
+
+	sc->page_count			= R92CU_TX_PAGE_COUNT;
+	sc->pktbuf_count		= R92C_TXPKTBUF_COUNT;
+
+	sc->ackto			= 0x40;
+	sc->npubqpages			= R92CU_PUBQ_NPAGES;
+	sc->page_size			= R92C_TX_PAGE_SIZE;
+
+	sc->txdesc_len			= sizeof(struct r92cu_tx_desc);
+	sc->efuse_maxlen		= R92C_EFUSE_MAX_LEN;
+	sc->efuse_maplen		= R92C_EFUSE_MAP_LEN;
+	sc->rx_dma_size			= R92C_RX_DMA_BUFFER_SIZE;
+
+	sc->macid_limit			= R92C_MACID_MAX + 1;
+	sc->cam_entry_limit		= R92C_CAM_ENTRY_COUNT;
+	sc->fwsize_limit		= R92C_MAX_FW_SIZE;
+	sc->temp_delta			= R92C_CALIB_THRESHOLD;
+
+	sc->bcn_status_reg[0]		= R92C_TDECTRL;
+	sc->bcn_status_reg[1]		= R92C_TDECTRL;
+	sc->rcr				= 0;
+
+	r92cu_attach_private(sc);
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,393 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/rtl8192c/r92c_var.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu.h>
+#include <dev/rtwn/rtl8192c/usb/r92cu_reg.h>
+
+
+void
+r92cu_init_bb(struct rtwn_softc *sc)
+{
+
+	/* Enable BB and RF. */
+	rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0,
+	    R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
+	    R92C_SYS_FUNC_EN_DIO_RF);
+
+	rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83);
+
+	rtwn_write_1(sc, R92C_RF_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
+	rtwn_write_1(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD |
+	    R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB);
+
+	rtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f);
+	rtwn_write_1(sc, 0x15, 0xe9);
+	rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80);
+
+	r92c_init_bb_common(sc);
+}
+
+int
+r92cu_power_on(struct rtwn_softc *sc)
+{
+#define RTWN_CHK(res) do {	\
+	if (res != 0)		\
+		return (EIO);	\
+} while(0)
+	uint32_t reg;
+	int ntries;
+
+	/* Wait for autoload done bit. */
+	for (ntries = 0; ntries < 5000; ntries++) {
+		if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN)
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 5000) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for chip autoload\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Unlock ISO/CLK/Power control register. */
+	RTWN_CHK(rtwn_write_1(sc, R92C_RSV_CTRL, 0));
+
+	/* Move SPS into PWM mode. */
+	RTWN_CHK(rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b));
+
+	/* just in case if power_off() was not properly executed. */
+	rtwn_delay(sc, 100);
+
+	reg = rtwn_read_1(sc, R92C_LDOV12D_CTRL);
+	if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) {
+		RTWN_CHK(rtwn_write_1(sc, R92C_LDOV12D_CTRL,
+		    reg | R92C_LDOV12D_CTRL_LDV12_EN));
+
+		rtwn_delay(sc, 100);
+
+		RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL,
+		    R92C_SYS_ISO_CTRL_MD2PP, 0));
+	}
+
+	/* Auto enable WLAN. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0,
+	    R92C_APS_FSMCO_APFM_ONMAC, 1));
+
+	for (ntries = 0; ntries < 5000; ntries++) {
+		if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
+		    R92C_APS_FSMCO_APFM_ONMAC))
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 5000) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for MAC auto ON\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Enable radio, GPIO and LED functions. */
+	RTWN_CHK(rtwn_write_2(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_HSUS |
+	    R92C_APS_FSMCO_PDN_EN |
+	    R92C_APS_FSMCO_PFM_ALDN));
+
+	/* Release RF digital isolation. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_SYS_ISO_CTRL,
+	    R92C_SYS_ISO_CTRL_DIOR, 0, 1));
+
+	/* Initialize MAC. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_APSD_CTRL,
+	    R92C_APSD_CTRL_OFF, 0));
+	for (ntries = 0; ntries < 1000; ntries++) {
+		if (!(rtwn_read_1(sc, R92C_APSD_CTRL) &
+		    R92C_APSD_CTRL_OFF_STATUS))
+			break;
+		rtwn_delay(sc, 50);
+	}
+	if (ntries == 1000) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for MAC initialization\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+	RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN |
+	    R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN |
+	    R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN |
+	    ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) |
+	    R92C_CR_CALTMR_EN));
+
+	RTWN_CHK(rtwn_write_1(sc, 0xfe10, 0x19));
+
+	return (0);
+#undef RTWN_CHK
+}
+
+void
+r92cu_power_off(struct rtwn_softc *sc)
+{
+#ifndef RTWN_WITHOUT_UCODE
+	struct r92c_softc *rs = sc->sc_priv;
+#endif
+	uint32_t reg;
+	int error;
+
+	/* Deinit C2H event handler. */
+#ifndef RTWN_WITHOUT_UCODE
+	callout_stop(&rs->rs_c2h_report);
+	rs->rs_c2h_paused = 0;
+	rs->rs_c2h_pending = 0;
+	rs->rs_c2h_timeout = hz;
+#endif
+
+	/* Block all Tx queues. */
+	error = rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
+	if (error == ENXIO)	/* hardware gone */
+		return;
+
+	/* Disable RF */
+	rtwn_rf_write(sc, 0, 0, 0);
+
+	rtwn_write_1(sc, R92C_APSD_CTRL, R92C_APSD_CTRL_OFF);
+
+	/* Reset BB state machine */
+	rtwn_write_1(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA |
+	    R92C_SYS_FUNC_EN_BB_GLB_RST);
+	rtwn_write_1(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA);
+
+	/*
+	 * Reset digital sequence
+	 */
+#ifndef RTWN_WITHOUT_UCODE
+	if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) {
+		/* Reset MCU ready status */
+		rtwn_write_1(sc, R92C_MCUFWDL, 0);
+
+		/* If firmware in ram code, do reset */
+		r92c_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN);
+	}
+#endif
+
+	/* Reset MAC and Enable 8051 */
+	rtwn_write_1(sc, R92C_SYS_FUNC_EN + 1,
+	    (R92C_SYS_FUNC_EN_CPUEN |
+	     R92C_SYS_FUNC_EN_ELDR |
+	     R92C_SYS_FUNC_EN_HWPDN) >> 8);
+
+	/* Reset MCU ready status */
+	rtwn_write_1(sc, R92C_MCUFWDL, 0);
+
+	/* Disable MAC clock */
+	rtwn_write_2(sc, R92C_SYS_CLKR,
+	    R92C_SYS_CLKR_ANAD16V_EN |
+	    R92C_SYS_CLKR_ANA8M |
+	    R92C_SYS_CLKR_LOADER_EN |
+	    R92C_SYS_CLKR_80M_SSC_DIS |
+	    R92C_SYS_CLKR_SYS_EN |
+	    R92C_SYS_CLKR_RING_EN |
+	    0x4000);
+
+	/* Disable AFE PLL */
+	rtwn_write_1(sc, R92C_AFE_PLL_CTRL, 0x80);
+
+	/* Gated AFE DIG_CLOCK */
+	rtwn_write_2(sc, R92C_AFE_XTAL_CTRL, 0x880F);
+
+	/* Isolated digital to PON */
+	rtwn_write_1(sc, R92C_SYS_ISO_CTRL,
+	    R92C_SYS_ISO_CTRL_MD2PP |
+	    R92C_SYS_ISO_CTRL_PA2PCIE |
+	    R92C_SYS_ISO_CTRL_PD2CORE |
+	    R92C_SYS_ISO_CTRL_IP2MAC |
+	    R92C_SYS_ISO_CTRL_DIOP |
+	    R92C_SYS_ISO_CTRL_DIOE);
+
+	/*
+	 * Pull GPIO PIN to balance level and LED control
+	 */
+	/* 1. Disable GPIO[7:0] */
+	rtwn_write_2(sc, R92C_GPIO_IOSEL, 0x0000);
+
+	reg = rtwn_read_4(sc, R92C_GPIO_PIN_CTRL) & ~0x0000ff00;
+	reg |= ((reg << 8) & 0x0000ff00) | 0x00ff0000;
+	rtwn_write_4(sc, R92C_GPIO_PIN_CTRL, reg);
+
+	/* Disable GPIO[10:8] */
+	rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0x00);
+
+	reg = rtwn_read_2(sc, R92C_GPIO_IO_SEL) & ~0x00f0;
+	reg |= (((reg & 0x000f) << 4) | 0x0780);
+	rtwn_write_2(sc, R92C_GPIO_IO_SEL, reg);
+
+	/* Disable LED0 & 1 */
+	rtwn_write_2(sc, R92C_LEDCFG0, 0x8080);
+
+	/*
+	 * Reset digital sequence
+	 */
+	/* Disable ELDR clock */
+	rtwn_write_2(sc, R92C_SYS_CLKR,
+	    R92C_SYS_CLKR_ANAD16V_EN |
+	    R92C_SYS_CLKR_ANA8M |
+	    R92C_SYS_CLKR_LOADER_EN |
+	    R92C_SYS_CLKR_80M_SSC_DIS |
+	    R92C_SYS_CLKR_SYS_EN |
+	    R92C_SYS_CLKR_RING_EN |
+	    0x4000);
+
+	/* Isolated ELDR to PON */
+	rtwn_write_1(sc, R92C_SYS_ISO_CTRL + 1,
+	    (R92C_SYS_ISO_CTRL_DIOR |
+	     R92C_SYS_ISO_CTRL_PWC_EV12V) >> 8);
+
+	/*
+	 * Disable analog sequence
+	 */
+	/* Disable A15 power */
+	rtwn_write_1(sc, R92C_LDOA15_CTRL, R92C_LDOA15_CTRL_OBUF);
+	/* Disable digital core power */
+	rtwn_setbits_1(sc, R92C_LDOV12D_CTRL,
+	    R92C_LDOV12D_CTRL_LDV12_EN, 0);
+
+	/* Enter PFM mode */
+	rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23);
+
+	/* Set USB suspend */
+	rtwn_write_2(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_APDM_HOST |
+	    R92C_APS_FSMCO_AFSM_HSUS |
+	    R92C_APS_FSMCO_PFM_ALDN);
+
+	/* Lock ISO/CLK/Power control register. */
+	rtwn_write_1(sc, R92C_RSV_CTRL, 0x0E);
+}
+
+void
+r92cu_init_intr(struct rtwn_softc *sc)
+{
+	rtwn_write_4(sc, R92C_HISR, 0xffffffff);
+	rtwn_write_4(sc, R92C_HIMR, 0xffffffff);
+}
+
+void
+r92cu_init_tx_agg(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+	uint32_t reg;
+
+	reg = rtwn_read_4(sc, R92C_TDECTRL);
+	reg = RW(reg, R92C_TDECTRL_BLK_DESC_NUM, uc->tx_agg_desc_num);
+	rtwn_write_4(sc, R92C_TDECTRL, reg);
+}
+
+void
+r92cu_init_rx_agg(struct rtwn_softc *sc)
+{
+
+	/* Rx aggregation (DMA & USB). */
+	rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0,
+	    R92C_TRXDMA_CTRL_RXDMA_AGG_EN);
+	rtwn_setbits_1(sc, R92C_USB_SPECIAL_OPTION, 0,
+	    R92C_USB_SPECIAL_OPTION_AGG_EN);
+
+	/* XXX dehardcode */
+	rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48);
+	rtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4);
+	rtwn_write_1(sc, R92C_USB_AGG_TH, 8);
+	rtwn_write_1(sc, R92C_USB_AGG_TO, 6);
+}
+
+void
+r92cu_post_init(struct rtwn_softc *sc)
+{
+
+	/* Perform LO and IQ calibrations. */
+	r92c_iq_calib(sc);
+	/* Perform LC calibration. */
+	r92c_lc_calib(sc);
+
+	/* Fix USB interference issue. */
+	rtwn_write_1(sc, 0xfe40, 0xe0);
+	rtwn_write_1(sc, 0xfe41, 0x8d);
+	rtwn_write_1(sc, 0xfe42, 0x80);
+
+	r92c_pa_bias_init(sc);
+
+	/* Fix for lower temperature. */
+	rtwn_write_1(sc, 0x15, 0xe9);
+
+#ifndef RTWN_WITHOUT_UCODE
+	if (sc->sc_flags & RTWN_FW_LOADED) {
+		struct r92c_softc *rs = sc->sc_priv;
+
+		if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) {
+			/* XXX firmware RA does not work yet */
+			sc->sc_ratectl = RTWN_RATECTL_NET80211;
+		} else
+			sc->sc_ratectl = sc->sc_ratectl_sysctl;
+
+		/* Start C2H event handling. */
+		callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout,
+		    r92c_handle_c2h_report, sc);
+	} else
+#endif
+		sc->sc_ratectl = RTWN_RATECTL_NONE;
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,68 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu.h>
+
+
+void
+r92cu_set_led(struct rtwn_softc *sc, int led, int on)
+{
+	uint8_t reg;
+
+	if (led == RTWN_LED_LINK) {
+		reg = rtwn_read_1(sc, R92C_LEDCFG0) & 0x70;
+		if (!on)
+			reg |= R92C_LEDCFG0_DIS;
+		rtwn_write_1(sc, R92C_LEDCFG0, reg);
+		sc->ledlink = on;	/* Save LED state. */
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,322 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92CU_PRIV_H
+#define R92CU_PRIV_H
+
+#include <dev/rtwn/rtl8192c/r92c_priv.h>
+
+
+/*
+ * MAC initialization values.
+ */
+static const struct rtwn_mac_prog rtl8192cu_mac[] = {
+	{ 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 },
+	{ 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 },
+	{ 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 },
+	{ 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 },
+	{ 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 },
+	{ 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f },
+	{ 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 },
+	{ 0x45b, 0xb9 }, { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x462, 0x08 },
+	{ 0x463, 0x03 }, { 0x4c8, 0xff }, { 0x4c9, 0x08 }, { 0x4cc, 0xff },
+	{ 0x4cd, 0xff }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 },
+	{ 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 },
+	{ 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 },
+	{ 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 },
+	{ 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a },
+	{ 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 },
+	{ 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x40 }, { 0x547, 0x00 },
+	{ 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, { 0x55a, 0x02 },
+	{ 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a },
+	{ 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0e }, { 0x63e, 0x0a },
+	{ 0x63f, 0x0e }, { 0x66e, 0x05 }, { 0x700, 0x21 }, { 0x701, 0x43 },
+	{ 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 },
+	{ 0x70a, 0x65 }, { 0x70b, 0x87 }
+};
+
+
+/*
+ * Baseband initialization values.
+ */
+static const uint16_t rtl8192cu_bb_regs0_88ru[] = {
+	0x024, 0x028, 0x040, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814,
+	0x818, 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838,
+	0x83c, 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c,
+	0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880,
+	0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904,
+	0x908, 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18,
+	0xa1c, 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04,
+	0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28,
+	0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c,
+	0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70
+}, rtl8192cu_bb_regs0[] = {
+	0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818,
+	0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c,
+	0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860,
+	0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884,
+	0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908,
+	0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c,
+	0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, 0xc08,
+	0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c,
+	0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50,
+	0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70
+}, rtl8192cu_bb_regs1[] = {
+	0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88
+}, rtl8192cu_bb_regs2[] = {
+	0xc8c, 0xc90, 0xc94, 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac,
+	0xcb0, 0xcb4, 0xcb8, 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0,
+	0xcd4, 0xcd8, 0xcdc, 0xce0, 0xce4, 0xce8, 0xcec, 0xd00
+}, rtl8192cu_bb_regs5_88ru[] = {
+	0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84,
+	0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xee8,
+	0xf14, 0xf4c, 0xf00
+};
+
+static const uint32_t rtl8192cu_bb_vals0_88cu[] = {
+	0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00,
+	0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+	0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a,
+	0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200,
+	0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070,
+	0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe,
+	0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+	0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+	0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+	0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+	0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000,
+	0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994,
+	0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f,
+	0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000,
+	0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d
+}, rtl8192cu_bb_vals0_88ru[] = {
+	0x0011800d, 0x00ffdb83, 0x000c0004, 0x80040000, 0x00000001,
+	0x0000fc00, 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385,
+	0x00000000, 0x01000100, 0x00390204, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x569a569a, 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000,
+	0x32323200, 0x03000300, 0x22004000, 0x00000808, 0x00ffc3f1,
+	0xc0083070, 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800,
+	0xfffffffe, 0x40302010, 0x00706050, 0x00000000, 0x00000023,
+	0x00000000, 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300,
+	0x2e68120f, 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00,
+	0x15160000, 0x070b0f12, 0x00000104, 0x00d30000, 0x101fbf00,
+	0x00000007, 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c,
+	0x08800000, 0x40000100, 0x08800000, 0x40000100, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf,
+	0x49795994, 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107,
+	0x007f037f, 0x6954342e, 0x43bc0094, 0x6954342f, 0x433c0094,
+	0x00000000, 0x5116848b, 0x47c00bff, 0x00000036, 0x2c56000d
+}, rtl8192cu_bb_vals0_92ce_92cu[] = {
+	0x0011800d, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00,
+	0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+	0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727,
+	0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000,
+	0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a,
+	0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27,
+	0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070,
+	0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe,
+	0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+	0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+	0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+	0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+	0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000,
+	0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994,
+	0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f,
+	0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000,
+	0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d
+}, rtl8192cu_bb_vals1_88ru[] = {
+	0x018610db, 0x0000001f, 0x00b91612, 0x24000090, 0x20f60000,
+	0x24000090
+}, rtl8192cu_bb_vals1_92cu[] = {
+	0x0186115b, 0x0000001f, 0x00b99612, 0x40000100, 0x20f60000,
+	0x40000100
+}, rtl8192cu_bb_vals1_88cu_92ce[] = {
+	0x018610db, 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000,
+	0x40000100
+}, rtl8192cu_bb_vals2[] = {
+	0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f,
+	0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427,
+	0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c,
+	0x00080740
+}, rtl8192cu_bb_vals5_88cu[] = {
+	0x00000008, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0,
+	0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0,
+	0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0,
+	0x001b25a0, 0x6b1b25a0, 0x00000003, 0x00000000, 0x00000300
+}, rtl8192cu_bb_vals5_88ru[] = {
+	0x00000010, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0,
+	0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0,
+	0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0,
+	0x001b25a0, 0x6b1b25a0, 0x31555448, 0x00000003, 0x00000000,
+	0x00000300
+};
+
+static const struct rtwn_bb_prog rtl8192cu_bb[] = {
+	/* RTL8188CE / RTL8188CU. */
+	{
+		nitems(rtl8192cu_bb_regs0),
+		rtl8192cu_bb_regs0,
+		rtl8192cu_bb_vals0_88cu,
+		{ R92C_COND_RTL8188CU | R92C_COND_RTL8188CE },
+		/* RTL8188RU. */
+		&(const struct rtwn_bb_prog){
+			nitems(rtl8192cu_bb_regs0_88ru),
+			rtl8192cu_bb_regs0_88ru,
+			rtl8192cu_bb_vals0_88ru,
+			{ R92C_COND_RTL8188RU },
+			/* Others. */
+			&(const struct rtwn_bb_prog){
+				nitems(rtl8192cu_bb_regs0),
+				rtl8192cu_bb_regs0,
+				rtl8192cu_bb_vals0_92ce_92cu,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	/* RTL8188RU. */
+	{
+		nitems(rtl8192cu_bb_regs1),
+		rtl8192cu_bb_regs1,
+		rtl8192cu_bb_vals1_88ru,
+		{ R92C_COND_RTL8188RU },
+		/* RTL8192CU. */
+		&(const struct rtwn_bb_prog){
+			nitems(rtl8192cu_bb_regs1),
+			rtl8192cu_bb_regs1,
+			rtl8192cu_bb_vals1_92cu,
+			{ R92C_COND_RTL8192CU },
+			/* Others. */
+			&(const struct rtwn_bb_prog){
+				nitems(rtl8192cu_bb_regs1),
+				rtl8192cu_bb_regs1,
+				rtl8192cu_bb_vals1_88cu_92ce,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	{
+		nitems(rtl8192cu_bb_regs2),
+		rtl8192cu_bb_regs2,
+		rtl8192cu_bb_vals2,
+		{ 0 },
+		NULL
+	},
+	/* RTL8192CE / RTL8192CU. */
+	{
+		nitems(rtl8192c_bb_regs3),
+		rtl8192c_bb_regs3,
+		rtl8192c_bb_vals3_92ce_92cu,
+		{ R92C_COND_RTL8192C },
+		/* Others. */
+		&(const struct rtwn_bb_prog){
+			nitems(rtl8192c_bb_regs3),
+			rtl8192c_bb_regs3,
+			rtl8192c_bb_vals3_88cu_88ru,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8192c_bb_regs4),
+		rtl8192c_bb_regs4,
+		rtl8192c_bb_vals4,
+		{ 0 },
+		NULL
+	},
+	/* RTL8188CE / RTL8188CU. */
+	{
+		nitems(rtl8192c_bb_regs5),
+		rtl8192c_bb_regs5,
+		rtl8192cu_bb_vals5_88cu,
+		{ R92C_COND_RTL8188CU | R92C_COND_RTL8188CE },
+		/* RTL8188RU. */
+		&(const struct rtwn_bb_prog){
+			nitems(rtl8192cu_bb_regs5_88ru),
+			rtl8192cu_bb_regs5_88ru,
+			rtl8192cu_bb_vals5_88ru,
+			{ R92C_COND_RTL8188RU },
+			/* Others. */
+			&(const struct rtwn_bb_prog){
+				nitems(rtl8192c_bb_regs5),
+				rtl8192c_bb_regs5,
+				rtl8192c_bb_vals5_92ce_92cu,
+				{ 0 },
+				NULL
+			}
+		}
+	}
+};
+
+
+static const uint32_t rtl8188ru_agc_vals[] = {
+	0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001,
+	0x7b050001, 0x7b060001, 0x7b070001, 0x7b080001, 0x7a090001,
+	0x790a0001, 0x780b0001, 0x770c0001, 0x760d0001, 0x750e0001,
+	0x740f0001, 0x73100001, 0x72110001, 0x71120001, 0x70130001,
+	0x6f140001, 0x6e150001, 0x6d160001, 0x6c170001, 0x6b180001,
+	0x6a190001, 0x691a0001, 0x681b0001, 0x671c0001, 0x661d0001,
+	0x651e0001, 0x641f0001, 0x63200001, 0x62210001, 0x61220001,
+	0x60230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001,
+	0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001,
+	0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001,
+	0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001,
+	0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001,
+	0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001,
+	0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001,
+	0x7b460001, 0x7b470001, 0x7b480001, 0x7a490001, 0x794a0001,
+	0x784b0001, 0x774c0001, 0x764d0001, 0x754e0001, 0x744f0001,
+	0x73500001, 0x72510001, 0x71520001, 0x70530001, 0x6f540001,
+	0x6e550001, 0x6d560001, 0x6c570001, 0x6b580001, 0x6a590001,
+	0x695a0001, 0x685b0001, 0x675c0001, 0x665d0001, 0x655e0001,
+	0x645f0001, 0x63600001, 0x62610001, 0x61620001, 0x60630001,
+	0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001,
+	0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001,
+	0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001,
+	0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001,
+	0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001,
+	0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e,
+	0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e,
+	0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e,
+	0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e,
+	0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e,
+	0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e,
+	0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e
+};
+
+static const struct rtwn_agc_prog rtl8188ru_agc[] = {
+	{
+		nitems(rtl8188ru_agc_vals),
+		rtl8188ru_agc_vals,
+		{ 0 },
+		NULL
+	}
+};
+
+#endif	/* R92CU_PRIV_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92CU_REG_H
+#define R92CU_REG_H
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+
+/*
+ * MAC registers.
+ */
+/* System Configuration. */
+#define R92C_USB_SIE_INTF		0x0e0
+
+
+/*
+ * USB registers.
+ */
+#define R92C_USB_SUSPEND		0xfe10
+#define R92C_USB_INFO			0xfe17
+#define R92C_USB_SPECIAL_OPTION		0xfe55
+#define R92C_USB_HCPWM			0xfe57
+#define R92C_USB_HRPWM			0xfe58
+#define R92C_USB_DMA_AGG_TO		0xfe5b
+#define R92C_USB_AGG_TO			0xfe5c
+#define R92C_USB_AGG_TH			0xfe5d
+#define R92C_USB_VID			0xfe60
+#define R92C_USB_PID			0xfe62
+#define R92C_USB_OPTIONAL		0xfe64
+#define R92C_USB_EP			0xfe65
+#define R92C_USB_PHY			0xfe68
+#define R92C_USB_MAC_ADDR		0xfe70
+#define R92C_USB_STRING			0xfe80
+
+/* Bits for R92C_USB_SPECIAL_OPTION. */
+#define R92C_USB_SPECIAL_OPTION_AGG_EN		0x08
+#define R92C_USB_SPECIAL_OPTION_INT_BULK_SEL	0x10
+
+/* Bits for R92C_USB_EP. */
+#define R92C_USB_EP_HQ_M	0x000f
+#define R92C_USB_EP_HQ_S	0
+#define R92C_USB_EP_NQ_M	0x00f0
+#define R92C_USB_EP_NQ_S	4
+#define R92C_USB_EP_LQ_M	0x0f00
+#define R92C_USB_EP_LQ_S	8
+
+#endif	/* R92CU_REG_H */
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,65 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu.h>
+
+
+int
+r92cu_classify_intr(struct rtwn_softc *sc, void *buf, int len)
+{
+	/* NB: reports are fetched from C2H_MSG register. */
+	return (RTWN_RX_DATA);
+}
+
+int
+r92cu_align_rx(int totlen, int len)
+{
+	return (roundup2(totlen, 128));
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,66 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu.h>
+#include <dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h>
+
+
+void
+r92cu_dump_tx_desc(struct rtwn_softc *sc, const void *desc)
+{
+#ifdef RTWN_DEBUG
+	const struct r92cu_tx_desc *txd = desc;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC,
+	    "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %04X "
+	    "(seq %04X), 4 %08X, 5 %08X, 6 %08X, sum %04X, pad %04X\n",
+	    __func__, le16toh(txd->pktlen), txd->offset, txd->flags0,
+	    le32toh(txd->txdw1), le32toh(txd->txdw2), le16toh(txd->txdw3),
+	    le16toh(txd->txdseq), le32toh(txd->txdw4), le32toh(txd->txdw5),
+	    le32toh(txd->txdw6), le16toh(txd->txdsum), le16toh(txd->pad));
+#endif
+}
Index: freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef R92CU_TX_DESC_H
+#define R92CU_TX_DESC_H
+
+#include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
+
+/* Tx MAC descriptor (USB). */
+struct r92cu_tx_desc {
+	uint16_t 	pktlen;
+	uint8_t		offset;
+	uint8_t		flags0;
+
+	uint32_t	txdw1;
+	uint32_t	txdw2;
+	uint16_t	txdw3;
+	uint16_t	txdseq;
+
+	uint32_t	txdw4;
+	uint32_t	txdw5;
+	uint32_t	txdw6;
+
+	uint16_t	txdsum;
+	uint16_t	pad;
+} __packed __attribute__((aligned(4)));
+
+#endif	/* R92CU_TX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTL8812A_H
+#define RTL8812A_H
+
+/*
+ * Global definitions.
+ */
+#define R12A_PUBQ_NPAGES	219
+#define R12A_TXPKTBUF_COUNT	255
+#define R12A_TX_PAGE_COUNT	248
+
+#define R12A_TX_PAGE_SIZE	512
+#define R12A_RX_DMA_BUFFER_SIZE	0x3e80
+
+#define R12A_MAX_FW_SIZE	0x8000
+#define R12A_MACID_MAX		127
+#define R12A_CAM_ENTRY_COUNT	64
+
+#define	R12A_INTR_MSG_LEN	60
+
+static const uint8_t r12a_chan_5ghz_0[] =
+	{ 36, 40, 44, 48, 52, 56, 60, 64 };
+static const uint8_t r12a_chan_5ghz_1[] =
+	{ 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144 };
+static const uint8_t r12a_chan_5ghz_2[] =
+	{ 149, 153, 157, 161, 165, 169, 173, 177 };
+
+
+/*
+ * Function declarations.
+ */
+/* r12a_attach.c */
+void	r12a_vap_preattach(struct rtwn_softc *, struct ieee80211vap *);
+void	r12a_detach_private(struct rtwn_softc *);
+
+/* r12a_beacon.c */
+void	r12a_beacon_init(struct rtwn_softc *, void *, int);
+void	r12a_beacon_set_rate(void *, int);
+
+/* r12a_calib.c */
+void	r12a_save_bb_afe_vals(struct rtwn_softc *, uint32_t[],
+	    const uint16_t[], int);
+void	r12a_restore_bb_afe_vals(struct rtwn_softc *, uint32_t[],
+	    const uint16_t[], int);
+void	r12a_save_rf_vals(struct rtwn_softc *, uint32_t[],
+	    const uint8_t[], int);
+void	r12a_restore_rf_vals(struct rtwn_softc *, uint32_t[],
+	    const uint8_t[], int);
+void	r12a_lc_calib(struct rtwn_softc *);
+#ifndef RTWN_WITHOUT_UCODE
+int	r12a_iq_calib_fw_supported(struct rtwn_softc *);
+#endif
+void	r12a_iq_calib_sw(struct rtwn_softc *);
+void	r12a_iq_calib(struct rtwn_softc *);
+
+/* r12a_caps.c */
+int	r12a_ioctl_net(struct ieee80211com *, u_long, void *);
+
+/* r12a_chan.c */
+void	r12a_fix_spur(struct rtwn_softc *, struct ieee80211_channel *);
+void	r12a_set_chan(struct rtwn_softc *, struct ieee80211_channel *);
+void	r12a_set_band_2ghz(struct rtwn_softc *, uint32_t);
+void	r12a_set_band_5ghz(struct rtwn_softc *, uint32_t);
+
+/* r12a_fw.c */
+#ifndef RTWN_WITHOUT_UCODE
+void	r12a_fw_reset(struct rtwn_softc *, int);
+void	r12a_fw_download_enable(struct rtwn_softc *, int);
+void	r12a_set_media_status(struct rtwn_softc *, int);
+int	r12a_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *,
+	    int);
+void	r12a_iq_calib_fw(struct rtwn_softc *);
+#endif
+
+/* r12a_init.c */
+int	r12a_check_condition(struct rtwn_softc *, const uint8_t[]);
+int	r12a_set_page_size(struct rtwn_softc *);
+void	r12a_init_edca(struct rtwn_softc *);
+void	r12a_init_bb(struct rtwn_softc *);
+void	r12a_init_rf(struct rtwn_softc *);
+void	r12a_crystalcap_write(struct rtwn_softc *);
+int	r12a_power_on(struct rtwn_softc *);
+void	r12a_power_off(struct rtwn_softc *);
+void	r12a_init_intr(struct rtwn_softc *);
+void	r12a_init_antsel(struct rtwn_softc *);
+
+/* r12a_led.c */
+void	r12a_set_led(struct rtwn_softc *, int, int);
+
+/* r12a_rf.c */
+uint32_t	r12a_rf_read(struct rtwn_softc *, int, uint8_t);
+uint32_t	r12a_c_cut_rf_read(struct rtwn_softc *, int, uint8_t);
+void		r12a_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t);
+
+/* r12a_rom.c */
+void	r12a_parse_rom_common(struct rtwn_softc *, uint8_t *);
+void	r12a_parse_rom(struct rtwn_softc *, uint8_t *);
+
+/* r12a_rx.c */
+void	r12a_ratectl_tx_complete(struct rtwn_softc *, uint8_t *, int);
+void	r12a_handle_c2h_report(struct rtwn_softc *, uint8_t *, int);
+int	r12a_check_frame_checksum(struct rtwn_softc *, struct mbuf *);
+uint8_t	r12a_rx_radiotap_flags(const void *);
+
+/* r12a_tx.c */
+void	r12a_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *,
+	    struct mbuf *, void *, uint8_t, int);
+void	r12a_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *,
+	    struct mbuf *, void *, const struct ieee80211_bpf_params *);
+void	r12a_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int);
+uint8_t	r12a_tx_radiotap_flags(const void *);
+
+#endif	/* RTL8812A_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,96 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_ridx.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+#include <dev/rtwn/rtl8812a/r12a_tx_desc.h>
+
+
+void
+r12a_beacon_init(struct rtwn_softc *sc, void *buf, int id)
+{
+	struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
+
+	txd->flags0 = R12A_FLAGS0_LSG | R12A_FLAGS0_FSG | R12A_FLAGS0_BMCAST;
+
+	/*
+	 * NB: there is no need to setup HWSEQ_EN bit;
+	 * QSEL_BEACON already implies it.
+	 */
+	txd->txdw1 = htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_BEACON));
+	txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC));
+
+	txd->txdw3 = htole32(R12A_TXDW3_DRVRATE);
+	txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id));
+
+	txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id));
+}
+
+void
+r12a_beacon_set_rate(void *buf, int is5ghz)
+{
+	struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
+
+	txd->txdw4 &= ~htole32(R12A_TXDW4_DATARATE_M);
+	if (is5ghz) {
+		txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE,
+		    RTWN_RIDX_OFDM6));
+	} else
+		txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, RTWN_RIDX_CCK1));
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,288 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_priv.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+
+void
+r12a_lc_calib(struct rtwn_softc *sc)
+{
+	uint32_t chnlbw;
+	uint8_t txmode;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
+	    "%s: LC calibration started\n", __func__);
+
+	txmode = rtwn_read_1(sc, R12A_SINGLETONE_CONT_TX + 2);
+
+	if ((txmode & 0x07) != 0) {
+		/* Disable all continuous Tx. */
+		/*
+		 * Skipped because BB turns off continuous Tx until
+		 * next packet comes in.
+		 */
+	} else {
+		/* Block all Tx queues. */
+		rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
+	}
+
+	/* Enter LCK mode. */
+	rtwn_rf_setbits(sc, 0, R12A_RF_LCK, 0, R12A_RF_LCK_MODE);
+
+	/* Start calibration. */
+	chnlbw = rtwn_rf_read(sc, 0, R92C_RF_CHNLBW);
+	rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, chnlbw | R92C_RF_CHNLBW_LCSTART);
+
+	/* Give calibration the time to complete. */
+	rtwn_delay(sc, 150000);	/* 150 ms */
+
+	/* Leave LCK mode. */
+	rtwn_rf_setbits(sc, 0, R12A_RF_LCK, R12A_RF_LCK_MODE, 0);
+
+	/* Restore configuration. */
+	if ((txmode & 0x07) != 0) {
+		/* Continuous Tx case. */
+		/*
+		 * Skipped because BB turns off continuous Tx until
+		 * next packet comes in.
+		 */
+	} else {
+		/* Unblock all Tx queues. */
+		rtwn_write_1(sc, R92C_TXPAUSE, 0);
+	}
+
+	/* Recover channel number. */
+	rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, chnlbw);
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
+	    "%s: LC calibration finished\n", __func__);
+}
+
+#ifndef RTWN_WITHOUT_UCODE
+int
+r12a_iq_calib_fw_supported(struct rtwn_softc *sc)
+{
+	if (sc->fwver == 0x19)
+		return (1);
+
+	return (0);
+}
+#endif
+
+void
+r12a_save_bb_afe_vals(struct rtwn_softc *sc, uint32_t vals[],
+    const uint16_t regs[], int size)
+{
+	int i;
+
+	/* Select page C. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0);
+
+	for (i = 0; i < size; i++)
+		vals[i] = rtwn_bb_read(sc, regs[i]);
+}
+
+void
+r12a_restore_bb_afe_vals(struct rtwn_softc *sc, uint32_t vals[],
+    const uint16_t regs[], int size)
+{
+	int i;
+
+	/* Select page C. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0);
+
+	for (i = 0; i < size; i++)
+		rtwn_bb_write(sc, regs[i], vals[i]);
+}
+
+void
+r12a_save_rf_vals(struct rtwn_softc *sc, uint32_t vals[],
+    const uint8_t regs[], int size)
+{
+	int c, i;
+
+	/* Select page C. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0);
+
+	for (c = 0; c < sc->nrxchains; c++)
+		for (i = 0; i < size; i++)
+			vals[c * size + i] = rtwn_rf_read(sc, c, regs[i]);
+}
+
+void
+r12a_restore_rf_vals(struct rtwn_softc *sc, uint32_t vals[],
+    const uint8_t regs[], int size)
+{
+	int c, i;
+
+	/* Select page C. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0);
+
+	for (c = 0; c < sc->nrxchains; c++)
+		for (i = 0; i < size; i++)
+			rtwn_rf_write(sc, c, regs[i], vals[c * size + i]);
+}
+
+#ifdef RTWN_TODO
+static void
+r12a_iq_tx(struct rtwn_softc *sc)
+{
+	/* TODO */
+}
+
+static void
+r12a_iq_config_mac(struct rtwn_softc *sc)
+{
+
+	/* Select page C. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0);
+	rtwn_write_1(sc, R92C_TXPAUSE,
+	    R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH);
+	/* BCN_CTRL & BCN_CTRL1 */
+	rtwn_setbits_1(sc, R92C_BCN_CTRL(0), R92C_BCN_CTRL_EN_BCN, 0);
+	rtwn_setbits_1(sc, R92C_BCN_CTRL(1), R92C_BCN_CTRL_EN_BCN, 0);
+	/* Rx ant off */
+	rtwn_write_1(sc, R12A_OFDMCCK_EN, 0);
+	/* CCA off */
+	rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0x03, 0x0c);
+	/* CCK RX Path off */
+	rtwn_write_1(sc, R12A_CCK_RX_PATH + 3, 0x0f);
+}
+#endif
+
+void
+r12a_iq_calib_sw(struct rtwn_softc *sc)
+{
+#define R12A_MAX_NRXCHAINS	2
+	uint32_t bb_vals[nitems(r12a_iq_bb_regs)];
+	uint32_t afe_vals[nitems(r12a_iq_afe_regs)];
+	uint32_t rf_vals[nitems(r12a_iq_rf_regs) * R12A_MAX_NRXCHAINS];
+	uint32_t rfe[2];
+
+	KASSERT(sc->nrxchains <= R12A_MAX_NRXCHAINS,
+	    ("nrxchains > %d (%d)\n", R12A_MAX_NRXCHAINS, sc->nrxchains));
+
+	/* Save registers. */
+	r12a_save_bb_afe_vals(sc, bb_vals, r12a_iq_bb_regs,
+	    nitems(r12a_iq_bb_regs));
+
+	/* Select page C1. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000);
+	rfe[0] = rtwn_bb_read(sc, R12A_RFE(0));
+	rfe[1] = rtwn_bb_read(sc, R12A_RFE(1));
+
+	r12a_save_bb_afe_vals(sc, afe_vals, r12a_iq_afe_regs,
+	    nitems(r12a_iq_afe_regs));
+	r12a_save_rf_vals(sc, rf_vals, r12a_iq_rf_regs,
+	    nitems(r12a_iq_rf_regs));
+
+#ifdef RTWN_TODO
+	/* Configure MAC. */
+	rtwn_iq_config_mac(sc);
+	rtwn_iq_tx(sc);
+#endif
+
+	r12a_restore_rf_vals(sc, rf_vals, r12a_iq_rf_regs,
+	    nitems(r12a_iq_rf_regs));
+	r12a_restore_bb_afe_vals(sc, afe_vals, r12a_iq_afe_regs,
+	    nitems(r12a_iq_afe_regs));
+
+	/* Select page C1. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000);
+
+	/* Chain 0. */
+	rtwn_bb_write(sc, R12A_SLEEP_NAV(0), 0);
+	rtwn_bb_write(sc, R12A_PMPD(0), 0);
+	rtwn_bb_write(sc, 0xc88, 0);
+	rtwn_bb_write(sc, 0xc8c, 0x3c000000);
+	rtwn_bb_setbits(sc, 0xc90, 0, 0x00000080);
+	rtwn_bb_setbits(sc, 0xcc4, 0, 0x20040000);
+	rtwn_bb_setbits(sc, 0xcc8, 0, 0x20000000);
+
+	/* Chain 1. */
+	rtwn_bb_write(sc, R12A_SLEEP_NAV(1), 0);
+	rtwn_bb_write(sc, R12A_PMPD(1), 0);
+	rtwn_bb_write(sc, 0xe88, 0);
+	rtwn_bb_write(sc, 0xe8c, 0x3c000000);
+	rtwn_bb_setbits(sc, 0xe90, 0, 0x00000080);
+	rtwn_bb_setbits(sc, 0xec4, 0, 0x20040000);
+	rtwn_bb_setbits(sc, 0xec8, 0, 0x20000000);
+
+	rtwn_bb_write(sc, R12A_RFE(0), rfe[0]);
+	rtwn_bb_write(sc, R12A_RFE(1), rfe[1]);
+
+	r12a_restore_bb_afe_vals(sc, bb_vals, r12a_iq_bb_regs,
+	    nitems(r12a_iq_bb_regs));
+#undef R12A_MAX_NRXCHAINS
+}
+
+void
+r12a_iq_calib(struct rtwn_softc *sc)
+{
+#ifndef RTWN_WITHOUT_UCODE
+	if ((sc->sc_flags & RTWN_FW_LOADED) &&
+	    rtwn_r12a_iq_calib_fw_supported(sc))
+		r12a_iq_calib_fw(sc);
+	else
+#endif
+		rtwn_r12a_iq_calib_sw(sc);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,122 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/sockio.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_rx.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+
+int
+r12a_ioctl_net(struct ieee80211com *ic, u_long cmd, void *data)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct r12a_softc *rs = sc->sc_priv;
+	struct ifreq *ifr = (struct ifreq *)data;
+	int error;
+
+	error = 0;
+	switch (cmd) {
+	case SIOCSIFCAP:
+	{
+		struct ieee80211vap *vap;
+		int changed, rxmask;
+
+		rxmask = ifr->ifr_reqcap & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
+
+		RTWN_LOCK(sc);
+		changed = 0;
+		if (!(rs->rs_flags & R12A_RXCKSUM_EN) ^
+		    !(ifr->ifr_reqcap & IFCAP_RXCSUM)) {
+			rs->rs_flags ^= R12A_RXCKSUM_EN;
+			changed = 1;
+		}
+		if (!(rs->rs_flags & R12A_RXCKSUM6_EN) ^
+		    !(ifr->ifr_reqcap & IFCAP_RXCSUM_IPV6)) {
+			rs->rs_flags ^= R12A_RXCKSUM6_EN;
+			changed = 1;
+		}
+		if (changed) {
+			if (rxmask == 0)
+				sc->rcr &= ~R12A_RCR_TCP_OFFLD_EN;
+			else
+				sc->rcr |= R12A_RCR_TCP_OFFLD_EN;
+
+			if (sc->sc_flags & RTWN_RUNNING)
+				rtwn_rxfilter_set(sc);
+		}
+		RTWN_UNLOCK(sc);
+
+		IEEE80211_LOCK(ic);	/* XXX */
+		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+			struct ifnet *ifp = vap->iv_ifp;
+
+			ifp->if_capenable &=
+			    ~(IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
+			ifp->if_capenable |= rxmask;
+		}
+		IEEE80211_UNLOCK(ic);
+		break;
+	}
+	default:
+		error = ENOTTY;		/* for net80211 */
+		break;
+	}
+
+	return (error);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,603 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_rx.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+
+static void
+r12a_write_txpower(struct rtwn_softc *sc, int chain,
+    struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT])
+{
+
+	if (IEEE80211_IS_CHAN_2GHZ(c)) {
+		/* Write per-CCK rate Tx power. */
+		rtwn_bb_write(sc, R12A_TXAGC_CCK11_1(chain),
+		    SM(R12A_TXAGC_CCK1,  power[RTWN_RIDX_CCK1]) |
+		    SM(R12A_TXAGC_CCK2,  power[RTWN_RIDX_CCK2]) |
+		    SM(R12A_TXAGC_CCK55, power[RTWN_RIDX_CCK55]) |
+		    SM(R12A_TXAGC_CCK11, power[RTWN_RIDX_CCK11]));
+	}
+
+	/* Write per-OFDM rate Tx power. */
+	rtwn_bb_write(sc, R12A_TXAGC_OFDM18_6(chain),
+	    SM(R12A_TXAGC_OFDM06, power[RTWN_RIDX_OFDM6]) |
+	    SM(R12A_TXAGC_OFDM09, power[RTWN_RIDX_OFDM9]) |
+	    SM(R12A_TXAGC_OFDM12, power[RTWN_RIDX_OFDM12]) |
+	    SM(R12A_TXAGC_OFDM18, power[RTWN_RIDX_OFDM18]));
+	rtwn_bb_write(sc, R12A_TXAGC_OFDM54_24(chain),
+	    SM(R12A_TXAGC_OFDM24, power[RTWN_RIDX_OFDM24]) |
+	    SM(R12A_TXAGC_OFDM36, power[RTWN_RIDX_OFDM36]) |
+	    SM(R12A_TXAGC_OFDM48, power[RTWN_RIDX_OFDM48]) |
+	    SM(R12A_TXAGC_OFDM54, power[RTWN_RIDX_OFDM54]));
+	/* Write per-MCS Tx power. */
+	rtwn_bb_write(sc, R12A_TXAGC_MCS3_0(chain),
+	    SM(R12A_TXAGC_MCS0, power[RTWN_RIDX_MCS(0)]) |
+	    SM(R12A_TXAGC_MCS1, power[RTWN_RIDX_MCS(1)]) |
+	    SM(R12A_TXAGC_MCS2, power[RTWN_RIDX_MCS(2)]) |
+	    SM(R12A_TXAGC_MCS3, power[RTWN_RIDX_MCS(3)]));
+	rtwn_bb_write(sc, R12A_TXAGC_MCS7_4(chain),
+	    SM(R12A_TXAGC_MCS4, power[RTWN_RIDX_MCS(4)]) |
+	    SM(R12A_TXAGC_MCS5, power[RTWN_RIDX_MCS(5)]) |
+	    SM(R12A_TXAGC_MCS6, power[RTWN_RIDX_MCS(6)]) |
+	    SM(R12A_TXAGC_MCS7, power[RTWN_RIDX_MCS(7)]));
+	if (sc->ntxchains >= 2) {
+		rtwn_bb_write(sc, R12A_TXAGC_MCS11_8(chain),
+		    SM(R12A_TXAGC_MCS8,  power[RTWN_RIDX_MCS(8)]) |
+		    SM(R12A_TXAGC_MCS9,  power[RTWN_RIDX_MCS(9)]) |
+		    SM(R12A_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) |
+		    SM(R12A_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)]));
+		rtwn_bb_write(sc, R12A_TXAGC_MCS15_12(chain),
+		    SM(R12A_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) |
+		    SM(R12A_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) |
+		    SM(R12A_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) |
+		    SM(R12A_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)]));
+	}
+
+	/* TODO: VHT rates */
+}
+
+static int
+r12a_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	uint8_t chan;
+	int group;
+
+	chan = rtwn_chan2centieee(c);
+	if (IEEE80211_IS_CHAN_2GHZ(c)) {
+		if (chan <= 2)			group = 0;
+		else if (chan <= 5)		group = 1;
+		else if (chan <= 8)		group = 2;
+		else if (chan <= 11)		group = 3;
+		else if (chan <= 14)		group = 4;
+		else {
+			KASSERT(0, ("wrong 2GHz channel %d!\n", chan));
+			return (-1);
+		}
+	} else if (IEEE80211_IS_CHAN_5GHZ(c)) {
+		if (chan < 36)
+			return (-1);
+
+		if (chan <= 42)			group = 0;
+		else if (chan <= 48)		group = 1;
+		else if (chan <= 58)		group = 2;
+		else if (chan <= 64)		group = 3;
+		else if (chan <= 106)		group = 4;
+		else if (chan <= 114)		group = 5;
+		else if (chan <= 122)		group = 6;
+		else if (chan <= 130)		group = 7;
+		else if (chan <= 138)		group = 8;
+		else if (chan <= 144)		group = 9;
+		else if (chan <= 155)		group = 10;
+		else if (chan <= 161)		group = 11;
+		else if (chan <= 171)		group = 12;
+		else if (chan <= 177)		group = 13;
+		else {
+			KASSERT(0, ("wrong 5GHz channel %d!\n", chan));
+			return (-1);
+		}
+	} else {
+		KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags));
+		return (-1);
+	}
+
+	return (group);
+}
+
+static void
+r12a_get_txpower(struct rtwn_softc *sc, int chain,
+    struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT])
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	int i, ridx, group, max_mcs;
+
+	/* Determine channel group. */
+	group = r12a_get_power_group(sc, c);
+	if (group == -1) {	/* shouldn't happen */
+		device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__);
+		return;
+	}
+
+	/* TODO: VHT rates. */
+	max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1);
+
+	/* XXX regulatory */
+	/* XXX net80211 regulatory */
+
+	if (IEEE80211_IS_CHAN_2GHZ(c)) {
+		for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
+			power[ridx] = rs->cck_tx_pwr[chain][group];
+		for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++)
+			power[ridx] = rs->ht40_tx_pwr_2g[chain][group];
+
+		for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++)
+			power[ridx] += rs->ofdm_tx_pwr_diff_2g[chain][0];
+
+		for (i = 0; i < sc->ntxchains; i++) {
+			uint8_t min_mcs;
+			uint8_t pwr_diff;
+
+#ifdef notyet
+			if (IEEE80211_IS_CHAN_HT80(c)) {
+				/* Vendor driver uses HT40 values here. */
+				pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i];
+			} else
+#endif
+			if (IEEE80211_IS_CHAN_HT40(c))
+				pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i];
+			else
+				pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i];
+
+			min_mcs = RTWN_RIDX_MCS(i * 8);
+			for (ridx = min_mcs; ridx <= max_mcs; ridx++)
+				power[ridx] += pwr_diff;
+		}
+	} else {	/* 5GHz */
+		for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++)
+			power[ridx] = rs->ht40_tx_pwr_5g[chain][group];
+
+		for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++)
+			power[ridx] += rs->ofdm_tx_pwr_diff_5g[chain][0];
+
+		for (i = 0; i < sc->ntxchains; i++) {
+			uint8_t min_mcs;
+			uint8_t pwr_diff;
+
+#ifdef notyet
+			if (IEEE80211_IS_CHAN_HT80(c)) {
+				/* TODO: calculate base value. */
+				pwr_diff = rs->bw80_tx_pwr_diff_5g[chain][i];
+			} else
+#endif
+			if (IEEE80211_IS_CHAN_HT40(c))
+				pwr_diff = rs->bw40_tx_pwr_diff_5g[chain][i];
+			else
+				pwr_diff = rs->bw20_tx_pwr_diff_5g[chain][i];
+
+			min_mcs = RTWN_RIDX_MCS(i * 8);
+			for (ridx = min_mcs; ridx <= max_mcs; ridx++)
+				power[ridx] += pwr_diff;
+		}
+	}
+
+	/* Apply max limit. */
+	for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) {
+		if (power[ridx] > R92C_MAX_TX_PWR)
+			power[ridx] = R92C_MAX_TX_PWR;
+	}
+
+#ifdef RTWN_DEBUG
+	if (sc->sc_debug & RTWN_DEBUG_TXPWR) {
+		/* Dump per-rate Tx power values. */
+		printf("Tx power for chain %d:\n", chain);
+		for (ridx = RTWN_RIDX_CCK1; ridx < RTWN_RIDX_COUNT; ridx++)
+			printf("Rate %d = %u\n", ridx, power[ridx]);
+	}
+#endif
+}
+
+static void
+r12a_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	uint8_t power[RTWN_RIDX_COUNT];
+	int i;
+
+	for (i = 0; i < sc->ntxchains; i++) {
+		memset(power, 0, sizeof(power));
+		/* Compute per-rate Tx power values. */
+		r12a_get_txpower(sc, i, c, power);
+		/* Write per-rate Tx power values to hardware. */
+		r12a_write_txpower(sc, i, c, power);
+	}
+}
+
+void
+r12a_fix_spur(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	uint16_t chan = rtwn_chan2centieee(c);
+
+	if (rs->chip & R12A_CHIP_C_CUT) {
+		if (IEEE80211_IS_CHAN_HT40(c) && chan == 11) {
+			rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0xc00);
+			rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0, 0x40000000);
+		} else {
+			rtwn_bb_setbits(sc, R12A_RFMOD, 0x400, 0x800);
+
+			if (!IEEE80211_IS_CHAN_HT40(c) &&	/* 20 MHz */
+			    (chan == 13 || chan == 14)) {
+				rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300);
+				rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK,
+				    0, 0x40000000);
+			} else {	/* !80 Mhz */
+				rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200);
+				rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK,
+				    0x40000000, 0);
+			}
+		}
+	} else {
+		/* Set ADC clock to 160M to resolve 2480 MHz spur. */
+		if (!IEEE80211_IS_CHAN_HT40(c) &&	/* 20 MHz */
+		    (chan == 13 || chan == 14))
+			rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300);
+		else if (IEEE80211_IS_CHAN_2GHZ(c))
+			rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200);
+	}
+}
+
+static void
+r12a_set_band(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct r12a_softc *rs = sc->sc_priv;
+	uint32_t basicrates;
+	uint8_t swing;
+	int i;
+
+	/* Check if band was changed. */
+	if ((sc->sc_flags & (RTWN_STARTED | RTWN_RUNNING)) !=
+	    RTWN_STARTED && IEEE80211_IS_CHAN_5GHZ(c) ^
+	    !(rtwn_read_1(sc, R12A_CCK_CHECK) & R12A_CCK_CHECK_5GHZ))
+		return;
+
+	rtwn_get_rates(sc, ieee80211_get_suprates(ic, c), NULL, &basicrates,
+	    NULL, 1);
+	if (IEEE80211_IS_CHAN_2GHZ(c)) {
+		rtwn_r12a_set_band_2ghz(sc, basicrates);
+		swing = rs->tx_bbswing_2g;
+	} else if (IEEE80211_IS_CHAN_5GHZ(c)) {
+		rtwn_r12a_set_band_5ghz(sc, basicrates);
+		swing = rs->tx_bbswing_5g;
+	} else {
+		KASSERT(0, ("wrong channel flags %08X\n", c->ic_flags));
+		return;
+	}
+
+	/* XXX PATH_B is set by vendor driver. */
+	for (i = 0; i < 2; i++) {
+		uint16_t val = 0;
+
+		switch ((swing >> i * 2) & 0x3) {
+		case 0:
+			val = 0x200;	/* 0 dB	*/
+			break;
+		case 1:
+			val = 0x16a;	/* -3 dB */
+			break;
+		case 2:
+			val = 0x101;	/* -6 dB */
+			break;
+		case 3:
+			val = 0xb6;	/* -9 dB */
+			break;
+		}
+
+		rtwn_bb_setbits(sc, R12A_TX_SCALE(i), R12A_TX_SCALE_SWING_M,
+		    val << R12A_TX_SCALE_SWING_S);
+	}
+}
+
+void
+r12a_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	uint32_t val;
+	uint16_t chan;
+	int i;
+
+	r12a_set_band(sc, c);
+
+	chan = rtwn_chan2centieee(c);
+	if (36 <= chan && chan <= 48)
+		val = 0x09280000;
+	else if (50 <= chan && chan <= 64)
+		val = 0x08a60000;
+	else if (100 <= chan && chan <= 116)
+		val = 0x08a40000;
+	else if (118 <= chan)
+		val = 0x08240000;
+	else
+		val = 0x12d40000;
+
+	rtwn_bb_setbits(sc, R12A_FC_AREA, 0x1ffe0000, val);
+
+	for (i = 0; i < sc->nrxchains; i++) {
+		if (36 <= chan && chan <= 64)
+			val = 0x10100;
+		else if (100 <= chan && chan <= 140)
+			val = 0x30100;
+		else if (140 < chan)
+			val = 0x50100;
+		else
+			val = 0x00000;
+
+		rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0x70300, val);
+
+		/* RTL8812AU-specific */
+		rtwn_r12a_fix_spur(sc, c);
+
+		KASSERT(chan <= 0xff, ("%s: chan %d\n", __func__, chan));
+		rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xff, chan);
+	}
+
+#ifdef notyet
+	if (IEEE80211_IS_CHAN_HT80(c)) {	/* 80 MHz */
+		rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x80, 0x100);
+
+		/* TODO */
+
+		val = 0x0;
+	} else
+#endif
+	if (IEEE80211_IS_CHAN_HT40(c)) {	/* 40 MHz */
+		uint8_t ext_chan;
+
+		if (IEEE80211_IS_CHAN_HT40U(c))
+			ext_chan = R12A_DATA_SEC_PRIM_DOWN_20;
+		else
+			ext_chan = R12A_DATA_SEC_PRIM_UP_20;
+
+		rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x100, 0x80);
+		rtwn_write_1(sc, R12A_DATA_SEC, ext_chan);
+
+		rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300201);
+		rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0);
+
+		/* discard high 4 bits */
+		val = rtwn_bb_read(sc, R12A_RFMOD);
+		val = RW(val, R12A_RFMOD_EXT_CHAN, ext_chan);
+		rtwn_bb_write(sc, R12A_RFMOD, val);
+
+		val = rtwn_bb_read(sc, R12A_CCA_ON_SEC);
+		val = RW(val, R12A_CCA_ON_SEC_EXT_CHAN, ext_chan);
+		rtwn_bb_write(sc, R12A_CCA_ON_SEC, val);
+
+		if (rtwn_read_1(sc, 0x837) & 0x04)
+			val = 0x01800000;
+		else if (sc->nrxchains == 2 && sc->ntxchains == 2)
+			val = 0x01c00000;
+		else
+			val = 0x02000000;
+
+		rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val);
+
+		if (IEEE80211_IS_CHAN_HT40U(c))
+			rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10, 0);
+		else
+			rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0, 0x10);
+
+		val = 0x400;
+	} else {	/* 20 MHz */
+		rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x180, 0);
+		rtwn_write_1(sc, R12A_DATA_SEC, R12A_DATA_SEC_NO_EXT);
+
+		rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300200);
+		rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0);
+
+		if (sc->nrxchains == 2 && sc->ntxchains == 2)
+			val = 0x01c00000;
+		else
+			val = 0x02000000;
+
+		rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val);
+
+		val = 0xc00;
+	}
+
+	/* RTL8812AU-specific */
+	rtwn_r12a_fix_spur(sc, c);
+
+	for (i = 0; i < sc->nrxchains; i++)
+		rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xc00, val);
+
+	/* Set Tx power for this new channel. */
+	r12a_set_txpower(sc, c);
+}
+
+void
+r12a_set_band_2ghz(struct rtwn_softc *sc, uint32_t basicrates)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+
+	/* Enable CCK / OFDM. */
+	rtwn_bb_setbits(sc, R12A_OFDMCCK_EN,
+	    0, R12A_OFDMCCK_EN_CCK | R12A_OFDMCCK_EN_OFDM);
+
+	rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x02, 0x01);
+	rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2e000);
+
+	/* Select AGC table. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0);
+
+	switch (rs->rfe_type) {
+	case 0:
+	case 1:
+	case 2:
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0);
+		break;
+	case 3:
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337770);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337770);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000);
+		rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01);
+		break;
+	case 4:
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x00100000);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x00100000);
+		break;
+	case 5:
+		rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x77);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777);
+		rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0x01, 0);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0);
+		break;
+	default:
+		break;
+	}
+
+	rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0x10);
+	rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0x0f000000, 0x01000000);
+
+	/* Write basic rates. */
+	rtwn_set_basicrates(sc, basicrates);
+
+	rtwn_write_1(sc, R12A_CCK_CHECK, 0);
+}
+
+void
+r12a_set_band_5ghz(struct rtwn_softc *sc, uint32_t basicrates)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	int ntries;
+
+	rtwn_write_1(sc, R12A_CCK_CHECK, R12A_CCK_CHECK_5GHZ);
+
+	for (ntries = 0; ntries < 100; ntries++) {
+		if ((rtwn_read_2(sc, R12A_TXPKT_EMPTY) & 0x30) == 0x30)
+			break;
+
+		rtwn_delay(sc, 25);
+	}
+	if (ntries == 100) {
+		device_printf(sc->sc_dev,
+		    "%s: TXPKT_EMPTY check failed (%04X)\n",
+		    __func__, rtwn_read_2(sc, R12A_TXPKT_EMPTY));
+	}
+
+	/* Enable OFDM. */
+	rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, R12A_OFDMCCK_EN_CCK,
+	    R12A_OFDMCCK_EN_OFDM);
+
+	rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x01, 0x02);
+	rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2a000);
+
+	/* Select AGC table. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0x01);
+
+	switch (rs->rfe_type) {
+	case 0:
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000);
+		break;
+	case 1:
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0);
+		break;
+	case 2:
+	case 4:
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337777);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000);
+		break;
+	case 3:
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337717);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337717);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000);
+		rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01);
+		break;
+	case 5:
+		rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x33);
+		rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777);
+		rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0, 0x01);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000);
+		break;
+	default:
+		break;
+	}
+
+	rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0);
+	rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0, 0x0f000000);
+
+	/* Write basic rates. */
+	rtwn_set_basicrates(sc, basicrates);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,196 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+#include <dev/rtwn/rtl8812a/r12a_fw_cmd.h>
+
+
+#ifndef RTWN_WITHOUT_UCODE
+void
+r12a_fw_reset(struct rtwn_softc *sc, int reason)
+{
+	/* Reset MCU IO wrapper. */
+	rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0);
+	rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0x08, 0);
+
+	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_CPUEN, 0, 1);
+
+	/* Enable MCU IO wrapper. */
+	rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0);
+	rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0, 0x08);
+
+	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
+	    0, R92C_SYS_FUNC_EN_CPUEN, 1);
+}
+
+void
+r12a_fw_download_enable(struct rtwn_softc *sc, int enable)
+{
+	if (enable) {
+		/* MCU firmware download enable. */
+		rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN);
+		/* 8051 reset. */
+		rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN,
+		    0, 2);
+	} else {
+		/* MCU download disable. */
+		rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0);
+	}
+}
+
+void
+r12a_set_media_status(struct rtwn_softc *sc, int macid)
+{
+	struct r12a_fw_cmd_msrrpt status;
+	int error;
+
+	if (macid & RTWN_MACID_VALID)
+		status.msrb0 = R12A_MSRRPT_B0_ASSOC;
+	else
+		status.msrb0 = R12A_MSRRPT_B0_DISASSOC;
+
+	status.macid = (macid & ~RTWN_MACID_VALID);
+	status.macid_end = 0;
+
+	error = r88e_fw_cmd(sc, R12A_CMD_MSR_RPT, &status, sizeof(status));
+	if (error != 0)
+		device_printf(sc->sc_dev, "cannot change media status!\n");
+}
+
+int
+r12a_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap,
+    int off)
+{
+	struct r12a_fw_cmd_pwrmode mode;
+	int error;
+
+	if (off && vap->iv_state == IEEE80211_S_RUN &&
+	    (vap->iv_flags & IEEE80211_F_PMGTON)) {
+		mode.mode = R88E_PWRMODE_LEG;
+		/*
+		 * TODO: switch to RFOFF state
+		 * (something is missing here - Rx stops with it).
+		 */
+#ifdef RTWN_TODO
+		mode.pwr_state = R88E_PWRMODE_STATE_RFOFF;
+#else
+		mode.pwr_state = R88E_PWRMODE_STATE_RFON;
+#endif
+	} else {
+		mode.mode = R88E_PWRMODE_CAM;
+		mode.pwr_state = R88E_PWRMODE_STATE_ALLON;
+	}
+	mode.pwrb1 =
+	    SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) |
+	    SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN);
+	/* XXX ignored */
+	mode.bcn_pass = 0;
+	mode.queue_uapsd = 0;
+	mode.pwrb5 = R12A_PWRMODE_B5_NO_BTCOEX;
+	error = r88e_fw_cmd(sc, R12A_CMD_SET_PWRMODE, &mode, sizeof(mode));
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: CMD_SET_PWRMODE was not sent, error %d\n",
+		    __func__, error);
+	}
+
+	return (error);
+}
+
+void
+r12a_iq_calib_fw(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	struct ieee80211_channel *c = sc->sc_ic.ic_curchan;
+	struct r12a_fw_cmd_iq_calib cmd;
+
+	if (rs->rs_flags & R12A_IQK_RUNNING)
+		return;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "Starting IQ calibration (FW)\n");
+
+	cmd.chan = rtwn_chan2centieee(c);
+	if (IEEE80211_IS_CHAN_5GHZ(c))
+		cmd.band_bw = RTWN_CMD_IQ_BAND_5GHZ;
+	else
+		cmd.band_bw = RTWN_CMD_IQ_BAND_2GHZ;
+
+	/* TODO: 80/160 MHz. */
+	if (IEEE80211_IS_CHAN_HT40(c))
+		cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_40;
+	else
+		cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_20;
+
+	cmd.ext_5g_pa_lna = RTWN_CMD_IQ_EXT_PA_5G(rs->ext_pa_5g);
+	cmd.ext_5g_pa_lna |= RTWN_CMD_IQ_EXT_LNA_5G(rs->ext_lna_5g);
+
+	if (r88e_fw_cmd(sc, R12A_CMD_IQ_CALIBRATE, &cmd, sizeof(cmd)) != 0) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
+		    "error while sending IQ calibration command to FW!\n");
+		return;
+	}
+
+	rs->rs_flags |= R12A_IQK_RUNNING;
+}
+#endif
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12A_FW_CMD_H
+#define R12A_FW_CMD_H
+
+#include <dev/rtwn/rtl8188e/r88e_fw_cmd.h>
+
+/*
+ * Host to firmware commands.
+ */
+/* Note: some parts are shared with RTL8188EU. */
+#define R12A_CMD_MSR_RPT		0x01
+#define R12A_CMD_SET_PWRMODE		0x20
+#define R12A_CMD_IQ_CALIBRATE		0x45
+
+/* Structure for R12A_CMD_MSR_RPT. */
+struct r12a_fw_cmd_msrrpt {
+	uint8_t		msrb0;
+#define R12A_MSRRPT_B0_DISASSOC		0x00
+#define R12A_MSRRPT_B0_ASSOC		0x01
+#define R12A_MSRRPT_B0_MACID_IND	0x02
+
+	uint8_t		macid;
+	uint8_t		macid_end;
+} __packed;
+
+/* Structure for R12A_CMD_SET_PWRMODE. */
+struct r12a_fw_cmd_pwrmode {
+	uint8_t		mode;
+	uint8_t		pwrb1;
+	uint8_t		bcn_pass;
+	uint8_t		queue_uapsd;
+	uint8_t		pwr_state;
+	uint8_t		pwrb5;
+#define R12A_PWRMODE_B5_NO_BTCOEX	0x40
+} __packed;
+
+/* Structure for R12A_CMD_IQ_CALIBRATE. */
+struct r12a_fw_cmd_iq_calib {
+	uint8_t		chan;
+	uint8_t		band_bw;
+#define RTWN_CMD_IQ_CHAN_WIDTH_20	0x01
+#define RTWN_CMD_IQ_CHAN_WIDTH_40	0x02
+#define RTWN_CMD_IQ_CHAN_WIDTH_80	0x04
+#define RTWN_CMD_IQ_CHAN_WIDTH_160	0x08
+#define RTWN_CMD_IQ_BAND_2GHZ		0x10
+#define RTWN_CMD_IQ_BAND_5GHZ		0x20
+
+	uint8_t		ext_5g_pa_lna;
+#define RTWN_CMD_IQ_EXT_PA_5G(pa)	(pa)
+#define RTWN_CMD_IQ_EXT_LNA_5G(lna)	((lna) << 1)
+} __packed;
+
+
+/*
+ * C2H event types.
+ */
+#define R12A_C2H_DEBUG		0x00
+#define R12A_C2H_TX_REPORT	0x03
+#define R12A_C2H_BT_INFO	0x09
+#define R12A_C2H_RA_REPORT	0x0c
+#define R12A_C2H_IQK_FINISHED	0x11
+
+/* Structure for R12A_C2H_TX_REPORT event. */
+struct r12a_c2h_tx_rpt {
+	uint8_t		txrptb0;
+#define R12A_TXRPTB0_QSEL_M		0x1f
+#define R12A_TXRPTB0_QSEL_S		0
+#define R12A_TXRPTB0_BC			0x20
+#define R12A_TXRPTB0_LIFE_EXPIRE	0x40
+#define R12A_TXRPTB0_RETRY_OVER		0x80
+
+	uint8_t		macid;
+	uint8_t		txrptb2;
+#define R12A_TXRPTB2_RETRY_CNT_M	0x3f
+#define R12A_TXRPTB2_RETRY_CNT_S	0
+
+	uint8_t		queue_time_low;	/* 256 msec unit */
+	uint8_t		queue_time_high;
+	uint8_t		final_rate;
+	uint16_t	reserved;
+} __packed;
+
+/* Structure for R12A_C2H_RA_REPORT event. */
+struct r12a_c2h_ra_report {
+	uint8_t		rarptb0;
+#define R12A_RARPTB0_RATE_M	0x3f
+#define R12A_RARPTB0_RATE_S	0
+
+	uint8_t		macid;
+	uint8_t		rarptb2;
+#define R12A_RARPTB0_LDPC	0x01
+#define R12A_RARPTB0_TXBF	0x02
+#define R12A_RARPTB0_NOISE	0x04
+} __packed;
+
+#endif	/* R12A_FW_CMD_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,488 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_priv.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+
+int
+r12a_check_condition(struct rtwn_softc *sc, const uint8_t cond[])
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	uint8_t mask[4];
+	int i, j, nmasks;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+	    "%s: condition byte 0: %02X; ext PA/LNA: %d/%d (2 GHz), "
+	    "%d/%d (5 GHz)\n", __func__, cond[0], rs->ext_pa_2g,
+	    rs->ext_lna_2g, rs->ext_pa_5g, rs->ext_lna_5g);
+
+	if (cond[0] == 0)
+		return (1);
+
+	if (!rs->ext_pa_2g && !rs->ext_lna_2g &&
+	    !rs->ext_pa_5g && !rs->ext_lna_5g)
+		return (0);
+
+	nmasks = 0;
+	if (rs->ext_pa_2g) {
+		mask[nmasks] = R12A_COND_GPA;
+		mask[nmasks] |= R12A_COND_TYPE(rs->type_pa_2g);
+		nmasks++;
+	}
+	if (rs->ext_pa_5g) {
+		mask[nmasks] = R12A_COND_APA;
+		mask[nmasks] |= R12A_COND_TYPE(rs->type_pa_5g);
+		nmasks++;
+	}
+	if (rs->ext_lna_2g) {
+		mask[nmasks] = R12A_COND_GLNA;
+		mask[nmasks] |= R12A_COND_TYPE(rs->type_lna_2g);
+		nmasks++;
+	}
+	if (rs->ext_lna_5g) {
+		mask[nmasks] = R12A_COND_ALNA;
+		mask[nmasks] |= R12A_COND_TYPE(rs->type_lna_5g);
+		nmasks++;
+	}
+
+	for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++)
+		for (j = 0; j < nmasks; j++)
+			if ((cond[i] & mask[j]) == mask[j])
+				return (1);
+
+	return (0);
+}
+
+int
+r12a_set_page_size(struct rtwn_softc *sc)
+{
+	return (rtwn_setbits_1(sc, R92C_PBP, R92C_PBP_PSTX_M,
+	    R92C_PBP_512 << R92C_PBP_PSTX_S) == 0);
+}
+
+void
+r12a_init_edca(struct rtwn_softc *sc)
+{
+	r92c_init_edca(sc);
+
+	/* 80 MHz clock */
+	rtwn_write_1(sc, R92C_USTIME_TSF, 0x50);
+	rtwn_write_1(sc, R92C_USTIME_EDCA, 0x50);
+}
+
+void
+r12a_init_bb(struct rtwn_softc *sc)
+{
+	int i, j;
+
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0, R92C_SYS_FUNC_EN_USBA);
+
+	/* Enable BB and RF. */
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0,
+	    R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST);
+
+	/* PathA RF Power On. */
+	rtwn_write_1(sc, R92C_RF_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
+
+	/* PathB RF Power On. */
+	rtwn_write_1(sc, R12A_RF_B_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
+
+	/* Write BB initialization values. */
+	for (i = 0; i < sc->bb_size; i++) {
+		const struct rtwn_bb_prog *bb_prog = &sc->bb_prog[i];
+
+		while (!rtwn_check_condition(sc, bb_prog->cond)) {
+			KASSERT(bb_prog->next != NULL,
+			    ("%s: wrong condition value (i %d)\n",
+			    __func__, i));
+			bb_prog = bb_prog->next;
+		}
+
+		for (j = 0; j < bb_prog->count; j++) {
+			RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+			    "BB: reg 0x%03x, val 0x%08x\n",
+			    bb_prog->reg[j], bb_prog->val[j]);
+
+			rtwn_bb_write(sc, bb_prog->reg[j], bb_prog->val[j]);
+			rtwn_delay(sc, 1);
+		}
+	}
+
+	/* XXX meshpoint mode? */
+
+	/* Write AGC values. */
+	for (i = 0; i < sc->agc_size; i++) {
+		const struct rtwn_agc_prog *agc_prog = &sc->agc_prog[i];
+
+		while (!rtwn_check_condition(sc, agc_prog->cond)) {
+			KASSERT(agc_prog->next != NULL,
+			    ("%s: wrong condition value (2) (i %d)\n",
+			    __func__, i));
+			agc_prog = agc_prog->next;
+		}
+
+		for (j = 0; j < agc_prog->count; j++) {
+			RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+			    "AGC: val 0x%08x\n", agc_prog->val[j]);
+
+			rtwn_bb_write(sc, 0x81c, agc_prog->val[j]);
+			rtwn_delay(sc, 1);
+		}
+	}
+
+	for (i = 0; i < sc->nrxchains; i++) {
+		rtwn_bb_write(sc, R12A_INITIAL_GAIN(i), 0x22);
+		rtwn_delay(sc, 1);
+		rtwn_bb_write(sc, R12A_INITIAL_GAIN(i), 0x20);
+		rtwn_delay(sc, 1);
+	}
+
+	rtwn_r12a_crystalcap_write(sc);
+
+	if (rtwn_bb_read(sc, R12A_CCK_RPT_FORMAT) & R12A_CCK_RPT_FORMAT_HIPWR)
+		sc->sc_flags |= RTWN_FLAG_CCK_HIPWR;
+}
+
+void
+r12a_init_rf(struct rtwn_softc *sc)
+{
+	int chain, i;
+
+	for (chain = 0, i = 0; chain < sc->nrxchains; chain++, i++) {
+		/* Write RF initialization values for this chain. */
+		i += r92c_init_rf_chain(sc, &sc->rf_prog[i], chain);
+	}
+}
+
+void
+r12a_crystalcap_write(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	uint32_t reg;
+	uint8_t val;
+
+	val = rs->crystalcap & 0x3f;
+	reg = rtwn_bb_read(sc, R92C_MAC_PHY_CTRL);
+	reg = RW(reg, R12A_MAC_PHY_CRYSTALCAP, val | (val << 6));
+	rtwn_bb_write(sc, R92C_MAC_PHY_CTRL, reg);
+}
+
+static void
+r12a_rf_init_workaround(struct rtwn_softc *sc)
+{
+
+	rtwn_write_1(sc, R92C_RF_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_SDMRSTB);
+	rtwn_write_1(sc, R92C_RF_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB |
+	    R92C_RF_CTRL_SDMRSTB);
+	rtwn_write_1(sc, R12A_RF_B_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_SDMRSTB);
+	rtwn_write_1(sc, R12A_RF_B_CTRL,
+	    R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB |
+	    R92C_RF_CTRL_SDMRSTB);
+}
+
+int
+r12a_power_on(struct rtwn_softc *sc)
+{
+#define RTWN_CHK(res) do {	\
+	if (res != 0)		\
+		return (EIO);	\
+} while(0)
+	int ntries;
+
+	r12a_rf_init_workaround(sc);
+
+	/* Force PWM mode. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_SPS0_CTRL + 1, 0, 0x01));
+
+	/* Turn off ZCD. */
+	RTWN_CHK(rtwn_setbits_2(sc, 0x014, 0x0180, 0));
+
+	/* Enable LDO normal mode. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_LPLDO_CTRL, R92C_LPLDO_CTRL_SLEEP,
+	    0));
+
+	/* GPIO 0...7 input mode. */
+	RTWN_CHK(rtwn_write_1(sc, R92C_GPIO_IOSEL, 0));
+
+	/* GPIO 11...8 input mode. */
+	RTWN_CHK(rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0));
+
+	/* Enable WL suspend. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_HSUS, 0, 1));
+
+	/* Enable 8051. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
+	    0, R92C_SYS_FUNC_EN_CPUEN, 1));
+
+	/* Disable SW LPS. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_APFM_RSM, 0, 1));
+
+	/* Wait for power ready bit. */
+	for (ntries = 0; ntries < 5000; ntries++) {
+		if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST)
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 5000) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for chip power up\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Disable WL suspend. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_HSUS, 0, 1));
+
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0,
+	    R92C_APS_FSMCO_APFM_ONMAC, 1));
+	for (ntries = 0; ntries < 5000; ntries++) {
+		if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
+		    R92C_APS_FSMCO_APFM_ONMAC))
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 5000)
+		return (ETIMEDOUT);
+
+	/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+	RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0x0000));
+	RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN |
+	    R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN |
+	    R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN |
+	    ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) |
+	    R92C_CR_CALTMR_EN));
+
+	return (0);
+}
+
+void
+r12a_power_off(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	int error, ntries;
+
+	/* Stop Rx. */
+	error = rtwn_write_1(sc, R92C_CR, 0);
+	if (error == ENXIO)	/* hardware gone */
+		return;
+
+	/* Move card to Low Power state. */
+	/* Block all Tx queues. */
+	rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
+
+	for (ntries = 0; ntries < 10; ntries++) {
+		/* Should be zero if no packet is transmitting. */
+		if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0)
+			break;
+
+		rtwn_delay(sc, 5000);
+	}
+	if (ntries == 10) {
+		device_printf(sc->sc_dev, "%s: failed to block Tx queues\n",
+		    __func__);
+		return;
+	}
+
+	/* Turn off 3-wire. */
+	rtwn_write_1(sc, R12A_HSSI_PARAM1(0), 0x04);
+	rtwn_write_1(sc, R12A_HSSI_PARAM1(1), 0x04);
+
+	/* CCK and OFDM are disabled, and clock are gated. */
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0);
+
+	rtwn_delay(sc, 1);
+
+	/* Reset whole BB. */
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0);
+
+	/* Reset MAC TRX. */
+	rtwn_write_1(sc, R92C_CR,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN);
+
+	/* check if removed later. (?) */
+	rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1);
+
+	/* Respond TxOK to scheduler */
+	rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, R92C_DUAL_TSF_RST_TXOK);
+
+	/* If firmware in ram code, do reset. */
+#ifndef RTWN_WITHOUT_UCODE
+	if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
+		r12a_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN);
+#endif
+
+	/* Reset MCU. */
+	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN,
+	    0, 1);
+	rtwn_write_1(sc, R92C_MCUFWDL, 0);
+
+	/* Move card to Disabled state. */
+	/* Turn off 3-wire. */
+	rtwn_write_1(sc, R12A_HSSI_PARAM1(0), 0x04);
+	rtwn_write_1(sc, R12A_HSSI_PARAM1(1), 0x04);
+
+	/* Reset BB, close RF. */
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0);
+
+	rtwn_delay(sc, 1);
+
+	/* SPS PWM mode. */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0xff,
+	    R92C_APS_FSMCO_SOP_RCK | R92C_APS_FSMCO_SOP_ABG, 3);
+
+	/* ANA clock = 500k. */
+	rtwn_setbits_1(sc, R92C_SYS_CLKR, R92C_SYS_CLKR_ANA8M, 0);
+
+	/* Turn off MAC by HW state machine */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_OFF,
+	    1);
+	for (ntries = 0; ntries < 10; ntries++) {
+		/* Wait until it will be disabled. */
+		if ((rtwn_read_2(sc, R92C_APS_FSMCO) &
+		    R92C_APS_FSMCO_APFM_OFF) == 0)
+			break;
+
+		rtwn_delay(sc, 5000);
+	}
+	if (ntries == 10) {
+		device_printf(sc->sc_dev, "%s: could not turn off MAC\n",
+		    __func__);
+		return;
+	}
+
+	/* Reset 8051. */
+	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN,
+	    0, 1);
+
+	/* Fill the default value of host_CPU handshake field. */
+	rtwn_write_1(sc, R92C_MCUFWDL,
+	    R92C_MCUFWDL_EN | R92C_MCUFWDL_CHKSUM_RPT);
+
+	rtwn_setbits_1(sc, R92C_GPIO_IO_SEL, 0xf0, 0xc0);
+
+	/* GPIO 11 input mode, 10...8 output mode. */
+	rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0x07);
+
+	/* GPIO 7...0, output = input */
+	rtwn_write_1(sc, R92C_GPIO_OUT, 0);
+
+	/* GPIO 7...0 output mode. */
+	rtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff);
+
+	rtwn_write_1(sc, R92C_GPIO_MOD, 0);
+
+	/* Turn on ZCD. */
+	rtwn_setbits_2(sc, 0x014, 0, 0x0180);
+
+	/* Force PFM mode. */
+	rtwn_setbits_1(sc, R92C_SPS0_CTRL + 1, 0x01, 0);
+
+	/* LDO sleep mode. */
+	rtwn_setbits_1(sc, R92C_LPLDO_CTRL, 0, R92C_LPLDO_CTRL_SLEEP);
+
+	/* ANA clock = 500k. */
+	rtwn_setbits_1(sc, R92C_SYS_CLKR, R92C_SYS_CLKR_ANA8M, 0);
+
+	/* SOP option to disable BG/MB. */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0xff,
+	    R92C_APS_FSMCO_SOP_RCK, 3);
+
+	/* Disable RFC_0. */
+	rtwn_setbits_1(sc, R92C_RF_CTRL, R92C_RF_CTRL_RSTB, 0);
+
+	/* Disable RFC_1. */
+	rtwn_setbits_1(sc, R12A_RF_B_CTRL, R92C_RF_CTRL_RSTB, 0);
+
+	/* Enable WL suspend. */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_AFSM_HSUS,
+	    1);
+
+	rs->rs_flags &= ~R12A_IQK_RUNNING;
+}
+
+void
+r12a_init_intr(struct rtwn_softc *sc)
+{
+	rtwn_write_4(sc, R88E_HIMR, 0);
+	rtwn_write_4(sc, R88E_HIMRE, 0);
+}
+
+void
+r12a_init_antsel(struct rtwn_softc *sc)
+{
+	uint32_t reg;
+
+	rtwn_write_1(sc, R92C_LEDCFG2, 0x82);
+	rtwn_bb_setbits(sc, R92C_FPGA0_RFPARAM(0), 0, 0x2000);
+	reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(0));
+	sc->sc_ant = MS(reg, R92C_FPGA0_RFIFACEOE0_ANT);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,74 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+
+
+void
+r12a_set_led(struct rtwn_softc *sc, int led, int on)
+{
+	/* XXX assume led #0 == LED_LINK */
+	/* XXX antenna diversity */
+
+	if (led == RTWN_LED_LINK) {
+		rtwn_setbits_1(sc, R92C_LEDCFG0, 0x8f,
+		    R12A_LEDCFG2_ENA | (on ? 0 : R92C_LEDCFG0_DIS));
+		sc->ledlink = on;	/* Save LED state. */
+	}
+
+	/* XXX leds #1/#2 ? */
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,852 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12A_PRIV_H
+#define R12A_PRIV_H
+
+/*
+ * MAC initialization values.
+ */
+#define RTL8812AU_MAC_PROG_START \
+	{ 0x010, 0x0c },
+
+#define RTL8812AU_MAC_PROG_END \
+	{ 0x025, 0x0f }, { 0x072, 0x00 }, { 0x420, 0x80 }, { 0x428, 0x0a }, \
+	{ 0x429, 0x10 }, { 0x430, 0x00 }, { 0x431, 0x00 }, { 0x432, 0x00 }, \
+	{ 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, { 0x436, 0x07 }, \
+	{ 0x437, 0x08 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, { 0x43e, 0x07 }, \
+	{ 0x43f, 0x08 }, { 0x440, 0x5d }, { 0x441, 0x01 }, { 0x442, 0x00 }, \
+	{ 0x444, 0x10 }, { 0x445, 0x00 }, { 0x446, 0x00 }, { 0x447, 0x00 }, \
+	{ 0x448, 0x00 }, { 0x449, 0xf0 }, { 0x44a, 0x0f }, { 0x44b, 0x3e }, \
+	{ 0x44c, 0x10 }, { 0x44d, 0x00 }, { 0x44e, 0x00 }, { 0x44f, 0x00 }, \
+	{ 0x450, 0x00 }, { 0x451, 0xf0 }, { 0x452, 0x0f }, { 0x453, 0x00 }, \
+	{ 0x45b, 0x80 }, { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x4c8, 0xff }, \
+	{ 0x4c9, 0x08 }, { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 }, \
+	{ 0x500, 0x26 }, { 0x501, 0xa2 }, { 0x502, 0x2f }, { 0x503, 0x00 }, \
+	{ 0x504, 0x28 }, { 0x505, 0xa3 }, { 0x506, 0x5e }, { 0x507, 0x00 }, \
+	{ 0x508, 0x2b }, { 0x509, 0xa4 }, { 0x50a, 0x5e }, { 0x50b, 0x00 }, \
+	{ 0x50c, 0x4f }, { 0x50d, 0xa4 }, { 0x50e, 0x00 }, { 0x50f, 0x00 }, \
+	{ 0x512, 0x1c }, { 0x514, 0x0a }, { 0x516, 0x0a }, { 0x525, 0x4f }, \
+	{ 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, { 0x55c, 0x50 }, \
+	{ 0x55d, 0xff }, { 0x604, 0x09 }, { 0x605, 0x30 }, { 0x607, 0x03 }, \
+	{ 0x608, 0x0e }, { 0x609, 0x2a }, { 0x620, 0xff }, { 0x621, 0xff }, \
+	{ 0x622, 0xff }, { 0x623, 0xff }, { 0x624, 0xff }, { 0x625, 0xff }, \
+	{ 0x626, 0xff }, { 0x627, 0xff }, { 0x638, 0x50 }, { 0x63c, 0x0a }, \
+	{ 0x63d, 0x0a }, { 0x63e, 0x0e }, { 0x63f, 0x0e }, { 0x640, 0x80 }, \
+	{ 0x642, 0x40 }, { 0x643, 0x00 }, { 0x652, 0xc8 }, { 0x66e, 0x05 }, \
+	{ 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, { 0x703, 0x87 }, \
+	{ 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, { 0x70b, 0x87 }, \
+	{ 0x718, 0x40 }
+
+static const struct rtwn_mac_prog rtl8812au_mac_no_ext_pa_lna[] = {
+	RTL8812AU_MAC_PROG_START
+	{ 0x11, 0x66 },
+	RTL8812AU_MAC_PROG_END
+}, rtl8812au_mac[] = {
+	RTL8812AU_MAC_PROG_START
+	{ 0x11, 0x5a },
+	RTL8812AU_MAC_PROG_END
+};
+
+
+/*
+ * Baseband initialization values.
+ */
+#define R12A_COND_GPA		0x01
+#define R12A_COND_APA		0x02
+#define R12A_COND_GLNA		0x04
+#define R12A_COND_ALNA		0x08
+#define R12A_COND_TYPE(t)	((t) << 4)
+
+static const uint16_t rtl8812au_bb_regs0[] = {
+	0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x820, 0x824,
+	0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, 0x840, 0x844, 0x848,
+	0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, 0x864, 0x868, 0x86c,
+	0x870, 0x874, 0x878, 0x87c, 0x8a0, 0x8a4, 0x8a8, 0x8ac, 0x8b0,
+	0x8b4, 0x8b8, 0x8bc, 0x8c0, 0x8c4, 0x8c8, 0x8cc, 0x8d0, 0x8dc,
+	0x8d4, 0x8d8, 0x8f8, 0x8fc, 0x900, 0x90c, 0x910, 0x914, 0x918,
+	0x91c, 0x920, 0x924, 0x928, 0x92c, 0x930, 0x934, 0x960, 0x964,
+	0x968, 0x96c, 0x970, 0x978, 0x97c, 0x980, 0x984, 0x988, 0x990,
+	0x994, 0x998, 0x99c, 0x9a0, 0x9a4, 0x9a8, 0x9ac, 0x9b0, 0x9b4,
+	0x9b8, 0x9bc, 0x9d0, 0x9d4, 0x9d8, 0x9dc, 0x9e4, 0x9e8, 0xa00,
+	0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24,
+	0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xa84, 0xb00,
+	0xb04, 0xb08, 0xb0c, 0xb10, 0xb14, 0xb18, 0xb1c, 0xb20, 0xb24,
+	0xb28, 0xb2c, 0xb30, 0xb34, 0xb38, 0xb3c, 0xb40, 0xb44, 0xb48,
+	0xb4c, 0xb50, 0xb54, 0xb58, 0xb5c, 0xc00, 0xc04, 0xc08, 0xc0c,
+	0xc10, 0xc14, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34,
+	0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58,
+	0xc5c, 0xc60, 0xc64
+}, rtl8812au_bb_regs1[] = {
+	0xc68
+}, rtl8812au_bb_regs2[] = {
+	0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc94, 0xc98,
+	0xc9c, 0xca0, 0xca4, 0xca8, 0xcb0, 0xcb4, 0xcb8, 0xe00, 0xe04,
+	0xe08, 0xe0c, 0xe10, 0xe14, 0xe1c, 0xe20, 0xe24, 0xe28, 0xe2c,
+	0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50,
+	0xe54, 0xe58, 0xe5c, 0xe60, 0xe64, 0xe68, 0xe6c, 0xe70, 0xe74,
+	0xe78, 0xe7c, 0xe80, 0xe84, 0xe94, 0xe98, 0xe9c, 0xea0, 0xea4,
+	0xea8, 0xeb0, 0xeb4, 0xeb8
+};
+
+static const uint32_t rtl8812au_bb_vals0[] = {
+	0x8020d010, 0x080112e0, 0x0e028233, 0x12131113, 0x20101263,
+	0x020c3d10, 0x03a00385, 0x00000000, 0x00030fe0, 0x00000000,
+	0x002083dd, 0x2eaaeeb8, 0x0037a706, 0x06c89b44, 0x0000095b,
+	0xc0000001, 0x40003cde, 0x6210ff8b, 0x6cfdffb8, 0x28874706,
+	0x0001520c, 0x8060e000, 0x74210168, 0x6929c321, 0x79727432,
+	0x8ca7a314, 0x338c2878, 0x03333333, 0x31602c2e, 0x00003152,
+	0x000fc000, 0x00000013, 0x7f7f7f7f, 0xa202033e, 0x0ff0fa0a,
+	0x00000600, 0x000fc080, 0x6c0057ff, 0x4ca520a3, 0x27f00020,
+	0x00000000, 0x00012d69, 0x08248492, 0x0000b800, 0x00000000,
+	0x940008a0, 0x290b5612, 0x400002c0, 0x00000000, 0x00000701,
+	0x00000000, 0x0000fc00, 0x00000404, 0x1c1028c0, 0x64b11a1c,
+	0xe0767233, 0x055aa500, 0x00000004, 0xfffe0000, 0xfffffffe,
+	0x001fffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x801fffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x27100000, 0xffff0100, 0xffffff5c, 0xffffffff,
+	0x000000ff, 0x00080080, 0x00000000, 0x00000000, 0x81081008,
+	0x00000000, 0x01081008, 0x01081008, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000003, 0x000002d5, 0x00d047c8,
+	0x01ff000c, 0x8c838300, 0x2e7f000f, 0x9500bb78, 0x11144028,
+	0x00881117, 0x89140f00, 0x1a1b0000, 0x090e1217, 0x00000305,
+	0x00900000, 0x101fff00, 0x00000008, 0x00000900, 0x225b0606,
+	0x218075b2, 0x001f8c80, 0x03100000, 0x0000b000, 0xae0201eb,
+	0x01003207, 0x00009807, 0x01000000, 0x00000002, 0x00000002,
+	0x0000001f, 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c,
+	0x13121110, 0x17161514, 0x0000003a, 0x00000000, 0x00000000,
+	0x13000032, 0x48080000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000007, 0x00042020, 0x80410231, 0x00000000,
+	0x00000100, 0x01000000, 0x40000003, 0x12121212, 0x12121212,
+	0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212,
+	0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212,
+	0x00000020, 0x0008121c, 0x30000c1c, 0x00000058, 0x34344443,
+	0x07003333
+}, rtl8812au_bb_vals1_ext_pa_lna[] = {
+	0x59791979
+}, rtl8812au_bb_vals1[] = {
+	0x59799979
+}, rtl8812au_bb_vals2[] = {
+	0x59795979, 0x19795979, 0x19795979, 0x19791979, 0x19791979,
+	0x19791979, 0x19791979, 0x0100005c, 0x00000000, 0x00000000,
+	0x00000029, 0x08040201, 0x80402010, 0x77547777, 0x00000077,
+	0x00508242, 0x00000007, 0x00042020, 0x80410231, 0x00000000,
+	0x00000100, 0x01000000, 0x40000003, 0x12121212, 0x12121212,
+	0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212,
+	0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212,
+	0x00000020, 0x0008121c, 0x30000c1c, 0x00000058, 0x34344443,
+	0x07003333, 0x59791979, 0x59795979, 0x19795979, 0x19795979,
+	0x19791979, 0x19791979, 0x19791979, 0x19791979, 0x0100005c,
+	0x00000000, 0x00000000, 0x00000029, 0x08040201, 0x80402010,
+	0x77547777, 0x00000077, 0x00508242
+};
+
+static const struct rtwn_bb_prog rtl8812au_bb[] = {
+	{
+		nitems(rtl8812au_bb_regs0),
+		rtl8812au_bb_regs0,
+		rtl8812au_bb_vals0,
+		{ 0 },
+		NULL
+	},
+	/*
+	 * Devices with:
+	 * * External 2GHz PA, type 0;
+	 * * External 5GHz PA, type 0 or 5;
+	 * * External 2GHz LNA, type 0 or 5;
+	 * * External 5GHz LNA, type 0;
+	 */
+	{
+		nitems(rtl8812au_bb_regs1),
+		rtl8812au_bb_regs1,
+		rtl8812au_bb_vals1_ext_pa_lna,
+		{
+			R12A_COND_GPA | R12A_COND_GLNA |
+			R12A_COND_APA | R12A_COND_ALNA |
+			R12A_COND_TYPE(0x0),
+			R12A_COND_APA | R12A_COND_GLNA |
+			R12A_COND_TYPE(0x5), 0
+		},
+		/*
+		 * Others.
+		 */
+		&(const struct rtwn_bb_prog){
+			nitems(rtl8812au_bb_regs1),
+			rtl8812au_bb_regs1,
+			rtl8812au_bb_vals1,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8812au_bb_regs2),
+		rtl8812au_bb_regs2,
+		rtl8812au_bb_vals2,
+		{ 0 },
+		NULL
+	}
+};
+
+
+static const uint32_t rtl8812au_agc_vals0_lna_g0[] = {
+	0xfc000001, 0xfb020001, 0xfa040001, 0xf9060001, 0xf8080001,
+	0xf70a0001, 0xf60c0001, 0xf50e0001, 0xf4100001, 0xf3120001,
+	0xf2140001, 0xf1160001, 0xf0180001, 0xef1a0001, 0xee1c0001,
+	0xed1e0001, 0xec200001, 0xeb220001, 0xea240001, 0xcd260001,
+	0xcc280001, 0xcb2a0001, 0xca2c0001, 0xc92e0001, 0xc8300001,
+	0xa6320001, 0xa5340001, 0xa4360001, 0xa3380001, 0xa23a0001,
+	0x883c0001, 0x873e0001, 0x86400001, 0x85420001, 0x84440001,
+	0x83460001, 0x82480001, 0x814a0001, 0x484c0001, 0x474e0001,
+	0x46500001, 0x45520001, 0x44540001, 0x43560001, 0x42580001,
+	0x415a0001, 0x255c0001, 0x245e0001, 0x23600001, 0x22620001,
+	0x21640001, 0x21660001, 0x21680001, 0x216a0001, 0x216c0001,
+	0x216e0001, 0x21700001, 0x21720001, 0x21740001, 0x21760001,
+	0x21780001, 0x217a0001, 0x217c0001, 0x217e0001
+}, rtl8812au_agc_vals0_lna_g5[] = {
+	0xf9000001, 0xf8020001, 0xf7040001, 0xf6060001, 0xf5080001,
+	0xf40a0001, 0xf30c0001, 0xf20e0001, 0xf1100001, 0xf0120001,
+	0xef140001, 0xee160001, 0xed180001, 0xec1a0001, 0xeb1c0001,
+	0xea1e0001, 0xcd200001, 0xcc220001, 0xcb240001, 0xca260001,
+	0xc9280001, 0xc82a0001, 0xc72c0001, 0xc62e0001, 0xa5300001,
+	0xa4320001, 0xa3340001, 0xa2360001, 0x88380001, 0x873a0001,
+	0x863c0001, 0x853e0001, 0x84400001, 0x83420001, 0x82440001,
+	0x81460001, 0x48480001, 0x474a0001, 0x464c0001, 0x454e0001,
+	0x44500001, 0x43520001, 0x42540001, 0x41560001, 0x25580001,
+	0x245a0001, 0x235c0001, 0x225e0001, 0x21600001, 0x21620001,
+	0x21640001, 0x21660001, 0x21680001, 0x216a0001, 0x236c0001,
+	0x226e0001, 0x21700001, 0x21720001, 0x21740001, 0x21760001,
+	0x21780001, 0x217a0001, 0x217c0001, 0x217e0001
+}, rtl8812au_agc_vals0[] = {
+	0xff000001, 0xff020001, 0xff040001, 0xff060001, 0xff080001,
+	0xfe0a0001, 0xfd0c0001, 0xfc0e0001, 0xfb100001, 0xfa120001,
+	0xf9140001, 0xf8160001, 0xf7180001, 0xf61a0001, 0xf51c0001,
+	0xf41e0001, 0xf3200001, 0xf2220001, 0xf1240001, 0xf0260001,
+	0xef280001, 0xee2a0001, 0xed2c0001, 0xec2e0001, 0xeb300001,
+	0xea320001, 0xe9340001, 0xe8360001, 0xe7380001, 0xe63a0001,
+	0xe53c0001, 0xc73e0001, 0xc6400001, 0xc5420001, 0xc4440001,
+	0xc3460001, 0xc2480001, 0xc14a0001, 0xa74c0001, 0xa64e0001,
+	0xa5500001, 0xa4520001, 0xa3540001, 0xa2560001, 0xa1580001,
+	0x675a0001, 0x665c0001, 0x655e0001, 0x64600001, 0x63620001,
+	0x48640001, 0x47660001, 0x46680001, 0x456a0001, 0x446c0001,
+	0x436e0001, 0x42700001, 0x41720001, 0x41740001, 0x41760001,
+	0x41780001, 0x417a0001, 0x417c0001, 0x417e0001
+}, rtl8812au_agc_vals1_lna_a0[] = {
+	0xfc800001, 0xfb820001, 0xfa840001, 0xf9860001, 0xf8880001,
+	0xf78a0001, 0xf68c0001, 0xf58e0001, 0xf4900001, 0xf3920001,
+	0xf2940001, 0xf1960001, 0xf0980001, 0xef9a0001, 0xee9c0001,
+	0xed9e0001, 0xeca00001, 0xeba20001, 0xeaa40001, 0xe9a60001,
+	0xe8a80001, 0xe7aa0001, 0xe6ac0001, 0xe5ae0001, 0xe4b00001,
+	0xe3b20001, 0xa8b40001, 0xa7b60001, 0xa6b80001, 0xa5ba0001,
+	0xa4bc0001, 0xa3be0001, 0xa2c00001, 0xa1c20001, 0x68c40001,
+	0x67c60001, 0x66c80001, 0x65ca0001, 0x64cc0001, 0x47ce0001,
+	0x46d00001, 0x45d20001, 0x44d40001, 0x43d60001, 0x42d80001,
+	0x08da0001, 0x07dc0001, 0x06de0001, 0x05e00001, 0x04e20001,
+	0x03e40001, 0x02e60001, 0x01e80001, 0x01ea0001, 0x01ec0001,
+	0x01ee0001, 0x01f00001, 0x01f20001, 0x01f40001, 0x01f60001,
+	0x01f80001, 0x01fa0001, 0x01fc0001, 0x01fe0001
+}, rtl8812au_agc_vals1[] = {
+	0xff800001, 0xff820001, 0xff840001, 0xfe860001, 0xfd880001,
+	0xfc8a0001, 0xfb8c0001, 0xfa8e0001, 0xf9900001, 0xf8920001,
+	0xf7940001, 0xf6960001, 0xf5980001, 0xf49a0001, 0xf39c0001,
+	0xf29e0001, 0xf1a00001, 0xf0a20001, 0xefa40001, 0xeea60001,
+	0xeda80001, 0xecaa0001, 0xebac0001, 0xeaae0001, 0xe9b00001,
+	0xe8b20001, 0xe7b40001, 0xe6b60001, 0xe5b80001, 0xe4ba0001,
+	0xe3bc0001, 0xa8be0001, 0xa7c00001, 0xa6c20001, 0xa5c40001,
+	0xa4c60001, 0xa3c80001, 0xa2ca0001, 0xa1cc0001, 0x68ce0001,
+	0x67d00001, 0x66d20001, 0x65d40001, 0x64d60001, 0x47d80001,
+	0x46da0001, 0x45dc0001, 0x44de0001, 0x43e00001, 0x42e20001,
+	0x08e40001, 0x07e60001, 0x06e80001, 0x05ea0001, 0x04ec0001,
+	0x03ee0001, 0x02f00001, 0x01f20001, 0x01f40001, 0x01f60001,
+	0x01f80001, 0x01fa0001, 0x01fc0001, 0x01fe0001
+};
+
+static const struct rtwn_agc_prog rtl8812au_agc[] = {
+	/*
+	 * External 2GHz LNA (type 0).
+	 */
+	{
+		nitems(rtl8812au_agc_vals0_lna_g0),
+		rtl8812au_agc_vals0_lna_g0,
+		{ R12A_COND_GLNA | R12A_COND_TYPE(0x0), 0 },
+		/*
+		 * External 2GHz LNA (type 5).
+		 */
+		&(const struct rtwn_agc_prog){
+			nitems(rtl8812au_agc_vals0_lna_g5),
+			rtl8812au_agc_vals0_lna_g5,
+			{ R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 },
+			/*
+			 * Others.
+			 */
+			&(const struct rtwn_agc_prog){
+				nitems(rtl8812au_agc_vals0),
+				rtl8812au_agc_vals0,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	/*
+	 * External 5GHz LNA (type 0).
+	 */
+	{
+		nitems(rtl8812au_agc_vals1_lna_a0),
+		rtl8812au_agc_vals1_lna_a0,
+		{ R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 },
+		/*
+		 * Others.
+		 */
+		&(const struct rtwn_agc_prog){
+			nitems(rtl8812au_agc_vals1),
+			rtl8812au_agc_vals1,
+			{ 0 },
+			NULL
+		}
+	}
+};
+
+/*
+ * RF initialization values.
+ */
+static const uint8_t rtl8812au_rf0_regs0[] = {
+	0x00, 0x18, 0x56, 0x66, 0x1e, 0x89
+}, rtl8812au_rf0_regs1[] = {
+	0x86
+}, rtl8812au_rf0_regs2[] = {
+	0x8b
+}, rtl8812au_rf0_regs3[] = {
+	0xb1, 0xb3, 0xb4, 0xba,	0x18, 0xef
+}, rtl8812au_rf0_regs4[] = {
+	0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b
+}, rtl8812au_rf0_regs5[] = {
+	0xef, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+	0x34
+}, rtl8812au_rf0_regs6[] = {
+	0xef, 0xef, 0xdf, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xef,
+	0x51, 0x52, 0x53, 0x54, 0xef, 0x08, 0x18, 0xef, 0x3a, 0x3b, 0x3c,
+	0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b,
+	0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a,
+	0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c,
+	0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b,
+	0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a,
+	0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c,
+	0x3a, 0x3b, 0x3c, 0xef
+}, rtl8812au_rf0_regs7[] = {
+	0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+	0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+	0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
+}, rtl8812au_rf0_regs8[] = {
+	0xef, 0x18, 0xef, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35,
+	0x35, 0xef, 0x18, 0xef, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x36, 0xef, 0xef, 0x3c, 0x3c, 0x3c,
+}, rtl8812au_rf0_regs9[] = {
+	0xef, 0x18, 0xef, 0xdf, 0x1f
+}, rtl8812au_rf0_regs10[] = {
+	0x61, 0x62, 0x63, 0x64, 0x65
+}, rtl8812au_rf0_regs11[] = {
+	0x08, 0x1c, 0xb4, 0x18, 0xfe, 0xfe, 0xfe, 0xfe, 0xb4, 0x18
+}, rtl8812au_rf1_regs0[] = {
+	0x56, 0x66, 0x89
+}, rtl8812au_rf1_regs3[] = {
+	0xb1, 0xb3, 0xb4, 0xba, 0x18, 0xef
+};
+
+static const uint32_t rtl8812au_rf0_vals0[] = {
+	0x10000, 0x1712a, 0x51cf2, 0x40000, 0x80000, 0x00080
+}, rtl8812au_rf0_vals1_lna_g0_g5[] = {
+	0x14b3a
+}, rtl8812au_rf0_vals1[] = {
+	0x14b38
+}, rtl8812au_rf0_vals2_lna_a0[] = {
+	0x80180
+}, rtl8812au_rf0_vals2[] = {
+	0x87180
+}, rtl8812au_rf0_vals3[] = {
+	0x1fc1a, 0xf0810, 0x1a78d, 0x86180, 0x00006, 0x02000
+}, rtl8812au_rf0_vals4_lna_g0_g5[] = {
+	0x3f218, 0x30a58, 0x2fa58, 0x22590, 0x1fa50, 0x10248, 0x08240
+}, rtl8812au_rf0_vals4[] = {
+	0x38a58, 0x37a58, 0x2a590, 0x27a50, 0x18248, 0x10240, 0x08240
+}, rtl8812au_rf0_vals5_pa_g0[] = {
+	0x00100, 0x0a4ee, 0x09076, 0x08073, 0x07070, 0x0606d, 0x0506a,
+	0x04049, 0x03046, 0x02028, 0x01025, 0x00022
+}, rtl8812au_rf0_vals5[] = {
+	0x00100, 0x0adf4, 0x09df1, 0x08dee, 0x07deb, 0x06de8, 0x05de5,
+	0x04de2, 0x03ce6, 0x024e7, 0x014e4, 0x004e1
+}, rtl8812au_rf0_vals6[] = {
+	0x00000, 0x020a2, 0x00080, 0x00192, 0x08192, 0x10192, 0x00024,
+	0x08024, 0x10024, 0x18024, 0x00000, 0x00c21, 0x006d9, 0xfc649,
+	0x0017e, 0x00002, 0x08400, 0x1712a, 0x01000, 0x00080, 0x3a02c,
+	0x04000, 0x00400, 0x3202c, 0x10000, 0x000a0, 0x2b064, 0x04000,
+	0x000d8, 0x23070, 0x04000, 0x00468, 0x1b870, 0x10000, 0x00098,
+	0x12085, 0xe4000, 0x00418, 0x0a080, 0xf0000, 0x00418, 0x02080,
+	0x10000, 0x00080, 0x7a02c, 0x04000, 0x00400, 0x7202c, 0x10000,
+	0x000a0, 0x6b064, 0x04000, 0x000d8, 0x63070, 0x04000, 0x00468,
+	0x5b870, 0x10000, 0x00098, 0x52085, 0xe4000, 0x00418, 0x4a080,
+	0xf0000, 0x00418, 0x42080, 0x10000, 0x00080, 0xba02c, 0x04000,
+	0x00400, 0xb202c, 0x10000, 0x000a0, 0xab064, 0x04000, 0x000d8,
+	0xa3070, 0x04000, 0x00468, 0x9b870, 0x10000, 0x00098, 0x92085,
+	0xe4000, 0x00418, 0x8a080, 0xf0000, 0x00418, 0x82080, 0x10000,
+	0x01100
+}, rtl8812au_rf0_vals7_pa_a0[] = {
+	0x4a0b2, 0x490af, 0x48070, 0x4706d, 0x46050, 0x4504d, 0x4404a,
+	0x43047, 0x4200a, 0x41007, 0x40004, 0x2a0b2, 0x290af, 0x28070,
+	0x2706d, 0x26050, 0x2504d, 0x2404a, 0x23047, 0x2200a, 0x21007,
+	0x20004, 0x0a0b2, 0x090af, 0x08070, 0x0706d, 0x06050, 0x0504d,
+	0x0404a, 0x03047, 0x0200a, 0x01007, 0x00004
+}, rtl8812au_rf0_vals7_pa_a5[] = {
+	0x4a0b2, 0x490af, 0x48070, 0x4706d, 0x4604d, 0x4504a, 0x44047,
+	0x43044, 0x42007, 0x41004, 0x40001, 0x2a0b4, 0x290b1, 0x28072,
+	0x2706f, 0x2604f, 0x2504c, 0x24049, 0x23046, 0x22009, 0x21006,
+	0x20003, 0x0a0b2, 0x090af, 0x08070, 0x0706d, 0x0604d, 0x0504a,
+	0x04047, 0x03044, 0x02007, 0x01004, 0x00001
+}, rtl8812au_rf0_vals7[] = {
+	0x4adf5, 0x49df2, 0x48def, 0x47dec, 0x46de9, 0x45de6, 0x44de3,
+	0x438c8, 0x428c5, 0x418c2, 0x408c0, 0x2adf5, 0x29df2, 0x28def,
+	0x27dec, 0x26de9, 0x25de6, 0x24de3, 0x238c8, 0x228c5, 0x218c2,
+	0x208c0, 0x0aff7, 0x09df7, 0x08df4, 0x07df1, 0x06dee, 0x05deb,
+	0x04de8, 0x038cc, 0x028c9, 0x018c6, 0x008c3
+}, rtl8812au_rf0_vals8_pa_a0_a5[] = {
+	0x00000, 0x1712a, 0x00040, 0x001d4, 0x081d4, 0x101d4, 0x201b4,
+	0x281b4, 0x301b4, 0x401b4, 0x481b4, 0x501b4, 0x00000, 0x1712a,
+	0x00010, 0x04bfb, 0x0cbfb, 0x14bfb, 0x1cbfb, 0x24f4b, 0x2cf4b,
+	0x34f4b, 0x3cf4b, 0x44f4b, 0x4cf4b, 0x54f4b, 0x5cf4b, 0x00000,
+	0x00008, 0x002cc, 0x00522, 0x00902
+}, rtl8812au_rf0_vals8[] = {
+	0x00000, 0x1712a, 0x00040, 0x00188, 0x08147, 0x10147, 0x201d7,
+	0x281d7, 0x301d7, 0x401d8, 0x481d8, 0x501d8, 0x00000, 0x1712a,
+	0x00010, 0x84eb4, 0x8cc35, 0x94c35, 0x9cc35, 0xa4c35, 0xacc35,
+	0xb4c35, 0xbcc35, 0xc4c34, 0xccc35, 0xd4c35, 0xdcc35, 0x00000,
+	0x00008, 0x002a8, 0x005a2, 0x00880
+}, rtl8812au_rf0_vals9[] = {
+	0x00000, 0x1712a, 0x00002, 0x00080, 0x00064
+}, rtl8812au_rf0_vals10_pa_a0[] = {
+	0xfdd43, 0x38f4b, 0x32117, 0x194ac, 0x931d1
+}, rtl8812au_rf0_vals10_pa_a5[] = {
+	0xfdd43, 0x38f4b, 0x32117, 0x194ac, 0x931d2
+}, rtl8812au_rf0_vals10[] = {
+	0xe5d53, 0x38fcd, 0x114eb, 0x196ac, 0x911d7
+}, rtl8812au_rf0_vals11[] = {
+	0x08400, 0x739d2, 0x1e78d, 0x1f12a, 0x0c350, 0x0c350, 0x0c350,
+	0x0c350, 0x1a78d, 0x1712a
+}, rtl8812au_rf1_vals0[] = {
+	0x51cf2, 0x40000, 0x00080
+}, rtl8812au_rf1_vals3[] = {
+	0x1fc1a, 0xf0810, 0x1a78d, 0x86180, 0x00006, 0x02000
+}, rtl8812au_rf1_vals6[] = {
+	0x00000, 0x020a2, 0x00080, 0x00192, 0x08192, 0x10192, 0x00024,
+	0x08024, 0x10024, 0x18024, 0x00000, 0x00c21, 0x006d9, 0xfc649,
+	0x0017e, 0x00002, 0x08400, 0x1712a, 0x01000, 0x00080, 0x3a02c,
+	0x04000, 0x00400, 0x3202c, 0x10000, 0x000a0, 0x2b064, 0x04000,
+	0x000d8, 0x23070, 0x04000, 0x00468, 0x1b870, 0x10000, 0x00098,
+	0x12085, 0xe4000, 0x00418, 0x0a080, 0xf0000, 0x00418, 0x02080,
+	0x10000, 0x00080, 0x7a02c, 0x04000, 0x00400, 0x7202c, 0x10000,
+	0x000a0, 0x6b064, 0x04000, 0x000d8, 0x63070, 0x04000, 0x00468,
+	0x5b870, 0x10000, 0x00098, 0x52085, 0xe4000, 0x00418, 0x4a080,
+	0xf0000, 0x00418, 0x42080, 0x10000, 0x00080, 0xba02c, 0x04000,
+	0x00400, 0xb202c, 0x10000, 0x000a0, 0xab064, 0x04000, 0x000d8,
+	0xa3070, 0x04000, 0x00468, 0x9b870, 0x10000, 0x00098, 0x92085,
+	0xe4000, 0x00418, 0x8a080, 0xf0000, 0x00418, 0x82080, 0x10000,
+	0x01100
+}, rtl8812au_rf1_vals7_pa_a5[] = {
+	0x4a0b1, 0x490ae, 0x4806f, 0x4706c, 0x4604c, 0x45049, 0x44046,
+	0x43043, 0x42006, 0x41003, 0x40000, 0x2a0b3, 0x290b0, 0x28071,
+	0x2706e, 0x2604e, 0x2504b, 0x24048, 0x23045, 0x22008, 0x21005,
+	0x20002, 0x0a0b3, 0x090b0, 0x08070, 0x0706d, 0x0604d, 0x0504a,
+	0x04047, 0x03044, 0x02007, 0x01004, 0x00001
+}, rtl8812au_rf1_vals8_pa_a0_a5[] = {
+	0x00000, 0x1712a, 0x00040, 0x001c5, 0x081c5, 0x101c5, 0x20174,
+	0x28174, 0x30174, 0x40185, 0x48185, 0x50185, 0x00000, 0x1712a,
+	0x00010, 0x05b8b, 0x0db8b, 0x15b8b, 0x1db8b, 0x262db, 0x2e2db,
+	0x362db, 0x3e2db, 0x4553b, 0x4d53b, 0x5553b, 0x5d53b, 0x00000,
+	0x00008, 0x002dc, 0x00524, 0x00902
+}, rtl8812au_rf1_vals10_pa_g0_a0[] = {
+	0xeac43, 0x38f47, 0x31157, 0x1c4ac, 0x931d1
+}, rtl8812au_rf1_vals10_pa_a5[] = {
+	0xeac43, 0x38f47, 0x31157, 0x1c4ac, 0x931d2
+};
+
+static const struct rtwn_rf_prog rtl8812au_rf[] = {
+	/* RF chain 0. */
+	{
+		nitems(rtl8812au_rf0_regs0),
+		rtl8812au_rf0_regs0,
+		rtl8812au_rf0_vals0,
+		{ 0 },
+		NULL
+	},
+	/* External 2GHz LNA, type 0 or 5. */
+	{
+		nitems(rtl8812au_rf0_regs1),
+		rtl8812au_rf0_regs1,
+		rtl8812au_rf0_vals1_lna_g0_g5,
+		{
+			R12A_COND_GLNA | R12A_COND_TYPE(0x0),
+			R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0
+		},
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs1),
+			rtl8812au_rf0_regs1,
+			rtl8812au_rf0_vals1,
+			{ 0 },
+			NULL
+		}
+	},
+	/* External 5GHz LNA, type 0. */
+	{
+		nitems(rtl8812au_rf0_regs2),
+		rtl8812au_rf0_regs2,
+		rtl8812au_rf0_vals2_lna_a0,
+		{ R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 },
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs2),
+			rtl8812au_rf0_regs2,
+			rtl8812au_rf0_vals2,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8812au_rf0_regs3),
+		rtl8812au_rf0_regs3,
+		rtl8812au_rf0_vals3,
+		{ 0 },
+		NULL
+	},
+	/* External 2GHz LNA, type 0 or 5. */
+	{
+		nitems(rtl8812au_rf0_regs4),
+		rtl8812au_rf0_regs4,
+		rtl8812au_rf0_vals4_lna_g0_g5,
+		{
+			R12A_COND_GLNA | R12A_COND_TYPE(0x0),
+			R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0
+		},
+		/* Others */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs4),
+			rtl8812au_rf0_regs4,
+			rtl8812au_rf0_vals4,
+			{ 0 },
+			NULL
+		}
+	},
+	/* External 2GHz PA, type 0. */
+	{
+		nitems(rtl8812au_rf0_regs5),
+		rtl8812au_rf0_regs5,
+		rtl8812au_rf0_vals5_pa_g0,
+		{ R12A_COND_GPA | R12A_COND_TYPE(0x0), 0 },
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs5),
+			rtl8812au_rf0_regs5,
+			rtl8812au_rf0_vals5,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8812au_rf0_regs6),
+		rtl8812au_rf0_regs6,
+		rtl8812au_rf0_vals6,
+		{ 0 },
+		NULL
+	},
+	/* External 5GHz PA, type 0. */
+	{
+		nitems(rtl8812au_rf0_regs7),
+		rtl8812au_rf0_regs7,
+		rtl8812au_rf0_vals7_pa_a0,
+		{ R12A_COND_APA | R12A_COND_TYPE(0x0), 0 },
+		/* External 5GHz PA, type 5. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs7),
+			rtl8812au_rf0_regs7,
+			rtl8812au_rf0_vals7_pa_a5,
+			{ R12A_COND_APA | R12A_COND_TYPE(0x5), 0 },
+			/* Others. */
+			&(const struct rtwn_rf_prog){
+				nitems(rtl8812au_rf0_regs7),
+				rtl8812au_rf0_regs7,
+				rtl8812au_rf0_vals7,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	/* External 5GHz PA, type 0 or 5. */
+	{
+		nitems(rtl8812au_rf0_regs8),
+		rtl8812au_rf0_regs8,
+		rtl8812au_rf0_vals8_pa_a0_a5,
+		{
+			R12A_COND_APA | R12A_COND_TYPE(0x0),
+			R12A_COND_APA | R12A_COND_TYPE(0x5), 0
+		},
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs8),
+			rtl8812au_rf0_regs8,
+			rtl8812au_rf0_vals8,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8812au_rf0_regs9),
+		rtl8812au_rf0_regs9,
+		rtl8812au_rf0_vals9,
+		{ 0 },
+		NULL
+	},
+	/* External 5GHz PA, type 0. */
+	{
+		nitems(rtl8812au_rf0_regs10),
+		rtl8812au_rf0_regs10,
+		rtl8812au_rf0_vals10_pa_a0,
+		{ R12A_COND_APA | R12A_COND_TYPE(0x0), 0 },
+		/* External 5GHz PA, type 5. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs10),
+			rtl8812au_rf0_regs10,
+			rtl8812au_rf0_vals10_pa_a5,
+			{ R12A_COND_APA | R12A_COND_TYPE(0x5), 0 },
+			/* Others. */
+			&(const struct rtwn_rf_prog){
+				nitems(rtl8812au_rf0_regs10),
+				rtl8812au_rf0_regs10,
+				rtl8812au_rf0_vals10,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	{
+		nitems(rtl8812au_rf0_regs11),
+		rtl8812au_rf0_regs11,
+		rtl8812au_rf0_vals11,
+		{ 0 },
+		NULL
+	},
+	{ 0, NULL, NULL, { 0 },	NULL },
+	/* RF chain 1. */
+	{
+		nitems(rtl8812au_rf1_regs0),
+		rtl8812au_rf1_regs0,
+		rtl8812au_rf1_vals0,
+		{ 0 },
+		NULL
+	},
+	/* rtl8812au_rf[1] */
+	/* External 2GHz LNA, type 0 or 5. */
+	{
+		nitems(rtl8812au_rf0_regs1),
+		rtl8812au_rf0_regs1,
+		rtl8812au_rf0_vals1_lna_g0_g5,
+		{
+			R12A_COND_GLNA | R12A_COND_TYPE(0x0),
+			R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0
+		},
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs1),
+			rtl8812au_rf0_regs1,
+			rtl8812au_rf0_vals1,
+			{ 0 },
+			NULL
+		}
+	},
+	/* rtl8812au_rf[2] */
+	/* External 5GHz LNA, type 0. */
+	{
+		nitems(rtl8812au_rf0_regs2),
+		rtl8812au_rf0_regs2,
+		rtl8812au_rf0_vals2_lna_a0,
+		{ R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 },
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs2),
+			rtl8812au_rf0_regs2,
+			rtl8812au_rf0_vals2,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8812au_rf1_regs3),
+		rtl8812au_rf1_regs3,
+		rtl8812au_rf1_vals3,
+		{ 0 },
+		NULL
+	},
+	/* rtl8812au_rf[4] */
+	/* External 2GHz LNA, type 0 or 5. */
+	{
+		nitems(rtl8812au_rf0_regs4),
+		rtl8812au_rf0_regs4,
+		rtl8812au_rf0_vals4_lna_g0_g5,
+		{
+			R12A_COND_GLNA | R12A_COND_TYPE(0x0),
+			R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0
+		},
+		/* Others */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs4),
+			rtl8812au_rf0_regs4,
+			rtl8812au_rf0_vals4,
+			{ 0 },
+			NULL
+		}
+	},
+	/* rtl8812au_rf[5] */
+	/* External 2GHz PA, type 0. */
+	{
+		nitems(rtl8812au_rf0_regs5),
+		rtl8812au_rf0_regs5,
+		rtl8812au_rf0_vals5_pa_g0,
+		{ R12A_COND_GPA | R12A_COND_TYPE(0x0), 0 },
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs5),
+			rtl8812au_rf0_regs5,
+			rtl8812au_rf0_vals5,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8812au_rf0_regs6),
+		rtl8812au_rf0_regs6,
+		rtl8812au_rf1_vals6,
+		{ 0 },
+		NULL
+	},
+	/* External 5GHz PA, type 0. */
+	{
+		nitems(rtl8812au_rf0_regs7),
+		rtl8812au_rf0_regs7,
+		rtl8812au_rf0_vals7_pa_a0,
+		{ R12A_COND_APA | R12A_COND_TYPE(0x0), 0 },
+		/* External 5GHz PA, type 5. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs7),
+			rtl8812au_rf0_regs7,
+			rtl8812au_rf1_vals7_pa_a5,
+			{ R12A_COND_APA | R12A_COND_TYPE(0x5), 0 },
+			/* Others. */
+			&(const struct rtwn_rf_prog){
+				nitems(rtl8812au_rf0_regs7),
+				rtl8812au_rf0_regs7,
+				rtl8812au_rf0_vals7,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	/* External 5GHz PA, type 0 or 5. */
+	{
+		nitems(rtl8812au_rf0_regs8),
+		rtl8812au_rf0_regs8,
+		rtl8812au_rf1_vals8_pa_a0_a5,
+		{
+			R12A_COND_APA | R12A_COND_TYPE(0x0),
+			R12A_COND_APA | R12A_COND_TYPE(0x5), 0
+		},
+		/* Others. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs8),
+			rtl8812au_rf0_regs8,
+			rtl8812au_rf0_vals8,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8812au_rf0_regs9) - 1,
+		rtl8812au_rf0_regs9,
+		rtl8812au_rf0_vals9,
+		{ 0 },
+		NULL
+	},
+
+	/* External 2GHz or 5GHz PA, type 0. */
+	{
+		nitems(rtl8812au_rf0_regs10),
+		rtl8812au_rf0_regs10,
+		rtl8812au_rf1_vals10_pa_g0_a0,
+		{
+			R12A_COND_GPA | R12A_COND_TYPE(0x0),
+			R12A_COND_APA | R12A_COND_TYPE(0x0), 0
+		},
+		/* External 5GHz PA, type 5. */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8812au_rf0_regs10),
+			rtl8812au_rf0_regs10,
+			rtl8812au_rf1_vals10_pa_a5,
+			{ R12A_COND_APA | R12A_COND_TYPE(0x5), 0 },
+			/* Others. */
+			&(const struct rtwn_rf_prog){
+				nitems(rtl8812au_rf0_regs10),
+				rtl8812au_rf0_regs10,
+				rtl8812au_rf0_vals10,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	{
+		1,
+		rtl8812au_rf0_regs11,
+		rtl8812au_rf0_vals11,
+		{ 0 },
+		NULL
+	},
+	{ 0, NULL, NULL, { 0 }, NULL }
+};
+
+
+/*
+ * Registers to save before IQ calibration.
+ */
+static const uint16_t r12a_iq_bb_regs[] = {
+	0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0xe00, 0x838, 0x82c
+};
+
+static const uint16_t r12a_iq_afe_regs[] = {
+	0xc5c, 0xc60, 0xc64, 0xc68, 0xcb0, 0xcb4, 0xe5c, 0xe60, 0xe64,
+	0xe68, 0xeb0, 0xeb4
+};
+
+static const uint8_t r12a_iq_rf_regs[] = {
+	0x65, 0x8f, 0x0
+};
+
+#endif	/* R12A_PRIV_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,236 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12A_REG_H
+#define R12A_REG_H
+
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
+
+/*
+ * MAC registers.
+ */
+/* System Configuration. */
+#define R12A_SDIO_CTRL			0x070
+#define R12A_RF_B_CTRL			0x076
+/* Rx DMA Configuration. */
+#define R12A_RXDMA_PRO			0x290
+#define R12A_EARLY_MODE_CONTROL		0x2bc
+/* Protocol Configuration. */
+#define R12A_TXPKT_EMPTY		0x41a
+#define R12A_ARFR_5G(i)			(0x444 + (i) * 8)
+#define R12A_CCK_CHECK			0x454
+#define R12A_AMPDU_MAX_TIME		0x456
+#define R12A_AMPDU_MAX_LENGTH		R92C_AGGLEN_LMT
+#define R12A_DATA_SEC			0x483
+#define R12A_ARFR_2G(i)			(0x48c + (i) * 8)
+#define R12A_HT_SINGLE_AMPDU		0x4c7
+
+
+/* Bits for R92C_MAC_PHY_CTRL. */
+#define R12A_MAC_PHY_CRYSTALCAP_M	0x7ff80000
+#define R12A_MAC_PHY_CRYSTALCAP_S	19
+
+/* Bits for R92C_LEDCFG2. */
+#define R12A_LEDCFG2_ENA		0x20
+
+/* Bits for R12A_CCK_CHECK. */
+#define R12A_CCK_CHECK_BCN1		0x20
+#define R12A_CCK_CHECK_5GHZ		0x80
+
+/* Bits for R12A_DATA_SEC. */
+#define R12A_DATA_SEC_NO_EXT		0x00
+#define R12A_DATA_SEC_PRIM_UP_20	0x01
+#define R12A_DATA_SEC_PRIM_DOWN_20	0x02
+#define R12A_DATA_SEC_PRIM_UPPER_20	0x03
+#define R12A_DATA_SEC_PRIM_LOWER_20	0x04
+#define R12A_DATA_SEC_PRIM_UP_40	0x90
+#define R12A_DATA_SEC_PRIM_DOWN_40	0xa0
+
+/* Bits for R12A_HT_SINGLE_AMPDU. */
+#define R12A_HT_SINGLE_AMPDU_PKT_ENA	0x80
+
+/* Bits for R92C_RCR. */
+#define R12A_RCR_DIS_CHK_14		0x00200000
+#define R12A_RCR_TCP_OFFLD_EN		0x02000000
+#define R12A_RCR_VHT_ACK		0x04000000
+
+
+/*
+ * Baseband registers.
+ */
+#define R12A_CCK_RPT_FORMAT		0x804
+#define R12A_OFDMCCK_EN			0x808
+#define R12A_RX_PATH			R12A_OFDMCCK_EN
+#define R12A_TX_PATH			0x80c
+#define R12A_TXAGC_TABLE_SELECT		0x82c
+#define R12A_PWED_TH			0x830
+#define R12A_BW_INDICATION		0x834
+#define R12A_CCA_ON_SEC			0x838
+#define R12A_L1_PEAK_TH			0x848
+#define R12A_FC_AREA			0x860
+#define R12A_RFMOD			0x8ac
+#define R12A_HSSI_PARAM2		0x8b0
+#define R12A_ADC_BUF_CLK		0x8c4
+#define R12A_ANTSEL_SW			0x900
+#define R12A_SINGLETONE_CONT_TX		0x914
+#define R12A_CCK_RX_PATH		0xa04
+#define R12A_HSSI_PARAM1(chain)		(0xc00 + (chain) * 0x200)
+#define R12A_TX_SCALE(chain)		(0xc1c + (chain) * 0x200)
+#define R12A_TXAGC_CCK11_1(chain)	(0xc20 + (chain) * 0x200)
+#define R12A_TXAGC_OFDM18_6(chain)	(0xc24 + (chain) * 0x200)
+#define R12A_TXAGC_OFDM54_24(chain)	(0xc28 + (chain) * 0x200)
+#define R12A_TXAGC_MCS3_0(chain)	(0xc2c + (chain) * 0x200)
+#define R12A_TXAGC_MCS7_4(chain)	(0xc30 + (chain) * 0x200)
+#define R12A_TXAGC_MCS11_8(chain)	(0xc34 + (chain) * 0x200)
+#define R12A_TXAGC_MCS15_12(chain)	(0xc38 + (chain) * 0x200)
+#define R12A_TXAGC_NSS1IX3_1IX0(chain)	(0xc3c + (chain) * 0x200)
+#define R12A_TXAGC_NSS1IX7_1IX4(chain)	(0xc40 + (chain) * 0x200)
+#define R12A_TXAGC_NSS2IX1_1IX8(chain)	(0xc44 + (chain) * 0x200)
+#define R12A_TXAGC_NSS2IX5_2IX2(chain)	(0xc48 + (chain) * 0x200)
+#define R12A_TXAGC_NSS2IX9_2IX6(chain)	(0xc4c + (chain) * 0x200)
+#define R12A_INITIAL_GAIN(chain)	(0xc50 + (chain) * 0x200)
+#define R12A_AFE_POWER_1(chain)		(0xc60 + (chain) * 0x200)
+#define R12A_AFE_POWER_2(chain)		(0xc64 + (chain) * 0x200)
+#define R12A_SLEEP_NAV(chain)		(0xc80 + (chain) * 0x200)
+#define R12A_PMPD(chain)		(0xc84 + (chain) * 0x200)
+#define R12A_LSSI_PARAM(chain)		(0xc90 + (chain) * 0x200)
+#define R12A_RFE_PINMUX(chain)		(0xcb0 + (chain) * 0x200)
+#define R12A_RFE_INV(chain)		(0xcb4 + (chain) * 0x200)
+#define R12A_RFE(chain)			(0xcb8 + (chain) * 0x200)
+#define R12A_HSPI_READBACK(chain)	(0xd04 + (chain) * 0x40)
+#define R12A_LSSI_READBACK(chain)	(0xd08 + (chain) * 0x40)
+
+/* Bits for R12A_CCK_RPT_FORMAT. */
+#define R12A_CCK_RPT_FORMAT_HIPWR	0x00010000
+
+/* Bits for R12A_OFDMCCK_EN. */
+#define R12A_OFDMCCK_EN_CCK	0x10000000
+#define R12A_OFDMCCK_EN_OFDM	0x20000000
+
+/* Bits for R12A_CCA_ON_SEC. */
+#define R12A_CCA_ON_SEC_EXT_CHAN_M	0xf0000000
+#define R12A_CCA_ON_SEC_EXT_CHAN_S	28
+
+/* Bits for R12A_RFE_PINMUX(i). */
+#define R12A_RFE_PINMUX_PA_A_MASK	0x000000f0
+#define R12A_RFE_PINMUX_LNA_MASK	0x0000f000
+
+/* Bits for R12A_RFMOD. */
+#define R12A_RFMOD_EXT_CHAN_M		0x3C
+#define R12A_RFMOD_EXT_CHAN_S		2
+
+/* Bits for R12A_HSSI_PARAM2. */
+#define R12A_HSSI_PARAM2_READ_ADDR_MASK	0xff
+
+/* Bits for R12A_HSSI_PARAM1(i). */
+#define R12A_HSSI_PARAM1_PI		0x00000004
+
+/* Bits for R12A_TX_SCALE(i). */
+#define R12A_TX_SCALE_SWING_M		0xffe00000
+#define R12A_TX_SCALE_SWING_S		21
+
+/* Bits for R12A_TXAGC_CCK11_1(i). */
+#define R12A_TXAGC_CCK1_M		0x000000ff
+#define R12A_TXAGC_CCK1_S		0
+#define R12A_TXAGC_CCK2_M		0x0000ff00
+#define R12A_TXAGC_CCK2_S		8
+#define R12A_TXAGC_CCK55_M		0x00ff0000
+#define R12A_TXAGC_CCK55_S		16
+#define R12A_TXAGC_CCK11_M		0xff000000
+#define R12A_TXAGC_CCK11_S		24
+
+/* Bits for R12A_TXAGC_OFDM18_6(i). */
+#define R12A_TXAGC_OFDM06_M		0x000000ff
+#define R12A_TXAGC_OFDM06_S		0
+#define R12A_TXAGC_OFDM09_M		0x0000ff00
+#define R12A_TXAGC_OFDM09_S		8
+#define R12A_TXAGC_OFDM12_M		0x00ff0000
+#define R12A_TXAGC_OFDM12_S		16
+#define R12A_TXAGC_OFDM18_M		0xff000000
+#define R12A_TXAGC_OFDM18_S		24
+
+/* Bits for R12A_TXAGC_OFDM54_24(i). */
+#define R12A_TXAGC_OFDM24_M		0x000000ff
+#define R12A_TXAGC_OFDM24_S		0
+#define R12A_TXAGC_OFDM36_M		0x0000ff00
+#define R12A_TXAGC_OFDM36_S		8
+#define R12A_TXAGC_OFDM48_M		0x00ff0000
+#define R12A_TXAGC_OFDM48_S		16
+#define R12A_TXAGC_OFDM54_M		0xff000000
+#define R12A_TXAGC_OFDM54_S		24
+
+/* Bits for R12A_TXAGC_MCS3_0(i). */
+#define R12A_TXAGC_MCS0_M		0x000000ff
+#define R12A_TXAGC_MCS0_S		0
+#define R12A_TXAGC_MCS1_M		0x0000ff00
+#define R12A_TXAGC_MCS1_S		8
+#define R12A_TXAGC_MCS2_M		0x00ff0000
+#define R12A_TXAGC_MCS2_S		16
+#define R12A_TXAGC_MCS3_M		0xff000000
+#define R12A_TXAGC_MCS3_S		24
+
+/* Bits for R12A_TXAGC_MCS7_4(i). */
+#define R12A_TXAGC_MCS4_M		0x000000ff
+#define R12A_TXAGC_MCS4_S		0
+#define R12A_TXAGC_MCS5_M		0x0000ff00
+#define R12A_TXAGC_MCS5_S		8
+#define R12A_TXAGC_MCS6_M		0x00ff0000
+#define R12A_TXAGC_MCS6_S		16
+#define R12A_TXAGC_MCS7_M		0xff000000
+#define R12A_TXAGC_MCS7_S		24
+
+/* Bits for R12A_TXAGC_MCS11_8(i). */
+#define R12A_TXAGC_MCS8_M		0x000000ff
+#define R12A_TXAGC_MCS8_S		0
+#define R12A_TXAGC_MCS9_M		0x0000ff00
+#define R12A_TXAGC_MCS9_S		8
+#define R12A_TXAGC_MCS10_M		0x00ff0000
+#define R12A_TXAGC_MCS10_S		16
+#define R12A_TXAGC_MCS11_M		0xff000000
+#define R12A_TXAGC_MCS11_S		24
+
+/* Bits for R12A_TXAGC_MCS15_12(i). */
+#define R12A_TXAGC_MCS12_M		0x000000ff
+#define R12A_TXAGC_MCS12_S		0
+#define R12A_TXAGC_MCS13_M		0x0000ff00
+#define R12A_TXAGC_MCS13_S		8
+#define R12A_TXAGC_MCS14_M		0x00ff0000
+#define R12A_TXAGC_MCS14_S		16
+#define R12A_TXAGC_MCS15_M		0xff000000
+#define R12A_TXAGC_MCS15_S		24
+
+
+/*
+ * RF (6052) registers.
+ */
+#define R12A_RF_LCK		0xb4
+
+/* Bits for R12A_RF_LCK. */
+#define R12A_RF_LCK_MODE	0x4000
+
+#endif	/* R12A_REG_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,112 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+
+
+uint32_t
+r12a_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr)
+{
+	uint32_t pi_mode, val;
+
+	/* Turn off CCA (avoids reading the wrong value). */
+	if (addr != R92C_RF_AC)
+		rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0, 0x08);
+
+	val = rtwn_bb_read(sc, R12A_HSSI_PARAM1(chain));
+	pi_mode = (val & R12A_HSSI_PARAM1_PI) ? 1 : 0;
+
+	rtwn_bb_setbits(sc, R12A_HSSI_PARAM2,
+	    R12A_HSSI_PARAM2_READ_ADDR_MASK, addr);
+
+	val = rtwn_bb_read(sc, pi_mode ? R12A_HSPI_READBACK(chain) :
+	    R12A_LSSI_READBACK(chain));
+
+	/* Turn on CCA (when exiting). */
+	if (addr != R92C_RF_AC)
+		rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0x08, 0);
+
+	return (MS(val, R92C_LSSI_READBACK_DATA));
+}
+
+uint32_t
+r12a_c_cut_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr)
+{
+	uint32_t pi_mode, val;
+
+	val = rtwn_bb_read(sc, R12A_HSSI_PARAM1(chain));
+	pi_mode = (val & R12A_HSSI_PARAM1_PI) ? 1 : 0;
+
+	rtwn_bb_setbits(sc, R12A_HSSI_PARAM2,
+	    R12A_HSSI_PARAM2_READ_ADDR_MASK, addr);
+	rtwn_delay(sc, 20);
+
+	val = rtwn_bb_read(sc, pi_mode ? R12A_HSPI_READBACK(chain) :
+	    R12A_LSSI_READBACK(chain));
+
+	return (MS(val, R92C_LSSI_READBACK_DATA));
+}
+
+void
+r12a_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr,
+    uint32_t val)
+{
+	rtwn_bb_write(sc, R12A_LSSI_PARAM(chain),
+	    SM(R88E_LSSI_PARAM_ADDR, addr) |
+	    SM(R92C_LSSI_PARAM_DATA, val));
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,224 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+#include <dev/rtwn/rtl8812a/r12a_rom_image.h>
+
+
+void
+r12a_parse_rom_common(struct rtwn_softc *sc, uint8_t *buf)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	struct r12a_rom *rom = (struct r12a_rom *)buf;
+	int i, j, k;
+
+	sc->thermal_meter = rom->thermal_meter;
+	rs->crystalcap = RTWN_GET_ROM_VAR(rom->crystalcap,
+	    R12A_ROM_CRYSTALCAP_DEF);
+	rs->tx_bbswing_2g = RTWN_GET_ROM_VAR(rom->tx_bbswing_2g, 0);
+	rs->tx_bbswing_5g = RTWN_GET_ROM_VAR(rom->tx_bbswing_5g, 0);
+
+	for (i = 0; i < sc->ntxchains; i++) {
+		struct r12a_tx_pwr_2g *pwr_2g = &rom->tx_pwr[i].pwr_2g;
+		struct r12a_tx_pwr_5g *pwr_5g = &rom->tx_pwr[i].pwr_5g;
+		struct r12a_tx_pwr_diff_2g *pwr_diff_2g =
+		    &rom->tx_pwr[i].pwr_diff_2g;
+		struct r12a_tx_pwr_diff_5g *pwr_diff_5g =
+		    &rom->tx_pwr[i].pwr_diff_5g;
+
+		for (j = 0; j < R12A_GROUP_2G - 1; j++) {
+			rs->cck_tx_pwr[i][j] =
+			    RTWN_GET_ROM_VAR(pwr_2g->cck[j],
+				R12A_DEF_TX_PWR_2G);
+			rs->ht40_tx_pwr_2g[i][j] =
+			    RTWN_GET_ROM_VAR(pwr_2g->ht40[j],
+				R12A_DEF_TX_PWR_2G);
+		}
+		rs->cck_tx_pwr[i][j] = RTWN_GET_ROM_VAR(pwr_2g->cck[j],
+		    R12A_DEF_TX_PWR_2G);
+
+		rs->cck_tx_pwr_diff_2g[i][0] = 0;
+		rs->ofdm_tx_pwr_diff_2g[i][0] = RTWN_SIGN4TO8(
+		    MS(pwr_diff_2g->ht20_ofdm, LOW_PART));
+		rs->bw20_tx_pwr_diff_2g[i][0] = RTWN_SIGN4TO8(
+		    MS(pwr_diff_2g->ht20_ofdm, HIGH_PART));
+		rs->bw40_tx_pwr_diff_2g[i][0] = 0;
+
+		for (j = 1, k = 0; k < nitems(pwr_diff_2g->diff123); j++, k++) {
+			rs->cck_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8(
+			    MS(pwr_diff_2g->diff123[k].ofdm_cck, LOW_PART));
+			rs->ofdm_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8(
+			    MS(pwr_diff_2g->diff123[k].ofdm_cck, HIGH_PART));
+			rs->bw20_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8(
+			    MS(pwr_diff_2g->diff123[k].ht40_ht20, LOW_PART));
+			rs->bw40_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8(
+			    MS(pwr_diff_2g->diff123[k].ht40_ht20, HIGH_PART));
+		}
+
+		for (j = 0; j < R12A_GROUP_5G; j++) {
+			rs->ht40_tx_pwr_5g[i][j] =
+			    RTWN_GET_ROM_VAR(pwr_5g->ht40[j],
+				R12A_DEF_TX_PWR_5G);
+		}
+
+		rs->ofdm_tx_pwr_diff_5g[i][0] = RTWN_SIGN4TO8(
+		    MS(pwr_diff_5g->ht20_ofdm, LOW_PART));
+		rs->ofdm_tx_pwr_diff_5g[i][1] = RTWN_SIGN4TO8(
+		    MS(pwr_diff_5g->ofdm_ofdm[0], HIGH_PART));
+		rs->ofdm_tx_pwr_diff_5g[i][2] = RTWN_SIGN4TO8(
+		    MS(pwr_diff_5g->ofdm_ofdm[0], LOW_PART));
+		rs->ofdm_tx_pwr_diff_5g[i][3] = RTWN_SIGN4TO8(
+		    MS(pwr_diff_5g->ofdm_ofdm[1], LOW_PART));
+
+		rs->bw20_tx_pwr_diff_5g[i][0] = RTWN_SIGN4TO8(
+		    MS(pwr_diff_5g->ht20_ofdm, HIGH_PART));
+		rs->bw40_tx_pwr_diff_5g[i][0] = 0;
+		for (j = 1, k = 0; k < nitems(pwr_diff_5g->ht40_ht20);
+		    j++, k++) {
+			rs->bw20_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8(
+			    MS(pwr_diff_5g->ht40_ht20[k], LOW_PART));
+			rs->bw40_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8(
+			    MS(pwr_diff_5g->ht40_ht20[k], HIGH_PART));
+		}
+
+		for (j = 0; j < nitems(pwr_diff_5g->ht80_ht160); j++) {
+			rs->bw80_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8(
+			    MS(pwr_diff_5g->ht80_ht160[j], HIGH_PART));
+			rs->bw160_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8(
+			    MS(pwr_diff_5g->ht80_ht160[j], LOW_PART));
+		}
+	}
+
+	rs->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY);
+	rs->board_type =
+	    MS(RTWN_GET_ROM_VAR(rom->rf_board_opt, R92C_BOARD_TYPE_DONGLE),
+		R92C_ROM_RF1_BOARD_TYPE);
+	RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type=%d\n",
+	    __func__, rs->regulatory);
+}
+
+void
+r12a_parse_rom(struct rtwn_softc *sc, uint8_t *buf)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	struct r12a_rom *rom = (struct r12a_rom *)buf;
+	uint8_t pa_type, lna_type_2g, lna_type_5g;
+
+	/* Read PA/LNA types. */
+	pa_type = RTWN_GET_ROM_VAR(rom->pa_type, 0);
+	lna_type_2g = RTWN_GET_ROM_VAR(rom->lna_type_2g, 0);
+	lna_type_5g = RTWN_GET_ROM_VAR(rom->lna_type_5g, 0);
+
+	rs->ext_pa_2g = R12A_ROM_IS_PA_EXT_2GHZ(pa_type);
+	rs->ext_pa_5g = R12A_ROM_IS_PA_EXT_5GHZ(pa_type);
+	rs->ext_lna_2g = R21A_ROM_IS_LNA_EXT(lna_type_2g);
+	rs->ext_lna_5g = R21A_ROM_IS_LNA_EXT(lna_type_5g);
+	rs->bt_coex = (MS(rom->rf_board_opt, R92C_ROM_RF1_BOARD_TYPE) ==
+	    R92C_BOARD_TYPE_HIGHPA);
+	rs->bt_ant_num = (rom->rf_bt_opt & R12A_RF_BT_OPT_ANT_NUM);
+
+	if (rs->ext_pa_2g) {
+		rs->type_pa_2g =
+		    R12A_GET_ROM_PA_TYPE(lna_type_2g, 0) |
+		    (R12A_GET_ROM_PA_TYPE(lna_type_2g, 1) << 2);
+	}
+	if (rs->ext_pa_5g) {
+		rs->type_pa_5g =
+		    R12A_GET_ROM_PA_TYPE(lna_type_5g, 0) |
+		    (R12A_GET_ROM_PA_TYPE(lna_type_5g, 1) << 2);
+	}
+	if (rs->ext_lna_2g) {
+		rs->type_lna_2g =
+		    R12A_GET_ROM_LNA_TYPE(lna_type_2g, 0) |
+		    (R12A_GET_ROM_LNA_TYPE(lna_type_2g, 1) << 2);
+	}
+	if (rs->ext_lna_5g) {
+		rs->type_lna_5g =
+		    R12A_GET_ROM_LNA_TYPE(lna_type_5g, 0) |
+		    (R12A_GET_ROM_LNA_TYPE(lna_type_5g, 1) << 2);
+	}
+
+	if (rom->rfe_option & 0x80) {
+		if (rs->ext_lna_5g) {
+			if (rs->ext_pa_5g) {
+				if (rs->ext_pa_2g && rs->ext_lna_2g)
+					rs->rfe_type = 3;
+				else
+					rs->rfe_type = 0;
+			} else
+				rs->rfe_type = 2;
+		} else
+			rs->rfe_type = 4;
+	} else {
+		rs->rfe_type = rom->rfe_option & 0x3f;
+
+		/* workaround for incorrect EFUSE map */
+		if (rs->rfe_type == 4 &&
+		    rs->ext_pa_2g && rs->ext_lna_2g &&
+		    rs->ext_pa_5g && rs->ext_lna_5g)
+			rs->rfe_type = 0;
+	}
+
+	/* Read MAC address. */
+	IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr_12a);
+
+	/* Execute common part of initialization. */
+	r12a_parse_rom_common(sc, buf);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12A_ROM_DEFS_H
+#define R12A_ROM_DEFS_H
+
+#include <dev/rtwn/rtl8192c/r92c_rom_defs.h>
+
+#define R12A_GROUP_2G		6
+#define R12A_GROUP_5G		14
+
+#define R12A_MAX_TX_COUNT	4
+#define R12A_MAX_RF_PATH	4
+
+#define	R12A_EFUSE_MAX_LEN	512
+#define R12A_EFUSE_MAP_LEN	512
+
+#endif	/* R12A_ROM_DEFS_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12A_ROM_IMAGE_H
+#define R12A_ROM_IMAGE_H
+
+#include <dev/rtwn/rtl8812a/r12a_rom_defs.h>
+
+#define R12A_DEF_TX_PWR_2G	0x2d
+#define R12A_DEF_TX_PWR_5G	0xfe
+
+struct r12a_tx_pwr_2g {
+	uint8_t		cck[R12A_GROUP_2G];
+	uint8_t		ht40[R12A_GROUP_2G - 1];
+} __packed;
+
+struct r12a_tx_pwr_diff_2g {
+	uint8_t		ht20_ofdm;
+	struct {
+		uint8_t	ht40_ht20;
+		uint8_t	ofdm_cck;
+	} __packed	diff123[R12A_MAX_TX_COUNT - 1];
+} __packed;
+
+struct r12a_tx_pwr_5g {
+	uint8_t		ht40[R12A_GROUP_5G];
+} __packed;
+
+struct r12a_tx_pwr_diff_5g {
+	uint8_t		ht20_ofdm;
+	uint8_t		ht40_ht20[R12A_MAX_TX_COUNT - 1];
+	uint8_t		ofdm_ofdm[2];
+	uint8_t		ht80_ht160[R12A_MAX_TX_COUNT];
+} __packed;
+
+struct r12a_tx_pwr {
+	struct r12a_tx_pwr_2g		pwr_2g;
+	struct r12a_tx_pwr_diff_2g	pwr_diff_2g;
+	struct r12a_tx_pwr_5g		pwr_5g;
+	struct r12a_tx_pwr_diff_5g	pwr_diff_5g;
+} __packed;
+
+/*
+ * RTL8812AU/RTL8821AU ROM image.
+ */
+struct r12a_rom {
+	uint8_t			reserved1[16];
+	struct r12a_tx_pwr	tx_pwr[R12A_MAX_RF_PATH];
+	uint8_t			channel_plan;
+	uint8_t			crystalcap;
+#define R12A_ROM_CRYSTALCAP_DEF		0x20
+
+	uint8_t			thermal_meter;
+	uint8_t			iqk_lck;
+	uint8_t			pa_type;
+#define R12A_ROM_IS_PA_EXT_2GHZ(pa_type)	(((pa_type) & 0x30) == 0x30)
+#define R12A_ROM_IS_PA_EXT_5GHZ(pa_type)	(((pa_type) & 0x03) == 0x03)
+#define R21A_ROM_IS_PA_EXT_2GHZ(pa_type)	(((pa_type) & 0x10) == 0x10)
+#define R21A_ROM_IS_PA_EXT_5GHZ(pa_type)	(((pa_type) & 0x01) == 0x01)
+
+	uint8_t			lna_type_2g;
+#define R12A_ROM_IS_LNA_EXT(lna_type)		(((lna_type) & 0x88) == 0x88)
+#define R21A_ROM_IS_LNA_EXT(lna_type)		(((lna_type) & 0x08) == 0x08)
+
+#define R12A_GET_ROM_PA_TYPE(lna_type, chain)		\
+	(((lna_type) >> ((chain) * 4 + 2)) & 0x01)
+#define R12A_GET_ROM_LNA_TYPE(lna_type, chain)	\
+	(((lna_type) >> ((chain) * 4)) & 0x03)
+
+	uint8_t			reserved2;
+	uint8_t			lna_type_5g;
+	uint8_t			reserved3;
+	uint8_t			rf_board_opt;
+#define R12A_BOARD_TYPE_COMBO_MF	5
+
+	uint8_t			rf_feature_opt;
+	uint8_t			rf_bt_opt;
+#define R12A_RF_BT_OPT_ANT_NUM		0x01
+
+	uint8_t			version;
+	uint8_t			customer_id;
+	uint8_t			tx_bbswing_2g;
+	uint8_t			tx_bbswing_5g;
+	uint8_t			tx_pwr_calib_rate;
+	uint8_t			rf_ant_opt;
+	uint8_t			rfe_option;
+	uint8_t			reserved4[5];
+	uint16_t		vid_12a;
+	uint16_t		pid_12a;
+	uint8_t			reserved5[3];
+	uint8_t			macaddr_12a[IEEE80211_ADDR_LEN];
+	uint8_t			reserved6[2];
+	uint8_t			string_12a[8];	/* "Realtek " */
+	uint8_t			reserved7[25];
+	uint16_t		vid_21a;
+	uint16_t		pid_21a;
+	uint8_t			reserved8[3];
+	uint8_t			macaddr_21a[IEEE80211_ADDR_LEN];
+	uint8_t			reserved9[2];
+	uint8_t			string_21a[8];	/* "Realtek " */
+	uint8_t			reserved10[2];
+	uint8_t			string_ven[23];	/* XXX variable length? */
+	uint8_t			reserved11[208];
+} __packed;
+
+_Static_assert(sizeof(struct r12a_rom) == R12A_EFUSE_MAP_LEN,
+    "R12A_EFUSE_MAP_LEN must be equal to sizeof(struct r12a_rom)!");
+
+#endif	/* R12A_ROM_IMAGE_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,240 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+#include <dev/rtwn/rtl8812a/r12a_fw_cmd.h>
+#include <dev/rtwn/rtl8812a/r12a_rx_desc.h>
+
+
+#ifndef RTWN_WITHOUT_UCODE
+void
+r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+#if __FreeBSD_version >= 1200012
+	struct ieee80211_ratectl_tx_status txs;
+#endif
+	struct r12a_c2h_tx_rpt *rpt;
+	struct ieee80211_node *ni;
+	int ntries;
+
+	/* Skip Rx descriptor / report id / sequence fields. */
+	buf += sizeof(struct r92c_rx_stat) + 2;
+	len -= sizeof(struct r92c_rx_stat) + 2;
+
+	rpt = (struct r12a_c2h_tx_rpt *)buf;
+	if (len != sizeof(*rpt)) {
+		device_printf(sc->sc_dev,
+		    "%s: wrong report size (%d, must be %zu)\n",
+		    __func__, len, sizeof(*rpt));
+		return;
+	}
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
+	    "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: "
+	    "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n",
+	    __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2,
+	    rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate,
+	    rpt->reserved);
+
+	if (rpt->macid > sc->macid_limit) {
+		device_printf(sc->sc_dev,
+		    "macid %u is too big; increase MACID_MAX limit\n",
+		    rpt->macid);
+		return;
+	}
+
+	ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT);
+
+	ni = sc->node_list[rpt->macid];
+	if (ni != NULL) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
+		    "%s sent (%d retries)\n", __func__, rpt->macid,
+		    (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER |
+		    R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries);
+
+#if __FreeBSD_version >= 1200012
+		txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY |
+			    IEEE80211_RATECTL_STATUS_FINAL_RATE;
+		txs.long_retries = ntries;
+		if (rpt->final_rate > RTWN_RIDX_OFDM54) {	/* MCS */
+			txs.final_rate =
+			    (rpt->final_rate - 12) | IEEE80211_RATE_MCS;
+		} else
+			txs.final_rate = ridx2rate[rpt->final_rate];
+		if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER)
+			txs.status = IEEE80211_RATECTL_TX_FAIL_LONG;
+		else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE)
+			txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
+		else
+			txs.status = IEEE80211_RATECTL_TX_SUCCESS;
+		ieee80211_ratectl_tx_complete(ni, &txs);
+#else
+		struct ieee80211vap *vap = ni->ni_vap;
+		if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) {
+			ieee80211_ratectl_tx_complete(vap, ni,
+			    IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
+		} else {
+			ieee80211_ratectl_tx_complete(vap, ni,
+			    IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
+		}
+#endif
+	} else {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
+		    "%s: macid %u, ni is NULL\n", __func__, rpt->macid);
+	}
+}
+
+void
+r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+
+	/* Skip Rx descriptor. */
+	buf += sizeof(struct r92c_rx_stat);
+	len -= sizeof(struct r92c_rx_stat);
+
+	if (len < 2) {
+		device_printf(sc->sc_dev, "C2H report too short (len %d)\n",
+		    len);
+		return;
+	}
+	len -= 2;
+
+	switch (buf[0]) {	/* command id */
+	case R12A_C2H_TX_REPORT:
+		/* NOTREACHED */
+		KASSERT(0, ("use handle_tx_report() instead of %s\n",
+		    __func__));
+		break;
+	case R12A_C2H_IQK_FINISHED:
+		RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
+		    "FW IQ calibration finished\n");
+		rs->rs_flags &= ~R12A_IQK_RUNNING;
+		break;
+	default:
+		device_printf(sc->sc_dev,
+		    "%s: C2H report %u was not handled\n",
+		    __func__, buf[0]);
+	}
+}
+#else
+void
+r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+	/* Should not happen. */
+	device_printf(sc->sc_dev, "%s: called\n", __func__);
+}
+
+void
+r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+	/* Should not happen. */
+	device_printf(sc->sc_dev, "%s: called\n", __func__);
+}
+#endif
+
+int
+r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	struct r92c_rx_stat *stat;
+	uint32_t rxdw1;
+
+	stat = mtod(m, struct r92c_rx_stat *);
+	rxdw1 = le32toh(stat->rxdw1);
+	if (rxdw1 & R12A_RXDW1_CKSUM) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
+		    "%s: %s/%s checksum is %s\n", __func__,
+		    (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP",
+		    (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP",
+		    (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid");
+
+		if (rxdw1 & R12A_RXDW1_CKSUM_ERR)
+			return (-1);
+
+		if ((rxdw1 & R12A_RXDW1_IPV6) ?
+		    (rs->rs_flags & R12A_RXCKSUM6_EN) :
+		    (rs->rs_flags & R12A_RXCKSUM_EN)) {
+			m->m_pkthdr.csum_flags = CSUM_IP_CHECKED |
+			    CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+			m->m_pkthdr.csum_data = 0xffff;
+		}
+	}
+
+	return (0);
+}
+
+uint8_t
+r12a_rx_radiotap_flags(const void *buf)
+{
+	const struct r92c_rx_stat *stat = buf;
+	uint8_t flags, rate;
+
+	if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP)))
+		return (0);
+	rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE);
+	if (RTWN_RATE_IS_CCK(rate))
+		flags = IEEE80211_RADIOTAP_F_SHORTPRE;
+	else
+		flags = IEEE80211_RADIOTAP_F_SHORTGI;
+	return (flags);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12A_RX_DESC_H
+#define R12A_RX_DESC_H
+
+#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
+
+/* Rx MAC descriptor defines (chip-specific). */
+/* Rx dword 1 */
+#define R12A_RXDW1_AMSDU	0x00002000
+#define R12A_RXDW1_CKSUM_ERR	0x00100000
+#define R12A_RXDW1_IPV6		0x00200000
+#define R12A_RXDW1_UDP		0x00400000
+#define R12A_RXDW1_CKSUM	0x00800000
+/* Rx dword 2 */
+#define R12A_RXDW2_RPT_C2H	0x10000000
+/* Rx dword 4 */
+#define R12A_RXDW4_SPLCP	0x00000001
+#define R12A_RXDW4_LDPC		0x00000002
+#define R12A_RXDW4_STBC		0x00000004
+#define R12A_RXDW4_BW_M		0x00000030
+#define R12A_RXDW4_BW_S		4
+
+/* Rx PHY descriptor. */
+struct r12a_rx_phystat {
+	uint8_t		gain_trsw[2];
+	uint16_t	phyw1;
+#define R12A_PHYW1_CHAN_M	0x03ff
+#define R12A_PHYW1_CHAN_S	0
+#define R12A_PHYW1_CHAN_EXT_M	0x3c00
+#define R12A_PHYW1_CHAN_EXT_S	10
+#define R12A_PHYW1_RFMOD_M	0xc000
+#define R12A_PHYW1_RFMOD_S	14
+
+	uint8_t		pwdb_all;
+	uint8_t		cfosho[4];
+	uint8_t		cfotail[4];
+	uint8_t		rxevm[2];
+	uint8_t		rxsnr[2];
+	uint8_t		pcts_msk_rpt[2];
+	uint8_t		pdsnr[2];
+	uint8_t		csi_current[2];
+	uint8_t		rx_gain_c;
+	uint8_t		rx_gain_d;
+	uint8_t		sigevm;
+	uint16_t	phyw13;
+#define R12A_PHYW13_ANTIDX_A_M	0x0700
+#define R12A_PHYW13_ANTIDX_A_S	8
+#define R12A_PHYW13_ANTIDX_B_M	0x3800
+#define R12A_PHYW13_ANTIDX_B_S	11
+} __packed;
+
+#endif	/* R12A_RX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,438 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_ridx.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_tx_desc.h>
+
+
+static int
+r12a_get_primary_channel(struct rtwn_softc *sc, struct ieee80211_channel *c)
+{
+	/* XXX 80 MHz */
+	if (IEEE80211_IS_CHAN_HT40U(c))
+		return (R12A_TXDW5_PRIM_CHAN_20_80_2);
+	else
+		return (R12A_TXDW5_PRIM_CHAN_20_80_3);
+}
+
+static void
+r12a_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
+{
+	struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
+
+	/* XXX 80 Mhz */
+	if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
+	    IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
+		int prim_chan;
+
+		prim_chan = r12a_get_primary_channel(sc, ni->ni_chan);
+		txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW,
+		    R12A_TXDW5_DATA_BW40));
+		txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN,
+		    prim_chan));
+	}
+}
+
+static void
+r12a_tx_protection(struct rtwn_softc *sc, struct r12a_tx_desc *txd,
+    enum ieee80211_protmode mode, uint8_t ridx)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint8_t rate;
+
+	switch (mode) {
+	case IEEE80211_PROT_CTSONLY:
+		txd->txdw3 |= htole32(R12A_TXDW3_CTS2SELF);
+		break;
+	case IEEE80211_PROT_RTSCTS:
+		txd->txdw3 |= htole32(R12A_TXDW3_RTSEN);
+		break;
+	default:
+		break;
+	}
+
+	if (mode == IEEE80211_PROT_CTSONLY ||
+	    mode == IEEE80211_PROT_RTSCTS) {
+		if (ridx >= RTWN_RIDX_MCS(0))
+			rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx);
+		else
+			rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]);
+		ridx = rate2ridx(rate);
+
+		txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE, ridx));
+		/* RTS rate fallback limit (max). */
+		txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE_FB_LMT, 0xf));
+
+		if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
+		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+			txd->txdw5 |= htole32(R12A_TXDW5_RTS_SHORT);
+	}
+}
+
+static void
+r12a_tx_raid(struct rtwn_softc *sc, struct r12a_tx_desc *txd,
+    struct ieee80211_node *ni, int ismcast)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct ieee80211_channel *chan;
+	enum ieee80211_phymode mode;
+	uint8_t raid;
+
+	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
+		ni->ni_chan : ic->ic_curchan;
+	mode = ieee80211_chan2mode(chan);
+
+	/* NB: group addressed frames are done at 11bg rates for now */
+	if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) {
+		switch (mode) {
+		case IEEE80211_MODE_11A:
+		case IEEE80211_MODE_11B:
+		case IEEE80211_MODE_11G:
+			break;
+		case IEEE80211_MODE_11NA:
+			mode = IEEE80211_MODE_11A;
+			break;
+		case IEEE80211_MODE_11NG:
+			mode = IEEE80211_MODE_11G;
+			break;
+		default:
+			device_printf(sc->sc_dev, "unknown mode(1) %d!\n",
+			    ic->ic_curmode);
+			return;
+		}
+	}
+
+	switch (mode) {
+	case IEEE80211_MODE_11A:
+		raid = R12A_RAID_11G;
+		break;
+	case IEEE80211_MODE_11B:
+		raid = R12A_RAID_11B;
+		break;
+	case IEEE80211_MODE_11G:
+		if (vap->iv_flags & IEEE80211_F_PUREG)
+			raid = R12A_RAID_11G;
+		else
+			raid = R12A_RAID_11BG;
+		break;
+	case IEEE80211_MODE_11NA:
+		if (sc->ntxchains == 1)
+			raid = R12A_RAID_11GN_1;
+		else
+			raid = R12A_RAID_11GN_2;
+		break;
+	case IEEE80211_MODE_11NG:
+		if (sc->ntxchains == 1) {
+			if (IEEE80211_IS_CHAN_HT40(chan))
+				raid = R12A_RAID_11BGN_1_40;
+			else
+				raid = R12A_RAID_11BGN_1;
+		} else {
+			if (IEEE80211_IS_CHAN_HT40(chan))
+				raid = R12A_RAID_11BGN_2_40;
+			else
+				raid = R12A_RAID_11BGN_2;
+		}
+		break;
+	default:
+		/* TODO: 80 MHz / 11ac */
+		device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode);
+		return;
+	}
+
+	txd->txdw1 |= htole32(SM(R12A_TXDW1_RAID, raid));
+}
+
+static void
+r12a_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
+{
+	struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
+	struct ieee80211vap *vap = ni->ni_vap;
+
+	if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) &&	/* HT20 */
+	    (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20))
+		txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT);
+	else if (ni->ni_chan != IEEE80211_CHAN_ANYC &&		/* HT40 */
+	    IEEE80211_IS_CHAN_HT40(ni->ni_chan) &&
+	    (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
+	    (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40))
+		txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT);
+}
+
+void
+r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m, void *buf, uint8_t ridx, int maxretry)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211_frame *wh;
+	struct r12a_tx_desc *txd;
+	enum ieee80211_protmode prot;
+	uint8_t type, tid, qos, qsel;
+	int hasqos, ismcast, macid;
+
+	wh = mtod(m, struct ieee80211_frame *);
+	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+	hasqos = IEEE80211_QOS_HAS_SEQ(wh);
+	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+
+	/* Select TX ring for this frame. */
+	if (hasqos) {
+		qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
+		tid = qos & IEEE80211_QOS_TID;
+	} else {
+		qos = 0;
+		tid = 0;
+	}
+
+	/* Fill Tx descriptor. */
+	txd = (struct r12a_tx_desc *)buf;
+	txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG;
+	if (ismcast)
+		txd->flags0 |= R12A_FLAGS0_BMCAST;
+
+	if (!ismcast) {
+		/* Unicast frame, check if an ACK is expected. */
+		if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) !=
+		    IEEE80211_QOS_ACKPOLICY_NOACK) {
+			txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA);
+			txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT,
+			    maxretry));
+		}
+
+		struct rtwn_node *un = RTWN_NODE(ni);
+		macid = un->id;
+
+		if (type == IEEE80211_FC0_TYPE_DATA) {
+			qsel = tid % RTWN_MAX_TID;
+
+			if (m->m_flags & M_AMPDU_MPDU) {
+				txd->txdw2 |= htole32(R12A_TXDW2_AGGEN);
+				txd->txdw2 |= htole32(SM(R12A_TXDW2_AMPDU_DEN,
+				    vap->iv_ampdu_density));
+				txd->txdw3 |= htole32(SM(R12A_TXDW3_MAX_AGG,
+				    0x1f));	/* XXX */
+			} else
+				txd->txdw2 |= htole32(R12A_TXDW2_AGGBK);
+
+			if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
+				txd->txdw2 |= htole32(R12A_TXDW2_SPE_RPT);
+				sc->sc_tx_n_active++;
+			}
+
+			if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
+			    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+				txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT);
+
+			prot = IEEE80211_PROT_NONE;
+			if (ridx >= RTWN_RIDX_MCS(0)) {
+				r12a_tx_set_ht40(sc, txd, ni);
+				r12a_tx_set_sgi(sc, txd, ni);
+				prot = ic->ic_htprotmode;
+			} else if (ic->ic_flags & IEEE80211_F_USEPROT)
+				prot = ic->ic_protmode;
+
+			/* XXX fix last comparison for A-MSDU (in net80211) */
+			/* XXX A-MPDU? */
+			if (m->m_pkthdr.len + IEEE80211_CRC_LEN >
+			    vap->iv_rtsthreshold &&
+			    vap->iv_rtsthreshold != IEEE80211_RTS_MAX)
+				prot = IEEE80211_PROT_RTSCTS;
+
+			if (prot != IEEE80211_PROT_NONE)
+				r12a_tx_protection(sc, txd, prot, ridx);
+		} else	/* IEEE80211_FC0_TYPE_MGT */
+			qsel = R12A_TXDW1_QSEL_MGNT;
+	} else {
+		macid = RTWN_MACID_BC;
+		qsel = R12A_TXDW1_QSEL_MGNT;
+	}
+
+	txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, qsel));
+	txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, macid));
+	txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx));
+	/* Data rate fallback limit (max). */
+	txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f));
+	/* XXX recheck for non-21au */
+	txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id));
+	r12a_tx_raid(sc, txd, ni, ismcast);
+
+	/* Force this rate if needed. */
+	if (sc->sc_ratectl != RTWN_RATECTL_FW)
+		txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE);
+
+	if (!hasqos) {
+		/* Use HW sequence numbering for non-QoS frames. */
+		txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN);
+		txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id));
+	} else {
+		uint16_t seqno;
+
+		if (m->m_flags & M_AMPDU_MPDU) {
+			seqno = ni->ni_txseqs[tid];
+			/* NB: clear Fragment Number field. */
+			*(uint16_t *)wh->i_seq = 0;
+			ni->ni_txseqs[tid]++;
+		} else
+			seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE;
+
+		/* Set sequence number. */
+		txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, seqno));
+	}
+}
+
+void
+r12a_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params)
+{
+	struct ieee80211vap *vap = ni->ni_vap;
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct ieee80211_frame *wh;
+	struct r12a_tx_desc *txd;
+	uint8_t ridx;
+	int ismcast;
+
+	/* XXX TODO: 11n checks, matching rtwn_fill_tx_desc() */
+
+	wh = mtod(m, struct ieee80211_frame *);
+	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+	ridx = rate2ridx(params->ibp_rate0);
+
+	/* Fill Tx descriptor. */
+	txd = (struct r12a_tx_desc *)buf;
+	txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG;
+	if (ismcast)
+		txd->flags0 |= R12A_FLAGS0_BMCAST;
+
+	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) {
+		txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA);
+		txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT,
+		    params->ibp_try0));
+	}
+	if (params->ibp_flags & IEEE80211_BPF_RTS)
+		r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx);
+	if (params->ibp_flags & IEEE80211_BPF_CTS)
+		r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx);
+
+	txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC));
+	txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT));
+
+	/* Set TX rate index. */
+	txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx));
+	txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f));
+	txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id));
+	txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE);
+	r12a_tx_raid(sc, txd, ni, ismcast);
+
+	if (!IEEE80211_QOS_HAS_SEQ(wh)) {
+		/* Use HW sequence numbering for non-QoS frames. */
+		txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN);
+		txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id));
+	} else {
+		/* Set sequence number. */
+		txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ,
+		    M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE));
+	}
+}
+
+void
+r12a_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, int qos,
+    int id)
+{
+	struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
+
+	txd->flags0 = R12A_FLAGS0_FSG | R12A_FLAGS0_LSG | R12A_FLAGS0_OWN;
+	txd->txdw1 = htole32(
+	    SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT));
+
+	txd->txdw3 = htole32(R12A_TXDW3_DRVRATE);
+	txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id));
+	if (is11b) {
+		txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE,
+		    RTWN_RIDX_CCK1));
+	} else {
+		txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE,
+		    RTWN_RIDX_OFDM6));
+	}
+
+	if (!qos) {
+		txd->txdw8 = htole32(R12A_TXDW8_HWSEQ_EN);
+		txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id));
+
+	}
+}
+
+uint8_t
+r12a_tx_radiotap_flags(const void *buf)
+{
+	const struct r12a_tx_desc *txd = buf;
+	uint8_t flags, rate;
+
+	if (!(txd->txdw5 & htole32(R12A_TXDW5_DATA_SHORT)))
+		return (0);
+
+	rate = MS(le32toh(txd->txdw4), R12A_TXDW4_DATARATE);
+	if (RTWN_RATE_IS_CCK(rate))
+		flags = IEEE80211_RADIOTAP_F_SHORTPRE;
+	else
+		flags = IEEE80211_RADIOTAP_F_SHORTGI;
+	return (flags);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12A_TX_DESC_H
+#define R12A_TX_DESC_H
+
+/* Tx MAC descriptor (common part). */
+struct r12a_tx_desc {
+	uint16_t	pktlen;
+	uint8_t		offset;
+	uint8_t		flags0;
+#define R12A_FLAGS0_BMCAST	0x01
+#define R12A_FLAGS0_LSG		0x04
+#define R12A_FLAGS0_FSG		0x08
+#define R12A_FLAGS0_OWN		0x80
+
+	uint32_t	txdw1;
+#define R12A_TXDW1_MACID_M	0x0000003f
+#define R12A_TXDW1_MACID_S	0
+#define R12A_TXDW1_QSEL_M	0x00001f00
+#define R12A_TXDW1_QSEL_S	8
+
+#define R12A_TXDW1_QSEL_BE	0x00	/* or 0x03 */
+#define R12A_TXDW1_QSEL_BK	0x01	/* or 0x02 */
+#define R12A_TXDW1_QSEL_VI	0x04	/* or 0x05 */
+#define R12A_TXDW1_QSEL_VO	0x06	/* or 0x07 */
+#define RTWN_MAX_TID		8
+
+#define R12A_TXDW1_QSEL_BEACON	0x10
+#define R12A_TXDW1_QSEL_MGNT	0x12
+
+#define R12A_TXDW1_RAID_M	0x001f0000
+#define R12A_TXDW1_RAID_S	16
+#define R12A_TXDW1_CIPHER_M	0x00c00000
+#define R12A_TXDW1_CIPHER_S	22
+#define R12A_TXDW1_CIPHER_NONE	0
+#define R12A_TXDW1_CIPHER_RC4	1
+#define R12A_TXDW1_CIPHER_SM4	2
+#define R12A_TXDW1_CIPHER_AES	3
+#define R12A_TXDW1_PKTOFF_M	0x1f000000
+#define R12A_TXDW1_PKTOFF_S	24
+
+	uint32_t	txdw2;
+#define R12A_TXDW2_AGGEN	0x00001000
+#define R12A_TXDW2_AGGBK	0x00010000
+#define R12A_TXDW2_MOREFRAG	0x00020000
+#define R12A_TXDW2_SPE_RPT	0x00080000
+#define R12A_TXDW2_AMPDU_DEN_M	0x00700000
+#define R12A_TXDW2_AMPDU_DEN_S	20
+
+	uint32_t	txdw3;
+#define R12A_TXDW3_SEQ_SEL_M	0x000000c0
+#define R12A_TXDW3_SEQ_SEL_S	6
+#define R12A_TXDW3_DRVRATE	0x00000100
+#define R12A_TXDW3_DISRTSFB	0x00000200
+#define R12A_TXDW3_DISDATAFB	0x00000400
+#define R12A_TXDW3_CTS2SELF	0x00000800
+#define R12A_TXDW3_RTSEN	0x00001000
+#define R12A_TXDW3_HWRTSEN	0x00002000
+#define R12A_TXDW3_MAX_AGG_M	0x003e0000
+#define R12A_TXDW3_MAX_AGG_S	17
+
+	uint32_t	txdw4;
+#define R12A_TXDW4_DATARATE_M		0x0000007f
+#define R12A_TXDW4_DATARATE_S		0
+#define R12A_TXDW4_DATARATE_FB_LMT_M	0x00001f00
+#define R12A_TXDW4_DATARATE_FB_LMT_S	8
+#define R12A_TXDW4_RTSRATE_FB_LMT_M	0x0001e000
+#define R12A_TXDW4_RTSRATE_FB_LMT_S	13
+#define R12A_TXDW4_RETRY_LMT_ENA	0x00020000
+#define R12A_TXDW4_RETRY_LMT_M		0x00fc0000
+#define R12A_TXDW4_RETRY_LMT_S		18
+#define R12A_TXDW4_RTSRATE_M		0x1f000000
+#define R12A_TXDW4_RTSRATE_S		24
+
+	uint32_t	txdw5;
+#define R12A_TXDW5_DATA_PRIM_CHAN_M	0x0000000f
+#define R12A_TXDW5_DATA_PRIM_CHAN_S	0
+#define R12A_TXDW5_PRIM_CHAN_20_80_3	1
+#define R12A_TXDW5_PRIM_CHAN_20_80_2	2
+#define R12A_TXDW5_PRIM_CHAN_20_80_4	3
+#define R12A_TXDW5_PRIM_CHAN_20_80_1	4
+#define R12A_TXDW5_PRIM_CHAN_40_80_1	9
+#define R12A_TXDW5_PRIM_CHAN_40_80_2	10
+#define R12A_TXDW5_DATA_SHORT		0x00000010
+#define R12A_TXDW5_DATA_BW_M		0x00000060
+#define R12A_TXDW5_DATA_BW_S		5
+#define R12A_TXDW5_DATA_BW40		1
+#define R12A_TXDW5_DATA_BW80		2
+#define R12A_TXDW5_DATA_LDPC		0x00000080
+#define R12A_TXDW5_RTS_SHORT		0x00001000
+#define R12A_TXDW5_RTS_PRIM_CHAN_M	0x0001e000
+#define R12A_TXDW5_RTS_PRIM_CHAN_S	13
+
+	uint32_t	txdw6;
+#define R21A_TXDW6_MBSSID_M	0x0000f000
+#define R21A_TXDW6_MBSSID_S	12
+
+	uint32_t	reserved;
+	uint32_t	txdw8;
+#define R12A_TXDW8_HWSEQ_EN	0x00008000
+
+	uint32_t	txdw9;
+#define R12A_TXDW9_SEQ_M	0x00fff000
+#define R12A_TXDW9_SEQ_S	12
+} __packed __attribute__((aligned(4)));
+
+
+/* Rate adaptation modes. */
+#define R12A_RAID_11BGN_2_40	0
+#define R12A_RAID_11BGN_1_40	1
+#define R12A_RAID_11BGN_2	2
+#define R12A_RAID_11BGN_1	3
+#define R12A_RAID_11GN_2	4
+#define R12A_RAID_11GN_1	5
+#define R12A_RAID_11BG		6
+#define R12A_RAID_11G		7	/* "pure" 11g */
+#define R12A_RAID_11B		8
+#define R12A_RAID_11AC_2_80	9
+#define R12A_RAID_11AC_1_80	10
+#define R12A_RAID_11AC_1	11
+#define R12A_RAID_11AC_2	12
+
+#endif	/* R12A_TX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12A_VAR_H
+#define R12A_VAR_H
+
+#include <dev/rtwn/rtl8812a/r12a_rom_defs.h>
+
+struct r12a_softc {
+	uint8_t			chip;
+#define R12A_CHIP_C_CUT		0x01
+
+	uint8_t			rs_flags;
+#define R12A_RXCKSUM_EN		0x01
+#define R12A_RXCKSUM6_EN	0x02
+#define R12A_IQK_RUNNING	0x04
+#define R12A_RADAR_ENABLED	0x08
+
+	int			rs_radar;
+	struct timeout_task	rs_chan_check;
+
+	/* ROM variables */
+	int			ext_pa_2g:1,
+				ext_pa_5g:1,
+				ext_lna_2g:1,
+				ext_lna_5g:1,
+				type_pa_2g:4,
+				type_pa_5g:4,
+				type_lna_2g:4,
+				type_lna_5g:4,
+				bt_coex:1,
+				bt_ant_num:1;
+
+	uint8_t			board_type;
+	uint8_t			regulatory;
+	uint8_t			crystalcap;
+
+	uint8_t			rfe_type;
+	uint8_t			tx_bbswing_2g;
+	uint8_t			tx_bbswing_5g;
+
+	uint8_t	cck_tx_pwr[R12A_MAX_RF_PATH][R12A_GROUP_2G];
+	uint8_t	ht40_tx_pwr_2g[R12A_MAX_RF_PATH][R12A_GROUP_2G];
+	uint8_t	ht40_tx_pwr_5g[R12A_MAX_RF_PATH][R12A_GROUP_5G];
+
+	int8_t	cck_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+	int8_t	ofdm_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+	int8_t	bw20_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+	int8_t	bw40_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+
+	int8_t	ofdm_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+	int8_t	bw20_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+	int8_t	bw40_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+	int8_t	bw80_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+	int8_t	bw160_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT];
+
+	int		sc_ant;
+
+	int		(*rs_newstate[RTWN_PORT_COUNT])(struct ieee80211vap *,
+			    enum ieee80211_state, int);
+	void		(*rs_scan_start)(struct ieee80211com *);
+	void		(*rs_scan_end)(struct ieee80211com *);
+
+	void		(*rs_crystalcap_write)(struct rtwn_softc *);
+	void		(*rs_fix_spur)(struct rtwn_softc *,
+			    struct ieee80211_channel *);
+	void		(*rs_set_band_2ghz)(struct rtwn_softc *, uint32_t);
+	void		(*rs_set_band_5ghz)(struct rtwn_softc *, uint32_t);
+	void		(*rs_init_burstlen)(struct rtwn_softc *);
+	void		(*rs_init_ampdu_fwhw)(struct rtwn_softc *);
+#ifndef RTWN_WITHOUT_UCODE
+	int		(*rs_iq_calib_fw_supported)(struct rtwn_softc *);
+#endif
+	void		(*rs_iq_calib_sw)(struct rtwn_softc *);
+
+	int		ac_usb_dma_size;
+	int		ac_usb_dma_time;
+	int		ampdu_max_time;
+};
+#define	R12A_SOFTC(_sc)	((struct r12a_softc *)((_sc)->sc_priv))
+
+#define rtwn_r12a_fix_spur(_sc, _c) \
+	((R12A_SOFTC(_sc)->rs_fix_spur)((_sc), (_c)))
+#define rtwn_r12a_set_band_2ghz(_sc, _rates) \
+	((R12A_SOFTC(_sc)->rs_set_band_2ghz)((_sc), (_rates)))
+#define rtwn_r12a_set_band_5ghz(_sc, _rates) \
+	((R12A_SOFTC(_sc)->rs_set_band_5ghz)((_sc), (_rates)))
+#define rtwn_r12a_init_burstlen(_sc) \
+	((R12A_SOFTC(_sc)->rs_init_burstlen)((_sc)))
+#define rtwn_r12a_init_ampdu_fwhw(_sc) \
+	((R12A_SOFTC(_sc)->rs_init_ampdu_fwhw)((_sc)))
+#define rtwn_r12a_crystalcap_write(_sc) \
+	((R12A_SOFTC(_sc)->rs_crystalcap_write)((_sc)))
+#ifndef RTWN_WITHOUT_UCODE
+#define rtwn_r12a_iq_calib_fw_supported(_sc) \
+	((R12A_SOFTC(_sc)->rs_iq_calib_fw_supported)((_sc)))
+#endif
+#define rtwn_r12a_iq_calib_sw(_sc) \
+	((R12A_SOFTC(_sc)->rs_iq_calib_sw)((_sc)))
+
+#endif	/* R12A_VAR_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTL8812AU_H
+#define RTL8812AU_H
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+
+
+/*
+ * Function declarations.
+ */
+/* r12au_init.c */
+void	r12au_init_rx_agg(struct rtwn_softc *);
+void	r12au_init_burstlen(struct rtwn_softc *);
+void	r12au_init_ampdu_fwhw(struct rtwn_softc *);
+void	r12au_init_ampdu(struct rtwn_softc *);
+void	r12au_post_init(struct rtwn_softc *);
+
+/* r12au_rx.c */
+int	r12au_classify_intr(struct rtwn_softc *, void *, int);
+int	r12au_align_rx(int, int);
+
+/* r12au_tx.c */
+void	r12au_dump_tx_desc(struct rtwn_softc *, const void *);
+
+#endif	/* RTL8812AU_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,290 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_nop.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+
+#include <dev/rtwn/rtl8812a/r12a_priv.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+#include <dev/rtwn/rtl8812a/usb/r12au.h>
+#include <dev/rtwn/rtl8812a/usb/r12au_tx_desc.h>
+
+
+void	r12au_attach(struct rtwn_usb_softc *);
+
+static void
+r12au_postattach(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+	struct r12a_softc *rs = sc->sc_priv;
+
+	if (usbd_get_speed(uc->uc_udev) == USB_SPEED_SUPER) {
+		rs->ac_usb_dma_size = 0x07;
+		rs->ac_usb_dma_time = 0x1a;
+	} else {
+		rs->ac_usb_dma_size = 0x01;
+		rs->ac_usb_dma_time = 0x10;
+	}
+
+	if (rs->chip & R12A_CHIP_C_CUT)
+		sc->sc_rf_read = r12a_c_cut_rf_read;
+	else
+		sc->sc_rf_read = r12a_rf_read;
+
+	if (rs->board_type == R92C_BOARD_TYPE_MINICARD ||
+	    rs->board_type == R92C_BOARD_TYPE_SOLO ||
+	    rs->board_type == R92C_BOARD_TYPE_COMBO)
+		sc->sc_set_led = r88e_set_led;
+	else
+		sc->sc_set_led = r12a_set_led;
+
+	if (!(rs->ext_pa_2g || rs->ext_lna_2g ||
+	    rs->ext_pa_5g || rs->ext_lna_5g))
+		sc->mac_prog = &rtl8812au_mac_no_ext_pa_lna[0];
+
+	sc->sc_ic.ic_ioctl = r12a_ioctl_net;
+}
+
+void
+r12a_vap_preattach(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	struct ifnet *ifp = vap->iv_ifp;
+
+	ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6;
+	RTWN_LOCK(sc);
+	if (rs->rs_flags & R12A_RXCKSUM_EN)
+		ifp->if_capenable |= IFCAP_RXCSUM;
+	if (rs->rs_flags & R12A_RXCKSUM6_EN)
+		ifp->if_capenable |= IFCAP_RXCSUM_IPV6;
+	RTWN_UNLOCK(sc);
+}
+
+static void
+r12a_attach_private(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs;
+
+	rs = malloc(sizeof(struct r12a_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO);
+
+	rs->rs_flags			= R12A_RXCKSUM_EN | R12A_RXCKSUM6_EN;
+
+	rs->rs_fix_spur			= r12a_fix_spur;
+	rs->rs_set_band_2ghz		= r12a_set_band_2ghz;
+	rs->rs_set_band_5ghz		= r12a_set_band_5ghz;
+	rs->rs_init_burstlen		= r12au_init_burstlen;
+	rs->rs_init_ampdu_fwhw		= r12au_init_ampdu_fwhw;
+	rs->rs_crystalcap_write		= r12a_crystalcap_write;
+#ifndef RTWN_WITHOUT_UCODE
+	rs->rs_iq_calib_fw_supported	= r12a_iq_calib_fw_supported;
+#endif
+	rs->rs_iq_calib_sw		= r12a_iq_calib_sw;
+
+	rs->ampdu_max_time		= 0x70;
+
+	sc->sc_priv = rs;
+}
+
+void
+r12a_detach_private(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+
+	free(rs, M_RTWN_PRIV);
+}
+
+static void
+r12a_read_chipid_vendor(struct rtwn_softc *sc, uint32_t reg_sys_cfg)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+
+	if (MS(reg_sys_cfg, R92C_SYS_CFG_CHIP_VER_RTL) == 1)
+		rs->chip |= R12A_CHIP_C_CUT;
+}
+
+static void
+r12au_adj_devcaps(struct rtwn_softc *sc)
+{
+	/* TODO: LDPC, STBC etc */
+}
+
+void
+r12au_attach(struct rtwn_usb_softc *uc)
+{
+	struct rtwn_softc *sc		= &uc->uc_sc;
+
+	/* USB part. */
+	uc->uc_align_rx			= r12au_align_rx;
+	uc->tx_agg_desc_num		= 1;
+
+	/* Common part. */
+	sc->sc_flags			= RTWN_FLAG_EXT_HDR;
+
+	sc->sc_set_chan			= r12a_set_chan;
+	sc->sc_fill_tx_desc		= r12a_fill_tx_desc;
+	sc->sc_fill_tx_desc_raw 	= r12a_fill_tx_desc_raw;
+	sc->sc_fill_tx_desc_null	= r12a_fill_tx_desc_null;
+	sc->sc_dump_tx_desc		= r12au_dump_tx_desc;
+	sc->sc_tx_radiotap_flags	= r12a_tx_radiotap_flags;
+	sc->sc_rx_radiotap_flags	= r12a_rx_radiotap_flags;
+	sc->sc_get_rssi_cck		= r88e_get_rssi_cck;
+	sc->sc_get_rssi_ofdm		= r88e_get_rssi_ofdm;
+	sc->sc_classify_intr		= r12au_classify_intr;
+	sc->sc_handle_tx_report		= r12a_ratectl_tx_complete;
+	sc->sc_handle_c2h_report	= r12a_handle_c2h_report;
+	sc->sc_check_frame		= r12a_check_frame_checksum;
+	sc->sc_rf_write			= r12a_rf_write;
+	sc->sc_check_condition		= r12a_check_condition;
+	sc->sc_efuse_postread		= rtwn_nop_softc;
+	sc->sc_parse_rom		= r12a_parse_rom;
+	sc->sc_power_on			= r12a_power_on;
+	sc->sc_power_off		= r12a_power_off;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_fw_reset			= r12a_fw_reset;
+	sc->sc_fw_download_enable	= r12a_fw_download_enable;
+#endif
+	sc->sc_set_page_size		= r12a_set_page_size;
+	sc->sc_lc_calib			= r12a_lc_calib;
+	sc->sc_iq_calib			= r12a_iq_calib;
+	sc->sc_read_chipid_vendor	= r12a_read_chipid_vendor;
+	sc->sc_adj_devcaps		= r12au_adj_devcaps;
+	sc->sc_vap_preattach		= r12a_vap_preattach;
+	sc->sc_postattach		= r12au_postattach;
+	sc->sc_detach_private		= r12a_detach_private;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_set_media_status		= r12a_set_media_status;
+	sc->sc_set_rsvd_page		= r88e_set_rsvd_page;
+	sc->sc_set_pwrmode		= r12a_set_pwrmode;
+	sc->sc_set_rssi			= rtwn_nop_softc;	/* XXX TODO */
+#else
+	sc->sc_set_media_status		= rtwn_nop_softc_int;
+#endif
+	sc->sc_beacon_init		= r12a_beacon_init;
+	sc->sc_beacon_enable		= r92c_beacon_enable;
+	sc->sc_beacon_set_rate		= r12a_beacon_set_rate;
+	sc->sc_beacon_select		= rtwn_nop_softc_int;
+	sc->sc_temp_measure		= r88e_temp_measure;
+	sc->sc_temp_read		= r88e_temp_read;
+	sc->sc_init_tx_agg		= r92cu_init_tx_agg;
+	sc->sc_init_rx_agg		= r12au_init_rx_agg;
+	sc->sc_init_ampdu		= r12au_init_ampdu;
+	sc->sc_init_intr		= r12a_init_intr;
+	sc->sc_init_edca		= r12a_init_edca;
+	sc->sc_init_bb			= r12a_init_bb;
+	sc->sc_init_rf			= r12a_init_rf;
+	sc->sc_init_antsel		= r12a_init_antsel;
+	sc->sc_post_init		= r12au_post_init;
+	sc->sc_init_bcnq1_boundary	= rtwn_nop_int_softc;
+
+	sc->chan_list_5ghz[0]		= r12a_chan_5ghz_0;
+	sc->chan_list_5ghz[1]		= r12a_chan_5ghz_1;
+	sc->chan_list_5ghz[2]		= r12a_chan_5ghz_2;
+	sc->chan_num_5ghz[0]		= nitems(r12a_chan_5ghz_0);
+	sc->chan_num_5ghz[1]		= nitems(r12a_chan_5ghz_1);
+	sc->chan_num_5ghz[2]		= nitems(r12a_chan_5ghz_2);
+
+	sc->mac_prog			= &rtl8812au_mac[0];
+	sc->mac_size			= nitems(rtl8812au_mac);
+	sc->bb_prog			= &rtl8812au_bb[0];
+	sc->bb_size			= nitems(rtl8812au_bb);
+	sc->agc_prog			= &rtl8812au_agc[0];
+	sc->agc_size			= nitems(rtl8812au_agc);
+	sc->rf_prog			= &rtl8812au_rf[0];
+
+	sc->name			= "RTL8812AU";
+	sc->fwname			= "rtwn-rtl8812aufw";
+	sc->fwsig			= 0x950;
+
+	sc->page_count			= R12A_TX_PAGE_COUNT;
+	sc->pktbuf_count		= R12A_TXPKTBUF_COUNT;
+
+	sc->ackto			= 0x80;
+	sc->npubqpages			= R12A_PUBQ_NPAGES;
+	sc->page_size			= R12A_TX_PAGE_SIZE;
+
+	sc->txdesc_len			= sizeof(struct r12au_tx_desc);
+	sc->efuse_maxlen		= R12A_EFUSE_MAX_LEN;
+	sc->efuse_maplen		= R12A_EFUSE_MAP_LEN;
+	sc->rx_dma_size			= R12A_RX_DMA_BUFFER_SIZE;
+
+	sc->macid_limit			= R12A_MACID_MAX + 1;
+	sc->cam_entry_limit		= R12A_CAM_ENTRY_COUNT;
+	sc->fwsize_limit		= R12A_MAX_FW_SIZE;
+	sc->temp_delta			= R88E_CALIB_THRESHOLD;
+
+	sc->bcn_status_reg[0]		= R92C_TDECTRL;
+	sc->bcn_status_reg[1]		= R92C_TDECTRL;
+	sc->rcr				= R12A_RCR_DIS_CHK_14 |
+					  R12A_RCR_VHT_ACK |
+					  R12A_RCR_TCP_OFFLD_EN;
+
+	sc->ntxchains			= 2;
+	sc->nrxchains			= 2;
+
+	r12a_attach_private(sc);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,189 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+#include <dev/rtwn/rtl8812a/usb/r12au.h>
+#include <dev/rtwn/rtl8812a/usb/r12au_reg.h>
+
+
+void
+r12au_init_rx_agg(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+
+	/* Rx aggregation (USB). */
+	rtwn_write_2(sc, R92C_RXDMA_AGG_PG_TH,
+	    rs->ac_usb_dma_size | (rs->ac_usb_dma_time << 8));
+	rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0,
+	    R92C_TRXDMA_CTRL_RXDMA_AGG_EN);
+}
+
+void
+r12au_init_burstlen(struct rtwn_softc *sc)
+{
+	if (rtwn_read_1(sc, R92C_TYPE_ID + 3) & 0x80)	{
+		if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) {
+			/* Set burst packet length to 512 B. */
+			rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x20, 0x1e);
+		} else {
+			/* Set burst packet length to 64 B. */
+			rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x10, 0x2e);
+		}
+	} else {	/* USB 3.0 */
+		/* Set burst packet length to 1 KB. */
+		rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x30, 0x0e);
+
+		rtwn_setbits_1(sc, 0xf008, 0x18, 0);
+	}
+}
+
+static void
+r12au_arfb_init(struct rtwn_softc *sc)
+{
+	/* ARFB table 9 for 11ac 5G 2SS. */
+	rtwn_write_4(sc, R12A_ARFR_5G(0), 0x00000010);
+	rtwn_write_4(sc, R12A_ARFR_5G(0) + 4, 0xfffff000);
+
+	/* ARFB table 10 for 11ac 5G 1SS. */
+	rtwn_write_4(sc, R12A_ARFR_5G(1), 0x00000010);
+	rtwn_write_4(sc, R12A_ARFR_5G(1) + 4, 0x003ff000);
+
+	/* ARFB table 11 for 11ac 2G 1SS. */
+	rtwn_write_4(sc, R12A_ARFR_2G(0), 0x00000015);
+	rtwn_write_4(sc, R12A_ARFR_2G(0) + 4, 0x003ff000);
+
+	/* ARFB table 12 for 11ac 2G 2SS. */
+	rtwn_write_4(sc, R12A_ARFR_2G(1), 0x00000015);
+	rtwn_write_4(sc, R12A_ARFR_2G(1) + 4, 0xffcff000);
+}
+
+void
+r12au_init_ampdu_fwhw(struct rtwn_softc *sc)
+{
+	rtwn_setbits_1(sc, R92C_FWHW_TXQ_CTRL,
+	    R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW, 0);
+}
+
+void
+r12au_init_ampdu(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+
+	/* Rx interval (USB3). */
+	rtwn_write_1(sc, 0xf050, 0x01);
+
+	/* burst length = 4 */
+	rtwn_write_2(sc, R92C_RXDMA_STATUS, 0x7400);
+
+	rtwn_write_1(sc, R92C_RXDMA_STATUS + 1, 0xf5);
+
+	/* Setup AMPDU aggregation. */
+	rtwn_write_1(sc, R12A_AMPDU_MAX_TIME, rs->ampdu_max_time);
+	rtwn_write_4(sc, R12A_AMPDU_MAX_LENGTH, 0xffffffff);
+
+	/* 80 MHz clock (again?) */
+	rtwn_write_1(sc, R92C_USTIME_TSF, 0x50);
+	rtwn_write_1(sc, R92C_USTIME_EDCA, 0x50);
+
+	rtwn_r12a_init_burstlen(sc);
+
+	/* Enable single packet AMPDU. */
+	rtwn_setbits_1(sc, R12A_HT_SINGLE_AMPDU, 0,
+	    R12A_HT_SINGLE_AMPDU_PKT_ENA);
+
+	/* 11K packet length for VHT. */
+	rtwn_write_1(sc, R92C_RX_PKT_LIMIT, 0x18);
+
+	rtwn_write_1(sc, R92C_PIFS, 0);
+
+	rtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x1f1f);
+
+	rtwn_r12a_init_ampdu_fwhw(sc);
+
+	/* Do not reset MAC. */
+	rtwn_setbits_1(sc, R92C_RSV_CTRL, 0, 0x60);
+
+	r12au_arfb_init(sc);
+}
+
+void
+r12au_post_init(struct rtwn_softc *sc)
+{
+
+	/* Setup RTS BW (equal to data BW). */
+	rtwn_setbits_1(sc, R92C_QUEUE_CTRL, 0x08, 0);
+
+	rtwn_write_1(sc, R12A_EARLY_MODE_CONTROL + 3, 0x01);
+
+	/* Reset USB mode switch setting. */
+	rtwn_write_1(sc, R12A_SDIO_CTRL, 0);
+	rtwn_write_1(sc, R92C_ACLK_MON, 0);
+
+	rtwn_write_1(sc, R92C_USB_HRPWM, 0);
+
+#ifndef RTWN_WITHOUT_UCODE
+	if (sc->sc_flags & RTWN_FW_LOADED) {
+		if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) {
+			/* TODO: implement */
+			sc->sc_ratectl = RTWN_RATECTL_NET80211;
+		} else
+			sc->sc_ratectl = sc->sc_ratectl_sysctl;
+	} else
+#endif
+		sc->sc_ratectl = RTWN_RATECTL_NONE;
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12AU_REG_H
+#define R12AU_REG_H
+
+#include <dev/rtwn/rtl8188e/usb/r88eu_reg.h>
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+
+#endif	/* R12AU_REG_H */
Index: freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,91 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8812a/r12a_fw_cmd.h>
+#include <dev/rtwn/rtl8812a/r12a_rx_desc.h>
+
+#include <dev/rtwn/rtl8812a/usb/r12au.h>
+
+
+int
+r12au_classify_intr(struct rtwn_softc *sc, void *buf, int len)
+{
+	struct r92c_rx_stat *stat = buf;
+	uint32_t rxdw2 = le32toh(stat->rxdw2);
+
+	if (rxdw2 & R12A_RXDW2_RPT_C2H) {
+		int pos = sizeof(struct r92c_rx_stat);
+		/* Check if Rx descriptor + command id/sequence fits. */
+		if (len < pos + 2)	/* unknown, skip */
+			return (RTWN_RX_DATA);
+
+		if (((uint8_t *)buf)[pos] == R12A_C2H_TX_REPORT)
+			return (RTWN_RX_TX_REPORT);
+		else
+			return (RTWN_RX_OTHER);
+	} else
+		return (RTWN_RX_DATA);
+}
+
+int
+r12au_align_rx(int totlen, int len)
+{
+	if (totlen < len)
+		return (roundup2(totlen, 8));
+
+	return (totlen);
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,77 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8812a/usb/r12au.h>
+#include <dev/rtwn/rtl8812a/usb/r12au_tx_desc.h>
+
+
+void
+r12au_dump_tx_desc(struct rtwn_softc *sc, const void *desc)
+{
+#ifdef RTWN_DEBUG
+	const struct r12au_tx_desc *txd = desc;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC,
+	    "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %08X, "
+	    "4 %08X, 5 %08X, 6 %08X, sum %04X, flags7 %04X, 8 %08X, 9 %08X\n",
+	    __func__, le16toh(txd->pktlen), txd->offset, txd->flags0,
+	    le32toh(txd->txdw1), le32toh(txd->txdw2), le32toh(txd->txdw3),
+	    le32toh(txd->txdw4), le32toh(txd->txdw5), le32toh(txd->txdw6),
+	    le16toh(txd->txdsum), le16toh(txd->flags7), le32toh(txd->txdw8),
+	    le32toh(txd->txdw9));
+#endif
+}
Index: freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R12AU_TX_DESC_H
+#define R12AU_TX_DESC_H
+
+#include <dev/rtwn/rtl8812a/r12a_tx_desc.h>
+
+/* Tx MAC descriptor (USB). */
+struct r12au_tx_desc {
+	uint16_t	pktlen;
+	uint8_t		offset;
+	uint8_t		flags0;
+
+	uint32_t	txdw1;
+	uint32_t	txdw2;
+	uint32_t	txdw3;
+	uint32_t	txdw4;
+	uint32_t	txdw5;
+	uint32_t	txdw6;
+
+	uint16_t	txdsum;
+	uint16_t	flags7;
+#define R12AU_FLAGS7_AGGNUM_M	0xff00
+#define R12AU_FLAGS7_AGGNUM_S	8
+
+	uint32_t	txdw8;
+	uint32_t	txdw9;
+} __packed __attribute__((aligned(4)));
+
+#endif	/* R12AU_TX_DESC_H */
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTL8821A_H
+#define RTL8821A_H
+
+/*
+ * Global definitions.
+ */
+#define R21A_TX_PAGE_COUNT	243
+#define R21A_BCNQ0_PAGE_COUNT	8
+#define R21A_BCNQ0_BOUNDARY	\
+	(R21A_TX_PAGE_COUNT + R21A_BCNQ0_PAGE_COUNT + 1)
+
+#define R21A_TX_PAGE_SIZE	256
+
+
+/*
+ * Function declarations.
+ */
+/* r21a_beacon.c */
+void	r21a_beacon_init(struct rtwn_softc *, void *, int);
+void	r21a_beacon_select(struct rtwn_softc *, int);
+
+/* r21a_calib.c */
+#ifndef RTWN_WITHOUT_UCODE
+int	r21a_iq_calib_fw_supported(struct rtwn_softc *);
+#endif
+void	r21a_iq_calib_sw(struct rtwn_softc *);
+
+/* r21a_chan.c */
+void	r21a_set_band_2ghz(struct rtwn_softc *, uint32_t);
+void	r21a_set_band_5ghz(struct rtwn_softc *, uint32_t);
+
+/* r21a_fw.c */
+void	r21a_fw_reset(struct rtwn_softc *, int);
+
+/* r21a_init.c */
+int	r21a_power_on(struct rtwn_softc *);
+void	r21a_power_off(struct rtwn_softc *);
+int	r21a_check_condition(struct rtwn_softc *, const uint8_t[]);
+void	r21a_crystalcap_write(struct rtwn_softc *);
+int	r21a_init_bcnq1_boundary(struct rtwn_softc *);
+void	r21a_init_ampdu_fwhw(struct rtwn_softc *);
+
+/* r21a_led.c */
+void	r21a_set_led(struct rtwn_softc *, int, int);
+
+/* r21a_rom.c */
+void	r21a_parse_rom(struct rtwn_softc *, uint8_t *);
+
+/* r21a_rx.c */
+int8_t	r21a_get_rssi_cck(struct rtwn_softc *, void *);
+
+#endif	/* RTL8821A_H */
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,95 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_tx_desc.h>
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+
+
+void
+r21a_beacon_init(struct rtwn_softc *sc, void *buf, int id)
+{
+	struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
+
+	r12a_beacon_init(sc, buf, id);
+
+	/* XXX sequence number for beacon 1 is not stable. */
+	txd->txdw3 &= ~htole32(R12A_TXDW3_SEQ_SEL_M);
+	txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id * 2));
+}
+
+void
+r21a_beacon_select(struct rtwn_softc *sc, int id)
+{
+	switch (id) {
+	case 0:
+		/* Switch to port 0 beacon. */
+		rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL,
+		    R21A_DWBCN1_CTRL_SEL_BCN1, 0, 2);
+		break;
+	case 1:
+		/* Switch to port 1 beacon. */
+		rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL,
+		    0, R21A_DWBCN1_CTRL_SEL_BCN1, 2);
+		break;
+	default:
+		KASSERT(0, ("wrong port id %d\n", id));
+		break;
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,128 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+#include <dev/rtwn/rtl8821a/r21a_priv.h>
+
+
+#ifndef RTWN_WITHOUT_UCODE
+int
+r21a_iq_calib_fw_supported(struct rtwn_softc *sc)
+{
+	if (sc->fwver == 0x16)
+		return (1);
+
+	return (0);
+}
+#endif
+
+void
+r21a_iq_calib_sw(struct rtwn_softc *sc)
+{
+#define R21A_MAX_NRXCHAINS	2
+	uint32_t saved_bb_vals[nitems(r21a_iq_bb_regs)];
+	uint32_t saved_afe_vals[nitems(r21a_iq_afe_regs)];
+	uint32_t saved_rf_vals[nitems(r21a_iq_rf_regs) * R21A_MAX_NRXCHAINS];
+
+	KASSERT(sc->nrxchains <= R21A_MAX_NRXCHAINS,
+	    ("nrxchains > %d (%d)\n", R21A_MAX_NRXCHAINS, sc->nrxchains));
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: SW IQ calibration: TODO\n",
+	    __func__);
+
+	/* Save registers. */
+	r12a_save_bb_afe_vals(sc, saved_bb_vals, r21a_iq_bb_regs,
+	    nitems(r21a_iq_bb_regs));
+	r12a_save_bb_afe_vals(sc, saved_afe_vals, r21a_iq_afe_regs,
+	    nitems(r21a_iq_afe_regs));
+	r12a_save_rf_vals(sc, saved_rf_vals, r21a_iq_rf_regs,
+	    nitems(r21a_iq_rf_regs));
+
+#ifdef RTWN_TODO
+	/* Configure MAC. */
+	r12a_iq_config_mac(sc);
+	r21a_iq_tx(sc);
+#endif
+
+	/* Restore registers. */
+	r12a_restore_rf_vals(sc, saved_rf_vals, r21a_iq_rf_regs,
+	    nitems(r21a_iq_rf_regs));
+	r12a_restore_bb_afe_vals(sc, saved_afe_vals, r21a_iq_afe_regs,
+	    nitems(r21a_iq_afe_regs));
+
+	/* Select page C1. */
+	rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000);
+
+	rtwn_bb_write(sc, R12A_SLEEP_NAV(0), 0);
+	rtwn_bb_write(sc, R12A_PMPD(0), 0);
+	rtwn_bb_write(sc, 0xc88, 0);
+	rtwn_bb_write(sc, 0xc8c, 0x3c000000);
+	rtwn_bb_write(sc, 0xc90, 0x80);
+	rtwn_bb_write(sc, 0xc94, 0);
+	rtwn_bb_write(sc, 0xcc4, 0x20040000);
+	rtwn_bb_write(sc, 0xcc8, 0x20000000);
+	rtwn_bb_write(sc, 0xcb8, 0);
+
+	r12a_restore_bb_afe_vals(sc, saved_bb_vals, r21a_iq_bb_regs,
+	    nitems(r21a_iq_bb_regs));
+#undef R21A_MAX_NRXCHAINS
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,155 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_rx.h>
+
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+
+
+static void
+r21a_bypass_ext_lna_2ghz(struct rtwn_softc *sc)
+{
+	rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00100000, 0);
+	rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00400000, 0);
+	rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0, 0x07);
+	rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0, 0x0700);
+}
+
+void
+r21a_set_band_2ghz(struct rtwn_softc *sc, uint32_t basicrates)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+
+	/* Enable CCK / OFDM. */
+	rtwn_bb_setbits(sc, R12A_OFDMCCK_EN,
+	    0, R12A_OFDMCCK_EN_CCK | R12A_OFDMCCK_EN_OFDM);
+
+	/* Turn off RF PA and LNA. */
+	rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0),
+	    R12A_RFE_PINMUX_LNA_MASK, 0x7000);
+	rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0),
+	    R12A_RFE_PINMUX_PA_A_MASK, 0x70);
+
+	if (rs->ext_lna_2g) {
+		/* Turn on 2.4 GHz external LNA. */
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0, 0x00100000);
+		rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00400000, 0);
+		rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0x05, 0x02);
+		rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0x0500, 0x0200);
+	} else {
+		/* Bypass 2.4 GHz external LNA. */
+		r21a_bypass_ext_lna_2ghz(sc);
+	}
+
+	/* Select AGC table. */
+	rtwn_bb_setbits(sc, R12A_TX_SCALE(0), 0x0f00, 0);
+
+	rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0x10);
+	rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0x0f000000, 0x01000000);
+
+	/* Write basic rates. */
+	rtwn_set_basicrates(sc, basicrates);
+
+	rtwn_write_1(sc, R12A_CCK_CHECK, 0);
+}
+
+void
+r21a_set_band_5ghz(struct rtwn_softc *sc, uint32_t basicrates)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	int ntries;
+
+	rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0),
+	    R12A_RFE_PINMUX_LNA_MASK, 0x5000);
+	rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0),
+	    R12A_RFE_PINMUX_PA_A_MASK, 0x40);
+
+	if (rs->ext_lna_2g) {
+		/* Bypass 2.4 GHz external LNA. */
+		r21a_bypass_ext_lna_2ghz(sc);
+	}
+
+	rtwn_write_1(sc, R12A_CCK_CHECK, R12A_CCK_CHECK_5GHZ);
+
+	for (ntries = 0; ntries < 100; ntries++) {
+		if ((rtwn_read_2(sc, R12A_TXPKT_EMPTY) & 0x30) == 0x30)
+			break;
+
+		rtwn_delay(sc, 25);
+	}
+	if (ntries == 100) {
+		device_printf(sc->sc_dev,
+		    "%s: TXPKT_EMPTY check failed (%04X)\n",
+		    __func__, rtwn_read_2(sc, R12A_TXPKT_EMPTY));
+	}
+
+	/* Enable OFDM. */
+	rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, R12A_OFDMCCK_EN_CCK,
+	    R12A_OFDMCCK_EN_OFDM);
+
+	/* Select AGC table. */
+	rtwn_bb_setbits(sc, R12A_TX_SCALE(0), 0x0f00, 0x0100);
+
+	rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0);
+	rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0, 0x0f000000);
+
+	/* Write basic rates. */
+	rtwn_set_basicrates(sc, basicrates);
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,80 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+
+
+#ifndef RTWN_WITHOUT_UCODE
+void
+r21a_fw_reset(struct rtwn_softc *sc, int reason)
+{
+
+	/* Reset MCU IO wrapper. */
+	rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0);
+	rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0x01, 0);
+
+	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
+	    R92C_SYS_FUNC_EN_CPUEN, 0, 1);
+
+	/* Enable MCU IO wrapper. */
+	rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0);
+	rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0, 0x01);
+
+	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
+	    0, R92C_SYS_FUNC_EN_CPUEN, 1);
+}
+#endif
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,360 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+#include <dev/rtwn/rtl8821a/r21a_priv.h>
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+
+
+int
+r21a_power_on(struct rtwn_softc *sc)
+{
+#define RTWN_CHK(res) do {	\
+	if (res != 0)		\
+		return (EIO);	\
+} while(0)
+	int ntries;
+
+	/* Clear suspend and power down bits.*/
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_APDM_HPDN, 0, 1));
+
+	/* Disable GPIO9 as EXT WAKEUP. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_GPIO_INTM + 2, 0x01, 0));
+
+	/* Enable WL suspend. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1));
+
+	/* Enable LDOA12 MACRO block for all interfaces. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_LDOA15_CTRL, 0, R92C_LDOA15_CTRL_EN));
+
+	/* Disable BT_GPS_SEL pins. */
+	RTWN_CHK(rtwn_setbits_1(sc, 0x067, 0x10, 0));
+
+	/* 1 ms delay. */
+	rtwn_delay(sc, 1000);
+
+	/* Release analog Ips to digital isolation. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL,
+	    R92C_SYS_ISO_CTRL_IP2MAC, 0));
+
+	/* Disable SW LPS and WL suspend. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_APFM_RSM |
+	    R92C_APS_FSMCO_AFSM_HSUS |
+	    R92C_APS_FSMCO_AFSM_PCIE, 0, 1));
+
+	/* Wait for power ready bit. */
+	for (ntries = 0; ntries < 5000; ntries++) {
+		if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST)
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 5000) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for chip power up\n");
+		return (ETIMEDOUT);
+	}
+
+	/* Release WLON reset. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0,
+	    R92C_APS_FSMCO_RDY_MACON, 2));
+
+	/* Disable HWPDN. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_APDM_HPDN, 0, 1));
+
+	/* Disable WL suspend. */
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO,
+	    R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1));
+
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0,
+	    R92C_APS_FSMCO_APFM_ONMAC, 1));
+	for (ntries = 0; ntries < 5000; ntries++) {
+		if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
+		    R92C_APS_FSMCO_APFM_ONMAC))
+			break;
+		rtwn_delay(sc, 10);
+	}
+	if (ntries == 5000)
+		return (ETIMEDOUT);
+
+	/* Switch DPDT_SEL_P output from WL BB. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_LEDCFG3, 0, 0x01));
+
+	/* switch for PAPE_G/PAPE_A from WL BB; switch LNAON from WL BB. */
+	RTWN_CHK(rtwn_setbits_1(sc, 0x067, 0, 0x30));
+
+	RTWN_CHK(rtwn_setbits_1(sc, 0x025, 0x40, 0));
+
+	/* Enable falling edge triggering interrupt. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_GPIO_INTM + 1, 0, 0x02));
+
+	/* Enable GPIO9 interrupt mode. */
+	RTWN_CHK(rtwn_setbits_1(sc, 0x063, 0, 0x02));
+
+	/* Enable GPIO9 input mode. */
+	RTWN_CHK(rtwn_setbits_1(sc, 0x062, 0x02, 0));
+
+	/* Enable HSISR GPIO interrupt. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_HSIMR, 0, 0x01));
+
+	/* Enable HSISR GPIO9 interrupt. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_HSIMR + 2, 0, 0x02));
+
+	/* XTAL trim. */
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_APE_PLL_CTRL_EXT + 2, 0xFF, 0x82));
+
+	RTWN_CHK(rtwn_setbits_1(sc, R92C_AFE_MISC, 0, 0x40));
+
+	/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+	RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0x0000));
+	RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN |
+	    R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN |
+	    R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN |
+	    ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) |
+	    R92C_CR_CALTMR_EN));
+
+	if (rtwn_read_4(sc, R92C_SYS_CFG) & R92C_SYS_CFG_TRP_BT_EN)
+		RTWN_CHK(rtwn_setbits_1(sc, 0x07C, 0, 0x40));
+
+	return (0);
+#undef RTWN_CHK
+}
+
+void
+r21a_power_off(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	int error, ntries;
+
+	/* Stop Rx. */
+	error = rtwn_write_1(sc, R92C_CR, 0);
+	if (error == ENXIO)	/* hardware gone */
+		return;
+
+	/* Move card to Low Power state. */
+	/* Block all Tx queues. */
+	rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
+
+	for (ntries = 0; ntries < 10; ntries++) {
+		/* Should be zero if no packet is transmitting. */
+		if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0)
+			break;
+
+		rtwn_delay(sc, 5000);
+	}
+	if (ntries == 10) {
+		device_printf(sc->sc_dev, "%s: failed to block Tx queues\n",
+		    __func__);
+		return;
+	}
+
+	/* CCK and OFDM are disabled, and clock are gated. */
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0);
+
+	rtwn_delay(sc, 1);
+
+	/* Reset whole BB. */
+	rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0);
+
+	/* Reset MAC TRX. */
+	rtwn_write_1(sc, R92C_CR,
+	    R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN);
+
+	/* check if removed later. (?) */
+	rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1);
+
+	/* Respond TxOK to scheduler */
+	rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, R92C_DUAL_TSF_RST_TXOK);
+
+	/* If firmware in ram code, do reset. */
+#ifndef RTWN_WITHOUT_UCODE
+	if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
+		r21a_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN);
+#endif
+
+	/* Reset MCU. */
+	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN,
+	    0, 1);
+	rtwn_write_1(sc, R92C_MCUFWDL, 0);
+
+	/* Move card to Disabled state. */
+	/* Turn off RF. */
+	rtwn_write_1(sc, R92C_RF_CTRL, 0);
+
+	rtwn_setbits_1(sc, R92C_LEDCFG3, 0x01, 0);
+
+	/* Enable rising edge triggering interrupt. */
+	rtwn_setbits_1(sc, R92C_GPIO_INTM + 1, 0x02, 0);
+
+	/* Release WLON reset. */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0,
+	    R92C_APS_FSMCO_RDY_MACON, 2);
+
+	/* Turn off MAC by HW state machine */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_OFF,
+	    1);
+	for (ntries = 0; ntries < 10; ntries++) {
+		/* Wait until it will be disabled. */
+		if ((rtwn_read_2(sc, R92C_APS_FSMCO) &
+		    R92C_APS_FSMCO_APFM_OFF) == 0)
+			break;
+
+		rtwn_delay(sc, 5000);
+	}
+	if (ntries == 10) {
+		device_printf(sc->sc_dev, "%s: could not turn off MAC\n",
+		    __func__);
+		return;
+	}
+
+	/* Analog Ips to digital isolation. */
+	rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL, 0, R92C_SYS_ISO_CTRL_IP2MAC);
+
+	/* Disable LDOA12 MACRO block. */
+	rtwn_setbits_1(sc, R92C_LDOA15_CTRL, R92C_LDOA15_CTRL_EN, 0);
+
+	/* Enable WL suspend. */
+	rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_AFSM_PCIE,
+	    R92C_APS_FSMCO_AFSM_HSUS, 1);
+
+	/* Enable GPIO9 as EXT WAKEUP. */
+	rtwn_setbits_1(sc, R92C_GPIO_INTM + 2, 0, 0x01);
+
+	rs->rs_flags &= ~(R12A_IQK_RUNNING | R12A_RADAR_ENABLED);
+}
+
+int
+r21a_check_condition(struct rtwn_softc *sc, const uint8_t cond[])
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	uint8_t mask;
+	int i;
+
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RESET,
+	    "%s: condition byte 0: %02X; ext 5ghz pa/lna %d/%d\n",
+	    __func__, cond[0], rs->ext_pa_5g, rs->ext_lna_5g);
+
+	if (cond[0] == 0)
+		return (1);
+
+	mask = 0;
+	if (rs->ext_pa_5g)
+		mask |= R21A_COND_EXT_PA_5G;
+	if (rs->ext_lna_5g)
+		mask |= R21A_COND_EXT_LNA_5G;
+	if (rs->bt_coex)
+		mask |= R21A_COND_BT;
+	if (!rs->ext_pa_2g && !rs->ext_lna_2g &&
+	    !rs->ext_pa_5g && !rs->ext_lna_5g && !rs->bt_coex)
+		mask = R21A_COND_BOARD_DEF;
+
+	if (mask == 0)
+		return (0);
+
+	for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++)
+		if (cond[i] == mask)
+			return (1);
+
+	return (0);
+}
+
+void
+r21a_crystalcap_write(struct rtwn_softc *sc)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	uint32_t reg;
+	uint8_t val;
+
+	val = rs->crystalcap & 0x3f;
+	reg = rtwn_bb_read(sc, R92C_MAC_PHY_CTRL);
+	reg = RW(reg, R21A_MAC_PHY_CRYSTALCAP, val | (val << 6));
+	rtwn_bb_write(sc, R92C_MAC_PHY_CTRL, reg);
+}
+
+int
+r21a_init_bcnq1_boundary(struct rtwn_softc *sc)
+{
+#define RTWN_CHK(res) do {	\
+	if (res != 0)		\
+		return (EIO);	\
+} while(0)
+	RTWN_CHK(rtwn_write_1(sc, R88E_TXPKTBUF_BCNQ1_BDNY,
+	    R21A_BCNQ0_BOUNDARY));
+	RTWN_CHK(rtwn_write_1(sc, R21A_DWBCN1_CTRL + 1,
+	    R21A_BCNQ0_BOUNDARY));
+	RTWN_CHK(rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL, 0,
+	    R21A_DWBCN1_CTRL_SEL_EN, 2));
+
+	return (0);
+#undef RTWN_CHK
+}
+
+void
+r21a_init_ampdu_fwhw(struct rtwn_softc *sc)
+{
+	rtwn_write_1(sc, R92C_FWHW_TXQ_CTRL,
+	    R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW);
+	rtwn_write_4(sc, R92C_FAST_EDCA_CTRL, 0x03087777);
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,69 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+
+
+void
+r21a_set_led(struct rtwn_softc *sc, int led, int on)
+{
+	if (led == RTWN_LED_LINK) {
+		rtwn_write_1(sc, R92C_LEDCFG2,
+		    R12A_LEDCFG2_ENA | (on ? 0 : R92C_LEDCFG0_DIS));
+		sc->ledlink = on;	/* Save LED state. */
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,464 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R21A_PRIV_H
+#define R21A_PRIV_H
+
+/*
+ * MAC initialization values.
+ */
+static const struct rtwn_mac_prog rtl8821au_mac[] = {
+	{ 0x421, 0x0f }, { 0x428, 0x0a }, { 0x429, 0x10 }, { 0x430, 0x00 },
+	{ 0x431, 0x00 }, { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 },
+	{ 0x435, 0x05 }, { 0x436, 0x07 }, { 0x437, 0x08 }, { 0x43c, 0x04 },
+	{ 0x43d, 0x05 }, { 0x43e, 0x07 }, { 0x43f, 0x08 }, { 0x440, 0x5d },
+	{ 0x441, 0x01 }, { 0x442, 0x00 }, { 0x444, 0x10 }, { 0x445, 0x00 },
+	{ 0x446, 0x00 }, { 0x447, 0x00 }, { 0x448, 0x00 }, { 0x449, 0xf0 },
+	{ 0x44a, 0x0f }, { 0x44b, 0x3e }, { 0x44c, 0x10 }, { 0x44d, 0x00 },
+	{ 0x44e, 0x00 }, { 0x44f, 0x00 }, { 0x450, 0x00 }, { 0x451, 0xf0 },
+	{ 0x452, 0x0f }, { 0x453, 0x00 }, { 0x456, 0x5e }, { 0x460, 0x66 },
+	{ 0x461, 0x66 }, { 0x4c8, 0x3f }, { 0x4c9, 0xff }, { 0x4cc, 0xff },
+	{ 0x4cd, 0xff }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 },
+	{ 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 },
+	{ 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 },
+	{ 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 },
+	{ 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a },
+	{ 0x516, 0x0a }, { 0x525, 0x4f }, { 0x550, 0x10 }, { 0x551, 0x10 },
+	{ 0x559, 0x02 }, { 0x55c, 0x50 }, { 0x55d, 0xff }, { 0x605, 0x30 },
+	{ 0x607, 0x07 }, { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x620, 0xff },
+	{ 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff }, { 0x624, 0xff },
+	{ 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff }, { 0x638, 0x50 },
+	{ 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e }, { 0x63f, 0x0e },
+	{ 0x640, 0x40 }, { 0x642, 0x40 }, { 0x643, 0x00 }, { 0x652, 0xc8 },
+	{ 0x66e, 0x05 }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 },
+	{ 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 },
+	{ 0x70b, 0x87 }, { 0x718, 0x40 }
+};
+
+
+/*
+ * Baseband initialization values.
+ */
+#define R21A_COND_EXT_PA_5G	0x01
+#define R21A_COND_EXT_LNA_5G	0x02
+#define R21A_COND_BOARD_DEF	0x04
+#define R21A_COND_BT		0x08
+
+static const uint16_t rtl8821au_bb_regs[] = {
+	0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x820, 0x824,
+	0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, 0x840, 0x844, 0x848,
+	0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, 0x864, 0x868, 0x86c,
+	0x870, 0x874, 0x878, 0x87c, 0x8a0, 0x8a4, 0x8a8, 0x8ac, 0x8b4,
+	0x8b8, 0x8bc, 0x8c0, 0x8c4, 0x8c8, 0x8cc, 0x8d4, 0x8d8, 0x8f8,
+	0x8fc, 0x900, 0x90c, 0x910, 0x914, 0x918, 0x91c, 0x920, 0x924,
+	0x928, 0x92c, 0x930, 0x934, 0x960, 0x964, 0x968, 0x96c, 0x970,
+	0x974, 0x978, 0x97c, 0x980, 0x984, 0x988, 0x990, 0x994, 0x998,
+	0x99c, 0x9a0, 0x9a4, 0x9a8, 0x9ac, 0x9b0, 0x9b4, 0x9b8, 0x9bc,
+	0x9d0, 0x9d4, 0x9d8, 0x9dc, 0x9e0, 0x9e4, 0x9e8, 0xa00, 0xa04,
+	0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, 0xa28,
+	0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xa84, 0xb00, 0xb04,
+	0xb08, 0xb0c, 0xb10, 0xb14, 0xb18, 0xb1c, 0xb20, 0xb24, 0xb28,
+	0xb2c, 0xb30, 0xb34, 0xb38, 0xb3c, 0xb40, 0xb44, 0xb48, 0xb4c,
+	0xb50, 0xb54, 0xb58, 0xb5c, 0xc00, 0xc04, 0xc08, 0xc0c, 0xc10,
+	0xc14, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, 0xc38,
+	0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, 0xc5c,
+	0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, 0xc80,
+	0xc84, 0xc94, 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcb0, 0xcb4,
+	0xcb8
+};
+
+static const uint32_t rtl8821au_bb_vals[] = {
+	0x0020d090, 0x080112e0, 0x0e028211, 0x92131111, 0x20101261,
+	0x020c3d10, 0x03a00385, 0x00000000, 0x00030fe0, 0x00000000,
+	0x002081dd, 0x2aaaeec8, 0x0037a706, 0x06489b44, 0x0000095b,
+	0xc0000001, 0x40003cde, 0x62103f8b, 0x6cfdffb8, 0x28874706,
+	0x0001520c, 0x8060e000, 0x74210168, 0x6929c321, 0x79727432,
+	0x8ca7a314, 0x888c2878, 0x08888888, 0x31612c2e, 0x00000152,
+	0x000fd000, 0x00000013, 0x7f7f7f7f, 0xa2000338, 0x0ff0fa0a,
+	0x000fc080, 0x6c10d7ff, 0x0ca52090, 0x1bf00020, 0x00000000,
+	0x00013169, 0x08248492, 0x940008a0, 0x290b5612, 0x400002c0,
+	0x00000000, 0x00000700, 0x00000000, 0x0000fc00, 0x00000404,
+	0x1c1028c0, 0x64b11a1c, 0xe0767233, 0x055aa500, 0x00000004,
+	0xfffe0000, 0xfffffffe, 0x001fffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x801fffff, 0x000003ff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x27100000,
+	0xffff0100, 0xffffff5c, 0xffffffff, 0x000000ff, 0x00480080,
+	0x00000000, 0x00000000, 0x81081008, 0x01081008, 0x01081008,
+	0x01081008, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00005d00, 0x00000003, 0x00000001, 0x00d047c8, 0x01ff800c,
+	0x8c8a8300, 0x2e68000f, 0x9500bb78, 0x11144028, 0x00881117,
+	0x89140f00, 0x1a1b0000, 0x090e1317, 0x00000204, 0x00900000,
+	0x101fff00, 0x00000008, 0x00000900, 0x225b0606, 0x21805490,
+	0x001f0000, 0x03100040, 0x0000b000, 0xae0201eb, 0x01003207,
+	0x00009807, 0x01000000, 0x00000002, 0x00000002, 0x0000001f,
+	0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, 0x13121110,
+	0x17161514, 0x0000003a, 0x00000000, 0x00000000, 0x13000032,
+	0x48080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000007, 0x00042020, 0x80410231, 0x00000000, 0x00000100,
+	0x01000000, 0x40000003, 0x2c2c2c2c, 0x30303030, 0x30303030,
+	0x2c2c2c2c, 0x2c2c2c2c, 0x2c2c2c2c, 0x2c2c2c2c, 0x2a2a2a2a,
+	0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000020,
+	0x001c1208, 0x30000c1c, 0x00000058, 0x34344443, 0x07003333,
+	0x19791979, 0x19791979, 0x19791979, 0x19791979, 0x19791979,
+	0x19791979, 0x19791979, 0x19791979, 0x0100005c, 0x00000000,
+	0x00000000, 0x00000029, 0x08040201, 0x80402010, 0x77775747,
+	0x10000077, 0x00508240
+};
+
+static const struct rtwn_bb_prog rtl8821au_bb[] = {
+	{
+		nitems(rtl8821au_bb_regs),
+		rtl8821au_bb_regs,
+		rtl8821au_bb_vals,
+		{ 0 },
+		NULL
+	}
+};
+
+static const uint32_t rtl8821au_agc_vals0[] = {
+	0xbf000001, 0xbf020001, 0xbf040001, 0xbf060001, 0xbe080001,
+	0xbd0a0001, 0xbc0c0001, 0xba0e0001, 0xb9100001, 0xb8120001,
+	0xb7140001, 0xb6160001, 0xb5180001, 0xb41a0001, 0xb31c0001,
+	0xb21e0001, 0xb1200001, 0xb0220001, 0xaf240001, 0xae260001,
+	0xad280001, 0xac2a0001, 0xab2c0001, 0xaa2e0001, 0xa9300001,
+	0xa8320001, 0xa7340001, 0xa6360001, 0xa5380001, 0xa43a0001,
+	0x683c0001, 0x673e0001, 0x66400001, 0x65420001, 0x64440001,
+	0x63460001, 0x62480001, 0x614a0001, 0x474c0001, 0x464e0001,
+	0x45500001, 0x44520001, 0x43540001, 0x42560001, 0x41580001,
+	0x285a0001, 0x275c0001, 0x265e0001, 0x25600001, 0x24620001,
+	0x0a640001, 0x09660001, 0x08680001, 0x076a0001, 0x066c0001,
+	0x056e0001, 0x04700001, 0x03720001, 0x02740001, 0x01760001,
+	0x01780001, 0x017a0001, 0x017c0001, 0x017e0001
+}, rtl8821au_agc_vals1_pa_lna_5g[] = {
+	0xfb000101, 0xfa020101, 0xf9040101, 0xf8060101, 0xf7080101,
+	0xf60a0101, 0xf50c0101, 0xf40e0101, 0xf3100101, 0xf2120101,
+	0xf1140101, 0xf0160101, 0xef180101, 0xee1a0101, 0xed1c0101,
+	0xec1e0101, 0xeb200101, 0xea220101, 0xe9240101, 0xe8260101,
+	0xe7280101, 0xe62a0101, 0xe52c0101, 0xe42e0101, 0xe3300101,
+	0xa5320101, 0xa4340101, 0xa3360101, 0x87380101, 0x863a0101,
+	0x853c0101, 0x843e0101, 0x69400101, 0x68420101, 0x67440101,
+	0x66460101, 0x49480101, 0x484a0101, 0x474c0101, 0x2a4e0101,
+	0x29500101, 0x28520101, 0x27540101, 0x26560101, 0x25580101,
+	0x245a0101, 0x235c0101, 0x055e0101, 0x04600101, 0x03620101,
+	0x02640101, 0x01660101, 0x01680101, 0x016a0101, 0x016c0101,
+	0x016e0101, 0x01700101, 0x01720101
+}, rtl8821au_agc_vals1[] = {
+	0xff000101, 0xff020101, 0xfe040101, 0xfd060101, 0xfc080101,
+	0xfd0a0101, 0xfc0c0101, 0xfb0e0101, 0xfa100101, 0xf9120101,
+	0xf8140101, 0xf7160101, 0xf6180101, 0xf51a0101, 0xf41c0101,
+	0xf31e0101, 0xf2200101, 0xf1220101, 0xf0240101, 0xef260101,
+	0xee280101, 0xed2a0101, 0xec2c0101, 0xeb2e0101, 0xea300101,
+	0xe9320101, 0xe8340101, 0xe7360101, 0xe6380101, 0xe53a0101,
+	0xe43c0101, 0xe33e0101, 0xa5400101, 0xa4420101, 0xa3440101,
+	0x87460101, 0x86480101, 0x854a0101, 0x844c0101, 0x694e0101,
+	0x68500101, 0x67520101, 0x66540101, 0x49560101, 0x48580101,
+	0x475a0101, 0x2a5c0101, 0x295e0101, 0x28600101, 0x27620101,
+	0x26640101, 0x25660101, 0x24680101, 0x236a0101, 0x056c0101,
+	0x046e0101, 0x03700101, 0x02720101
+}, rtl8821au_agc_vals2[] = {
+	0x01740101, 0x01760101, 0x01780101, 0x017a0101, 0x017c0101,
+	0x017e0101
+};
+
+static const struct rtwn_agc_prog rtl8821au_agc[] = {
+	{
+		nitems(rtl8821au_agc_vals0),
+		rtl8821au_agc_vals0,
+		{ 0 },
+		NULL
+	},
+	/*
+	 * For devices with external 5GHz PA / LNA.
+	 */
+	{
+		nitems(rtl8821au_agc_vals1_pa_lna_5g),
+		rtl8821au_agc_vals1_pa_lna_5g,
+		{ R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 },
+		/*
+		 * Others.
+		 */
+		&(const struct rtwn_agc_prog){
+			nitems(rtl8821au_agc_vals1),
+			rtl8821au_agc_vals1,
+			{ 0 },
+			NULL
+		}
+	},
+	{
+		nitems(rtl8821au_agc_vals2),
+		rtl8821au_agc_vals2,
+		{ 0 },
+		NULL
+	}
+};
+
+
+/*
+ * RF initialization values.
+ */
+static const uint8_t rtl8821au_rf_regs0[] = {
+	0x18, 0x56, 0x66, 0x00, 0x1e, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xef, 0x3e, 0x3f,
+	0x3e, 0x3f, 0x3e, 0x3f, 0x3e, 0x3f, 0xef, 0x18, 0x89, 0x8b, 0xef,
+	0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b,
+	0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a,
+	0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c,
+	0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b,
+	0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a,
+	0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0xef, 0xef
+}, rtl8821au_rf_regs1[] = {
+	0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+	0x34, 0x34
+}, rtl8821au_rf_regs2[] = {
+	0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+	0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0xef, 0x18,
+	0xef
+}, rtl8821au_rf_regs3[] = {
+	0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0xef, 0x18,
+	0xef, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0xef, 0xef, 0x3c, 0x3c
+}, rtl8821au_rf_regs4[] = {
+	0x3c, 0xef, 0x18, 0xef, 0x08, 0xef, 0xdf, 0x1f, 0x58, 0x59, 0x61,
+	0x62, 0x63, 0x64, 0x65
+}, rtl8821au_rf_regs5[] = {
+	0x18, 0xef, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+	0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0xef, 0x34, 0x34,
+	0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0xef, 0xed,
+	0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+	0xed, 0xed, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xed,
+	0xef, 0xdf, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xef, 0x51,
+	0x52, 0x53, 0x54, 0x56, 0x51, 0x52, 0x53, 0x70, 0x71, 0x72, 0x74,
+	0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xed, 0x45, 0x45, 0x45,
+	0x46, 0x46, 0x46, 0x46, 0xdf, 0xb3, 0xb4, 0xb7, 0x1c, 0xc4, 0x18,
+	0xfe, 0xfe, 0x18,
+};
+
+static const uint32_t rtl8821au_rf_vals0[] = {
+	0x1712a, 0x51cf2, 0x40000, 0x10000, 0x80000, 0x00830, 0x21800,
+	0x28000, 0x48000, 0x94838, 0x44980, 0x48000, 0x0d480, 0x42240,
+	0xf0380, 0x90000, 0x22852, 0x65540, 0x88001, 0x20000, 0x00380,
+	0x90018, 0x20380, 0xa0018, 0x40308, 0xa0018, 0x60018, 0xa0018,
+	0x00000, 0x1712a, 0x00080, 0x80180, 0x01000, 0x00244, 0x38027,
+	0x82000, 0x00244, 0x30113, 0x82000, 0x0014c, 0x28027, 0x82000,
+	0x000cc, 0x27027, 0x42000, 0x0014c, 0x1f913, 0x42000, 0x0010c,
+	0x17f10, 0x12000, 0x000d0, 0x08027, 0xca000, 0x00244, 0x78027,
+	0x82000, 0x00244, 0x70113, 0x82000, 0x0014c, 0x68027, 0x82000,
+	0x000cc, 0x67027, 0x42000, 0x0014c, 0x5f913, 0x42000, 0x0010c,
+	0x57f10, 0x12000, 0x000d0, 0x48027, 0xca000, 0x00244, 0xb8027,
+	0x82000, 0x00244, 0xb0113, 0x82000, 0x0014c, 0xa8027, 0x82000,
+	0x000cc, 0xa7027, 0x42000, 0x0014c, 0x9f913, 0x42000, 0x0010c,
+	0x97f10, 0x12000, 0x000d0, 0x88027, 0xca000, 0x00000, 0x01100
+}, rtl8821au_rf_vals1_def_or_bt[] = {
+	0x4adf5, 0x49df2, 0x48def, 0x47dec, 0x46de9, 0x45ccb, 0x4488d,
+	0x4348d, 0x4248a, 0x4108d, 0x4008a, 0x2adf4, 0x29df1
+}, rtl8821au_rf_vals1_ext_5g[] = {
+	0x4a0f3, 0x490b1, 0x480ae, 0x470ab, 0x4608b, 0x45069, 0x44048,
+	0x43045, 0x42026, 0x41023, 0x40002, 0x2a0f3, 0x290f0
+}, rtl8821au_rf_vals1[] = {
+	0x4adf7, 0x49df3, 0x48def, 0x47dec, 0x46de9, 0x45ccb, 0x4488d,
+	0x4348d, 0x4248a, 0x4108d, 0x4008a, 0x2adf7, 0x29df2
+}, rtl8821au_rf_vals2_ext_5g[] = {
+	0x280af, 0x270ac, 0x2608b, 0x25069, 0x24048, 0x23045, 0x22026,
+	0x21023, 0x20002, 0x0a0d7, 0x090d3, 0x080b1, 0x070ae, 0x0608d,
+	0x0506b, 0x0404a, 0x03047, 0x02044, 0x01025, 0x00004, 0x00000,
+	0x1712a, 0x00040
+}, rtl8821au_rf_vals2[] = {
+	0x28dee, 0x27deb, 0x26ccd, 0x25cca, 0x2488c, 0x2384c, 0x22849,
+	0x21449, 0x2004d, 0x0adf7, 0x09df4, 0x08df1, 0x07dee, 0x06dcd,
+	0x05ccd, 0x04cca, 0x0388c, 0x02888, 0x01488, 0x00486, 0x00000,
+	0x1712a, 0x00040
+}, rtl8821au_rf_vals3_def_or_bt[] = {
+	0x00128, 0x08128, 0x10128, 0x201c8, 0x281c8, 0x301c8, 0x401c8,
+	0x481c8, 0x501c8, 0x00000, 0x1712a, 0x00010, 0x063b5, 0x0e3b5,
+	0x163b5, 0x1e3b5, 0x263b5, 0x2e3b5, 0x363b5, 0x3e3b5, 0x463b5,
+	0x4e3b5, 0x563b5, 0x5e3b5, 0x00000, 0x00008, 0x001b6, 0x00492
+}, rtl8821au_rf_vals3[] = {
+	0x00145, 0x08145, 0x10145, 0x20196, 0x28196, 0x30196, 0x401c7,
+	0x481c7, 0x501c7, 0x00000, 0x1712a, 0x00010, 0x056b3, 0x0d6b3,
+	0x156b3, 0x1d6b3, 0x26634, 0x2e634, 0x36634, 0x3e634, 0x467b4,
+	0x4e7b4, 0x567b4, 0x5e7b4, 0x00000, 0x00008, 0x0022a, 0x00594
+}, rtl8821au_rf_vals4_def_or_bt[] = {
+	0x00800, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0,
+	0x00064, 0x81184, 0x6016c, 0xefd83, 0x93fcc, 0x110eb, 0x1c27c,
+	0x93016
+}, rtl8821au_rf_vals4_ext_5g[] = {
+	0x00820, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0,
+	0x00064, 0x81184, 0x6016c, 0xead53, 0x93bc4, 0x110e9, 0x1c67c,
+	0x93015
+}, rtl8821au_rf_vals4[] = {
+	0x00900, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0,
+	0x00064, 0x81184, 0x6016c, 0xead53, 0x93bc4, 0x714e9, 0x1c67c,
+	0x91016
+}, rtl8821au_rf_vals5[] = {
+	0x00006, 0x02000, 0x3824b, 0x3024b, 0x2844b, 0x20f4b, 0x18f4b,
+	0x104b2, 0x08049, 0x00148, 0x7824b, 0x7024b, 0x6824b, 0x60f4b,
+	0x58f4b, 0x504b2, 0x48049, 0x40148, 0x00000, 0x00100, 0x0adf3,
+	0x09df0, 0x08d70, 0x07d6d, 0x06cee, 0x05ccc, 0x044ec, 0x034ac,
+	0x0246d, 0x0106f, 0x0006c, 0x00000, 0x00010, 0x0adf2, 0x09def,
+	0x08dec, 0x07de9, 0x06cec, 0x05ce9, 0x044ec, 0x034e9, 0x0246c,
+	0x01469, 0x0006c, 0x00000, 0x00001, 0x38da7, 0x300c2, 0x288e2,
+	0x200b8, 0x188a5, 0x10fbc, 0x08f71, 0x00240, 0x00000, 0x020a2,
+	0x00080, 0x00120, 0x08120, 0x10120, 0x00085, 0x08085, 0x10085,
+	0x18085, 0x00000, 0x00c31, 0x00622, 0xfc70b, 0x0017e, 0x51df3,
+	0x00c01, 0x006d6, 0xfc649, 0x49661, 0x7843e, 0x00382, 0x51400,
+	0x00160, 0x08160, 0x10160, 0x00124, 0x08124, 0x10124, 0x18124,
+	0x0000c, 0x00140, 0x08140, 0x10140, 0x00124, 0x08124, 0x10124,
+	0x18124, 0x00088, 0xf0e18, 0x1214c, 0x3000c, 0x539d2, 0xafe00,
+	0x1f12a, 0x0c350, 0x0c350, 0x1712a,
+};
+
+static const struct rtwn_rf_prog rtl8821au_rf[] = {
+	/* RF chain 0. */
+	{
+		nitems(rtl8821au_rf_regs0),
+		rtl8821au_rf_regs0,
+		rtl8821au_rf_vals0,
+		{ 0 },
+		NULL
+	},
+	/*
+	 * No external PA/LNA; with or without BT.
+	 */
+	{
+		nitems(rtl8821au_rf_regs1),
+		rtl8821au_rf_regs1,
+		rtl8821au_rf_vals1_def_or_bt,
+		{ R21A_COND_BOARD_DEF, R21A_COND_BT, 0 },
+		/*
+		 * With external 5GHz PA and LNA.
+		 */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8821au_rf_regs1),
+			rtl8821au_rf_regs1,
+			rtl8821au_rf_vals1_ext_5g,
+			{ R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 },
+			/*
+			 * Others.
+			 */
+			&(const struct rtwn_rf_prog){
+				nitems(rtl8821au_rf_regs1),
+				rtl8821au_rf_regs1,
+				rtl8821au_rf_vals1,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	/*
+	 * With external 5GHz PA and LNA.
+	 */
+	{
+		nitems(rtl8821au_rf_regs2),
+		rtl8821au_rf_regs2,
+		rtl8821au_rf_vals2_ext_5g,
+		{ R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 },
+		/*
+		 * Others.
+		 */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8821au_rf_regs2),
+			rtl8821au_rf_regs2,
+			rtl8821au_rf_vals2,
+			{ 0 },
+			NULL
+		}
+	},
+	/*
+	 * No external PA/LNA; with or without BT.
+	 */
+	{
+		nitems(rtl8821au_rf_regs3),
+		rtl8821au_rf_regs3,
+		rtl8821au_rf_vals3_def_or_bt,
+		{ R21A_COND_BOARD_DEF, R21A_COND_BT, 0 },
+		/*
+		 * Others.
+		 */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8821au_rf_regs3),
+			rtl8821au_rf_regs3,
+			rtl8821au_rf_vals3,
+			{ 0 },
+			NULL
+		}
+	},
+	/*
+	 * No external PA/LNA; with or without BT.
+	 */
+	{
+		nitems(rtl8821au_rf_regs4),
+		rtl8821au_rf_regs4,
+		rtl8821au_rf_vals4_def_or_bt,
+		{ R21A_COND_BOARD_DEF, R21A_COND_BT, 0 },
+		/*
+		 * With external 5GHz PA and LNA.
+		 */
+		&(const struct rtwn_rf_prog){
+			nitems(rtl8821au_rf_regs4),
+			rtl8821au_rf_regs4,
+			rtl8821au_rf_vals4_ext_5g,
+			{ R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 },
+			/*
+			 * Others.
+			 */
+			&(const struct rtwn_rf_prog){
+				nitems(rtl8821au_rf_regs4),
+				rtl8821au_rf_regs4,
+				rtl8821au_rf_vals4,
+				{ 0 },
+				NULL
+			}
+		}
+	},
+	{
+		nitems(rtl8821au_rf_regs5),
+		rtl8821au_rf_regs5,
+		rtl8821au_rf_vals5,
+		{ 0 },
+		NULL
+	},
+	{ 0, NULL, NULL, { 0 }, NULL }
+};
+
+
+/*
+ * Registers to save before IQ calibration.
+ */
+static const uint16_t r21a_iq_bb_regs[] = {
+	0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0x838, 0x82c
+};
+
+static const uint16_t r21a_iq_afe_regs[] = {
+	0xc5c, 0xc60, 0xc64, 0xc68
+};
+
+static const uint8_t r21a_iq_rf_regs[] = {
+	0x65, 0x8f, 0x0
+};
+
+#endif	/* R21A_PRIV_H */
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R21A_REG_H
+#define R21A_REG_H
+
+#include <dev/rtwn/rtl8812a/r12a_reg.h>
+
+/*
+ * MAC registers.
+ */
+/* Tx DMA Configuration. */
+#define R21A_DWBCN0_CTRL		R92C_TDECTRL
+#define R21A_DWBCN1_CTRL		0x228
+
+
+/* Bits for R92C_MAC_PHY_CTRL. */
+#define R21A_MAC_PHY_CRYSTALCAP_M	0x00fff000
+#define R21A_MAC_PHY_CRYSTALCAP_S	12
+
+/* Bits for R21A_DWBCN1_CTRL. */
+#define R21A_DWBCN1_CTRL_SEL_EN		0x00020000
+#define R21A_DWBCN1_CTRL_SEL_BCN1	0x00100000
+
+#endif	/* R21A_REG_H */
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,93 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8812a/r12a.h>
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+#include <dev/rtwn/rtl8812a/r12a_rom_image.h>
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+
+
+void
+r21a_parse_rom(struct rtwn_softc *sc, uint8_t *buf)
+{
+	struct r12a_softc *rs = sc->sc_priv;
+	struct r12a_rom *rom = (struct r12a_rom *)buf;
+	uint8_t pa_type, lna_type_2g, lna_type_5g;
+
+	/* Read PA/LNA types. */
+	pa_type = RTWN_GET_ROM_VAR(rom->pa_type, 0);
+	lna_type_2g = RTWN_GET_ROM_VAR(rom->lna_type_2g, 0);
+	lna_type_5g = RTWN_GET_ROM_VAR(rom->lna_type_5g, 0);
+
+	rs->ext_pa_2g = R21A_ROM_IS_PA_EXT_2GHZ(pa_type);
+	rs->ext_pa_5g = R21A_ROM_IS_PA_EXT_5GHZ(pa_type);
+	rs->ext_lna_2g = R21A_ROM_IS_LNA_EXT(lna_type_2g);
+	rs->ext_lna_5g = R21A_ROM_IS_LNA_EXT(lna_type_5g);
+
+	RTWN_LOCK(sc);
+	rs->bt_coex =
+	    !!(rtwn_read_4(sc, R92C_MULTI_FUNC_CTRL) & R92C_MULTI_BT_FUNC_EN);
+	RTWN_UNLOCK(sc);
+	rs->bt_ant_num = (rom->rf_bt_opt & R12A_RF_BT_OPT_ANT_NUM);
+
+	/* Read MAC address. */
+	IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr_21a);
+
+	/* Execute common part of initialization. */
+	r12a_parse_rom_common(sc, buf);
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,90 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/rtl8812a/r12a_rx_desc.h>
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+
+
+int8_t
+r21a_get_rssi_cck(struct rtwn_softc *sc, void *physt)
+{
+	struct r12a_rx_phystat *stat = (struct r12a_rx_phystat *)physt;
+	int8_t lna_idx, rssi;
+
+	lna_idx = (stat->cfosho[0] & 0xe0) >> 5;
+	rssi = -6 - 2*(stat->cfosho[0] & 0x1f);	/* Pout - (2 * VGA_idx) */
+
+	switch (lna_idx) {
+	case 5:
+		rssi -= 32;
+		break;
+	case 4:
+		rssi -= 24;
+		break;
+	case 2:
+		rssi -= 11;
+		break;
+	case 1:
+		rssi += 5;
+		break;
+	case 0:
+		rssi += 21;
+		break;
+	}
+
+	return (rssi);
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTL8821AU_H
+#define RTL8821AU_H
+
+#include <dev/rtwn/rtl8821a/r21a.h>
+
+
+/*
+ * Function declarations.
+ */
+/* r21au_init.c */
+void	r21au_init_tx_agg(struct rtwn_softc *);
+void	r21au_init_burstlen(struct rtwn_softc *);
+
+/* r21au_dfs.c */
+void	r21au_chan_check(void *, int);
+int	r21au_newstate(struct ieee80211vap *, enum ieee80211_state, int);
+void	r21au_scan_start(struct ieee80211com *);
+void	r21au_scan_end(struct ieee80211com *);
+
+#endif	/* RTL8821AU_H */
Index: freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,283 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_nop.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/rtl8192c/r92c.h>
+
+#include <dev/rtwn/rtl8188e/r88e.h>
+
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+#include <dev/rtwn/rtl8812a/usb/r12au.h>
+#include <dev/rtwn/rtl8812a/usb/r12au_tx_desc.h>
+
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+#include <dev/rtwn/rtl8821a/r21a_priv.h>
+
+#include <dev/rtwn/rtl8821a/usb/r21au.h>
+
+
+void	r21au_attach(struct rtwn_usb_softc *);
+
+static void
+r21a_postattach(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct r12a_softc *rs = sc->sc_priv;
+
+	if (rs->board_type == R92C_BOARD_TYPE_MINICARD ||
+	    rs->board_type == R92C_BOARD_TYPE_SOLO ||
+	    rs->board_type == R92C_BOARD_TYPE_COMBO)
+		sc->sc_set_led = r88e_set_led;
+	else
+		sc->sc_set_led = r21a_set_led;
+
+	TIMEOUT_TASK_INIT(taskqueue_thread, &rs->rs_chan_check, 0,
+	    r21au_chan_check, sc);
+
+	/* RXCKSUM */
+	ic->ic_ioctl = r12a_ioctl_net;
+	/* DFS */
+	rs->rs_scan_start = ic->ic_scan_start;
+	ic->ic_scan_start = r21au_scan_start;
+	rs->rs_scan_end = ic->ic_scan_end;
+	ic->ic_scan_end = r21au_scan_end;
+}
+
+static void
+r21au_vap_preattach(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct rtwn_vap *rvp = RTWN_VAP(vap);
+	struct r12a_softc *rs = sc->sc_priv;
+
+	r12a_vap_preattach(sc, vap);
+
+	/* Install DFS newstate handler (non-monitor vaps only). */
+	if (rvp->id != RTWN_VAP_ID_INVALID) {
+		KASSERT(rvp->id >= 0 && rvp->id <= nitems(rs->rs_newstate),
+		    ("%s: wrong vap id %d\n", __func__, rvp->id));
+
+		rs->rs_newstate[rvp->id] = vap->iv_newstate;
+		vap->iv_newstate = r21au_newstate;
+	}
+}
+
+static void
+r21a_attach_private(struct rtwn_softc *sc)
+{
+	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+	struct r12a_softc *rs;
+
+	rs = malloc(sizeof(struct r12a_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO);
+
+	rs->rs_flags			= R12A_RXCKSUM_EN | R12A_RXCKSUM6_EN;
+
+	rs->rs_radar = 0;
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "radar_detection", CTLFLAG_RDTUN, &rs->rs_radar,
+	    rs->rs_radar, "Enable radar detection (untested)");
+
+	rs->rs_fix_spur			= rtwn_nop_softc_chan;
+	rs->rs_set_band_2ghz		= r21a_set_band_2ghz;
+	rs->rs_set_band_5ghz		= r21a_set_band_5ghz;
+	rs->rs_init_burstlen		= r21au_init_burstlen;
+	rs->rs_init_ampdu_fwhw		= r21a_init_ampdu_fwhw;
+	rs->rs_crystalcap_write		= r21a_crystalcap_write;
+#ifndef RTWN_WITHOUT_UCODE
+	rs->rs_iq_calib_fw_supported	= r21a_iq_calib_fw_supported;
+#endif
+	rs->rs_iq_calib_sw		= r21a_iq_calib_sw;
+
+	rs->ampdu_max_time		= 0x5e;
+
+	rs->ac_usb_dma_size		= 0x01;
+	rs->ac_usb_dma_time		= 0x10;
+
+	sc->sc_priv			= rs;
+}
+
+static void
+r21au_adj_devcaps(struct rtwn_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct r12a_softc *rs = sc->sc_priv;
+
+	if (rs->rs_radar != 0)
+		ic->ic_caps |= IEEE80211_C_DFS;
+
+	/* TODO: LDPC etc */
+}
+
+void
+r21au_attach(struct rtwn_usb_softc *uc)
+{
+	struct rtwn_softc *sc		= &uc->uc_sc;
+
+	/* USB part. */
+	uc->uc_align_rx			= r12au_align_rx;
+	uc->tx_agg_desc_num		= 6;
+
+	/* Common part. */
+	sc->sc_flags			= RTWN_FLAG_EXT_HDR;
+
+	sc->sc_set_chan			= r12a_set_chan;
+	sc->sc_fill_tx_desc		= r12a_fill_tx_desc;
+	sc->sc_fill_tx_desc_raw		= r12a_fill_tx_desc_raw;
+	sc->sc_fill_tx_desc_null	= r12a_fill_tx_desc_null;
+	sc->sc_dump_tx_desc		= r12au_dump_tx_desc;
+	sc->sc_tx_radiotap_flags	= r12a_tx_radiotap_flags;
+	sc->sc_rx_radiotap_flags	= r12a_rx_radiotap_flags;
+	sc->sc_get_rssi_cck		= r21a_get_rssi_cck;
+	sc->sc_get_rssi_ofdm		= r88e_get_rssi_ofdm;
+	sc->sc_classify_intr		= r12au_classify_intr;
+	sc->sc_handle_tx_report		= r12a_ratectl_tx_complete;
+	sc->sc_handle_c2h_report	= r12a_handle_c2h_report;
+	sc->sc_check_frame		= r12a_check_frame_checksum;
+	sc->sc_rf_read			= r12a_c_cut_rf_read;
+	sc->sc_rf_write			= r12a_rf_write;
+	sc->sc_check_condition		= r21a_check_condition;
+	sc->sc_efuse_postread		= rtwn_nop_softc;
+	sc->sc_parse_rom		= r21a_parse_rom;
+	sc->sc_power_on			= r21a_power_on;
+	sc->sc_power_off		= r21a_power_off;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_fw_reset			= r21a_fw_reset;
+	sc->sc_fw_download_enable	= r12a_fw_download_enable;
+#endif
+	sc->sc_set_page_size 		= rtwn_nop_int_softc;
+	sc->sc_lc_calib			= rtwn_nop_softc;	/* XXX not used */
+	sc->sc_iq_calib			= r12a_iq_calib;
+	sc->sc_read_chipid_vendor	= rtwn_nop_softc_uint32;
+	sc->sc_adj_devcaps		= r21au_adj_devcaps;
+	sc->sc_vap_preattach		= r21au_vap_preattach;
+	sc->sc_postattach		= r21a_postattach;
+	sc->sc_detach_private		= r12a_detach_private;
+#ifndef RTWN_WITHOUT_UCODE
+	sc->sc_set_media_status		= r12a_set_media_status;
+	sc->sc_set_rsvd_page		= r88e_set_rsvd_page;
+	sc->sc_set_pwrmode		= r12a_set_pwrmode;
+	sc->sc_set_rssi			= rtwn_nop_softc;	/* XXX TODO */
+#else
+	sc->sc_set_media_status		= rtwn_nop_softc_int;
+#endif
+	sc->sc_beacon_init		= r21a_beacon_init;
+	sc->sc_beacon_enable		= r92c_beacon_enable;
+	sc->sc_beacon_set_rate		= r12a_beacon_set_rate;
+	sc->sc_beacon_select		= r21a_beacon_select;
+	sc->sc_temp_measure		= r88e_temp_measure;
+	sc->sc_temp_read		= r88e_temp_read;
+	sc->sc_init_tx_agg		= r21au_init_tx_agg;
+	sc->sc_init_rx_agg 		= r12au_init_rx_agg;
+	sc->sc_init_ampdu		= r12au_init_ampdu;
+	sc->sc_init_intr		= r12a_init_intr;
+	sc->sc_init_edca		= r12a_init_edca;
+	sc->sc_init_bb			= r12a_init_bb;
+	sc->sc_init_rf			= r12a_init_rf;
+	sc->sc_init_antsel		= r12a_init_antsel;
+	sc->sc_post_init		= r12au_post_init;
+	sc->sc_init_bcnq1_boundary	= r21a_init_bcnq1_boundary;
+
+	sc->chan_list_5ghz[0]		= r12a_chan_5ghz_0;
+	sc->chan_list_5ghz[1]		= r12a_chan_5ghz_1;
+	sc->chan_list_5ghz[2]		= r12a_chan_5ghz_2;
+	sc->chan_num_5ghz[0]		= nitems(r12a_chan_5ghz_0);
+	sc->chan_num_5ghz[1]		= nitems(r12a_chan_5ghz_1);
+	sc->chan_num_5ghz[2]		= nitems(r12a_chan_5ghz_2);
+
+	sc->mac_prog			= &rtl8821au_mac[0];
+	sc->mac_size			= nitems(rtl8821au_mac);
+	sc->bb_prog			= &rtl8821au_bb[0];
+	sc->bb_size			= nitems(rtl8821au_bb);
+	sc->agc_prog			= &rtl8821au_agc[0];
+	sc->agc_size			= nitems(rtl8821au_agc);
+	sc->rf_prog			= &rtl8821au_rf[0];
+
+	sc->name			= "RTL8821AU";
+	sc->fwname			= "rtwn-rtl8821aufw";
+	sc->fwsig			= 0x210;
+
+	sc->page_count			= R21A_TX_PAGE_COUNT;
+	sc->pktbuf_count		= R12A_TXPKTBUF_COUNT;
+
+	sc->ackto			= 0x80;
+	sc->npubqpages			= R12A_PUBQ_NPAGES;
+	sc->page_size			= R21A_TX_PAGE_SIZE;
+
+	sc->txdesc_len			= sizeof(struct r12au_tx_desc);
+	sc->efuse_maxlen		= R12A_EFUSE_MAX_LEN;
+	sc->efuse_maplen		= R12A_EFUSE_MAP_LEN;
+	sc->rx_dma_size			= R12A_RX_DMA_BUFFER_SIZE;
+
+	sc->macid_limit			= R12A_MACID_MAX + 1;
+	sc->cam_entry_limit		= R12A_CAM_ENTRY_COUNT;
+	sc->fwsize_limit		= R12A_MAX_FW_SIZE;
+	sc->temp_delta			= R88E_CALIB_THRESHOLD;
+
+	sc->bcn_status_reg[0]		= R92C_TDECTRL;
+	sc->bcn_status_reg[1]		= R21A_DWBCN1_CTRL;
+	sc->rcr				= R12A_RCR_DIS_CHK_14 |
+					  R12A_RCR_VHT_ACK |
+					  R12A_RCR_TCP_OFFLD_EN;
+
+	sc->ntxchains			= 1;
+	sc->nrxchains			= 1;
+
+	r21a_attach_private(sc);
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,282 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/rtl8812a/r12a_var.h>
+
+#include <dev/rtwn/rtl8821a/usb/r21au.h>
+#include <dev/rtwn/rtl8821a/usb/r21au_reg.h>
+
+
+#define R21AU_RADAR_CHECK_PERIOD	(2 * hz)
+
+static void
+r21au_dfs_radar_disable(struct rtwn_softc *sc)
+{
+	rtwn_bb_setbits(sc, 0x924, 0x00008000, 0);
+}
+
+static int
+r21au_dfs_radar_is_enabled(struct rtwn_softc *sc)
+{
+	return !!(rtwn_bb_read(sc, 0x924) & 0x00008000);
+}
+
+static int
+r21au_dfs_radar_reset(struct rtwn_softc *sc)
+{
+	int error;
+
+	error = rtwn_bb_setbits(sc, 0x924, 0x00008000, 0);
+	if (error != 0)
+		return (error);
+
+	return (rtwn_bb_setbits(sc, 0x924, 0, 0x00008000));
+}
+
+static int
+r21au_dfs_radar_enable(struct rtwn_softc *sc)
+{
+#define RTWN_CHK(res) do {	\
+	if (res != 0)		\
+		return (EIO);	\
+} while(0)
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	RTWN_CHK(rtwn_bb_setbits(sc, 0x814, 0x3fffffff, 0x04cc4d10));
+	RTWN_CHK(rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0xff, 0x06));
+	RTWN_CHK(rtwn_bb_write(sc, 0x918, 0x1c16ecdf));
+	RTWN_CHK(rtwn_bb_write(sc, 0x924, 0x0152a400));
+	RTWN_CHK(rtwn_bb_write(sc, 0x91c, 0x0fa21a20));
+	RTWN_CHK(rtwn_bb_write(sc, 0x920, 0xe0f57204));
+
+	return (r21au_dfs_radar_reset(sc));
+
+#undef RTWN_CHK
+}
+
+static int
+r21au_dfs_radar_is_detected(struct rtwn_softc *sc)
+{
+	return !!(rtwn_bb_read(sc, 0xf98) & 0x00020000);
+}
+
+void
+r21au_chan_check(void *arg, int npending __unused)
+{
+	struct rtwn_softc *sc = arg;
+	struct r12a_softc *rs = sc->sc_priv;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	RTWN_LOCK(sc);
+#ifdef DIAGNOSTIC
+	RTWN_DPRINTF(sc, RTWN_DEBUG_STATE,
+	    "%s: periodical radar detection task\n", __func__);
+#endif
+
+	if (!r21au_dfs_radar_is_enabled(sc)) {
+		if (rs->rs_flags & R12A_RADAR_ENABLED) {
+			/* should not happen */
+			device_printf(sc->sc_dev,
+			    "%s: radar detection was turned off "
+			    "unexpectedly, resetting...\n", __func__);
+
+			/* XXX something more appropriate? */
+			ieee80211_restart_all(ic);
+		}
+		RTWN_UNLOCK(sc);
+		return;
+	}
+
+	if (r21au_dfs_radar_is_detected(sc)) {
+		r21au_dfs_radar_reset(sc);
+
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR, "%s: got radar event\n",
+		    __func__);
+
+		RTWN_UNLOCK(sc);
+		IEEE80211_LOCK(ic);
+
+		ieee80211_dfs_notify_radar(ic, ic->ic_curchan);
+
+		IEEE80211_UNLOCK(ic);
+		RTWN_LOCK(sc);
+	}
+
+	if (rs->rs_flags & R12A_RADAR_ENABLED) {
+		taskqueue_enqueue_timeout(taskqueue_thread,
+		    &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD);
+	}
+	RTWN_UNLOCK(sc);
+}
+
+int
+r21au_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+	struct ieee80211com *ic = vap->iv_ic;
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct rtwn_vap *rvp = RTWN_VAP(vap);
+	struct r12a_softc *rs = sc->sc_priv;
+	int error;
+
+	KASSERT(rvp->id == 0 || rvp->id == 1,
+	    ("%s: unexpected vap id %d\n", __func__, rvp->id));
+
+	IEEE80211_UNLOCK(ic);
+	RTWN_LOCK(sc);
+
+	error = 0;
+	if (nstate == IEEE80211_S_CAC &&
+	    !(rs->rs_flags & R12A_RADAR_ENABLED)) {
+		error = r21au_dfs_radar_enable(sc);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "%s: cannot enable radar detection\n", __func__);
+			goto fail;
+		}
+		rs->rs_flags |= R12A_RADAR_ENABLED;
+
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR,
+		    "%s: radar detection was enabled\n", __func__);
+
+		taskqueue_enqueue_timeout(taskqueue_thread,
+		    &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD);
+	}
+
+	if ((nstate < IEEE80211_S_CAC || nstate == IEEE80211_S_CSA) &&
+	    (rs->rs_flags & R12A_RADAR_ENABLED) &&
+	    (sc->vaps[!rvp->id] == NULL ||
+	    sc->vaps[!rvp->id]->vap.iv_state < IEEE80211_S_CAC ||
+	    sc->vaps[!rvp->id]->vap.iv_state == IEEE80211_S_CSA)) {
+		taskqueue_cancel_timeout(taskqueue_thread, &rs->rs_chan_check,
+		    NULL);
+
+		rs->rs_flags &= ~R12A_RADAR_ENABLED;
+		r21au_dfs_radar_disable(sc);
+
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR,
+		    "%s: radar detection was disabled\n", __func__);
+	}
+
+fail:
+	RTWN_UNLOCK(sc);
+	IEEE80211_LOCK(ic);
+
+	if (error != 0)
+		return (error);
+
+	return (rs->rs_newstate[rvp->id](vap, nstate, arg));
+}
+
+void
+r21au_scan_start(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct r12a_softc *rs = sc->sc_priv;
+
+	RTWN_LOCK(sc);
+	if (rs->rs_flags & R12A_RADAR_ENABLED) {
+		RTWN_UNLOCK(sc);
+		while (taskqueue_cancel_timeout(taskqueue_thread,
+		    &rs->rs_chan_check, NULL) != 0) {
+			taskqueue_drain_timeout(taskqueue_thread,
+			    &rs->rs_chan_check);
+		}
+		RTWN_LOCK(sc);
+
+		r21au_dfs_radar_disable(sc);
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR,
+		    "%s: radar detection was (temporarily) disabled\n",
+		    __func__);
+	}
+	RTWN_UNLOCK(sc);
+
+	rs->rs_scan_start(ic);
+}
+
+void
+r21au_scan_end(struct ieee80211com *ic)
+{
+	struct rtwn_softc *sc = ic->ic_softc;
+	struct r12a_softc *rs = sc->sc_priv;
+	int error;
+
+	RTWN_LOCK(sc);
+	if (rs->rs_flags & R12A_RADAR_ENABLED) {
+		error = r21au_dfs_radar_enable(sc);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "%s: cannot re-enable radar detection\n",
+			    __func__);
+
+			/* XXX */
+			ieee80211_restart_all(ic);
+			RTWN_UNLOCK(sc);
+			return;
+		}
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR,
+		    "%s: radar detection was re-enabled\n", __func__);
+
+		taskqueue_enqueue_timeout(taskqueue_thread,
+		    &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD);
+	}
+	RTWN_UNLOCK(sc);
+
+	rs->rs_scan_end(ic);
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,85 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu.h>
+
+#include <dev/rtwn/rtl8821a/usb/r21au.h>
+#include <dev/rtwn/rtl8821a/usb/r21au_reg.h>
+
+
+void
+r21au_init_tx_agg(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+
+	r92cu_init_tx_agg(sc);
+
+	rtwn_write_1(sc, R21A_DWBCN1_CTRL, uc->tx_agg_desc_num << 1);
+}
+
+void
+r21au_init_burstlen(struct rtwn_softc *sc)
+{
+	if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) {
+		/* Set burst packet length to 512 B. */
+		rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x20, 0x1e);
+	} else {
+		/* Set burst packet length to 64 B. */
+		rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x10, 0x2e);
+	}
+}
Index: freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef R21AU_REG_H
+#define R21AU_REG_H
+
+#include <dev/rtwn/rtl8812a/usb/r12au_reg.h>
+#include <dev/rtwn/rtl8821a/r21a_reg.h>
+
+#endif	/* R21AU_REG_H */
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,444 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/sysctl.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/linker.h>
+#include <sys/kdb.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <rtems/bsd/local/usbdevs.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_nop.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/usb/rtwn_usb_attach.h>
+#include <dev/rtwn/usb/rtwn_usb_ep.h>
+#include <dev/rtwn/usb/rtwn_usb_reg.h>
+#include <dev/rtwn/usb/rtwn_usb_tx.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>
+
+static device_probe_t	rtwn_usb_match;
+static device_attach_t	rtwn_usb_attach;
+static device_detach_t	rtwn_usb_detach;
+static device_suspend_t	rtwn_usb_suspend;
+static device_resume_t	rtwn_usb_resume;
+
+static int	rtwn_usb_alloc_list(struct rtwn_softc *,
+		    struct rtwn_data[], int, int);
+static int	rtwn_usb_alloc_rx_list(struct rtwn_softc *);
+static int	rtwn_usb_alloc_tx_list(struct rtwn_softc *);
+static void	rtwn_usb_free_list(struct rtwn_softc *,
+		    struct rtwn_data data[], int);
+static void	rtwn_usb_free_rx_list(struct rtwn_softc *);
+static void	rtwn_usb_free_tx_list(struct rtwn_softc *);
+static void	rtwn_usb_reset_lists(struct rtwn_softc *,
+		    struct ieee80211vap *);
+static void	rtwn_usb_reset_tx_list(struct rtwn_usb_softc *,
+		    rtwn_datahead *, struct ieee80211vap *);
+static void	rtwn_usb_start_xfers(struct rtwn_softc *);
+static void	rtwn_usb_abort_xfers(struct rtwn_softc *);
+static int	rtwn_usb_fw_write_block(struct rtwn_softc *,
+		    const uint8_t *, uint16_t, int);
+static void	rtwn_usb_drop_incorrect_tx(struct rtwn_softc *);
+static void	rtwn_usb_attach_methods(struct rtwn_softc *);
+
+#define RTWN_CONFIG_INDEX	0
+
+
+static int
+rtwn_usb_match(device_t self)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(self);
+
+	if (uaa->usb_mode != USB_MODE_HOST)
+		return (ENXIO);
+	if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX)
+		return (ENXIO);
+	if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX)
+		return (ENXIO);
+
+	return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa));
+}
+
+static int
+rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[],
+    int ndata, int maxsz)
+{
+	int i, error;
+
+	for (i = 0; i < ndata; i++) {
+		struct rtwn_data *dp = &data[i];
+		dp->m = NULL;
+		dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT);
+		if (dp->buf == NULL) {
+			device_printf(sc->sc_dev,
+			    "could not allocate buffer\n");
+			error = ENOMEM;
+			goto fail;
+		}
+		dp->ni = NULL;
+	}
+
+	return (0);
+fail:
+	rtwn_usb_free_list(sc, data, ndata);
+	return (error);
+}
+
+static int
+rtwn_usb_alloc_rx_list(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+	int error, i;
+
+	/* XXX recheck */
+	error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT,
+	    sc->rx_dma_size + 1024);
+	if (error != 0)
+		return (error);
+
+	STAILQ_INIT(&uc->uc_rx_active);
+	STAILQ_INIT(&uc->uc_rx_inactive);
+
+	for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++)
+		STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next);
+
+	return (0);
+}
+
+static int
+rtwn_usb_alloc_tx_list(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+	int error, i;
+
+	error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT,
+	    RTWN_TXBUFSZ);
+	if (error != 0)
+		return (error);
+
+	STAILQ_INIT(&uc->uc_tx_active);
+	STAILQ_INIT(&uc->uc_tx_inactive);
+	STAILQ_INIT(&uc->uc_tx_pending);
+
+	for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++)
+		STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next);
+
+	return (0);
+}
+
+static void
+rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata)
+{
+	int i;
+
+	for (i = 0; i < ndata; i++) {
+		struct rtwn_data *dp = &data[i];
+
+		if (dp->buf != NULL) {
+			free(dp->buf, M_USBDEV);
+			dp->buf = NULL;
+		}
+		if (dp->ni != NULL) {
+			ieee80211_free_node(dp->ni);
+			dp->ni = NULL;
+		}
+		if (dp->m != NULL) {
+			m_freem(dp->m);
+			dp->m = NULL;
+		}
+	}
+}
+
+static void
+rtwn_usb_free_rx_list(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+
+	rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT);
+
+	STAILQ_INIT(&uc->uc_rx_active);
+	STAILQ_INIT(&uc->uc_rx_inactive);
+}
+
+static void
+rtwn_usb_free_tx_list(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+
+	rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT);
+
+	STAILQ_INIT(&uc->uc_tx_active);
+	STAILQ_INIT(&uc->uc_tx_inactive);
+	STAILQ_INIT(&uc->uc_tx_pending);
+}
+
+static void
+rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap);
+	rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap);
+	if (vap == NULL)
+		sc->qfullmsk = 0;
+}
+
+static void
+rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc,
+    rtwn_datahead *head, struct ieee80211vap *vap)
+{
+	struct rtwn_vap *uvp = RTWN_VAP(vap);
+	struct rtwn_data *dp, *tmp;
+	int id;
+
+	id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID);
+
+	STAILQ_FOREACH_SAFE(dp, head, next, tmp) {
+		if (vap == NULL || (dp->ni == NULL &&
+		    (dp->id == id || id == RTWN_VAP_ID_INVALID)) ||
+		    (dp->ni != NULL && dp->ni->ni_vap == vap)) {
+			if (dp->ni != NULL) {
+				ieee80211_free_node(dp->ni);
+				dp->ni = NULL;
+			}
+
+			if (dp->m != NULL) {
+				m_freem(dp->m);
+				dp->m = NULL;
+			}
+
+			STAILQ_REMOVE(head, dp, rtwn_data, next);
+			STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next);
+		}
+	}
+}
+
+static void
+rtwn_usb_start_xfers(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+
+	usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]);
+}
+
+static void
+rtwn_usb_abort_xfers(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+	int i;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	/* abort any pending transfers */
+	RTWN_UNLOCK(sc);
+	for (i = 0; i < RTWN_N_TRANSFER; i++)
+		usbd_transfer_drain(uc->uc_xfer[i]);
+	RTWN_LOCK(sc);
+}
+
+static int
+rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf,
+    uint16_t reg, int mlen)
+{
+	int error;
+
+	/* XXX fix this deconst */
+	error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf),
+	    mlen);
+
+	return (error);
+}
+
+static void
+rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc)
+{
+
+	rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0,
+	    R92C_TXDMA_OFFSET_DROP_DATA_EN, 1);
+}
+
+static void
+rtwn_usb_attach_methods(struct rtwn_softc *sc)
+{
+	sc->sc_write_1		= rtwn_usb_write_1;
+	sc->sc_write_2		= rtwn_usb_write_2;
+	sc->sc_write_4		= rtwn_usb_write_4;
+	sc->sc_read_1		= rtwn_usb_read_1;
+	sc->sc_read_2		= rtwn_usb_read_2;
+	sc->sc_read_4		= rtwn_usb_read_4;
+	sc->sc_delay		= rtwn_usb_delay;
+	sc->sc_tx_start		= rtwn_usb_tx_start;
+	sc->sc_start_xfers	= rtwn_usb_start_xfers;
+	sc->sc_reset_lists	= rtwn_usb_reset_lists;
+	sc->sc_abort_xfers	= rtwn_usb_abort_xfers;
+	sc->sc_fw_write_block	= rtwn_usb_fw_write_block;
+	sc->sc_get_qmap		= rtwn_usb_get_qmap;
+	sc->sc_set_desc_addr	= rtwn_nop_softc;
+	sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx;
+	sc->sc_beacon_update_begin = rtwn_nop_softc_vap;
+	sc->sc_beacon_update_end = rtwn_nop_softc_vap;
+	sc->sc_beacon_unload	= rtwn_nop_softc_int;
+
+	sc->bcn_check_interval	= 100;
+}
+
+static int
+rtwn_usb_attach(device_t self)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(self);
+	struct rtwn_usb_softc *uc = device_get_softc(self);
+	struct rtwn_softc *sc = &uc->uc_sc;
+	struct ieee80211com *ic = &sc->sc_ic;
+	int error;
+
+	device_set_usb_desc(self);
+	uc->uc_udev = uaa->device;
+	sc->sc_dev = self;
+	ic->ic_name = device_get_nameunit(self);
+
+	/* Need to be initialized early. */
+	rtwn_sysctlattach(sc);
+	mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF);
+
+	rtwn_usb_attach_methods(sc);
+	rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa));
+
+	error = rtwn_usb_setup_endpoints(uc);
+	if (error != 0)
+		goto detach;
+
+	/* Allocate Tx/Rx buffers. */
+	error = rtwn_usb_alloc_rx_list(sc);
+	if (error != 0)
+		goto detach;
+
+	error = rtwn_usb_alloc_tx_list(sc);
+	if (error != 0)
+		goto detach;
+
+	/* Generic attach. */
+	error = rtwn_attach(sc);
+	if (error != 0)
+		goto detach;
+
+	return (0);
+
+detach:
+	rtwn_usb_detach(self);		/* failure */
+	return (ENXIO);
+}
+
+static int
+rtwn_usb_detach(device_t self)
+{
+	struct rtwn_usb_softc *uc = device_get_softc(self);
+	struct rtwn_softc *sc = &uc->uc_sc;
+
+	/* Generic detach. */
+	rtwn_detach(sc);
+
+	/* Free Tx/Rx buffers. */
+	rtwn_usb_free_tx_list(sc);
+	rtwn_usb_free_rx_list(sc);
+
+	/* Detach all USB transfers. */
+	usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER);
+
+	rtwn_detach_private(sc);
+	mtx_destroy(&sc->sc_mtx);
+
+	return (0);
+}
+
+static int
+rtwn_usb_suspend(device_t self)
+{
+	struct rtwn_usb_softc *uc = device_get_softc(self);
+
+	rtwn_suspend(&uc->uc_sc);
+
+	return (0);
+}
+
+static int
+rtwn_usb_resume(device_t self)
+{
+	struct rtwn_usb_softc *uc = device_get_softc(self);
+
+	rtwn_resume(&uc->uc_sc);
+
+	return (0);
+}
+
+static device_method_t rtwn_usb_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		rtwn_usb_match),
+	DEVMETHOD(device_attach,	rtwn_usb_attach),
+	DEVMETHOD(device_detach,	rtwn_usb_detach),
+	DEVMETHOD(device_suspend,	rtwn_usb_suspend),
+	DEVMETHOD(device_resume,	rtwn_usb_resume),
+
+	DEVMETHOD_END
+};
+
+static driver_t rtwn_usb_driver = {
+	"rtwn",
+	rtwn_usb_methods,
+	sizeof(struct rtwn_usb_softc)
+};
+
+static devclass_t rtwn_usb_devclass;
+
+DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, rtwn_usb_devclass, NULL, NULL);
+MODULE_VERSION(rtwn_usb, 1);
+MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1);
+MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1);
+MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2);
+USB_PNP_HOST_INFO(rtwn_devs);
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,160 @@
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+void	r92cu_attach(struct rtwn_usb_softc *);
+void	r88eu_attach(struct rtwn_usb_softc *);
+void	r12au_attach(struct rtwn_usb_softc *);
+void	r21au_attach(struct rtwn_usb_softc *);
+
+enum {
+	RTWN_CHIP_RTL8192CU,
+	RTWN_CHIP_RTL8188EU,
+	RTWN_CHIP_RTL8812AU,
+	RTWN_CHIP_RTL8821AU,
+	RTWN_CHIP_MAX_USB
+};
+
+/* various supported device vendors/products */
+static const STRUCT_USB_HOST_ID rtwn_devs[] = {
+	/* RTL8188CE-VAU/RTL8188CUS/RTL8188RU/RTL8192CU */
+#define RTWN_RTL8192CU_DEV(v,p) \
+	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8192CU) }
+	RTWN_RTL8192CU_DEV(ABOCOM,		RTL8188CU_1),
+	RTWN_RTL8192CU_DEV(ABOCOM,		RTL8188CU_2),
+	RTWN_RTL8192CU_DEV(ABOCOM,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(ASUS,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(ASUS,		USBN10NANO),
+	RTWN_RTL8192CU_DEV(AZUREWAVE,		RTL8188CE_1),
+	RTWN_RTL8192CU_DEV(AZUREWAVE,		RTL8188CE_2),
+	RTWN_RTL8192CU_DEV(AZUREWAVE,		RTL8188CU),
+	RTWN_RTL8192CU_DEV(BELKIN,		F7D2102),
+	RTWN_RTL8192CU_DEV(BELKIN,		RTL8188CU),
+	RTWN_RTL8192CU_DEV(BELKIN,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(CHICONY,		RTL8188CUS_1),
+	RTWN_RTL8192CU_DEV(CHICONY,		RTL8188CUS_2),
+	RTWN_RTL8192CU_DEV(CHICONY,		RTL8188CUS_3),
+	RTWN_RTL8192CU_DEV(CHICONY,		RTL8188CUS_4),
+	RTWN_RTL8192CU_DEV(CHICONY,		RTL8188CUS_5),
+	RTWN_RTL8192CU_DEV(COREGA,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(DLINK,		RTL8188CU),
+	RTWN_RTL8192CU_DEV(DLINK,		RTL8192CU_1),
+	RTWN_RTL8192CU_DEV(DLINK,		RTL8192CU_2),
+	RTWN_RTL8192CU_DEV(DLINK,		RTL8192CU_3),
+	RTWN_RTL8192CU_DEV(DLINK,		DWA131B),
+	RTWN_RTL8192CU_DEV(EDIMAX,		EW7811UN),
+	RTWN_RTL8192CU_DEV(EDIMAX,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(FEIXUN,		RTL8188CU),
+	RTWN_RTL8192CU_DEV(FEIXUN,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(GUILLEMOT,		HWNUP150),
+	RTWN_RTL8192CU_DEV(HAWKING,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(HP3,			RTL8188CU),
+	RTWN_RTL8192CU_DEV(NETGEAR,		WNA1000M),
+	RTWN_RTL8192CU_DEV(NETGEAR,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(NETGEAR4,		RTL8188CU),
+	RTWN_RTL8192CU_DEV(NOVATECH,		RTL8188CU),
+	RTWN_RTL8192CU_DEV(PLANEX2,		RTL8188CU_1),
+	RTWN_RTL8192CU_DEV(PLANEX2,		RTL8188CU_2),
+	RTWN_RTL8192CU_DEV(PLANEX2,		RTL8188CU_3),
+	RTWN_RTL8192CU_DEV(PLANEX2,		RTL8188CU_4),
+	RTWN_RTL8192CU_DEV(PLANEX2,		RTL8188CUS),
+	RTWN_RTL8192CU_DEV(PLANEX2,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CE_0),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CE_1),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CTV),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CU_0),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CU_1),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CU_2),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CU_3),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CU_COMBO),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188CUS),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188RU_1),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188RU_2),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8188RU_3),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8191CU),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8192CE),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(REALTEK,		RTL8192CU_1),
+	RTWN_RTL8192CU_DEV(SITECOMEU,		RTL8188CU_1),
+	RTWN_RTL8192CU_DEV(SITECOMEU,		RTL8188CU_2),
+	RTWN_RTL8192CU_DEV(SITECOMEU,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(TRENDNET,		RTL8188CU),
+	RTWN_RTL8192CU_DEV(TRENDNET,		RTL8192CU),
+	RTWN_RTL8192CU_DEV(ZYXEL,		RTL8192CU),
+#undef RTWN_RTL8192CU_DEV
+
+	/* RTL8188EU */
+#define RTWN_RTL8188EU_DEV(v,p) \
+	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8188EU) }
+	RTWN_RTL8188EU_DEV(ABOCOM,		RTL8188EU),
+	RTWN_RTL8188EU_DEV(DLINK,		DWA123D1),
+	RTWN_RTL8188EU_DEV(DLINK,		DWA125D1),
+	RTWN_RTL8188EU_DEV(ELECOM,		WDC150SU2M),
+	RTWN_RTL8188EU_DEV(REALTEK,		RTL8188ETV),
+	RTWN_RTL8188EU_DEV(REALTEK,		RTL8188EU),
+#undef RTWN_RTL8188EU_DEV
+
+	/* RTL8812AU */
+#define RTWN_RTL8812AU_DEV(v,p) \
+	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8812AU) }
+	RTWN_RTL8812AU_DEV(ASUS,		USBAC56),
+	RTWN_RTL8812AU_DEV(CISCOLINKSYS,	WUSB6300),
+	RTWN_RTL8812AU_DEV(DLINK,		DWA182C1),
+	RTWN_RTL8812AU_DEV(DLINK,		DWA180A1),
+	RTWN_RTL8812AU_DEV(EDIMAX,		EW7822UAC),
+	RTWN_RTL8812AU_DEV(IODATA,		WNAC867U),
+	RTWN_RTL8812AU_DEV(MELCO,		WIU3866D),
+	RTWN_RTL8812AU_DEV(NEC,			WL900U),
+	RTWN_RTL8812AU_DEV(PLANEX2,		GW900D),
+	RTWN_RTL8812AU_DEV(SENAO,		EUB1200AC),
+	RTWN_RTL8812AU_DEV(SITECOMEU,		WLA7100),
+	RTWN_RTL8812AU_DEV(TPLINK,		T4U),
+	RTWN_RTL8812AU_DEV(TRENDNET,		TEW805UB),
+	RTWN_RTL8812AU_DEV(ZYXEL,		NWD6605),
+#undef RTWN_RTL8812AU_DEV
+
+	/* RTL8821AU */
+#define RTWN_RTL8821AU_DEV(v,p) \
+	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8821AU) }
+	RTWN_RTL8821AU_DEV(DLINK,		DWA171A1),
+	RTWN_RTL8821AU_DEV(DLINK,		DWA172A1),
+	RTWN_RTL8821AU_DEV(EDIMAX,		EW7811UTC_1),
+	RTWN_RTL8821AU_DEV(EDIMAX,		EW7811UTC_2),
+	RTWN_RTL8821AU_DEV(HAWKING,		HD65U),
+	RTWN_RTL8821AU_DEV(MELCO,		WIU2433DM),
+	RTWN_RTL8821AU_DEV(NETGEAR,		A6100)
+#undef RTWN_RTL8821AU_DEV
+};
+
+typedef void	(*chip_usb_attach)(struct rtwn_usb_softc *);
+
+static const chip_usb_attach rtwn_chip_usb_attach[RTWN_CHIP_MAX_USB] = {
+	[RTWN_CHIP_RTL8192CU] = r92cu_attach,
+	[RTWN_CHIP_RTL8188EU] = r88eu_attach,
+	[RTWN_CHIP_RTL8812AU] = r12au_attach,
+	[RTWN_CHIP_RTL8821AU] = r21au_attach
+};
+
+static __inline void
+rtwn_usb_attach_private(struct rtwn_usb_softc *uc, int chip)
+{
+	rtwn_chip_usb_attach[chip](uc);
+}
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,255 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_device.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+#include <dev/rtwn/usb/rtwn_usb_ep.h>
+#include <dev/rtwn/usb/rtwn_usb_rx.h>
+#include <dev/rtwn/usb/rtwn_usb_tx.h>
+
+#include <dev/rtwn/rtl8192c/usb/r92cu_reg.h>
+
+
+static struct usb_config rtwn_config[RTWN_N_TRANSFER] = {
+	[RTWN_BULK_RX] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = {
+			.pipe_bof = 1,
+			.short_xfer_ok = 1
+		},
+		.callback = rtwn_bulk_rx_callback,
+	},
+	[RTWN_BULK_TX_BE] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.bufsize = RTWN_TXBUFSZ,
+		.flags = {
+			.ext_buffer = 1,
+			.pipe_bof = 1,
+			.force_short_xfer = 1,
+		},
+		.callback = rtwn_bulk_tx_callback,
+		.timeout = RTWN_TX_TIMEOUT,	/* ms */
+	},
+	[RTWN_BULK_TX_BK] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.bufsize = RTWN_TXBUFSZ,
+		.flags = {
+			.ext_buffer = 1,
+			.pipe_bof = 1,
+			.force_short_xfer = 1,
+		},
+		.callback = rtwn_bulk_tx_callback,
+		.timeout = RTWN_TX_TIMEOUT,	/* ms */
+	},
+	[RTWN_BULK_TX_VI] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.bufsize = RTWN_TXBUFSZ,
+		.flags = {
+			.ext_buffer = 1,
+			.pipe_bof = 1,
+			.force_short_xfer = 1
+		},
+		.callback = rtwn_bulk_tx_callback,
+		.timeout = RTWN_TX_TIMEOUT,	/* ms */
+	},
+	[RTWN_BULK_TX_VO] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.bufsize = RTWN_TXBUFSZ,
+		.flags = {
+			.ext_buffer = 1,
+			.pipe_bof = 1,
+			.force_short_xfer = 1
+		},
+		.callback = rtwn_bulk_tx_callback,
+		.timeout = RTWN_TX_TIMEOUT,	/* ms */
+	},
+};
+
+static void
+rtwn_usb_setup_queues(struct rtwn_usb_softc *uc)
+{
+	struct rtwn_softc *sc = &uc->uc_sc;
+	int hasnq, haslq, nqueues, nqpages, nrempages;
+
+	/* Get Tx queues to USB endpoints mapping. */
+	hasnq = haslq = 0;
+	switch (uc->ntx) {
+	case 4:
+	case 3:
+		haslq = 1;
+		/* FALLTHROUGH */
+	case 2:
+		hasnq = 1;
+		/* FALLTHROUGH */
+	default:
+		break;
+	}
+	nqueues = 1 + hasnq + haslq;
+
+	/* Get the number of pages for each queue. */
+	nqpages = (sc->page_count - sc->npubqpages) / nqueues;
+
+	/*
+	 * The remaining pages are assigned to the high priority
+	 * queue.
+	 */
+	nrempages = (sc->page_count - sc->npubqpages) % nqueues;
+
+	sc->nhqpages = nqpages + nrempages;
+	sc->nnqpages = (hasnq ? nqpages : 0);
+	sc->nlqpages = (haslq ? nqpages : 0);
+}
+
+int
+rtwn_usb_setup_endpoints(struct rtwn_usb_softc *uc)
+{
+	struct rtwn_softc *sc = &uc->uc_sc;
+	const uint8_t iface_index = RTWN_IFACE_INDEX;
+	struct usb_endpoint *ep, *ep_end;
+	uint8_t addr[RTWN_MAX_EPOUT];
+	int error;
+
+	/* Determine the number of bulk-out pipes. */
+	uc->ntx = 0;
+	ep = uc->uc_udev->endpoints;
+	ep_end = uc->uc_udev->endpoints + uc->uc_udev->endpoints_max;
+	for (; ep != ep_end; ep++) {
+		uint8_t eaddr;
+
+		if ((ep->edesc == NULL) || (ep->iface_index != iface_index))
+			continue;
+
+		eaddr = ep->edesc->bEndpointAddress;
+		RTWN_DPRINTF(sc, RTWN_DEBUG_USB,
+		    "%s: endpoint: addr %u, direction %s\n", __func__,
+		    UE_GET_ADDR(eaddr), UE_GET_DIR(eaddr) == UE_DIR_OUT ?
+		    "output" : "input");
+
+		if (UE_GET_DIR(eaddr) == UE_DIR_OUT) {
+			if (uc->ntx == RTWN_MAX_EPOUT)
+				break;
+
+			addr[uc->ntx++] = UE_GET_ADDR(eaddr);
+		}
+	}
+	if (uc->ntx == 0 || uc->ntx > RTWN_MAX_EPOUT) {
+		device_printf(sc->sc_dev,
+		    "%s: invalid number of Tx bulk pipes (%d)\n", __func__,
+		    uc->ntx);
+		return (EINVAL);
+	}
+
+	/* NB: keep in sync with rtwn_dma_init(). */
+	rtwn_config[RTWN_BULK_TX_VO].endpoint = addr[0];
+	switch (uc->ntx) {
+	case 4:
+	case 3:
+		rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[2];
+		rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[2];
+		rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[1];
+		break;
+	case 2:
+		rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[1];
+		rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[1];
+		rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0];
+		break;
+	case 1:
+		rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[0];
+		rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[0];
+		rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0];
+		break;
+	default:
+		KASSERT(0, ("unhandled number of endpoints %d\n", uc->ntx));
+		break;
+	}
+
+	rtwn_config[RTWN_BULK_RX].bufsize = sc->rx_dma_size + 1024;
+	error = usbd_transfer_setup(uc->uc_udev, &iface_index,
+	    uc->uc_xfer, rtwn_config, RTWN_N_TRANSFER, uc, &sc->sc_mtx);
+	if (error) {
+		device_printf(sc->sc_dev, "could not allocate USB transfers, "
+		    "err=%s\n", usbd_errstr(error));
+		return (error);
+	}
+
+	/* Assign pages for each queue (if not done). */
+	if (sc->nhqpages == 0 && sc->nnqpages == 0 && sc->nlqpages == 0)
+		rtwn_usb_setup_queues(uc);
+
+	return (0);
+}
+
+uint16_t
+rtwn_usb_get_qmap(struct rtwn_softc *sc)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+
+	switch (uc->ntx) {
+	case 1:
+		return (R92C_TRXDMA_CTRL_QMAP_HQ);
+	case 2:
+		return (R92C_TRXDMA_CTRL_QMAP_HQ_NQ);
+	default:
+		return (R92C_TRXDMA_CTRL_QMAP_3EP);
+	}
+}
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,25 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_RTWN_EP_H
+#define IF_RTWN_EP_H
+
+int		rtwn_usb_setup_endpoints(struct rtwn_usb_softc *);
+uint16_t	rtwn_usb_get_qmap(struct rtwn_softc *);
+
+#endif	/* IF_RTWN_EP_H */
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,181 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/rtwn/if_rtwnvar.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+#include <dev/rtwn/usb/rtwn_usb_reg.h>
+
+static int	rtwn_do_request(struct rtwn_softc *,
+		    struct usb_device_request *, void *);
+static int	rtwn_usb_read_region_1(struct rtwn_softc *,
+		    uint16_t, uint8_t *, int);
+
+/* USB Requests. */
+#define R92C_REQ_REGS		0x05
+
+
+static int
+rtwn_do_request(struct rtwn_softc *sc, struct usb_device_request *req,
+    void *data)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+	usb_error_t err;
+	int ntries = 10;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	while (ntries--) {
+		err = usbd_do_request_flags(uc->uc_udev, &sc->sc_mtx,
+		    req, data, 0, NULL, 250 /* ms */);
+		if (err == USB_ERR_NORMAL_COMPLETION)
+			return (0);
+
+		RTWN_DPRINTF(sc, RTWN_DEBUG_USB,
+		    "%s: control request failed, %s (retries left: %d)\n",
+		    __func__, usbd_errstr(err), ntries);
+		if (err == USB_ERR_NOT_CONFIGURED)
+			return (ENXIO);
+
+		usb_pause_mtx(&sc->sc_mtx, hz / 100);
+	}
+	return (EIO);
+}
+
+/* export for rtwn_fw_write_block() */
+int
+rtwn_usb_write_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf,
+    int len)
+{
+	usb_device_request_t req;
+
+	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+	req.bRequest = R92C_REQ_REGS;
+	USETW(req.wValue, addr);
+	USETW(req.wIndex, 0);
+	USETW(req.wLength, len);
+	return (rtwn_do_request(sc, &req, buf));
+}
+
+int
+rtwn_usb_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val)
+{
+	return (rtwn_usb_write_region_1(sc, addr, &val, sizeof(val)));
+}
+
+int
+rtwn_usb_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val)
+{
+	val = htole16(val);
+	return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val)));
+}
+
+int
+rtwn_usb_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val)
+{
+	val = htole32(val);
+	return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val)));
+}
+
+static int
+rtwn_usb_read_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf,
+    int len)
+{
+	usb_device_request_t req;
+
+	req.bmRequestType = UT_READ_VENDOR_DEVICE;
+	req.bRequest = R92C_REQ_REGS;
+	USETW(req.wValue, addr);
+	USETW(req.wIndex, 0);
+	USETW(req.wLength, len);
+	return (rtwn_do_request(sc, &req, buf));
+}
+
+uint8_t
+rtwn_usb_read_1(struct rtwn_softc *sc, uint16_t addr)
+{
+	uint8_t val;
+
+	if (rtwn_usb_read_region_1(sc, addr, &val, 1) != 0)
+		return (0xff);
+	return (val);
+}
+
+uint16_t
+rtwn_usb_read_2(struct rtwn_softc *sc, uint16_t addr)
+{
+	uint16_t val;
+
+	if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0)
+		return (0xffff);
+	return (le16toh(val));
+}
+
+uint32_t
+rtwn_usb_read_4(struct rtwn_softc *sc, uint16_t addr)
+{
+	uint32_t val;
+
+	if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0)
+		return (0xffffffff);
+	return (le32toh(val));
+}
+
+void
+rtwn_usb_delay(struct rtwn_softc *sc, int usec)
+{
+
+	/* 1ms delay as default is too big. */
+	if (usec < 1000)
+		DELAY(usec);
+	else {
+		usb_pause_mtx(&sc->sc_mtx,
+		    MAX(msecs_to_ticks(usec / 1000), 1));
+	}
+}
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTWN_USB_REG_H
+#define RTWN_USB_REG_H
+
+static __inline uint16_t
+rtwn_usb_calc_tx_checksum(void *buf)
+{
+	uint16_t sum = 0;
+	int i;
+
+	/* NB: checksum calculation takes into account only first 32 bytes. */
+	for (i = 0; i < 32 / 2; i++)
+		sum ^= ((uint16_t *)buf)[i];
+
+	return (sum);		/* NB: already little endian. */
+}
+
+int		rtwn_usb_write_region_1(struct rtwn_softc *, uint16_t,
+		    uint8_t *, int);
+int		rtwn_usb_write_1(struct rtwn_softc *, uint16_t, uint8_t);
+int		rtwn_usb_write_2(struct rtwn_softc *, uint16_t, uint16_t);
+int		rtwn_usb_write_4(struct rtwn_softc *, uint16_t, uint32_t);
+uint8_t		rtwn_usb_read_1(struct rtwn_softc *, uint16_t);
+uint16_t	rtwn_usb_read_2(struct rtwn_softc *, uint16_t);
+uint32_t	rtwn_usb_read_4(struct rtwn_softc *, uint16_t);
+void		rtwn_usb_delay(struct rtwn_softc *, int);
+
+#endif	/* RTWN_USB_REG_H */
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,342 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#ifdef	IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_rx.h>
+#include <dev/rtwn/if_rtwn_task.h>
+#include <dev/rtwn/if_rtwn_tx.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+#include <dev/rtwn/usb/rtwn_usb_rx.h>
+
+#include <dev/rtwn/rtl8192c/r92c_reg.h>	/* for CAM_ALGO_NONE */
+#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
+
+
+static struct mbuf *
+rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct r92c_rx_stat *stat,
+    int totlen)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct mbuf *m;
+	uint32_t rxdw0;
+	int pktlen;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	/* Dump Rx descriptor. */
+	RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
+	    "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X\n",
+	    __func__, le32toh(stat->rxdw0), le32toh(stat->rxdw1),
+	    le32toh(stat->rxdw2), le32toh(stat->rxdw3), le32toh(stat->rxdw4),
+	    le32toh(stat->tsf_low));
+
+	/*
+	 * don't pass packets to the ieee80211 framework if the driver isn't
+	 * RUNNING.
+	 */
+	if (!(sc->sc_flags & RTWN_RUNNING))
+		return (NULL);
+
+	rxdw0 = le32toh(stat->rxdw0);
+	if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) {
+		/*
+		 * This should not happen since we setup our Rx filter
+		 * to not receive these frames.
+		 */
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
+		    "%s: RX flags error (%s)\n", __func__,
+		    rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV");
+		goto fail;
+	}
+
+	pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+	if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack))) {
+		/*
+		 * Should not happen (because of Rx filter setup).
+		 */
+		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
+		    "%s: frame is too short: %d\n", __func__, pktlen);
+		goto fail;
+	}
+
+	m = m_get2(totlen, M_NOWAIT, MT_DATA, M_PKTHDR);
+	if (__predict_false(m == NULL)) {
+		device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n",
+		    __func__);
+		goto fail;
+	}
+
+	/* Finalize mbuf. */
+	memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen);
+	m->m_pkthdr.len = m->m_len = totlen;
+
+	if (rtwn_check_frame(sc, m) != 0) {
+		m_freem(m);
+		goto fail;
+	}
+
+	return (m);
+fail:
+	counter_u64_add(ic->ic_ierrors, 1);
+	return (NULL);
+}
+
+static struct mbuf *
+rtwn_rxeof(struct rtwn_softc *sc, uint8_t *buf, int len)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+	struct r92c_rx_stat *stat;
+	struct mbuf *m, *m0 = NULL;
+	uint32_t rxdw0;
+	int totlen, pktlen, infosz;
+
+	/* Process packets. */
+	while (len >= sizeof(*stat)) {
+		stat = (struct r92c_rx_stat *)buf;
+		rxdw0 = le32toh(stat->rxdw0);
+
+		pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+		if (__predict_false(pktlen == 0))
+			break;
+
+		infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
+
+		/* Make sure everything fits in xfer. */
+		totlen = sizeof(*stat) + infosz + pktlen;
+		if (totlen > len) {
+			device_printf(sc->sc_dev,
+			    "%s: totlen (%d) > len (%d)!\n",
+			    __func__, totlen, len);
+			break;
+		}
+
+		if (m0 == NULL)
+			m0 = m = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
+		else {
+			m->m_next = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
+			if (m->m_next != NULL)
+				m = m->m_next;
+		}
+
+		/* Align next frame. */
+		totlen = rtwn_usb_align_rx(uc, totlen, len);
+		buf += totlen;
+		len -= totlen;
+	}
+
+	return (m0);
+}
+
+static struct mbuf *
+rtwn_report_intr(struct rtwn_usb_softc *uc, struct usb_xfer *xfer,
+    struct rtwn_data *data)
+{
+	struct rtwn_softc *sc = &uc->uc_sc;
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint8_t *buf;
+	int len;
+
+	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
+
+	if (__predict_false(len < sizeof(struct r92c_rx_stat))) {
+		counter_u64_add(ic->ic_ierrors, 1);
+		return (NULL);
+	}
+
+	buf = data->buf;
+	switch (rtwn_classify_intr(sc, buf, len)) {
+	case RTWN_RX_DATA:
+		return (rtwn_rxeof(sc, buf, len));
+	case RTWN_RX_TX_REPORT:
+		if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
+			/* shouldn't happen */
+			device_printf(sc->sc_dev,
+			    "%s called while ratectl = %d!\n",
+			    __func__, sc->sc_ratectl);
+			break;
+		}
+
+		RTWN_NT_LOCK(sc);
+		rtwn_handle_tx_report(sc, buf, len);
+		RTWN_NT_UNLOCK(sc);
+
+#ifdef IEEE80211_SUPPORT_SUPERG
+		/*
+		 * NB: this will executed only when 'report' bit is set.
+		 */
+		if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
+			rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
+#endif
+		break;
+	case RTWN_RX_OTHER:
+		rtwn_handle_c2h_report(sc, buf, len);
+		break;
+	default:
+		/* NOTREACHED */
+		KASSERT(0, ("unknown Rx classification code"));
+		break;
+	}
+
+	return (NULL);
+}
+
+static struct ieee80211_node *
+rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m, int8_t *rssi)
+{
+	struct r92c_rx_stat stat;
+
+	/* Imitate PCIe layout. */
+	m_copydata(m, 0, sizeof(struct r92c_rx_stat), (caddr_t)&stat);
+	m_adj(m, sizeof(struct r92c_rx_stat));
+
+	return (rtwn_rx_common(sc, m, &stat, rssi));
+}
+
+void
+rtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer);
+	struct rtwn_softc *sc = &uc->uc_sc;
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_node *ni;
+	struct mbuf *m = NULL, *next;
+	struct rtwn_data *data;
+	int8_t nf, rssi;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+		data = STAILQ_FIRST(&uc->uc_rx_active);
+		if (data == NULL)
+			goto tr_setup;
+		STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next);
+		m = rtwn_report_intr(uc, xfer, data);
+		STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next);
+		/* FALLTHROUGH */
+	case USB_ST_SETUP:
+tr_setup:
+		data = STAILQ_FIRST(&uc->uc_rx_inactive);
+		if (data == NULL) {
+			KASSERT(m == NULL, ("mbuf isn't NULL"));
+			goto finish;
+		}
+		STAILQ_REMOVE_HEAD(&uc->uc_rx_inactive, next);
+		STAILQ_INSERT_TAIL(&uc->uc_rx_active, data, next);
+		usbd_xfer_set_frame_data(xfer, 0, data->buf,
+		    usbd_xfer_max_len(xfer));
+		usbd_transfer_submit(xfer);
+
+		/*
+		 * To avoid LOR we should unlock our private mutex here to call
+		 * ieee80211_input() because here is at the end of a USB
+		 * callback and safe to unlock.
+		 */
+		while (m != NULL) {
+			next = m->m_next;
+			m->m_next = NULL;
+
+			ni = rtwn_rx_frame(sc, m, &rssi);
+
+			RTWN_UNLOCK(sc);
+
+			nf = RTWN_NOISE_FLOOR;
+			if (ni != NULL) {
+				if (ni->ni_flags & IEEE80211_NODE_HT)
+					m->m_flags |= M_AMPDU;
+				(void)ieee80211_input(ni, m, rssi - nf, nf);
+				ieee80211_free_node(ni);
+			} else {
+				(void)ieee80211_input_all(ic, m,
+				    rssi - nf, nf);
+			}
+			RTWN_LOCK(sc);
+			m = next;
+		}
+		break;
+	default:
+		/* needs it to the inactive queue due to a error. */
+		data = STAILQ_FIRST(&uc->uc_rx_active);
+		if (data != NULL) {
+			STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next);
+			STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next);
+		}
+		if (error != USB_ERR_CANCELLED) {
+			usbd_xfer_set_stall(xfer);
+			counter_u64_add(ic->ic_ierrors, 1);
+			goto tr_setup;
+		}
+		break;
+	}
+finish:
+	/* Finished receive; age anything left on the FF queue by a little bump */
+	/*
+	 * XXX TODO: just make this a callout timer schedule so we can
+	 * flush the FF staging queue if we're approaching idle.
+	 */
+#ifdef	IEEE80211_SUPPORT_SUPERG
+	if (!(sc->sc_flags & RTWN_FW_LOADED) ||
+	    sc->sc_ratectl != RTWN_RATECTL_NET80211)
+		rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
+#endif
+
+	/* Kick-start more transmit in case we stalled */
+	rtwn_start(sc);
+}
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,24 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTWN_USB_RX_H
+#define RTWN_USB_RX_H
+
+void	rtwn_bulk_rx_callback(struct usb_xfer *, usb_error_t);
+
+#endif	/* RTWN_USB_RX_H */
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,284 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
+ * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_wlan.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+#include <dev/rtwn/if_rtwnvar.h>
+
+#include <dev/rtwn/if_rtwn_beacon.h>
+#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/if_rtwn_ridx.h>
+#include <dev/rtwn/if_rtwn_task.h>
+#include <dev/rtwn/if_rtwn_tx.h>
+
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
+#include <dev/rtwn/usb/rtwn_usb_reg.h>
+#include <dev/rtwn/usb/rtwn_usb_tx.h>
+
+static struct rtwn_data * _rtwn_usb_getbuf(struct rtwn_usb_softc *);
+static struct rtwn_data * rtwn_usb_getbuf(struct rtwn_usb_softc *);
+static void		rtwn_usb_txeof(struct rtwn_usb_softc *,
+			    struct rtwn_data *, int);
+
+
+static const uint8_t wme2qid[] =
+	{ RTWN_BULK_TX_BE, RTWN_BULK_TX_BK,
+	  RTWN_BULK_TX_VI, RTWN_BULK_TX_VO };
+
+
+static struct rtwn_data *
+_rtwn_usb_getbuf(struct rtwn_usb_softc *uc)
+{
+	struct rtwn_softc *sc = &uc->uc_sc;
+	struct rtwn_data *bf;
+
+	bf = STAILQ_FIRST(&uc->uc_tx_inactive);
+	if (bf != NULL)
+		STAILQ_REMOVE_HEAD(&uc->uc_tx_inactive, next);
+	else {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
+		    "%s: out of xmit buffers\n", __func__);
+	}
+	return (bf);
+}
+
+static struct rtwn_data *
+rtwn_usb_getbuf(struct rtwn_usb_softc *uc)
+{
+	struct rtwn_softc *sc = &uc->uc_sc;
+	struct rtwn_data *bf;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	bf = _rtwn_usb_getbuf(uc);
+	if (bf == NULL) {
+		RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: stop queue\n",
+		    __func__);
+	}
+	return (bf);
+}
+
+static void
+rtwn_usb_txeof(struct rtwn_usb_softc *uc, struct rtwn_data *data, int status)
+{
+	struct rtwn_softc *sc = &uc->uc_sc;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	if (data->ni != NULL)	/* not a beacon frame */
+		ieee80211_tx_complete(data->ni, data->m, status);
+
+	if (sc->sc_ratectl != RTWN_RATECTL_NET80211)
+		if (sc->sc_tx_n_active > 0)
+			sc->sc_tx_n_active--;
+
+	data->ni = NULL;
+	data->m = NULL;
+
+	STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, data, next);
+	sc->qfullmsk = 0;
+#ifndef D4054
+	if (STAILQ_EMPTY(&uc->uc_tx_active) && STAILQ_EMPTY(&uc->uc_tx_pending))
+		sc->sc_tx_timer = 0;
+	else
+		sc->sc_tx_timer = 5;
+#endif
+}
+
+void
+rtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer);
+	struct rtwn_softc *sc = &uc->uc_sc;
+	struct rtwn_data *data;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	switch (USB_GET_STATE(xfer)){
+	case USB_ST_TRANSFERRED:
+		data = STAILQ_FIRST(&uc->uc_tx_active);
+		if (data == NULL)
+			goto tr_setup;
+		STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next);
+		rtwn_usb_txeof(uc, data, 0);
+		/* FALLTHROUGH */
+	case USB_ST_SETUP:
+tr_setup:
+		data = STAILQ_FIRST(&uc->uc_tx_pending);
+		if (data == NULL) {
+			RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
+			    "%s: empty pending queue\n", __func__);
+			sc->sc_tx_n_active = 0;
+			goto finish;
+		}
+		STAILQ_REMOVE_HEAD(&uc->uc_tx_pending, next);
+		STAILQ_INSERT_TAIL(&uc->uc_tx_active, data, next);
+
+		/*
+		 * Note: if this is a beacon frame, ensure that it will go
+		 * into appropriate queue.
+		 */
+		if (data->ni == NULL && RTWN_CHIP_HAS_BCNQ1(sc))
+			rtwn_switch_bcnq(sc, data->id);
+		usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
+		usbd_transfer_submit(xfer);
+		if (sc->sc_ratectl != RTWN_RATECTL_NET80211)
+			sc->sc_tx_n_active++;
+		break;
+	default:
+		data = STAILQ_FIRST(&uc->uc_tx_active);
+		if (data == NULL)
+			goto tr_setup;
+		STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next);
+		rtwn_usb_txeof(uc, data, 1);
+		if (error != USB_ERR_CANCELLED) {
+			usbd_xfer_set_stall(xfer);
+			goto tr_setup;
+		}
+		break;
+	}
+finish:
+#ifdef	IEEE80211_SUPPORT_SUPERG
+	/*
+	 * If the TX active queue drops below a certain
+	 * threshold, ensure we age fast-frames out so they're
+	 * transmitted.
+	 */
+	if (sc->sc_ratectl != RTWN_RATECTL_NET80211 &&
+	    sc->sc_tx_n_active <= 1) {
+		/* XXX ew - net80211 should defer this for us! */
+
+		/*
+		 * Note: this sc_tx_n_active currently tracks
+		 * the number of pending transmit submissions
+		 * and not the actual depth of the TX frames
+		 * pending to the hardware.  That means that
+		 * we're going to end up with some sub-optimal
+		 * aggregation behaviour.
+		 */
+		/*
+		 * XXX TODO: just make this a callout timer schedule so we can
+		 * flush the FF staging queue if we're approaching idle.
+		 */
+		rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
+	}
+#endif
+	/* Kick-start more transmit */
+	rtwn_start(sc);
+}
+
+static void
+rtwn_usb_tx_checksum(struct rtwn_tx_desc_common *txd)
+{
+	txd->txdw7.usb_checksum = 0;
+	txd->txdw7.usb_checksum = rtwn_usb_calc_tx_checksum(txd);
+}
+
+int
+rtwn_usb_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni,
+    struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id)
+{
+	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+	struct rtwn_tx_desc_common *txd;
+	struct rtwn_data *data;
+	struct usb_xfer *xfer;
+	uint16_t ac;
+
+	RTWN_ASSERT_LOCKED(sc);
+
+	data = rtwn_usb_getbuf(uc);
+	if (data == NULL)
+		return (ENOBUFS);
+
+	ac = M_WME_GETAC(m);
+
+	switch (type) {
+	case IEEE80211_FC0_TYPE_CTL:
+	case IEEE80211_FC0_TYPE_MGT:
+		xfer = uc->uc_xfer[RTWN_BULK_TX_VO];
+		break;
+	default:
+		xfer = uc->uc_xfer[wme2qid[ac]];
+		break;
+	}
+
+	txd = (struct rtwn_tx_desc_common *)tx_desc;
+	txd->pktlen = htole16(m->m_pkthdr.len);
+	txd->offset = sc->txdesc_len;
+	txd->flags0 |= RTWN_FLAGS0_OWN;
+	rtwn_usb_tx_checksum(txd);
+
+	/* Dump Tx descriptor. */
+	rtwn_dump_tx_desc(sc, tx_desc);
+
+	memcpy(data->buf, tx_desc, sc->txdesc_len);
+	m_copydata(m, 0, m->m_pkthdr.len,
+	    (caddr_t)(data->buf + sc->txdesc_len));
+
+	data->buflen = m->m_pkthdr.len + sc->txdesc_len;
+	data->id = id;
+	data->ni = ni;
+	if (data->ni != NULL) {
+		data->m = m;
+#ifndef D4054
+		sc->sc_tx_timer = 5;
+#endif
+	}
+
+	STAILQ_INSERT_TAIL(&uc->uc_tx_pending, data, next);
+	if (STAILQ_EMPTY(&uc->uc_tx_inactive))
+		sc->qfullmsk = 1;
+
+	usbd_transfer_start(xfer);
+
+	return (0);
+}
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,26 @@
+/*-
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTWN_USB_TX_H
+#define RTWN_USB_TX_H
+
+void	rtwn_bulk_tx_callback(struct usb_xfer *, usb_error_t);
+int	rtwn_usb_tx_start(struct rtwn_softc *, struct ieee80211_node *,
+	    struct mbuf *, uint8_t *, uint8_t, int);
+
+#endif	/* RTWN_USB_TX_H */
Index: freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h
===================================================================
--- freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
+++ freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $
+ * $FreeBSD$
+ */
+
+#ifndef RTWN_USBVAR_H
+#define RTWN_USBVAR_H
+
+#define RTWN_IFACE_INDEX		0
+
+#define RTWN_USB_RX_LIST_COUNT		1
+#define RTWN_USB_TX_LIST_COUNT		16
+
+struct rtwn_data {
+	uint8_t				*buf;
+	/* 'id' is meaningful for beacons only */
+	int				id;
+	uint16_t			buflen;
+	struct mbuf			*m;
+	struct ieee80211_node		*ni;
+	STAILQ_ENTRY(rtwn_data)	next;
+};
+typedef STAILQ_HEAD(, rtwn_data) rtwn_datahead;
+
+enum {
+	RTWN_BULK_RX,
+	RTWN_BULK_TX_BE,	/* = WME_AC_BE */
+	RTWN_BULK_TX_BK,	/* = WME_AC_BK */
+	RTWN_BULK_TX_VI,	/* = WME_AC_VI */
+	RTWN_BULK_TX_VO,	/* = WME_AC_VO */
+	RTWN_N_TRANSFER = 5,
+};
+
+#define RTWN_EP_QUEUES		RTWN_BULK_RX
+
+struct rtwn_usb_softc {
+	struct rtwn_softc	uc_sc;		/* must be the first */
+	struct usb_device	*uc_udev;
+	struct usb_xfer		*uc_xfer[RTWN_N_TRANSFER];
+
+	struct rtwn_data	uc_rx[RTWN_USB_RX_LIST_COUNT];
+	rtwn_datahead		uc_rx_active;
+	rtwn_datahead		uc_rx_inactive;
+	struct rtwn_data	uc_tx[RTWN_USB_TX_LIST_COUNT];
+	rtwn_datahead		uc_tx_active;
+	rtwn_datahead		uc_tx_inactive;
+	rtwn_datahead		uc_tx_pending;
+
+	int			(*uc_align_rx)(int, int);
+
+	int			ntx;
+	int			tx_agg_desc_num;
+};
+#define RTWN_USB_SOFTC(sc)	((struct rtwn_usb_softc *)(sc))
+
+#define rtwn_usb_align_rx(_uc, _totlen, _len) \
+	(((_uc)->uc_align_rx)((_totlen), (_len)))
+
+#endif	/* RTWN_USBVAR_H */
Index: libbsd.txt
===================================================================
--- libbsd.txt	(revision 9bc41d057eff79fa15d944db06a492183cc525f1)
+++ libbsd.txt	(revision 0cbb715adeec510cd0556d9807d95eb60b4b6db8)
@@ -778,6 +778,4 @@
 
 . *, trunk, 2017-01-09, 1f8e4a995a6ede4bdb24e6d335ccda2bdb0175ab.
-
-== How to import code from FreeBSD
 
 . In case you import files from a special FreeBSD version, then update the list above.
