summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mauderer <Christian.Mauderer@embedded-brains.de>2016-11-22 10:41:47 +0100
committerChristian Mauderer <Christian.Mauderer@embedded-brains.de>2017-01-17 12:50:58 +0100
commit0cbb715adeec510cd0556d9807d95eb60b4b6db8 (patch)
tree24759593608739ad0caca52c78b6816aefde5118
parentlib80211/regdomain: Port to RTEMS. (diff)
downloadrtems-libbsd-0cbb715adeec510cd0556d9807d95eb60b4b6db8.tar.bz2
rtwn: Import from FreeBSD.
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn.c2020
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_beacon.c271
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_beacon.h28
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_calib.c130
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_calib.h24
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_cam.c366
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_cam.h30
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_debug.h60
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_efuse.c267
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_efuse.h25
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_fw.c226
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_fw.h59
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_nop.h69
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_ridx.h94
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_rx.c466
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_rx.h39
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_task.c124
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_task.h27
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_tx.c348
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_tx.h31
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwnreg.h118
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwnvar.h624
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c784
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h48
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c125
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h30
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c329
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h27
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c274
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h25
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h140
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e.h94
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c64
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c69
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c169
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c227
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h84
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c160
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c70
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h273
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h91
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c62
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c87
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h29
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h60
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c213
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h100
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c81
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h38
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h39
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c218
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c226
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h27
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c76
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h74
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c265
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c388
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c77
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c325
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c69
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h182
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h103
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c134
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h41
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c117
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h55
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c.h114
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c82
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c88
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c115
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c353
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c522
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h148
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c319
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h408
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h855
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c95
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c141
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h57
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h71
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c104
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h95
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c438
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h122
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h83
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h56
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c247
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c393
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c68
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h322
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h65
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c65
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c66
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h45
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a.h140
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c96
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c288
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c122
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c603
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c196
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h123
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c488
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c74
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h852
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h236
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c112
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c224
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h43
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h134
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c240
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h79
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c438
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h149
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h126
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h52
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c290
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c189
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h35
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c91
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c77
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h56
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a.h80
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c95
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c128
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c155
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c80
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c360
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c69
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h464
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h50
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c93
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c90
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h48
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c283
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c282
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c85
-rw-r--r--freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h35
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c444
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h160
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c255
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h25
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c181
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h45
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c342
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h24
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c284
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h26
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h74
-rw-r--r--libbsd.txt2
149 files changed, 26962 insertions, 2 deletions
diff --git a/freebsd/sys/dev/rtwn/if_rtwn.c b/freebsd/sys/dev/rtwn/if_rtwn.c
new file mode 100644
index 00000000..a553814f
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn.c
@@ -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
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_beacon.c b/freebsd/sys/dev/rtwn/if_rtwn_beacon.c
new file mode 100644
index 00000000..a6a49f76
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_beacon.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_beacon.h b/freebsd/sys/dev/rtwn/if_rtwn_beacon.h
new file mode 100644
index 00000000..c38f7568
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_beacon.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_calib.c b/freebsd/sys/dev/rtwn/if_rtwn_calib.c
new file mode 100644
index 00000000..8943b557
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_calib.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_calib.h b/freebsd/sys/dev/rtwn/if_rtwn_calib.h
new file mode 100644
index 00000000..ee50fd06
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_calib.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_cam.c b/freebsd/sys/dev/rtwn/if_rtwn_cam.c
new file mode 100644
index 00000000..2539bc70
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_cam.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_cam.h b/freebsd/sys/dev/rtwn/if_rtwn_cam.h
new file mode 100644
index 00000000..280509b9
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_cam.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_debug.h b/freebsd/sys/dev/rtwn/if_rtwn_debug.h
new file mode 100644
index 00000000..1559ff57
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_debug.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_efuse.c b/freebsd/sys/dev/rtwn/if_rtwn_efuse.c
new file mode 100644
index 00000000..bdf28a5d
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_efuse.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_efuse.h b/freebsd/sys/dev/rtwn/if_rtwn_efuse.h
new file mode 100644
index 00000000..62125c24
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_efuse.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_fw.c b/freebsd/sys/dev/rtwn/if_rtwn_fw.c
new file mode 100644
index 00000000..a4c9506e
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_fw.c
@@ -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
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_fw.h b/freebsd/sys/dev/rtwn/if_rtwn_fw.h
new file mode 100644
index 00000000..41e84ee8
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_fw.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_nop.h b/freebsd/sys/dev/rtwn/if_rtwn_nop.h
new file mode 100644
index 00000000..2b8b3e1a
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_nop.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_ridx.h b/freebsd/sys/dev/rtwn/if_rtwn_ridx.h
new file mode 100644
index 00000000..eef43898
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_ridx.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_rx.c b/freebsd/sys/dev/rtwn/if_rtwn_rx.c
new file mode 100644
index 00000000..8d103dc7
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_rx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_rx.h b/freebsd/sys/dev/rtwn/if_rtwn_rx.h
new file mode 100644
index 00000000..dfdcc4bf
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_rx.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_task.c b/freebsd/sys/dev/rtwn/if_rtwn_task.c
new file mode 100644
index 00000000..ecff85a5
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_task.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_task.h b/freebsd/sys/dev/rtwn/if_rtwn_task.h
new file mode 100644
index 00000000..a9d60c20
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_task.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_tx.c b/freebsd/sys/dev/rtwn/if_rtwn_tx.c
new file mode 100644
index 00000000..1ea9a766
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_tx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_tx.h b/freebsd/sys/dev/rtwn/if_rtwn_tx.h
new file mode 100644
index 00000000..e02fb564
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwn_tx.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/if_rtwnreg.h b/freebsd/sys/dev/rtwn/if_rtwnreg.h
new file mode 100644
index 00000000..9dc830a2
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwnreg.h
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/if_rtwnvar.h b/freebsd/sys/dev/rtwn/if_rtwnvar.h
new file mode 100644
index 00000000..0c010adb
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/if_rtwnvar.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c
new file mode 100644
index 00000000..5b28d27f
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c
@@ -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);
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h
new file mode 100644
index 00000000..6df5812e
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c
new file mode 100644
index 00000000..3801f811
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c
@@ -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));
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h
new file mode 100644
index 00000000..7c900345
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c
new file mode 100644
index 00000000..8da0061b
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h
new file mode 100644
index 00000000..265d32d8
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c
new file mode 100644
index 00000000..a2f4221c
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h
new file mode 100644
index 00000000..9b9d2e33
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h
new file mode 100644
index 00000000..5a9e64e7
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e.h
new file mode 100644
index 00000000..999ab400
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c
new file mode 100644
index 00000000..752b29dd
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c
@@ -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);
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c
new file mode 100644
index 00000000..c996749a
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c
new file mode 100644
index 00000000..405edb2b
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c
new file mode 100644
index 00000000..409084f6
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c
@@ -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
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h
new file mode 100644
index 00000000..c152729c
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c
new file mode 100644
index 00000000..62e5463b
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c
@@ -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
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c
new file mode 100644
index 00000000..02ec644a
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c
@@ -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? */
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h
new file mode 100644
index 00000000..cb4f7edb
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h
new file mode 100644
index 00000000..f6f26fa4
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c
new file mode 100644
index 00000000..18991ba8
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c
new file mode 100644
index 00000000..9fc7c4c4
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h
new file mode 100644
index 00000000..5734246f
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h
new file mode 100644
index 00000000..c80028e0
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c
new file mode 100644
index 00000000..464542b4
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h
new file mode 100644
index 00000000..2b72f3dd
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c
new file mode 100644
index 00000000..4f70e61c
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h
new file mode 100644
index 00000000..98338fb7
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h
new file mode 100644
index 00000000..85b637cb
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
new file mode 100644
index 00000000..4d5452be
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
new file mode 100644
index 00000000..3f9ae320
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
@@ -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;
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h
new file mode 100644
index 00000000..fc61eaae
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c
new file mode 100644
index 00000000..3c2671c7
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c
@@ -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);
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h
new file mode 100644
index 00000000..93379f8b
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c
new file mode 100644
index 00000000..d53dbf98
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c
new file mode 100644
index 00000000..e1b4f507
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c
@@ -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
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c
new file mode 100644
index 00000000..c4905429
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c
@@ -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
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c
new file mode 100644
index 00000000..e7ec8bfd
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c
@@ -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;
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c
new file mode 100644
index 00000000..28273a38
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c
@@ -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. */
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h
new file mode 100644
index 00000000..7416516c
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h
new file mode 100644
index 00000000..355d8f46
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c
new file mode 100644
index 00000000..d496e7b8
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c
@@ -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
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h
new file mode 100644
index 00000000..476a9e88
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c
new file mode 100644
index 00000000..31d621bd
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c
@@ -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
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h
new file mode 100644
index 00000000..4153710a
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c.h
new file mode 100644
index 00000000..2b63179e
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c
new file mode 100644
index 00000000..cfb76acc
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c
@@ -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;
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c
new file mode 100644
index 00000000..fc106a47
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c
@@ -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);
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c
new file mode 100644
index 00000000..e7706b8d
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c
new file mode 100644
index 00000000..a4ba2766
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c
new file mode 100644
index 00000000..74c7d205
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h
new file mode 100644
index 00000000..998a7805
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c
new file mode 100644
index 00000000..d8db0286
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h
new file mode 100644
index 00000000..13c38fb2
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h
new file mode 100644
index 00000000..ff03d191
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c
new file mode 100644
index 00000000..22507e6c
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c
new file mode 100644
index 00000000..1c1595fc
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h
new file mode 100644
index 00000000..35fc42df
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h
new file mode 100644
index 00000000..304324e6
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c
new file mode 100644
index 00000000..b77c76f6
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h
new file mode 100644
index 00000000..7fec70be
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c
new file mode 100644
index 00000000..0e3c408d
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h
new file mode 100644
index 00000000..037ac0e2
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h
new file mode 100644
index 00000000..c48318d9
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h
new file mode 100644
index 00000000..2486d7fa
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
new file mode 100644
index 00000000..ce3f7a1a
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c
new file mode 100644
index 00000000..44b3a509
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c
@@ -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;
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c
new file mode 100644
index 00000000..4db6b167
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c
@@ -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. */
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h
new file mode 100644
index 00000000..8e3203f0
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h
new file mode 100644
index 00000000..a9db29cc
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c
new file mode 100644
index 00000000..ec55da6d
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c
new file mode 100644
index 00000000..0954316d
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c
@@ -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
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h
new file mode 100644
index 00000000..16c2d058
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h
@@ -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 */ \ No newline at end of file
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a.h
new file mode 100644
index 00000000..ec1d61e1
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c
new file mode 100644
index 00000000..37b1a183
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c
new file mode 100644
index 00000000..73f1df0f
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c
new file mode 100644
index 00000000..fc022e91
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c
new file mode 100644
index 00000000..11db1a5d
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c
new file mode 100644
index 00000000..12a3d855
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c
@@ -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
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h
new file mode 100644
index 00000000..58b82ed1
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c
new file mode 100644
index 00000000..4835966e
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c
new file mode 100644
index 00000000..e38dbd44
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c
@@ -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 ? */
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h
new file mode 100644
index 00000000..e75e32fc
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h
new file mode 100644
index 00000000..41cc160f
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c
new file mode 100644
index 00000000..29922ba2
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c
@@ -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));
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c
new file mode 100644
index 00000000..a6a0b8c1
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h
new file mode 100644
index 00000000..4cdb8b54
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h
new file mode 100644
index 00000000..1f992e1e
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c
new file mode 100644
index 00000000..049717a4
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h
new file mode 100644
index 00000000..8642ca85
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c
new file mode 100644
index 00000000..f7bd3a8e
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h
new file mode 100644
index 00000000..9d3ad8b1
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h
new file mode 100644
index 00000000..0092fb67
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h
new file mode 100644
index 00000000..55d132c7
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c
new file mode 100644
index 00000000..684076eb
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c
new file mode 100644
index 00000000..f55ecb81
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c
@@ -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;
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h
new file mode 100644
index 00000000..f768c262
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c
new file mode 100644
index 00000000..9015631a
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c
new file mode 100644
index 00000000..20f13f93
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c
@@ -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
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h
new file mode 100644
index 00000000..b7613f2b
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a.h b/freebsd/sys/dev/rtwn/rtl8821a/r21a.h
new file mode 100644
index 00000000..cfc99cb9
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c
new file mode 100644
index 00000000..e60b777c
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c
@@ -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;
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c
new file mode 100644
index 00000000..d4679bc0
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c
@@ -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
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c
new file mode 100644
index 00000000..9277b6af
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c
new file mode 100644
index 00000000..dad74ed1
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c
@@ -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
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c
new file mode 100644
index 00000000..a3bcde77
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c
new file mode 100644
index 00000000..83d67c67
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c
@@ -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. */
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h b/freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h
new file mode 100644
index 00000000..d4cfa46a
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h b/freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h
new file mode 100644
index 00000000..d13872d5
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c
new file mode 100644
index 00000000..be64a064
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c
new file mode 100644
index 00000000..498d2423
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h
new file mode 100644
index 00000000..60aa476c
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c
new file mode 100644
index 00000000..6f7129f8
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c
new file mode 100644
index 00000000..796ce6e0
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c
new file mode 100644
index 00000000..484d2dad
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c
@@ -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);
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h
new file mode 100644
index 00000000..cd0deb5f
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c
new file mode 100644
index 00000000..f378ca3c
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c
@@ -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);
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h
new file mode 100644
index 00000000..48a4d6e5
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c
new file mode 100644
index 00000000..a1fafb46
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c
@@ -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);
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h
new file mode 100644
index 00000000..0cdd738e
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c
new file mode 100644
index 00000000..1461205b
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c
@@ -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));
+ }
+}
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h
new file mode 100644
index 00000000..1149248d
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c
new file mode 100644
index 00000000..8795e16d
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h
new file mode 100644
index 00000000..e3708169
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c
new file mode 100644
index 00000000..9ae41d28
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c
@@ -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);
+}
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h
new file mode 100644
index 00000000..01527080
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h
@@ -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 */
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h
new file mode 100644
index 00000000..be7f8f19
--- /dev/null
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h
@@ -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 */
diff --git a/libbsd.txt b/libbsd.txt
index ed8bbe29..f6690815 100644
--- a/libbsd.txt
+++ b/libbsd.txt
@@ -778,8 +778,6 @@ detail and debug level information from the command.
. *, 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.
. Run `git status` and make sure your working directory is clean.
. Run `./freebsd-to-rtems.py -R`