diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile index 88c767d89d..fead0f50e4 100644 --- a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile @@ -21,6 +21,7 @@ KernelAddon ralinkwifi : rt2661.c rt2860.c + if_mtw.c if_ural.c if_run.c if_rum.c @@ -31,7 +32,7 @@ KernelAddon ralinkwifi : libfreebsd_network.a ; -ObjectHdrs [ FGristFiles if_ural$(SUFOBJ) if_run$(SUFOBJ) if_rum$(SUFOBJ) ] +ObjectHdrs [ FGristFiles if_mtw$(SUFOBJ) if_ural$(SUFOBJ) if_run$(SUFOBJ) if_rum$(SUFOBJ) ] : [ FDirName $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) libs compat freebsd_network ] ; -Includes [ FGristFiles if_ural.c if_run.c if_rum.c ] +Includes [ FGristFiles if_mtw.c if_ural.c if_run.c if_rum.c ] : usbdevs.h ; diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtw.c b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtw.c new file mode 100644 index 0000000000..a42d217a04 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtw.c @@ -0,0 +1,4687 @@ +/*- + * Copyright (c) 2008-2010 Damien Bergamini + * Copyright (c) 2013-2014 Kevin Lo + * Copyright (c) 2021 James Hastings + * Ported to FreeBSD by Jesper Schmitz Mouridsen jsm@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. + */ + +/* + * MediaTek MT7601U 802.11b/g/n WLAN. + */ + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "usbdevs.h" + +#define USB_DEBUG_VAR mtw_debug +#include +#ifndef __HAIKU__ +#include +#endif + +#include "if_mtwreg.h" +#include "if_mtwvar.h" + +#define MTW_DEBUG + +#ifdef MTW_DEBUG +int mtw_debug; +static SYSCTL_NODE(_hw_usb, OID_AUTO, mtw, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, + "USB mtw"); +SYSCTL_INT(_hw_usb_mtw, OID_AUTO, debug, CTLFLAG_RWTUN, &mtw_debug, 0, + "mtw debug level"); + +enum { + MTW_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + MTW_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */ + MTW_DEBUG_RECV = 0x00000004, /* basic recv operation */ + MTW_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */ + MTW_DEBUG_STATE = 0x00000010, /* 802.11 state transitions */ + MTW_DEBUG_RATE = 0x00000020, /* rate adaptation */ + MTW_DEBUG_USB = 0x00000040, /* usb requests */ + MTW_DEBUG_FIRMWARE = 0x00000080, /* firmware(9) loading debug */ + MTW_DEBUG_BEACON = 0x00000100, /* beacon handling */ + MTW_DEBUG_INTR = 0x00000200, /* ISR */ + MTW_DEBUG_TEMP = 0x00000400, /* temperature calibration */ + MTW_DEBUG_ROM = 0x00000800, /* various ROM info */ + MTW_DEBUG_KEY = 0x00001000, /* crypto keys management */ + MTW_DEBUG_TXPWR = 0x00002000, /* dump Tx power values */ + MTW_DEBUG_RSSI = 0x00004000, /* dump RSSI lookups */ + MTW_DEBUG_RESET = 0x00008000, /* initialization progress */ + MTW_DEBUG_CALIB = 0x00010000, /* calibration progress */ + MTW_DEBUG_CMD = 0x00020000, /* command queue */ + MTW_DEBUG_ANY = 0xffffffff +}; + +#define MTW_DPRINTF(_sc, _m, ...) \ + do { \ + if (mtw_debug & (_m)) \ + device_printf((_sc)->sc_dev, __VA_ARGS__); \ + } while (0) + +#else +#define MTW_DPRINTF(_sc, _m, ...) \ + do { \ + (void)_sc; \ + } while (0) +#endif + +#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) + +/* NB: "11" is the maximum number of padding bytes needed for Tx */ +#define MTW_MAX_TXSZ \ + (sizeof(struct mtw_txd) + sizeof(struct mtw_txwi) + MCLBYTES + 11) + +/* + * Because of LOR in mtw_key_delete(), use atomic instead. + * '& MTW_CMDQ_MASQ' is to loop cmdq[]. + */ +#define MTW_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & MTW_CMDQ_MASQ) + +static const STRUCT_USB_HOST_ID mtw_devs[] = { +#define MTW_DEV(v, p) \ + { \ + USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) \ + } + MTW_DEV(EDIMAX, MT7601U), + MTW_DEV(RALINK, MT7601U), + MTW_DEV(XIAOMI, MT7601U) +}; +#undef MTW_DEV + +static device_probe_t mtw_match; +static device_attach_t mtw_attach; +static device_detach_t mtw_detach; + +static usb_callback_t mtw_bulk_rx_callback; +static usb_callback_t mtw_bulk_tx_callback0; +static usb_callback_t mtw_bulk_tx_callback1; +static usb_callback_t mtw_bulk_tx_callback2; +static usb_callback_t mtw_bulk_tx_callback3; +static usb_callback_t mtw_bulk_tx_callback4; +static usb_callback_t mtw_bulk_tx_callback5; +static usb_callback_t mtw_fw_callback; + +static void mtw_autoinst(void *, struct usb_device *, struct usb_attach_arg *); +static int mtw_driver_loaded(struct module *, int, void *); +static void mtw_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, + u_int index); +static struct ieee80211vap *mtw_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 mtw_vap_delete(struct ieee80211vap *); +static void mtw_cmdq_cb(void *, int); +static void mtw_setup_tx_list(struct mtw_softc *, struct mtw_endpoint_queue *); +static void mtw_unsetup_tx_list(struct mtw_softc *, + struct mtw_endpoint_queue *); +static void mtw_load_microcode(void *arg); + +static usb_error_t mtw_do_request(struct mtw_softc *, + struct usb_device_request *, void *); +static int mtw_read(struct mtw_softc *, uint16_t, uint32_t *); +static int mtw_read_region_1(struct mtw_softc *, uint16_t, uint8_t *, int); +static int mtw_write_2(struct mtw_softc *, uint16_t, uint16_t); +static int mtw_write(struct mtw_softc *, uint16_t, uint32_t); +static int mtw_write_region_1(struct mtw_softc *, uint16_t, uint8_t *, int); +static int mtw_set_region_4(struct mtw_softc *, uint16_t, uint32_t, int); +static int mtw_efuse_read_2(struct mtw_softc *, uint16_t, uint16_t *); +static int mtw_bbp_read(struct mtw_softc *, uint8_t, uint8_t *); +static int mtw_bbp_write(struct mtw_softc *, uint8_t, uint8_t); +static int mtw_mcu_cmd(struct mtw_softc *sc, uint8_t cmd, void *buf, int len); +static void mtw_get_txpower(struct mtw_softc *); +static int mtw_read_eeprom(struct mtw_softc *); +static struct ieee80211_node *mtw_node_alloc(struct ieee80211vap *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static int mtw_media_change(if_t); +static int mtw_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static int mtw_wme_update(struct ieee80211com *); +static void mtw_key_set_cb(void *); +static int mtw_key_set(struct ieee80211vap *, struct ieee80211_key *); +static void mtw_key_delete_cb(void *); +static int mtw_key_delete(struct ieee80211vap *, struct ieee80211_key *); +static void mtw_ratectl_to(void *); +static void mtw_ratectl_cb(void *, int); +static void mtw_drain_fifo(void *); +static void mtw_iter_func(void *, struct ieee80211_node *); +static void mtw_newassoc_cb(void *); +static void mtw_newassoc(struct ieee80211_node *, int); +static int mtw_mcu_radio(struct mtw_softc *sc, int func, uint32_t val); +static void mtw_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, + const struct ieee80211_rx_stats *, int, int); +static void mtw_rx_frame(struct mtw_softc *, struct mbuf *, uint32_t); +static void mtw_tx_free(struct mtw_endpoint_queue *pq, struct mtw_tx_data *, + int); +static void mtw_set_tx_desc(struct mtw_softc *, struct mtw_tx_data *); +static int mtw_tx(struct mtw_softc *, struct mbuf *, struct ieee80211_node *); +static int mtw_tx_mgt(struct mtw_softc *, struct mbuf *, + struct ieee80211_node *); +static int mtw_sendprot(struct mtw_softc *, const struct mbuf *, + struct ieee80211_node *, int, int); +static int mtw_tx_param(struct mtw_softc *, struct mbuf *, + struct ieee80211_node *, const struct ieee80211_bpf_params *); +static int mtw_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); +static int mtw_transmit(struct ieee80211com *, struct mbuf *); +static void mtw_start(struct mtw_softc *); +static void mtw_parent(struct ieee80211com *); +static void mtw_select_chan_group(struct mtw_softc *, int); + +static int mtw_set_chan(struct mtw_softc *, struct ieee80211_channel *); +static void mtw_set_channel(struct ieee80211com *); +static void mtw_getradiocaps(struct ieee80211com *, int, int *, + struct ieee80211_channel[]); +static void mtw_scan_start(struct ieee80211com *); +static void mtw_scan_end(struct ieee80211com *); +static void mtw_update_beacon(struct ieee80211vap *, int); +static void mtw_update_beacon_cb(void *); +static void mtw_updateprot(struct ieee80211com *); +static void mtw_updateprot_cb(void *); +static void mtw_usb_timeout_cb(void *); +static int mtw_reset(struct mtw_softc *sc); +static void mtw_enable_tsf_sync(struct mtw_softc *); + + +static void mtw_enable_mrr(struct mtw_softc *); +static void mtw_set_txpreamble(struct mtw_softc *); +static void mtw_set_basicrates(struct mtw_softc *); +static void mtw_set_leds(struct mtw_softc *, uint16_t); +static void mtw_set_bssid(struct mtw_softc *, const uint8_t *); +static void mtw_set_macaddr(struct mtw_softc *, const uint8_t *); +static void mtw_updateslot(struct ieee80211com *); +static void mtw_updateslot_cb(void *); +static void mtw_update_mcast(struct ieee80211com *); +static int8_t mtw_rssi2dbm(struct mtw_softc *, uint8_t, uint8_t); +static void mtw_update_promisc_locked(struct mtw_softc *); +static void mtw_update_promisc(struct ieee80211com *); +static int mtw_txrx_enable(struct mtw_softc *); +static void mtw_init_locked(struct mtw_softc *); +static void mtw_stop(void *); +static void mtw_delay(struct mtw_softc *, u_int); +static void mtw_update_chw(struct ieee80211com *ic); +static int mtw_ampdu_enable(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap); + +static eventhandler_tag mtw_etag; + +static const struct { + uint8_t reg; + uint8_t val; +} mt7601_rf_bank0[] = { MT7601_BANK0_RF }, + mt7601_rf_bank4[] = { MT7601_BANK4_RF }, + mt7601_rf_bank5[] = { MT7601_BANK5_RF }; +static const struct { + uint32_t reg; + uint32_t val; +} mt7601_def_mac[] = { MT7601_DEF_MAC }; +static const struct { + uint8_t reg; + uint8_t val; +} mt7601_def_bbp[] = { MT7601_DEF_BBP }; + + +static const struct { + u_int chan; + uint8_t r17, r18, r19, r20; +} mt7601_rf_chan[] = { MT7601_RF_CHAN }; + + +static const struct usb_config mtw_config[MTW_N_XFER] = { + [MTW_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = MTW_MAX_RXSZ, + .flags = {.pipe_bof = 1, + .short_xfer_ok = 1,}, + .callback = mtw_bulk_rx_callback, + }, + [MTW_BULK_TX_BE] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = MTW_MAX_TXSZ, + .flags = {.pipe_bof = 1, + .force_short_xfer = 0,}, + .callback = mtw_bulk_tx_callback0, + .timeout = 5000, /* ms */ + }, + [MTW_BULK_TX_BK] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = MTW_MAX_TXSZ, + .flags = {.pipe_bof = 1, + .force_short_xfer = 1,}, + .callback = mtw_bulk_tx_callback1, + .timeout = 5000, /* ms */ + }, + [MTW_BULK_TX_VI] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = MTW_MAX_TXSZ, + .flags = {.pipe_bof = 1, + .force_short_xfer = 1,}, + .callback = mtw_bulk_tx_callback2, + .timeout = 5000, /* ms */ + }, + [MTW_BULK_TX_VO] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = MTW_MAX_TXSZ, + .flags = {.pipe_bof = 1, + .force_short_xfer = 1,}, + .callback = mtw_bulk_tx_callback3, + .timeout = 5000, /* ms */ + }, + [MTW_BULK_TX_HCCA] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = MTW_MAX_TXSZ, + .flags = {.pipe_bof = 1, + .force_short_xfer = 1, .no_pipe_ok = 1,}, + .callback = mtw_bulk_tx_callback4, + .timeout = 5000, /* ms */ + }, + [MTW_BULK_TX_PRIO] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = MTW_MAX_TXSZ, + .flags = {.pipe_bof = 1, + .force_short_xfer = 1, .no_pipe_ok = 1,}, + .callback = mtw_bulk_tx_callback5, + .timeout = 5000, /* ms */ + }, + + [MTW_BULK_FW_CMD] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = 0x2c44, + .flags = {.pipe_bof = 1, + .force_short_xfer = 1, .no_pipe_ok = 1,}, + .callback = mtw_fw_callback, + + }, + + [MTW_BULK_RAW_TX] = { + .type = UE_BULK, + .ep_index = 0, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = MTW_MAX_TXSZ, + .flags = {.pipe_bof = 1, + .force_short_xfer = 1, .no_pipe_ok = 1,}, + .callback = mtw_bulk_tx_callback0, + .timeout = 5000, /* ms */ + }, + +}; +static uint8_t mtw_wme_ac_xfer_map[4] = { + [WME_AC_BE] = MTW_BULK_TX_BE, + [WME_AC_BK] = MTW_BULK_TX_BK, + [WME_AC_VI] = MTW_BULK_TX_VI, + [WME_AC_VO] = MTW_BULK_TX_VO, +}; +static void +mtw_autoinst(void *arg, struct usb_device *udev, struct usb_attach_arg *uaa) +{ +#ifndef __HAIKU__ + struct usb_interface *iface; + struct usb_interface_descriptor *id; + + if (uaa->dev_state != UAA_DEV_READY) + return; + + iface = usbd_get_iface(udev, 0); + if (iface == NULL) + return; + id = iface->idesc; + if (id == NULL || id->bInterfaceClass != UICLASS_MASS) + return; + if (usbd_lookup_id_by_uaa(mtw_devs, sizeof(mtw_devs), uaa)) + return; + + if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0) + uaa->dev_state = UAA_DEV_EJECTING; +#endif +} + +static int +mtw_driver_loaded(struct module *mod, int what, void *arg) +{ + switch (what) { + case MOD_LOAD: + mtw_etag = EVENTHANDLER_REGISTER(usb_dev_configured, + mtw_autoinst, NULL, EVENTHANDLER_PRI_ANY); + break; + case MOD_UNLOAD: + EVENTHANDLER_DEREGISTER(usb_dev_configured, mtw_etag); + break; + default: + return (EOPNOTSUPP); + } + return (0); +} + +static const char * +mtw_get_rf(int rev) +{ + switch (rev) { + case MT7601_RF_7601: + return ("MT7601"); + case MT7610_RF_7610: + return ("MT7610"); + case MT7612_RF_7612: + return ("MT7612"); + } + return ("unknown"); +} +static int +mtw_wlan_enable(struct mtw_softc *sc, int enable) +{ + uint32_t tmp; + int error = 0; + + if (enable) { + mtw_read(sc, MTW_WLAN_CTRL, &tmp); + if (sc->asic_ver == 0x7612) + tmp &= ~0xfffff000; + + tmp &= ~MTW_WLAN_CLK_EN; + tmp |= MTW_WLAN_EN; + mtw_write(sc, MTW_WLAN_CTRL, tmp); + mtw_delay(sc, 2); + + tmp |= MTW_WLAN_CLK_EN; + if (sc->asic_ver == 0x7612) { + tmp |= (MTW_WLAN_RESET | MTW_WLAN_RESET_RF); + } + mtw_write(sc, MTW_WLAN_CTRL, tmp); + mtw_delay(sc, 2); + + mtw_read(sc, MTW_OSC_CTRL, &tmp); + tmp |= MTW_OSC_EN; + mtw_write(sc, MTW_OSC_CTRL, tmp); + tmp |= MTW_OSC_CAL_REQ; + mtw_write(sc, MTW_OSC_CTRL, tmp); + } else { + mtw_read(sc, MTW_WLAN_CTRL, &tmp); + tmp &= ~(MTW_WLAN_CLK_EN | MTW_WLAN_EN); + mtw_write(sc, MTW_WLAN_CTRL, tmp); + + mtw_read(sc, MTW_OSC_CTRL, &tmp); + tmp &= ~MTW_OSC_EN; + mtw_write(sc, MTW_OSC_CTRL, tmp); + } + return (error); +} + +static int +mtw_read_cfg(struct mtw_softc *sc, uint16_t reg, uint32_t *val) +{ + usb_device_request_t req; + uint32_t tmp; + uint16_t actlen; + int error; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = MTW_READ_CFG; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, 4); + error = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &tmp, 0, + &actlen, 1000); + + if (error == 0) + *val = le32toh(tmp); + else + *val = 0xffffffff; + return (error); +} + +static int +mtw_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 != 0) + return (ENXIO); + if (uaa->info.bIfaceIndex != 0) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(mtw_devs, sizeof(mtw_devs), uaa)); +} + +static int +mtw_attach(device_t self) +{ + struct mtw_softc *sc = device_get_softc(self); + struct usb_attach_arg *uaa = device_get_ivars(self); + struct ieee80211com *ic = &sc->sc_ic; + uint32_t ver; + int i, ret; + // uint32_t tmp; + uint8_t iface_index; + int ntries, error; + + device_set_usb_desc(self); + sc->sc_udev = uaa->device; + sc->sc_dev = self; + sc->sc_sent = 0; + + mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), + MTX_NETWORK_LOCK, MTX_DEF); + + iface_index = 0; + + error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, + mtw_config, MTW_N_XFER, sc, &sc->sc_mtx); + if (error) { + device_printf(sc->sc_dev, + "could not allocate USB transfers, " + "err=%s\n", + usbd_errstr(error)); + goto detach; + } + for (i = 0; i < 4; i++) { + sc->txd_fw[i] = (struct mtw_txd_fw *) + malloc(sizeof(struct mtw_txd_fw), + M_USBDEV, M_NOWAIT | M_ZERO); + } + MTW_LOCK(sc); + sc->sc_idx = 0; + mbufq_init(&sc->sc_snd, ifqmaxlen); + + /*enable WLAN core */ + if ((error = mtw_wlan_enable(sc, 1)) != 0) { + device_printf(sc->sc_dev, "could not enable WLAN core\n"); + return (ENXIO); + } + + /* wait for the chip to settle */ + DELAY(100); + for (ntries = 0; ntries < 100; ntries++) { + if (mtw_read(sc, MTW_ASIC_VER, &ver) != 0) { + goto detach; + } + if (ver != 0 && ver != 0xffffffff) + break; + DELAY(10); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "timeout waiting for NIC to initialize\n"); + goto detach; + } + sc->asic_ver = ver >> 16; + sc->asic_rev = ver & 0xffff; + DELAY(100); + if (sc->asic_ver != 0x7601) { + device_printf(sc->sc_dev, + "Your revision 0x04%x is not supported yet\n", + sc->asic_rev); + goto detach; + } + + mtw_load_microcode(sc); + ret = msleep(&sc->fwloading, &sc->sc_mtx, 0, "fwload", 3 * hz); + if (ret == EWOULDBLOCK || sc->fwloading != 1) { + device_printf(sc->sc_dev, + "timeout waiting for MCU to initialize\n"); + goto detach; + } + + sc->sc_srom_read = mtw_efuse_read_2; + /* retrieve RF rev. no and various other things from EEPROM */ + mtw_read_eeprom(sc); + + device_printf(sc->sc_dev, + "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", + sc->asic_ver, sc->mac_rev, mtw_get_rf(sc->rf_rev), sc->ntxchains, + sc->nrxchains, ether_sprintf(ic->ic_macaddr)); + DELAY(100); + + //mtw_set_leds(sc,5); + // mtw_mcu_radio(sc,0x31,0); + MTW_UNLOCK(sc); + + + ic->ic_softc = sc; + ic->ic_name = device_get_nameunit(self); + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ + + ic->ic_caps = IEEE80211_C_STA | /* station mode supported */ + IEEE80211_C_MONITOR | /* monitor mode supported */ + IEEE80211_C_IBSS | + IEEE80211_C_HOSTAP | + IEEE80211_C_WDS | /* 4-address traffic works */ + IEEE80211_C_MBSS | + IEEE80211_C_SHPREAMBLE | /* short preamble supported */ + IEEE80211_C_SHSLOT | /* short slot time supported */ + IEEE80211_C_WME | /* WME */ + IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ + device_printf(sc->sc_dev, "[HT] Enabling 802.11n\n"); + ic->ic_htcaps = IEEE80211_HTC_HT + | IEEE80211_HTC_AMPDU + | IEEE80211_HTC_AMSDU + | IEEE80211_HTCAP_MAXAMSDU_3839 + | IEEE80211_HTCAP_SMPS_OFF; + + ic->ic_rxstream = sc->nrxchains; + ic->ic_txstream = sc->ntxchains; + + ic->ic_cryptocaps = IEEE80211_CRYPTO_WEP | IEEE80211_CRYPTO_AES_CCM | + IEEE80211_CRYPTO_AES_OCB | IEEE80211_CRYPTO_TKIP | + IEEE80211_CRYPTO_TKIPMIC; + + ic->ic_flags |= IEEE80211_F_DATAPAD; + ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; + + mtw_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, + ic->ic_channels); + + ieee80211_ifattach(ic); + + ic->ic_scan_start = mtw_scan_start; + ic->ic_scan_end = mtw_scan_end; + ic->ic_set_channel = mtw_set_channel; + ic->ic_getradiocaps = mtw_getradiocaps; + ic->ic_node_alloc = mtw_node_alloc; + ic->ic_newassoc = mtw_newassoc; + ic->ic_update_mcast = mtw_update_mcast; + ic->ic_updateslot = mtw_updateslot; + ic->ic_wme.wme_update = mtw_wme_update; + ic->ic_raw_xmit = mtw_raw_xmit; + ic->ic_update_promisc = mtw_update_promisc; + ic->ic_vap_create = mtw_vap_create; + ic->ic_vap_delete = mtw_vap_delete; + ic->ic_transmit = mtw_transmit; + ic->ic_parent = mtw_parent; + + ic->ic_update_chw = mtw_update_chw; + ic->ic_ampdu_enable = mtw_ampdu_enable; + + ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, + sizeof(sc->sc_txtap), MTW_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + MTW_RX_RADIOTAP_PRESENT); + TASK_INIT(&sc->cmdq_task, 0, mtw_cmdq_cb, sc); + TASK_INIT(&sc->ratectl_task, 0, mtw_ratectl_cb, sc); + usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0); + + if (bootverbose) + ieee80211_announce(ic); + + return (0); + +detach: + MTW_UNLOCK(sc); + mtw_detach(self); + return (ENXIO); +} + +static void +mtw_drain_mbufq(struct mtw_softc *sc) +{ + struct mbuf *m; + struct ieee80211_node *ni; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + 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); + } +} + +static int +mtw_detach(device_t self) +{ + struct mtw_softc *sc = device_get_softc(self); + struct ieee80211com *ic = &sc->sc_ic; + int i; + MTW_LOCK(sc); + mtw_reset(sc); + DELAY(10000); + sc->sc_detached = 1; + MTW_UNLOCK(sc); + + + /* stop all USB transfers */ + for (i = 0; i < MTW_N_XFER; i++) + usbd_transfer_drain(sc->sc_xfer[i]); + + MTW_LOCK(sc); + sc->ratectl_run = MTW_RATECTL_OFF; + sc->cmdq_run = sc->cmdq_key_set = MTW_CMDQ_ABORT; + + /* free TX list, if any */ + if (ic->ic_nrunning > 0) + for (i = 0; i < MTW_EP_QUEUES; i++) + mtw_unsetup_tx_list(sc, &sc->sc_epq[i]); + + /* Free TX queue */ + mtw_drain_mbufq(sc); + MTW_UNLOCK(sc); + if (sc->sc_ic.ic_softc == sc) { + /* drain tasks */ + usb_callout_drain(&sc->ratectl_ch); + ieee80211_draintask(ic, &sc->cmdq_task); + ieee80211_draintask(ic, &sc->ratectl_task); + ieee80211_ifdetach(ic); + } + for (i = 0; i < 4; i++) { + free(sc->txd_fw[i], M_USBDEV); + } +#ifndef __HAIKU__ + firmware_unregister("/mediatek/mt7601u"); +#endif + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static struct ieee80211vap * +mtw_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 mtw_softc *sc = ic->ic_softc; + struct mtw_vap *rvp; + struct ieee80211vap *vap; + int i; + + if (sc->rvp_cnt >= MTW_VAP_MAX) { + device_printf(sc->sc_dev, "number of VAPs maxed out\n"); + return (NULL); + } + + switch (opmode) { + case IEEE80211_M_STA: + /* enable s/w bmiss handling for sta mode */ + flags |= IEEE80211_CLONE_NOBEACONS; + /* fall though */ + case IEEE80211_M_IBSS: + case IEEE80211_M_MONITOR: + case IEEE80211_M_HOSTAP: + case IEEE80211_M_MBSS: + /* other than WDS vaps, only one at a time */ + if (!TAILQ_EMPTY(&ic->ic_vaps)) + return (NULL); + break; + case IEEE80211_M_WDS: + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + if (vap->iv_opmode != IEEE80211_M_HOSTAP) + continue; + /* WDS vap's always share the local mac address. */ + flags &= ~IEEE80211_CLONE_BSSID; + break; + } + if (vap == NULL) { + device_printf(sc->sc_dev, + "wds only supported in ap mode\n"); + return (NULL); + } + break; + default: + device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); + return (NULL); + } + + rvp = malloc(sizeof(struct mtw_vap), M_80211_VAP, M_WAITOK | M_ZERO); + vap = &rvp->vap; + + if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid) != + 0) { + /* out of memory */ + free(rvp, M_80211_VAP); + return (NULL); + } + + vap->iv_update_beacon = mtw_update_beacon; + vap->iv_max_aid = MTW_WCID_MAX; + + /* + * The linux rt2800 driver limits 1 stream devices to a 32KB + * RX AMPDU. + */ + if (ic->ic_rxstream > 1) + vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K; + else + vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K; + vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_2; /* 2uS */ + + /* + * To delete the right key from h/w, we need wcid. + * Luckily, there is unused space in ieee80211_key{}, wk_pad, + * and matching wcid will be written into there. So, cast + * some spells to remove 'const' from ieee80211_key{} + */ + vap->iv_key_delete = (void *)mtw_key_delete; + vap->iv_key_set = (void *)mtw_key_set; + + // override state transition machine + rvp->newstate = vap->iv_newstate; + vap->iv_newstate = mtw_newstate; + if (opmode == IEEE80211_M_IBSS) { + rvp->recv_mgmt = vap->iv_recv_mgmt; + vap->iv_recv_mgmt = mtw_recv_mgmt; + } + + ieee80211_ratectl_init(vap); + ieee80211_ratectl_setinterval(vap, 1000); // 1 second + + /* complete setup */ + ieee80211_vap_attach(vap, mtw_media_change, ieee80211_media_status, + mac); + + /* make sure id is always unique */ + for (i = 0; i < MTW_VAP_MAX; i++) { + if ((sc->rvp_bmap & 1 << i) == 0) { + sc->rvp_bmap |= 1 << i; + rvp->rvp_id = i; + break; + } + } + if (sc->rvp_cnt++ == 0) + ic->ic_opmode = opmode; + + if (opmode == IEEE80211_M_HOSTAP) + sc->cmdq_run = MTW_CMDQ_GO; + + MTW_DPRINTF(sc, MTW_DEBUG_STATE, "rvp_id=%d bmap=%x rvp_cnt=%d\n", + rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); + + return (vap); +} + +static void +mtw_vap_delete(struct ieee80211vap *vap) +{ + struct mtw_vap *rvp = MTW_VAP(vap); + struct ieee80211com *ic; + struct mtw_softc *sc; + uint8_t rvp_id; + + if (vap == NULL) + return; + + ic = vap->iv_ic; + sc = ic->ic_softc; + + MTW_LOCK(sc); + m_freem(rvp->beacon_mbuf); + rvp->beacon_mbuf = NULL; + + rvp_id = rvp->rvp_id; + sc->ratectl_run &= ~(1 << rvp_id); + sc->rvp_bmap &= ~(1 << rvp_id); + mtw_set_region_4(sc, MTW_SKEY(rvp_id, 0), 0, 256); + mtw_set_region_4(sc, (0x7800 + (rvp_id) * 512), 0, 512); + --sc->rvp_cnt; + + MTW_DPRINTF(sc, MTW_DEBUG_STATE, + "vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", vap, rvp_id, sc->rvp_bmap, + sc->rvp_cnt); + + MTW_UNLOCK(sc); + + ieee80211_ratectl_deinit(vap); + ieee80211_vap_detach(vap); + free(rvp, M_80211_VAP); +} + +/* + * There are numbers of functions need to be called in context thread. + * Rather than creating taskqueue event for each of those functions, + * here is all-for-one taskqueue callback function. This function + * guarantees deferred functions are executed in the same order they + * were enqueued. + * '& MTW_CMDQ_MASQ' is to loop cmdq[]. + */ +static void +mtw_cmdq_cb(void *arg, int pending) +{ + struct mtw_softc *sc = arg; + uint8_t i; + /* call cmdq[].func locked */ + MTW_LOCK(sc); + for (i = sc->cmdq_exec; sc->cmdq[i].func && pending; + i = sc->cmdq_exec, pending--) { + MTW_DPRINTF(sc, MTW_DEBUG_CMD, "cmdq_exec=%d pending=%d\n", i, + pending); + if (sc->cmdq_run == MTW_CMDQ_GO) { + /* + * If arg0 is NULL, callback func needs more + * than one arg. So, pass ptr to cmdq struct. + */ + if (sc->cmdq[i].arg0) + sc->cmdq[i].func(sc->cmdq[i].arg0); + else + sc->cmdq[i].func(&sc->cmdq[i]); + } + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].func = NULL; + sc->cmdq_exec++; + sc->cmdq_exec &= MTW_CMDQ_MASQ; + } + MTW_UNLOCK(sc); +} + +static void +mtw_setup_tx_list(struct mtw_softc *sc, struct mtw_endpoint_queue *pq) +{ + struct mtw_tx_data *data; + + memset(pq, 0, sizeof(*pq)); + + STAILQ_INIT(&pq->tx_qh); + STAILQ_INIT(&pq->tx_fh); + + for (data = &pq->tx_data[0]; data < &pq->tx_data[MTW_TX_RING_COUNT]; + data++) { + data->sc = sc; + STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); + } + pq->tx_nfree = MTW_TX_RING_COUNT; +} + +static void +mtw_unsetup_tx_list(struct mtw_softc *sc, struct mtw_endpoint_queue *pq) +{ + struct mtw_tx_data *data; + /* make sure any subsequent use of the queues will fail */ + pq->tx_nfree = 0; + + STAILQ_INIT(&pq->tx_fh); + STAILQ_INIT(&pq->tx_qh); + + /* free up all node references and mbufs */ + for (data = &pq->tx_data[0]; data < &pq->tx_data[MTW_TX_RING_COUNT]; + data++) { + if (data->m != NULL) { + m_freem(data->m); + data->m = NULL; + } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; + } + } +} + +static int +mtw_write_ivb(struct mtw_softc *sc, void *buf, uint16_t len) +{ + usb_device_request_t req; + uint16_t actlen; + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = MTW_RESET; + USETW(req.wValue, 0x12); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + + int error = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, buf, + 0, &actlen, 1000); + + return (error); +} + +static int +mtw_write_cfg(struct mtw_softc *sc, uint16_t reg, uint32_t val) +{ + usb_device_request_t req; + int error; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = MTW_WRITE_CFG; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, 4); + val = htole32(val); + error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &val); + return (error); +} + +static int +mtw_usb_dma_write(struct mtw_softc *sc, uint32_t val) +{ + // if (sc->asic_ver == 0x7612) + // return mtw_write_cfg(sc, MTW_USB_U3DMA_CFG, val); + // else + return (mtw_write(sc, MTW_USB_DMA_CFG, val)); +} + +static void +mtw_ucode_setup(struct mtw_softc *sc) +{ + + mtw_usb_dma_write(sc, (MTW_USB_TX_EN | MTW_USB_RX_EN)); + mtw_write(sc, MTW_FCE_PSE_CTRL, 1); + mtw_write(sc, MTW_TX_CPU_FCE_BASE, 0x400230); + mtw_write(sc, MTW_TX_CPU_FCE_MAX_COUNT, 1); + mtw_write(sc, MTW_MCU_FW_IDX, 1); + mtw_write(sc, MTW_FCE_PDMA, 0x44); + mtw_write(sc, MTW_FCE_SKIP_FS, 3); +} +static int +mtw_ucode_write(struct mtw_softc *sc, const uint8_t *fw, const uint8_t *ivb, + int32_t len, uint32_t offset) +{ + + // struct usb_attach_arg *uaa = device_get_ivars(sc->sc_dev); +#if 0 // firmware not tested + + if (sc->asic_ver == 0x7612 && offset >= 0x90000) + blksz = 0x800; /* MT7612 ROM Patch */ + + xfer = usbd_alloc_xfer(sc->sc_udev); + if (xfer == NULL) { + error = ENOMEM; + goto fail; + } + buf = usbd_alloc_buffer(xfer, blksz + 12); + if (buf == NULL) { + error = ENOMEM; + goto fail; + } +#endif + + + + int mlen; + int idx = 0; + + mlen = 0x2c44; + + while (len > 0) { + + if (len < 0x2c44 && len > 0) { + mlen = len; + } + + sc->txd_fw[idx]->len = htole16(mlen); + sc->txd_fw[idx]->flags = htole16(MTW_TXD_DATA | MTW_TXD_MCU); + + memcpy(&sc->txd_fw[idx]->fw, fw, mlen); + // memcpy(&txd[1], fw, mlen); + // memset(&txd[1] + mlen, 0, MTW_DMA_PAD); + // mtw_write_cfg(sc, MTW_MCU_DMA_ADDR, offset + //+sent); 1mtw_write_cfg(sc, MTW_MCU_DMA_LEN, (mlen << 16)); + + // sc->sc_fw_data[idx]->len=htole16(mlen); + + // memcpy(tmpbuf,fw,mlen); + // memset(tmpbuf+mlen,0,MTW_DMA_PAD); + // memcpy(sc->sc_fw_data[idx].buf, fw, mlen); + + fw += mlen; + len -= mlen; + // sent+=mlen; + idx++; + } + sc->sc_sent = 0; + memcpy(sc->sc_ivb_1, ivb, MTW_MCU_IVB_LEN); + + usbd_transfer_start(sc->sc_xfer[7]); + + return (0); +} + +static void +mtw_load_microcode(void *arg) +{ + + struct mtw_softc *sc = (struct mtw_softc *)arg; + const struct mtw_ucode_hdr *hdr; + // onst struct mtw_ucode *fw = NULL; + const char *fwname; + size_t size; + int error = 0; + uint32_t tmp, iofs = 0x40; + // int ntries; + int dlen, ilen; + device_printf(sc->sc_dev, "version:0x%hx\n", sc->asic_ver); + /* is firmware already running? */ + mtw_read_cfg(sc, MTW_MCU_DMA_ADDR, &tmp); + if (tmp == MTW_MCU_READY) { + return; + } + if (sc->asic_ver == 0x7612) { + fwname = "mtw-mt7662u_rom_patch"; + + const struct firmware *firmware = firmware_get_flags(fwname,FIRMWARE_GET_NOWARN); + if (firmware == NULL) { + device_printf(sc->sc_dev, + "failed loadfirmware of file %s (error %d)\n", + fwname, error); + return; + } + size = firmware->datasize; + + const struct mtw_ucode *fw = (const struct mtw_ucode *) + firmware->data; + hdr = (const struct mtw_ucode_hdr *)&fw->hdr; + // memcpy(fw,(const unsigned char*)firmware->data + + // 0x1e,size-0x1e); + ilen = size - 0x1e; + + mtw_ucode_setup(sc); + + if ((error = mtw_ucode_write(sc, firmware->data, fw->ivb, ilen, + 0x90000)) != 0) { + goto fail; + } + mtw_usb_dma_write(sc, 0x00e41814); + } + + fwname = "/mediatek/mt7601u.bin"; + iofs = 0x40; + // dofs = 0; + if (sc->asic_ver == 0x7612) { + fwname = "mtw-mt7662u"; + iofs = 0x80040; + // dofs = 0x110800; + } else if (sc->asic_ver == 0x7610) { + fwname = "mt7610u"; + // dofs = 0x80000; + } + MTW_UNLOCK(sc); + const struct firmware *firmware = firmware_get_flags(fwname, FIRMWARE_GET_NOWARN); + + if (firmware == NULL) { + device_printf(sc->sc_dev, + "failed loadfirmware of file %s (error %d)\n", fwname, + error); + MTW_LOCK(sc); + return; + } + MTW_LOCK(sc); + size = firmware->datasize; + MTW_DPRINTF(sc, MTW_DEBUG_FIRMWARE, "firmware size:%zu\n", size); + const struct mtw_ucode *fw = (const struct mtw_ucode *)firmware->data; + + if (size < sizeof(struct mtw_ucode_hdr)) { + device_printf(sc->sc_dev, "firmware header too short\n"); + goto fail; + } + + hdr = (const struct mtw_ucode_hdr *)&fw->hdr; + + if (size < sizeof(struct mtw_ucode_hdr) + le32toh(hdr->ilm_len) + + le32toh(hdr->dlm_len)) { + device_printf(sc->sc_dev, "firmware payload too short\n"); + goto fail; + } + + ilen = le32toh(hdr->ilm_len) - MTW_MCU_IVB_LEN; + dlen = le32toh(hdr->dlm_len); + + if (ilen > size || dlen > size) { + device_printf(sc->sc_dev, "firmware payload too large\n"); + goto fail; + } + + mtw_write(sc, MTW_FCE_PDMA, 0); + mtw_write(sc, MTW_FCE_PSE_CTRL, 0); + mtw_ucode_setup(sc); + + if ((error = mtw_ucode_write(sc, fw->data, fw->ivb, ilen, iofs)) != 0) + device_printf(sc->sc_dev, "Could not write ucode errro=%d\n", + error); + + device_printf(sc->sc_dev, "loaded firmware ver %.8x %.8x %s\n", + le32toh(hdr->fw_ver), le32toh(hdr->build_ver), hdr->build_time); + +#ifndef __HAIKU__ + return; +fail: + return; +#else +fail: + firmware_put(firmware, 0); + return; +#endif +} +static usb_error_t +mtw_do_request(struct mtw_softc *sc, struct usb_device_request *req, void *data) +{ + usb_error_t err; + int ntries = 5; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + while (ntries--) { + err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, req, data, + 0, NULL, 2000); // ms seconds + if (err == 0) + break; + MTW_DPRINTF(sc, MTW_DEBUG_USB, + "Control request failed, %s (retrying)\n", + usbd_errstr(err)); + mtw_delay(sc, 10); + } + return (err); +} + +static int +mtw_read(struct mtw_softc *sc, uint16_t reg, uint32_t *val) +{ + uint32_t tmp; + int error; + + error = mtw_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); + if (error == 0) + *val = le32toh(tmp); + else + *val = 0xffffffff; + return (error); +} + +static int +mtw_read_region_1(struct mtw_softc *sc, uint16_t reg, uint8_t *buf, int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = MTW_READ_REGION_1; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, len); + + return (mtw_do_request(sc, &req, buf)); +} + +static int +mtw_write_2(struct mtw_softc *sc, uint16_t reg, uint16_t val) +{ + + usb_device_request_t req; + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = MTW_WRITE_2; + USETW(req.wValue, val); + USETW(req.wIndex, reg); + USETW(req.wLength, 0); + return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); +} + +static int +mtw_write(struct mtw_softc *sc, uint16_t reg, uint32_t val) +{ + + int error; + + if ((error = mtw_write_2(sc, reg, val & 0xffff)) == 0) { + + error = mtw_write_2(sc, reg + 2, val >> 16); + } + + return (error); +} + +static int +mtw_write_region_1(struct mtw_softc *sc, uint16_t reg, uint8_t *buf, int len) +{ + + usb_device_request_t req; + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = MTW_WRITE_REGION_1; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, len); + return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, buf)); +} + +static int +mtw_set_region_4(struct mtw_softc *sc, uint16_t reg, uint32_t val, int count) +{ + int i, error = 0; + + KASSERT((count & 3) == 0, ("mte_set_region_4: Invalid data length.\n")); + for (i = 0; i < count && error == 0; i += 4) + error = mtw_write(sc, reg + i, val); + return (error); +} + +static int +mtw_efuse_read_2(struct mtw_softc *sc, uint16_t addr, uint16_t *val) +{ + + uint32_t tmp; + uint16_t reg; + int error, ntries; + + if ((error = mtw_read(sc, MTW_EFUSE_CTRL, &tmp)) != 0) + return (error); + + addr *= 2; + /* + * Read one 16-byte block into registers EFUSE_DATA[0-3]: + * DATA0: 3 2 1 0 + * DATA1: 7 6 5 4 + * DATA2: B A 9 8 + * DATA3: F E D C + */ + tmp &= ~(MTW_EFSROM_MODE_MASK | MTW_EFSROM_AIN_MASK); + tmp |= (addr & ~0xf) << MTW_EFSROM_AIN_SHIFT | MTW_EFSROM_KICK; + mtw_write(sc, MTW_EFUSE_CTRL, tmp); + for (ntries = 0; ntries < 100; ntries++) { + if ((error = mtw_read(sc, MTW_EFUSE_CTRL, &tmp)) != 0) + return (error); + if (!(tmp & MTW_EFSROM_KICK)) + break; + DELAY(2); + } + if (ntries == 100) + return (ETIMEDOUT); + + if ((tmp & MTW_EFUSE_AOUT_MASK) == MTW_EFUSE_AOUT_MASK) { + *val = 0xffff; // address not found + return (0); + } +// determine to which 32-bit register our 16-bit word belongs + reg = MTW_EFUSE_DATA0 + (addr & 0xc); + if ((error = mtw_read(sc, reg, &tmp)) != 0) + return (error); + + *val = (addr & 2) ? tmp >> 16 : tmp & 0xffff; + return (0); +} + +static __inline int +mtw_srom_read(struct mtw_softc *sc, uint16_t addr, uint16_t *val) +{ + /* either eFUSE ROM or EEPROM */ + return (sc->sc_srom_read(sc, addr, val)); +} + +static int +mtw_bbp_read(struct mtw_softc *sc, uint8_t reg, uint8_t *val) +{ + uint32_t tmp; + int ntries, error; + + for (ntries = 0; ntries < 10; ntries++) { + if ((error = mtw_read(sc, MTW_BBP_CSR, &tmp)) != 0) + return (error); + if (!(tmp & MTW_BBP_CSR_KICK)) + break; + } + if (ntries == 10) + return (ETIMEDOUT); + + tmp = MTW_BBP_CSR_READ | MTW_BBP_CSR_KICK | reg << 8; + if ((error = mtw_write(sc, MTW_BBP_CSR, tmp)) != 0) + return (error); + + for (ntries = 0; ntries < 10; ntries++) { + if ((error = mtw_read(sc, MTW_BBP_CSR, &tmp)) != 0) + return (error); + if (!(tmp & MTW_BBP_CSR_KICK)) + break; + } + if (ntries == 10) + return (ETIMEDOUT); + + *val = tmp & 0xff; + return (0); +} + +static int +mtw_bbp_write(struct mtw_softc *sc, uint8_t reg, uint8_t val) +{ + uint32_t tmp; + int ntries, error; + + for (ntries = 0; ntries < 10; ntries++) { + if ((error = mtw_read(sc, MTW_BBP_CSR, &tmp)) != 0) + return (error); + if (!(tmp & MTW_BBP_CSR_KICK)) + break; + } + if (ntries == 10) + return (ETIMEDOUT); + + tmp = MTW_BBP_CSR_KICK | reg << 8 | val; + return (mtw_write(sc, MTW_BBP_CSR, tmp)); +} + +static int +mtw_mcu_cmd(struct mtw_softc *sc, u_int8_t cmd, void *buf, int len) +{ + sc->sc_idx = 0; + sc->txd_fw[sc->sc_idx]->len = htole16( + len + 8); + sc->txd_fw[sc->sc_idx]->flags = htole16(MTW_TXD_CMD | MTW_TXD_MCU | + (cmd & 0x1f) << MTW_TXD_CMD_SHIFT | (0 & 0xf)); + + memset(&sc->txd_fw[sc->sc_idx]->fw, 0, 2004); + memcpy(&sc->txd_fw[sc->sc_idx]->fw, buf, len); + usbd_transfer_start(sc->sc_xfer[7]); + return (0); +} + +/* + * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. + * Used to adjust per-rate Tx power registers. + */ +static __inline uint32_t +b4inc(uint32_t b32, int8_t delta) +{ + int8_t i, b4; + + for (i = 0; i < 8; i++) { + b4 = b32 & 0xf; + b4 += delta; + if (b4 < 0) + b4 = 0; + else if (b4 > 0xf) + b4 = 0xf; + b32 = b32 >> 4 | b4 << 28; + } + return (b32); +} +static void +mtw_get_txpower(struct mtw_softc *sc) +{ + uint16_t val; + int i; + + /* Read power settings for 2GHz channels. */ + for (i = 0; i < 14; i += 2) { + mtw_srom_read(sc, MTW_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); + sc->txpow1[i + 0] = (int8_t)(val & 0xff); + sc->txpow1[i + 1] = (int8_t)(val >> 8); + mtw_srom_read(sc, MTW_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); + sc->txpow2[i + 0] = (int8_t)(val & 0xff); + sc->txpow2[i + 1] = (int8_t)(val >> 8); + } + /* Fix broken Tx power entries. */ + for (i = 0; i < 14; i++) { + if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27) + sc->txpow1[i] = 5; + if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27) + sc->txpow2[i] = 5; + MTW_DPRINTF(sc, MTW_DEBUG_TXPWR, + "chan %d: power1=%d, power2=%d\n", mt7601_rf_chan[i].chan, + sc->txpow1[i], sc->txpow2[i]); + } +} + +struct ieee80211_node * +mtw_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + return (malloc(sizeof(struct mtw_node), M_80211_NODE, + M_NOWAIT | M_ZERO)); +} +static int +mtw_read_eeprom(struct mtw_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + int8_t delta_2ghz, delta_5ghz; + uint16_t val; + int ridx, ant; + + sc->sc_srom_read = mtw_efuse_read_2; + + /* read RF information */ + mtw_srom_read(sc, MTW_EEPROM_CHIPID, &val); + sc->rf_rev = val; + mtw_srom_read(sc, MTW_EEPROM_ANTENNA, &val); + sc->ntxchains = (val >> 4) & 0xf; + sc->nrxchains = val & 0xf; + MTW_DPRINTF(sc, MTW_DEBUG_ROM, "EEPROM RF rev=0x%02x chains=%dT%dR\n", + sc->rf_rev, sc->ntxchains, sc->nrxchains); + + /* read ROM version */ + mtw_srom_read(sc, MTW_EEPROM_VERSION, &val); + MTW_DPRINTF(sc, MTW_DEBUG_ROM, "EEPROM rev=%d, FAE=%d\n", val & 0xff, + val >> 8); + + /* read MAC address */ + mtw_srom_read(sc, MTW_EEPROM_MAC01, &val); + ic->ic_macaddr[0] = val & 0xff; + ic->ic_macaddr[1] = val >> 8; + mtw_srom_read(sc, MTW_EEPROM_MAC23, &val); + ic->ic_macaddr[2] = val & 0xff; + ic->ic_macaddr[3] = val >> 8; + mtw_srom_read(sc, MTW_EEPROM_MAC45, &val); + ic->ic_macaddr[4] = val & 0xff; + ic->ic_macaddr[5] = val >> 8; +#if 0 + printf("eFUSE ROM\n00: "); + for (int i = 0; i < 256; i++) { + if (((i % 8) == 0) && i > 0) + printf("\n%02x: ", i); + mtw_srom_read(sc, i, &val); + printf(" %04x", val); + } + printf("\n"); +#endif + /* check if RF supports automatic Tx access gain control */ + mtw_srom_read(sc, MTW_EEPROM_CONFIG, &val); + device_printf(sc->sc_dev, "EEPROM CFG 0x%04x\n", val); + if ((val & 0xff) != 0xff) { + sc->ext_5ghz_lna = (val >> 3) & 1; + sc->ext_2ghz_lna = (val >> 2) & 1; + /* check if RF supports automatic Tx access gain control */ + sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; + /* check if we have a hardware radio switch */ + sc->rfswitch = val & 1; + } + + /* read RF frequency offset from EEPROM */ + mtw_srom_read(sc, MTW_EEPROM_FREQ_OFFSET, &val); + if ((val & 0xff) != 0xff) + sc->rf_freq_offset = val; + else + sc->rf_freq_offset = 0; + MTW_DPRINTF(sc, MTW_DEBUG_ROM, "frequency offset 0x%x\n", + sc->rf_freq_offset); + + /* Read Tx power settings. */ + mtw_get_txpower(sc); + + /* read Tx power compensation for each Tx rate */ + mtw_srom_read(sc, MTW_EEPROM_DELTAPWR, &val); + delta_2ghz = delta_5ghz = 0; + if ((val & 0xff) != 0xff && (val & 0x80)) { + delta_2ghz = val & 0xf; + if (!(val & 0x40)) /* negative number */ + delta_2ghz = -delta_2ghz; + } + val >>= 8; + if ((val & 0xff) != 0xff && (val & 0x80)) { + delta_5ghz = val & 0xf; + if (!(val & 0x40)) /* negative number */ + delta_5ghz = -delta_5ghz; + } + MTW_DPRINTF(sc, MTW_DEBUG_ROM | MTW_DEBUG_TXPWR, + "power compensation=%d (2GHz), %d (5GHz)\n", delta_2ghz, + delta_5ghz); + + for (ridx = 0; ridx < 5; ridx++) { + uint32_t reg; + + mtw_srom_read(sc, MTW_EEPROM_RPWR + ridx * 2, &val); + reg = val; + mtw_srom_read(sc, MTW_EEPROM_RPWR + ridx * 2 + 1, &val); + reg |= (uint32_t)val << 16; + + sc->txpow20mhz[ridx] = reg; + sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); + sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); + + MTW_DPRINTF(sc, MTW_DEBUG_ROM | MTW_DEBUG_TXPWR, + "ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " + "40MHz/5GHz=0x%08x\n", + ridx, sc->txpow20mhz[ridx], sc->txpow40mhz_2ghz[ridx], + sc->txpow40mhz_5ghz[ridx]); + } + + /* read RSSI offsets and LNA gains from EEPROM */ + val = 0; + mtw_srom_read(sc, MTW_EEPROM_RSSI1_2GHZ, &val); + sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ + sc->rssi_2ghz[1] = val >> 8; /* Ant B */ + mtw_srom_read(sc, MTW_EEPROM_RSSI2_2GHZ, &val); + /* + * On RT3070 chips (limited to 2 Rx chains), this ROM + * field contains the Tx mixer gain for the 2GHz band. + */ + if ((val & 0xff) != 0xff) + sc->txmixgain_2ghz = val & 0x7; + MTW_DPRINTF(sc, MTW_DEBUG_ROM, "tx mixer gain=%u (2GHz)\n", + sc->txmixgain_2ghz); + sc->lna[2] = val >> 8; /* channel group 2 */ + mtw_srom_read(sc, MTW_EEPROM_RSSI1_5GHZ, &val); + sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ + sc->rssi_5ghz[1] = val >> 8; /* Ant B */ + mtw_srom_read(sc, MTW_EEPROM_RSSI2_5GHZ, &val); + sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ + + sc->lna[3] = val >> 8; /* channel group 3 */ + + mtw_srom_read(sc, MTW_EEPROM_LNA, &val); + sc->lna[0] = val & 0xff; /* channel group 0 */ + sc->lna[1] = val >> 8; /* channel group 1 */ + MTW_DPRINTF(sc, MTW_DEBUG_ROM, "LNA0 0x%x\n", sc->lna[0]); + + /* fix broken 5GHz LNA entries */ + if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { + MTW_DPRINTF(sc, MTW_DEBUG_ROM, + "invalid LNA for channel group %d\n", 2); + sc->lna[2] = sc->lna[1]; + } + if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { + MTW_DPRINTF(sc, MTW_DEBUG_ROM, + "invalid LNA for channel group %d\n", 3); + sc->lna[3] = sc->lna[1]; + } + + /* fix broken RSSI offset entries */ + for (ant = 0; ant < 3; ant++) { + if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { + MTW_DPRINTF(sc, MTW_DEBUG_ROM, + "invalid RSSI%d offset: %d (2GHz)\n", ant + 1, + sc->rssi_2ghz[ant]); + sc->rssi_2ghz[ant] = 0; + } + if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { + MTW_DPRINTF(sc, MTW_DEBUG_ROM, + "invalid RSSI%d offset: %d (5GHz)\n", ant + 1, + sc->rssi_5ghz[ant]); + sc->rssi_5ghz[ant] = 0; + } + } + return (0); +} +static int +mtw_media_change(if_t ifp) +{ + struct ieee80211vap *vap = if_getsoftc(ifp); + struct ieee80211com *ic = vap->iv_ic; + const struct ieee80211_txparam *tp; + struct mtw_softc *sc = ic->ic_softc; + uint8_t rate, ridx; + + MTW_LOCK(sc); + ieee80211_media_change(ifp); + //tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; + tp = &vap->iv_txparms[ic->ic_curmode]; + if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + struct ieee80211_node *ni; + struct mtw_node *rn; + /* XXX TODO: methodize with MCS rates */ + rate = + ic->ic_sup_rates[ic->ic_curmode].rs_rates[tp->ucastrate] & + IEEE80211_RATE_VAL; + for (ridx = 0; ridx < MTW_RIDX_MAX; ridx++) { + if (rt2860_rates[ridx].rate == rate) + break; + } + ni = ieee80211_ref_node(vap->iv_bss); + rn = MTW_NODE(ni); + rn->fix_ridx = ridx; + + MTW_DPRINTF(sc, MTW_DEBUG_RATE, "rate=%d, fix_ridx=%d\n", rate, + rn->fix_ridx); + ieee80211_free_node(ni); + } + MTW_UNLOCK(sc); + + return (0); +} + +void +mtw_set_leds(struct mtw_softc *sc, uint16_t which) +{ + struct mtw_mcu_cmd_8 cmd; + cmd.func = htole32(0x1); + cmd.val = htole32(which); + mtw_mcu_cmd(sc, CMD_LED_MODE, &cmd, sizeof(struct mtw_mcu_cmd_8)); +} +static void +mtw_abort_tsf_sync(struct mtw_softc *sc) +{ + uint32_t tmp; + + mtw_read(sc, MTW_BCN_TIME_CFG, &tmp); + tmp &= ~(MTW_BCN_TX_EN | MTW_TSF_TIMER_EN | MTW_TBTT_TIMER_EN); + mtw_write(sc, MTW_BCN_TIME_CFG, tmp); +} +static int +mtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + const struct ieee80211_txparam *tp; + struct ieee80211com *ic = vap->iv_ic; + struct mtw_softc *sc = ic->ic_softc; + struct mtw_vap *rvp = MTW_VAP(vap); + enum ieee80211_state ostate; + uint32_t sta[3]; + uint8_t ratectl = 0; + uint8_t restart_ratectl = 0; + uint8_t bid = 1 << rvp->rvp_id; + + + ostate = vap->iv_state; + MTW_DPRINTF(sc, MTW_DEBUG_STATE, "%s -> %s\n", + ieee80211_state_name[ostate], ieee80211_state_name[nstate]); + IEEE80211_UNLOCK(ic); + MTW_LOCK(sc); + ratectl = sc->ratectl_run; /* remember current state */ + usb_callout_stop(&sc->ratectl_ch); + sc->ratectl_run = MTW_RATECTL_OFF; + if (ostate == IEEE80211_S_RUN) { + /* turn link LED off */ + } + + switch (nstate) { + case IEEE80211_S_INIT: + restart_ratectl = 1; + if (ostate != IEEE80211_S_RUN) + break; + + ratectl &= ~bid; + sc->runbmap &= ~bid; + + /* abort TSF synchronization if there is no vap running */ + if (--sc->running == 0) + mtw_abort_tsf_sync(sc); + break; + + case IEEE80211_S_RUN: + if (!(sc->runbmap & bid)) { + if (sc->running++) + restart_ratectl = 1; + sc->runbmap |= bid; + } + + m_freem(rvp->beacon_mbuf); + rvp->beacon_mbuf = NULL; + + switch (vap->iv_opmode) { + case IEEE80211_M_HOSTAP: + case IEEE80211_M_MBSS: + sc->ap_running |= bid; + ic->ic_opmode = vap->iv_opmode; + mtw_update_beacon_cb(vap); + break; + case IEEE80211_M_IBSS: + sc->adhoc_running |= bid; + if (!sc->ap_running) + ic->ic_opmode = vap->iv_opmode; + mtw_update_beacon_cb(vap); + break; + case IEEE80211_M_STA: + sc->sta_running |= bid; + if (!sc->ap_running && !sc->adhoc_running) + ic->ic_opmode = vap->iv_opmode; + + /* read statistic counters (clear on read) */ + mtw_read_region_1(sc, MTW_TX_STA_CNT0, (uint8_t *)sta, + sizeof sta); + + break; + default: + ic->ic_opmode = vap->iv_opmode; + break; + } + + if (vap->iv_opmode != IEEE80211_M_MONITOR) { + struct ieee80211_node *ni; + + if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { + MTW_UNLOCK(sc); + IEEE80211_LOCK(ic); + return (-1); + } + mtw_updateslot(ic); + mtw_enable_mrr(sc); + mtw_set_txpreamble(sc); + mtw_set_basicrates(sc); + ni = ieee80211_ref_node(vap->iv_bss); + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); + mtw_set_bssid(sc, sc->sc_bssid); + ieee80211_free_node(ni); + mtw_enable_tsf_sync(sc); + + /* enable automatic rate adaptation */ + tp = &vap->iv_txparms[ieee80211_chan2mode( + ic->ic_curchan)]; + if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) + ratectl |= bid; + } else { + mtw_enable_tsf_sync(sc); + } + + break; + default: + MTW_DPRINTF(sc, MTW_DEBUG_STATE, "undefined state\n"); + break; + } + + /* restart amrr for running VAPs */ + if ((sc->ratectl_run = ratectl) && restart_ratectl) { + usb_callout_reset(&sc->ratectl_ch, hz, mtw_ratectl_to, sc); + } + MTW_UNLOCK(sc); + IEEE80211_LOCK(ic); + return (rvp->newstate(vap, nstate, arg)); +} + +static int +mtw_wme_update(struct ieee80211com *ic) +{ + struct chanAccParams chp; + struct mtw_softc *sc = ic->ic_softc; + const struct wmeParams *ac; + int aci, error = 0; + ieee80211_wme_ic_getparams(ic, &chp); + ac = chp.cap_wmeParams; + + MTW_LOCK(sc); + /* update MAC TX configuration registers */ + for (aci = 0; aci < WME_NUM_AC; aci++) { + error = mtw_write(sc, MTW_EDCA_AC_CFG(aci), + ac[aci].wmep_logcwmax << 16 | ac[aci].wmep_logcwmin << 12 | + ac[aci].wmep_aifsn << 8 | ac[aci].wmep_txopLimit); + if (error) + goto err; + } + + /* update SCH/DMA registers too */ + error = mtw_write(sc, MTW_WMM_AIFSN_CFG, + ac[WME_AC_VO].wmep_aifsn << 12 | ac[WME_AC_VI].wmep_aifsn << 8 | + ac[WME_AC_BK].wmep_aifsn << 4 | ac[WME_AC_BE].wmep_aifsn); + if (error) + goto err; + error = mtw_write(sc, MTW_WMM_CWMIN_CFG, + ac[WME_AC_VO].wmep_logcwmin << 12 | + ac[WME_AC_VI].wmep_logcwmin << 8 | + ac[WME_AC_BK].wmep_logcwmin << 4 | ac[WME_AC_BE].wmep_logcwmin); + if (error) + goto err; + error = mtw_write(sc, MTW_WMM_CWMAX_CFG, + ac[WME_AC_VO].wmep_logcwmax << 12 | + ac[WME_AC_VI].wmep_logcwmax << 8 | + ac[WME_AC_BK].wmep_logcwmax << 4 | ac[WME_AC_BE].wmep_logcwmax); + if (error) + goto err; + error = mtw_write(sc, MTW_WMM_TXOP0_CFG, + ac[WME_AC_BK].wmep_txopLimit << 16 | ac[WME_AC_BE].wmep_txopLimit); + if (error) + goto err; + error = mtw_write(sc, MTW_WMM_TXOP1_CFG, + ac[WME_AC_VO].wmep_txopLimit << 16 | ac[WME_AC_VI].wmep_txopLimit); + +err: + MTW_UNLOCK(sc); + if (error) + MTW_DPRINTF(sc, MTW_DEBUG_USB, "WME update failed\n"); + + return (error); +} + +static int +mtw_key_set(struct ieee80211vap *vap, struct ieee80211_key *k) +{ + struct ieee80211com *ic = vap->iv_ic; + struct mtw_softc *sc = ic->ic_softc; + uint32_t i; + + i = MTW_CMDQ_GET(&sc->cmdq_store); + MTW_DPRINTF(sc, MTW_DEBUG_KEY, "cmdq_store=%d\n", i); + sc->cmdq[i].func = mtw_key_set_cb; + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].arg1 = vap; + sc->cmdq[i].k = k; + IEEE80211_ADDR_COPY(sc->cmdq[i].mac, k->wk_macaddr); + ieee80211_runtask(ic, &sc->cmdq_task); + + /* + * To make sure key will be set when hostapd + * calls iv_key_set() before if_init(). + */ + if (vap->iv_opmode == IEEE80211_M_HOSTAP) { + MTW_LOCK(sc); + sc->cmdq_key_set = MTW_CMDQ_GO; + MTW_UNLOCK(sc); + } + + return (1); +} +static void +mtw_key_set_cb(void *arg) +{ + struct mtw_cmdq *cmdq = arg; + struct ieee80211vap *vap = cmdq->arg1; + struct ieee80211_key *k = cmdq->k; + struct ieee80211com *ic = vap->iv_ic; + struct mtw_softc *sc = ic->ic_softc; + struct ieee80211_node *ni; + u_int cipher = k->wk_cipher->ic_cipher; + uint32_t attr; + uint16_t base; + uint8_t mode, wcid, iv[8]; + MTW_LOCK_ASSERT(sc, MA_OWNED); + + if (vap->iv_opmode == IEEE80211_M_HOSTAP) + ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); + else + ni = vap->iv_bss; + + /* map net80211 cipher to RT2860 security mode */ + switch (cipher) { + case IEEE80211_CIPHER_WEP: + if (k->wk_keylen < 8) + mode = MTW_MODE_WEP40; + else + mode = MTW_MODE_WEP104; + break; + case IEEE80211_CIPHER_TKIP: + mode = MTW_MODE_TKIP; + break; + case IEEE80211_CIPHER_AES_CCM: + mode = MTW_MODE_AES_CCMP; + break; + default: + MTW_DPRINTF(sc, MTW_DEBUG_KEY, "undefined case\n"); + return; + } + + if (k->wk_flags & IEEE80211_KEY_GROUP) { + wcid = 0; /* NB: update WCID0 for group keys */ + base = MTW_SKEY(0, k->wk_keyix); + } else { + wcid = (ni != NULL) ? MTW_AID2WCID(ni->ni_associd) : 0; + base = MTW_PKEY(wcid); + } + + if (cipher == IEEE80211_CIPHER_TKIP) { + mtw_write_region_1(sc, base, k->wk_key, 16); + mtw_write_region_1(sc, base + 16, &k->wk_key[24], 8); + mtw_write_region_1(sc, base + 24, &k->wk_key[16], 8); + } else { + /* roundup len to 16-bit: XXX fix write_region_1() instead */ + mtw_write_region_1(sc, base, k->wk_key, + (k->wk_keylen + 1) & ~1); + } + + if (!(k->wk_flags & IEEE80211_KEY_GROUP) || + (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { + /* set initial packet number in IV+EIV */ + if (cipher == IEEE80211_CIPHER_WEP) { + memset(iv, 0, sizeof iv); + iv[3] = vap->iv_def_txkey << 6; + } else { + if (cipher == IEEE80211_CIPHER_TKIP) { + iv[0] = k->wk_keytsc >> 8; + iv[1] = (iv[0] | 0x20) & 0x7f; + iv[2] = k->wk_keytsc; + } else { //CCMP + iv[0] = k->wk_keytsc; + iv[1] = k->wk_keytsc >> 8; + iv[2] = 0; + } + iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; + iv[4] = k->wk_keytsc >> 16; + iv[5] = k->wk_keytsc >> 24; + iv[6] = k->wk_keytsc >> 32; + iv[7] = k->wk_keytsc >> 40; + } + mtw_write_region_1(sc, MTW_IVEIV(wcid), iv, 8); + } + + if (k->wk_flags & IEEE80211_KEY_GROUP) { + /* install group key */ + mtw_read(sc, MTW_SKEY_MODE_0_7, &attr); + attr &= ~(0xf << (k->wk_keyix * 4)); + attr |= mode << (k->wk_keyix * 4); + mtw_write(sc, MTW_SKEY_MODE_0_7, attr); + + if (cipher & (IEEE80211_CIPHER_WEP)) { + mtw_read(sc, MTW_WCID_ATTR(wcid + 1), &attr); + attr = (attr & ~0xf) | (mode << 1); + mtw_write(sc, MTW_WCID_ATTR(wcid + 1), attr); + + mtw_set_region_4(sc, MTW_IVEIV(0), 0, 4); + + mtw_read(sc, MTW_WCID_ATTR(wcid), &attr); + attr = (attr & ~0xf) | (mode << 1); + mtw_write(sc, MTW_WCID_ATTR(wcid), attr); + } + } else { + /* install pairwise key */ + mtw_read(sc, MTW_WCID_ATTR(wcid), &attr); + attr = (attr & ~0xf) | (mode << 1) | MTW_RX_PKEY_EN; + mtw_write(sc, MTW_WCID_ATTR(wcid), attr); + } + k->wk_pad = wcid; +} + +/* + * If wlan is destroyed without being brought down i.e. without + * wlan down or wpa_cli terminate, this function is called after + * vap is gone. Don't refer it. + */ +static void +mtw_key_delete_cb(void *arg) +{ + struct mtw_cmdq *cmdq = arg; + struct mtw_softc *sc = cmdq->arg1; + struct ieee80211_key *k = &cmdq->key; + uint32_t attr; + uint8_t wcid; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + if (k->wk_flags & IEEE80211_KEY_GROUP) { + /* remove group key */ + MTW_DPRINTF(sc, MTW_DEBUG_KEY, "removing group key\n"); + mtw_read(sc, MTW_SKEY_MODE_0_7, &attr); + attr &= ~(0xf << (k->wk_keyix * 4)); + mtw_write(sc, MTW_SKEY_MODE_0_7, attr); + } else { + /* remove pairwise key */ + MTW_DPRINTF(sc, MTW_DEBUG_KEY, "removing key for wcid %x\n", + k->wk_pad); + /* matching wcid was written to wk_pad in mtw_key_set() */ + wcid = k->wk_pad; + mtw_read(sc, MTW_WCID_ATTR(wcid), &attr); + attr &= ~0xf; + mtw_write(sc, MTW_WCID_ATTR(wcid), attr); + } + + k->wk_pad = 0; +} + +/* + * return 0 on error + */ +static int +mtw_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) +{ + struct ieee80211com *ic = vap->iv_ic; + struct mtw_softc *sc = ic->ic_softc; + struct ieee80211_key *k0; + uint32_t i; + if (sc->sc_flags & MTW_RUNNING) + return (1); + + /* + * When called back, key might be gone. So, make a copy + * of some values need to delete keys before deferring. + * But, because of LOR with node lock, cannot use lock here. + * So, use atomic instead. + */ + i = MTW_CMDQ_GET(&sc->cmdq_store); + MTW_DPRINTF(sc, MTW_DEBUG_KEY, "cmdq_store=%d\n", i); + sc->cmdq[i].func = mtw_key_delete_cb; + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].arg1 = sc; + k0 = &sc->cmdq[i].key; + k0->wk_flags = k->wk_flags; + k0->wk_keyix = k->wk_keyix; + /* matching wcid was written to wk_pad in mtw_key_set() */ + k0->wk_pad = k->wk_pad; + ieee80211_runtask(ic, &sc->cmdq_task); + return (1); /* return fake success */ +} + +static void +mtw_ratectl_to(void *arg) +{ + struct mtw_softc *sc = arg; + /* do it in a process context, so it can go sleep */ + ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task); + /* next timeout will be rescheduled in the callback task */ +} + +/* ARGSUSED */ +static void +mtw_ratectl_cb(void *arg, int pending) +{ + + struct mtw_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + if (vap == NULL) + return; + + ieee80211_iterate_nodes(&ic->ic_sta, mtw_iter_func, sc); + + usb_callout_reset(&sc->ratectl_ch, hz, mtw_ratectl_to, sc); + + +} + +static void +mtw_drain_fifo(void *arg) +{ + struct mtw_softc *sc = arg; + uint32_t stat; + uint16_t(*wstat)[3]; + uint8_t wcid, mcs, pid; + int8_t retry; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + for (;;) { + /* drain Tx status FIFO (maxsize = 16) */ + mtw_read(sc, MTW_TX_STAT_FIFO, &stat); + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "tx stat 0x%08x\n", stat); + if (!(stat & MTW_TXQ_VLD)) + break; + + wcid = (stat >> MTW_TXQ_WCID_SHIFT) & 0xff; + + /* if no ACK was requested, no feedback is available */ + if (!(stat & MTW_TXQ_ACKREQ) || wcid > MTW_WCID_MAX || + wcid == 0) + continue; + + /* + * Even though each stat is Tx-complete-status like format, + * the device can poll stats. Because there is no guarantee + * that the referring node is still around when read the stats. + * So that, if we use ieee80211_ratectl_tx_update(), we will + * have hard time not to refer already freed node. + * + * To eliminate such page faults, we poll stats in softc. + * Then, update the rates later with + * ieee80211_ratectl_tx_update(). + */ + wstat = &(sc->wcid_stats[wcid]); + (*wstat)[MTW_TXCNT]++; + if (stat & MTW_TXQ_OK) + (*wstat)[MTW_SUCCESS]++; + else + counter_u64_add(sc->sc_ic.ic_oerrors, 1); + /* + * Check if there were retries, ie if the Tx success rate is + * different from the requested rate. Note that it works only + * because we do not allow rate fallback from OFDM to CCK. + */ + mcs = (stat >> MTW_TXQ_MCS_SHIFT) & 0x7f; + pid = (stat >> MTW_TXQ_PID_SHIFT) & 0xf; + if ((retry = pid - 1 - mcs) > 0) { + (*wstat)[MTW_TXCNT] += retry; + (*wstat)[MTW_RETRY] += retry; + } + } + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "count=%d\n", sc->fifo_cnt); + + sc->fifo_cnt = 0; +} + +static void +mtw_iter_func(void *arg, struct ieee80211_node *ni) +{ + struct mtw_softc *sc = arg; + MTW_LOCK(sc); + struct ieee80211_ratectl_tx_stats *txs = &sc->sc_txs; + struct ieee80211vap *vap = ni->ni_vap; + struct mtw_node *rn = MTW_NODE(ni); + uint32_t sta[3]; + uint16_t(*wstat)[3]; + int error, ridx; + + + /* Check for special case */ + if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA && + ni != vap->iv_bss) + goto fail; + + txs->flags = IEEE80211_RATECTL_TX_STATS_NODE | + IEEE80211_RATECTL_TX_STATS_RETRIES; + txs->ni = ni; + if (sc->rvp_cnt <= 1 && + (vap->iv_opmode == IEEE80211_M_IBSS || + vap->iv_opmode == IEEE80211_M_STA)) { + /* + * read statistic counters (clear on read) and update AMRR state + */ + error = mtw_read_region_1(sc, MTW_TX_STA_CNT0, (uint8_t *)sta, + sizeof sta); + MTW_DPRINTF(sc, MTW_DEBUG_RATE, "error:%d\n", error); + if (error != 0) + goto fail; + + /* count failed TX as errors */ + if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, + le32toh(sta[0]) & 0xffff); + + txs->nretries = (le32toh(sta[1]) >> 16); + txs->nsuccess = (le32toh(sta[1]) & 0xffff); + /* nretries??? */ + txs->nframes = txs->nsuccess + (le32toh(sta[0]) & 0xffff); + + MTW_DPRINTF(sc, MTW_DEBUG_RATE, + "retrycnt=%d success=%d failcnt=%d\n", txs->nretries, + txs->nsuccess, le32toh(sta[0]) & 0xffff); + } else { + wstat = &(sc->wcid_stats[MTW_AID2WCID(ni->ni_associd)]); + + if (wstat == &(sc->wcid_stats[0]) || + wstat > &(sc->wcid_stats[MTW_WCID_MAX])) + goto fail; + + txs->nretries = (*wstat)[MTW_RETRY]; + txs->nsuccess = (*wstat)[MTW_SUCCESS]; + txs->nframes = (*wstat)[MTW_TXCNT]; + MTW_DPRINTF(sc, MTW_DEBUG_RATE, + "wstat retrycnt=%d txcnt=%d success=%d\n", txs->nretries, + txs->nframes, txs->nsuccess); + + memset(wstat, 0, sizeof(*wstat)); + } + + ieee80211_ratectl_tx_update(vap, txs); + ieee80211_ratectl_rate(ni, NULL, 0); + /* XXX TODO: methodize with MCS rates */ + for (ridx = 0; ridx < MTW_RIDX_MAX; ridx++) { + MTW_DPRINTF(sc, MTW_DEBUG_RATE, "ni_txrate=0x%x\n", + ni->ni_txrate); + if (rt2860_rates[ridx].rate == ni->ni_txrate) { + break; + } + } + rn->amrr_ridx = ridx; +fail: + MTW_UNLOCK(sc); + + MTW_DPRINTF(sc, MTW_DEBUG_RATE, "rate=%d, ridx=%d\n", + ni->ni_txrate, rn->amrr_ridx); +} + +static void +mtw_newassoc_cb(void *arg) +{ + struct mtw_cmdq *cmdq = arg; + struct ieee80211_node *ni = cmdq->arg1; + struct mtw_softc *sc = ni->ni_vap->iv_ic->ic_softc; + + uint8_t wcid = cmdq->wcid; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + mtw_write_region_1(sc, MTW_WCID_ENTRY(wcid), ni->ni_macaddr, + IEEE80211_ADDR_LEN); + + memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid])); +} + +static void +mtw_newassoc(struct ieee80211_node *ni, int isnew) +{ + + struct mtw_node *mn = MTW_NODE(ni); + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = vap->iv_ic; + struct mtw_softc *sc = ic->ic_softc; + + uint8_t rate; + uint8_t ridx; + uint8_t wcid; + //int i; + // int i,j; + wcid = MTW_AID2WCID(ni->ni_associd); + + if (wcid > MTW_WCID_MAX) { + device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); + return; + } + + /* only interested in true associations */ + if (isnew && ni->ni_associd != 0) { + /* + * This function could is called though timeout function. + * Need to deferggxr. + */ + + uint32_t cnt = MTW_CMDQ_GET(&sc->cmdq_store); + MTW_DPRINTF(sc, MTW_DEBUG_STATE, "cmdq_store=%d\n", cnt); + sc->cmdq[cnt].func = mtw_newassoc_cb; + sc->cmdq[cnt].arg0 = NULL; + sc->cmdq[cnt].arg1 = ni; + sc->cmdq[cnt].wcid = wcid; + ieee80211_runtask(ic, &sc->cmdq_task); + } + + MTW_DPRINTF(sc, MTW_DEBUG_STATE, + "new assoc isnew=%d associd=%x addr=%s\n", isnew, ni->ni_associd, + ether_sprintf(ni->ni_macaddr)); + rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; + /* XXX TODO: methodize with MCS rates */ + for (ridx = 0; ridx < MTW_RIDX_MAX; ridx++) + if (rt2860_rates[ridx].rate == rate) + break; + mn->mgt_ridx = ridx; + MTW_DPRINTF(sc, MTW_DEBUG_STATE | MTW_DEBUG_RATE, + "rate=%d, ctl_ridx=%d\n", rate, ridx); + MTW_LOCK(sc); + if (sc->ratectl_run != MTW_RATECTL_OFF) { + usb_callout_reset(&sc->ratectl_ch, hz, &mtw_ratectl_to, sc); + } + MTW_UNLOCK(sc); + +} + +/* + * Return the Rx chain with the highest RSSI for a given frame. + */ +static __inline uint8_t +mtw_maxrssi_chain(struct mtw_softc *sc, const struct mtw_rxwi *rxwi) +{ + uint8_t rxchain = 0; + + if (sc->nrxchains > 1) { + if (rxwi->rssi[1] > rxwi->rssi[rxchain]) + rxchain = 1; + if (sc->nrxchains > 2) + if (rxwi->rssi[2] > rxwi->rssi[rxchain]) + rxchain = 2; + } + return (rxchain); +} +static void +mtw_get_tsf(struct mtw_softc *sc, uint64_t *buf) +{ + mtw_read_region_1(sc, MTW_TSF_TIMER_DW0, (uint8_t *)buf, sizeof(*buf)); +} + +static void +mtw_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 mtw_softc *sc = vap->iv_ic->ic_softc; + struct mtw_vap *rvp = MTW_VAP(vap); + uint64_t ni_tstamp, rx_tstamp; + + rvp->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); + MTW_LOCK(sc); + mtw_get_tsf(sc, &rx_tstamp); + MTW_UNLOCK(sc); + rx_tstamp = le64toh(rx_tstamp); + + if (ni_tstamp >= rx_tstamp) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV | MTW_DEBUG_BEACON, + "ibss merge, tsf %ju tstamp %ju\n", + (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp); + (void)ieee80211_ibss_merge(ni); + } + } +} +static void +mtw_rx_frame(struct mtw_softc *sc, struct mbuf *m, uint32_t dmalen) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + struct epoch_tracker et; + + struct mtw_rxwi *rxwi; + uint32_t flags; + uint16_t len, rxwisize; + uint8_t ant, rssi; + int8_t nf; + + rxwisize = sizeof(struct mtw_rxwi); + + if (__predict_false( + dmalen < rxwisize + sizeof(struct ieee80211_frame_ack))) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV, + "payload is too short: dma length %u < %zu\n", dmalen, + rxwisize + sizeof(struct ieee80211_frame_ack)); + goto fail; + } + + rxwi = mtod(m, struct mtw_rxwi *); + len = le16toh(rxwi->len) & 0xfff; + flags = le32toh(rxwi->flags); + if (__predict_false(len > dmalen - rxwisize)) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV, "bad RXWI length %u > %u\n", + len, dmalen); + goto fail; + } + + if (__predict_false(flags & (MTW_RX_CRCERR | MTW_RX_ICVERR))) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV, "%s error.\n", + (flags & MTW_RX_CRCERR) ? "CRC" : "ICV"); + goto fail; + } + + if (flags & MTW_RX_L2PAD) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV, + "received RT2860_RX_L2PAD frame\n"); + len += 2; + } + + m->m_data += rxwisize; + m->m_pkthdr.len = m->m_len = len; + + wh = mtod(m, struct ieee80211_frame *); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; + m->m_flags |= M_WEP; + } + + if (len >= sizeof(struct ieee80211_frame_min)) { + ni = ieee80211_find_rxnode(ic, + mtod(m, struct ieee80211_frame_min *)); + } else + ni = NULL; + + if (ni && ni->ni_flags & IEEE80211_NODE_HT) { + m->m_flags |= M_AMPDU; + } + + if (__predict_false(flags & MTW_RX_MICERR)) { + /* report MIC failures to net80211 for TKIP */ + if (ni != NULL) + ieee80211_notify_michael_failure(ni->ni_vap, wh, + rxwi->keyidx); + MTW_DPRINTF(sc, MTW_DEBUG_RECV, + "MIC error. Someone is lying.\n"); + goto fail; + } + + ant = mtw_maxrssi_chain(sc, rxwi); + rssi = rxwi->rssi[ant]; + nf = mtw_rssi2dbm(sc, rssi, ant); + + if (__predict_false(ieee80211_radiotap_active(ic))) { + struct mtw_rx_radiotap_header *tap = &sc->sc_rxtap; + uint16_t phy; + + tap->wr_flags = 0; + if (flags & MTW_RX_L2PAD) + tap->wr_flags |= IEEE80211_RADIOTAP_F_DATAPAD; + tap->wr_antsignal = rssi; + tap->wr_antenna = ant; + tap->wr_dbm_antsignal = mtw_rssi2dbm(sc, rssi, ant); + tap->wr_rate = 2; /* in case it can't be found below */ + //MTW_LOCK(sc); + + // MTW_UNLOCK(sc); + phy = le16toh(rxwi->phy); + switch (phy >> MT7601_PHY_SHIFT) { + case MTW_PHY_CCK: + switch ((phy & MTW_PHY_MCS) & ~MTW_PHY_SHPRE) { + case 0: + tap->wr_rate = 2; + break; + case 1: + tap->wr_rate = 4; + break; + case 2: + tap->wr_rate = 11; + break; + case 3: + tap->wr_rate = 22; + break; + } + if (phy & MTW_PHY_SHPRE) + tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + break; + case MTW_PHY_OFDM: + switch (phy & MTW_PHY_MCS) { + case 0: + tap->wr_rate = 12; + break; + case 1: + tap->wr_rate = 18; + break; + case 2: + tap->wr_rate = 24; + break; + case 3: + tap->wr_rate = 36; + break; + case 4: + tap->wr_rate = 48; + break; + case 5: + tap->wr_rate = 72; + break; + case 6: + tap->wr_rate = 96; + break; + case 7: + tap->wr_rate = 108; + break; + } + break; + } + } + + NET_EPOCH_ENTER(et); + if (ni != NULL) { + (void)ieee80211_input(ni, m, rssi, nf); + ieee80211_free_node(ni); + } else { + (void)ieee80211_input_all(ic, m, rssi, nf); + } + NET_EPOCH_EXIT(et); + + return; + +fail: + m_freem(m); + counter_u64_add(ic->ic_ierrors, 1); +} + +static void +mtw_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct mtw_softc *sc = usbd_xfer_softc(xfer); + struct ieee80211com *ic = &sc->sc_ic; + struct mbuf *m = NULL; + struct mbuf *m0; + uint32_t dmalen, mbuf_len; + uint16_t rxwisize; + int xferlen; + + rxwisize = sizeof(struct mtw_rxwi); + + usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + MTW_DPRINTF(sc, MTW_DEBUG_RECV, "rx done, actlen=%d\n", + xferlen); + if (xferlen < (int)(sizeof(uint32_t) + rxwisize + + sizeof(struct mtw_rxd))) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV_DESC | MTW_DEBUG_USB, + "xfer too short %d %d\n", xferlen, + (int)(sizeof(uint32_t) + rxwisize + + sizeof(struct mtw_rxd))); + goto tr_setup; + } + + m = sc->rx_m; + sc->rx_m = NULL; + + /* FALLTHROUGH */ + case USB_ST_SETUP: + tr_setup: + + if (sc->rx_m == NULL) { + sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, + MTW_MAX_RXSZ); + } + if (sc->rx_m == NULL) { + MTW_DPRINTF(sc, + MTW_DEBUG_RECV | MTW_DEBUG_RECV_DESC | + MTW_DEBUG_USB, + "could not allocate mbuf - idle with stall\n"); + counter_u64_add(ic->ic_ierrors, 1); + usbd_xfer_set_stall(xfer); + usbd_xfer_set_frames(xfer, 0); + } else { + /* + * Directly loading a mbuf cluster into DMA to + * save some data copying. This works because + * there is only one cluster. + */ + usbd_xfer_set_frame_data(xfer, 0, + mtod(sc->rx_m, caddr_t), MTW_MAX_RXSZ); + usbd_xfer_set_frames(xfer, 1); + } + usbd_transfer_submit(xfer); + break; + + default: /* Error */ + MTW_DPRINTF(sc, MTW_DEBUG_XMIT | MTW_DEBUG_USB, + "USB transfer error, %s\n", usbd_errstr(error)); + + if (error != USB_ERR_CANCELLED) { + /* try to clear stall first */ + usbd_xfer_set_stall(xfer); + if (error == USB_ERR_TIMEOUT) + device_printf(sc->sc_dev, "device timeout %s\n", + __func__); + counter_u64_add(ic->ic_ierrors, 1); + goto tr_setup; + } + if (sc->rx_m != NULL) { + m_freem(sc->rx_m); + sc->rx_m = NULL; + } + break; + } + + if (m == NULL) + return; + + /* inputting all the frames must be last */ + + MTW_UNLOCK(sc); + + m->m_pkthdr.len = m->m_len = xferlen; + + /* HW can aggregate multiple 802.11 frames in a single USB xfer */ + for (;;) { + dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; + + if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || + ((dmalen & 3) != 0)) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV_DESC | MTW_DEBUG_USB, + "bad DMA length %u\n", dmalen); + break; + } + if ((dmalen + 8) > (uint32_t)xferlen) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV_DESC | MTW_DEBUG_USB, + "bad DMA length %u > %d\n", dmalen + 8, xferlen); + break; + } + + /* If it is the last one or a single frame, we won't copy. */ + if ((xferlen -= dmalen + 8) <= 8) { + /* trim 32-bit DMA-len header */ + m->m_data += 4; + m->m_pkthdr.len = m->m_len -= 4; + mtw_rx_frame(sc, m, dmalen); + m = NULL; /* don't free source buffer */ + break; + } + + mbuf_len = dmalen + sizeof(struct mtw_rxd); + if (__predict_false(mbuf_len > MCLBYTES)) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV_DESC | MTW_DEBUG_USB, + "payload is too big: mbuf_len %u\n", mbuf_len); + counter_u64_add(ic->ic_ierrors, 1); + break; + } + + /* copy aggregated frames to another mbuf */ + m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (__predict_false(m0 == NULL)) { + MTW_DPRINTF(sc, MTW_DEBUG_RECV_DESC, + "could not allocate mbuf\n"); + counter_u64_add(ic->ic_ierrors, 1); + break; + } + m_copydata(m, 4 /* skip 32-bit DMA-len header */, mbuf_len, + mtod(m0, caddr_t)); + m0->m_pkthdr.len = m0->m_len = mbuf_len; + mtw_rx_frame(sc, m0, dmalen); + + /* update data ptr */ + m->m_data += mbuf_len + 4; + m->m_pkthdr.len = m->m_len -= mbuf_len + 4; + } + + /* make sure we free the source buffer, if any */ + m_freem(m); + +#ifdef IEEE80211_SUPPORT_SUPERG + ieee80211_ff_age_all(ic, 100); +#endif + MTW_LOCK(sc); +} + +static void +mtw_tx_free(struct mtw_endpoint_queue *pq, struct mtw_tx_data *data, int txerr) +{ + + ieee80211_tx_complete(data->ni, data->m, txerr); + data->m = NULL; + data->ni = NULL; + + STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); + pq->tx_nfree++; +} +static void +mtw_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) +{ + struct mtw_softc *sc = usbd_xfer_softc(xfer); + struct ieee80211com *ic = &sc->sc_ic; + struct mtw_tx_data *data; + struct ieee80211vap *vap = NULL; + struct usb_page_cache *pc; + struct mtw_endpoint_queue *pq = &sc->sc_epq[index]; + struct mbuf *m; + usb_frlength_t size; + int actlen; + int sumlen; + usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + MTW_DPRINTF(sc, MTW_DEBUG_XMIT | MTW_DEBUG_USB, + "transfer complete: %d bytes @ index %d\n", actlen, index); + + data = usbd_xfer_get_priv(xfer); + mtw_tx_free(pq, data, 0); + usbd_xfer_set_priv(xfer, NULL); + + /* FALLTHROUGH */ + case USB_ST_SETUP: + tr_setup: + data = STAILQ_FIRST(&pq->tx_qh); + if (data == NULL) + break; + + STAILQ_REMOVE_HEAD(&pq->tx_qh, next); + + m = data->m; + + size = sizeof(data->desc); + if ((m->m_pkthdr.len + size + 3 + 8) > MTW_MAX_TXSZ) { + MTW_DPRINTF(sc, MTW_DEBUG_XMIT_DESC | MTW_DEBUG_USB, + "data overflow, %u bytes\n", m->m_pkthdr.len); + mtw_tx_free(pq, data, 1); + goto tr_setup; + } + + pc = usbd_xfer_get_frame(xfer, 0); + usbd_copy_in(pc, 0, &data->desc, size); + usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); + size += m->m_pkthdr.len; + /* + * Align end on a 4-byte boundary, pad 8 bytes (CRC + + * 4-byte padding), and be sure to zero those trailing + * bytes: + */ + usbd_frame_zero(pc, size, ((-size) & 3) + MTW_DMA_PAD); + size += ((-size) & 3) + MTW_DMA_PAD; + + vap = data->ni->ni_vap; + if (ieee80211_radiotap_active_vap(vap)) { + const struct ieee80211_frame *wh; + struct mtw_tx_radiotap_header *tap = &sc->sc_txtap; + struct mtw_txwi *txwi = + (struct mtw_txwi *)(&data->desc + + sizeof(struct mtw_txd)); + int has_l2pad; + + wh = mtod(m, struct ieee80211_frame *); + has_l2pad = IEEE80211_HAS_ADDR4(wh) != + IEEE80211_QOS_HAS_SEQ(wh); + + tap->wt_flags = 0; + tap->wt_rate = rt2860_rates[data->ridx].rate; + tap->wt_hwqueue = index; + if (le16toh(txwi->phy) & MTW_PHY_SHPRE) + tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + if (has_l2pad) + tap->wt_flags |= IEEE80211_RADIOTAP_F_DATAPAD; + + ieee80211_radiotap_tx(vap, m); + } + + MTW_DPRINTF(sc, MTW_DEBUG_XMIT | MTW_DEBUG_USB, + "sending frame len=%u/%u @ index %d\n", m->m_pkthdr.len, + size, index); + + usbd_xfer_set_frame_len(xfer, 0, size); + usbd_xfer_set_priv(xfer, data); + usbd_transfer_submit(xfer); + mtw_start(sc); + + break; + + default: + MTW_DPRINTF(sc, MTW_DEBUG_XMIT | MTW_DEBUG_USB, + "USB transfer error, %s\n", usbd_errstr(error)); + + data = usbd_xfer_get_priv(xfer); + + if (data != NULL) { + if (data->ni != NULL) + vap = data->ni->ni_vap; + mtw_tx_free(pq, data, error); + usbd_xfer_set_priv(xfer, NULL); + } + + if (vap == NULL) + vap = TAILQ_FIRST(&ic->ic_vaps); + + if (error != USB_ERR_CANCELLED) { + if (error == USB_ERR_TIMEOUT) { + device_printf(sc->sc_dev, "device timeout %s\n", + __func__); + uint32_t i = MTW_CMDQ_GET(&sc->cmdq_store); + MTW_DPRINTF(sc, MTW_DEBUG_XMIT | MTW_DEBUG_USB, + "cmdq_store=%d\n", i); + sc->cmdq[i].func = mtw_usb_timeout_cb; + sc->cmdq[i].arg0 = vap; + ieee80211_runtask(ic, &sc->cmdq_task); + } + + /* + * Try to clear stall first, also if other + * errors occur, hence clearing stall + * introduces a 50 ms delay: + */ + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +#ifdef IEEE80211_SUPPORT_SUPERG + /* XXX TODO: make this deferred rather than unlock/relock */ + /* XXX TODO: should only do the QoS AC this belongs to */ + if (pq->tx_nfree >= RUN_TX_RING_COUNT) { + RUN_UNLOCK(sc); + ieee80211_ff_flush_all(ic); + RUN_LOCK(sc); + } +#endif +} + +static void +mtw_fw_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct mtw_softc *sc = usbd_xfer_softc(xfer); + + int actlen; + int ntries, tmp; + // struct mtw_txd *data; + + usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); + // data = usbd_xfer_get_priv(xfer); + usbd_xfer_set_priv(xfer, NULL); + switch (USB_GET_STATE(xfer)) { + + case USB_ST_TRANSFERRED: + sc->sc_sent += actlen; + memset(sc->txd_fw[sc->sc_idx], 0, actlen); + + if (actlen < 0x2c44 && sc->sc_idx == 0) { + return; + } + if (sc->sc_idx == 3) { + + if ((error = mtw_write_ivb(sc, sc->sc_ivb_1, + MTW_MCU_IVB_LEN)) != 0) { + device_printf(sc->sc_dev, + "Could not write ivb error: %d\n", error); + } + + mtw_delay(sc, 10); + for (ntries = 0; ntries < 100; ntries++) { + if ((error = mtw_read_cfg(sc, MTW_MCU_DMA_ADDR, + &tmp)) != 0) { + device_printf(sc->sc_dev, + "Could not read cfg error: %d\n", error); + + } + if (tmp == MTW_MCU_READY) { + MTW_DPRINTF(sc, MTW_DEBUG_FIRMWARE, + "mcu reaady %d\n", tmp); + sc->fwloading = 1; + break; + } + + mtw_delay(sc, 10); + } + if (ntries == 100) + sc->fwloading = 0; + wakeup(&sc->fwloading); + return; + } + + if (actlen == 0x2c44) { + sc->sc_idx++; + DELAY(1000); + } + + case USB_ST_SETUP: { + int dlen = 0; + dlen = sc->txd_fw[sc->sc_idx]->len; + + mtw_write_cfg(sc, MTW_MCU_DMA_ADDR, 0x40 + sc->sc_sent); + mtw_write_cfg(sc, MTW_MCU_DMA_LEN, (dlen << 16)); + + usbd_xfer_set_frame_len(xfer, 0, dlen); + usbd_xfer_set_frame_data(xfer, 0, sc->txd_fw[sc->sc_idx], dlen); + + // usbd_xfer_set_priv(xfer,sc->txd[sc->sc_idx]); + usbd_transfer_submit(xfer); + break; + + default: /* Error */ + device_printf(sc->sc_dev, "%s:%d %s\n", __FILE__, __LINE__, + usbd_errstr(error)); + sc->fwloading = 0; + wakeup(&sc->fwloading); + /* + * Print error message and clear stall + * for example. + */ + break; + } + /* + * Here it is safe to do something without the private + * USB mutex locked. + */ + } + return; +} +static void +mtw_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) +{ + mtw_bulk_tx_callbackN(xfer, error, 0); +} + +static void +mtw_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) +{ + + + mtw_bulk_tx_callbackN(xfer, error, 1); +} + +static void +mtw_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) +{ + mtw_bulk_tx_callbackN(xfer, error, 2); +} + +static void +mtw_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) +{ + mtw_bulk_tx_callbackN(xfer, error, 3); +} + +static void +mtw_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) +{ + mtw_bulk_tx_callbackN(xfer, error, 4); +} + +static void +mtw_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) +{ + mtw_bulk_tx_callbackN(xfer, error, 5); +} + +static void +mtw_set_tx_desc(struct mtw_softc *sc, struct mtw_tx_data *data) +{ + struct mbuf *m = data->m; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = data->ni->ni_vap; + struct ieee80211_frame *wh; + struct mtw_txd *txd; + struct mtw_txwi *txwi; + uint16_t xferlen, txwisize; + uint16_t mcs; + uint8_t ridx = data->ridx; + uint8_t pad; + + /* get MCS code from rate index */ + mcs = rt2860_rates[ridx].mcs; + + txwisize = sizeof(*txwi); + xferlen = txwisize + m->m_pkthdr.len; + + /* roundup to 32-bit alignment */ + xferlen = (xferlen + 3) & ~3; + + txd = (struct mtw_txd *)&data->desc; + txd->len = htole16(xferlen); + + wh = mtod(m, struct ieee80211_frame *); + + /* + * Ether both are true or both are false, the header + * are nicely aligned to 32-bit. So, no L2 padding. + */ + if (IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) + pad = 0; + else + pad = 2; + + /* setup TX Wireless Information */ + txwi = (struct mtw_txwi *)(txd + 1); + txwi->len = htole16(m->m_pkthdr.len - pad); + if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { + mcs |= MTW_PHY_CCK; + if (ridx != MTW_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + mcs |= MTW_PHY_SHPRE; + } else if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) { + mcs |= MTW_PHY_OFDM; + } else if (rt2860_rates[ridx].phy == IEEE80211_T_HT) { + /* XXX TODO: [adrian] set short preamble for MCS? */ + mcs |= MTW_PHY_HT; /* Mixed, not greenfield */ + } + txwi->phy = htole16(mcs); + + /* check if RTS/CTS or CTS-to-self protection is required */ + if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && + ((m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) || + ((ic->ic_flags & IEEE80211_F_USEPROT) && + rt2860_rates[ridx].phy == IEEE80211_T_OFDM) || + ((ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) && + rt2860_rates[ridx].phy == IEEE80211_T_HT))) + txwi->txop |= MTW_TX_TXOP_HT; + else + txwi->txop |= MTW_TX_TXOP_BACKOFF; + +} + +/* This function must be called locked */ +static int +mtw_tx(struct mtw_softc *sc, struct mbuf *m, struct ieee80211_node *ni) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_frame *wh; + + + //const struct ieee80211_txparam *tp = ni->ni_txparms; + struct mtw_node *rn = MTW_NODE(ni); + struct mtw_tx_data *data; + struct mtw_txd *txd; + struct mtw_txwi *txwi; + uint16_t qos; + uint16_t dur; + uint16_t qid; + uint8_t type; + uint8_t tid; + uint16_t ridx; + uint8_t ctl_ridx; + uint16_t qflags; + uint8_t xflags = 0; + + int hasqos; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + wh = mtod(m, struct ieee80211_frame *); + const struct ieee80211_txparam *tp = ni->ni_txparms; + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + qflags = htole16(MTW_TXD_DATA | MTW_TXD_80211 | + MTW_TXD_WLAN | MTW_TXD_QSEL_HCCA); + + if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { + uint8_t *frm; + frm = ieee80211_getqos(wh); + + + //device_printf(sc->sc_dev,"JSS:frm:%d",*frm); + qos = le16toh(*(const uint16_t *)frm); + tid = ieee80211_gettid(wh); + qid = TID_TO_WME_AC(tid); + qflags |= MTW_TXD_QSEL_EDCA; + } else { + qos = 0; + tid = 0; + qid = WME_AC_BE; + } + if (type & IEEE80211_FC0_TYPE_MGT) { + qid = 0; + } + + if (type != IEEE80211_FC0_TYPE_DATA) + qflags |= htole16(MTW_TXD_WIV); + + if (IEEE80211_IS_MULTICAST(wh->i_addr1) || + type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) { + /* XXX TODO: methodize for 11n; use MCS0 for 11NA/11NG */ + ridx = (ic->ic_curmode == IEEE80211_MODE_11A + || ic->ic_curmode == IEEE80211_MODE_11NA) ? + MTW_RIDX_OFDM6 : MTW_RIDX_CCK1; + if (type == IEEE80211_MODE_11NG) { + ridx = 12; + } + ctl_ridx = rt2860_rates[ridx].ctl_ridx; + } else { + if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + ridx = rn->fix_ridx; + + } else { + ridx = rn->amrr_ridx; + ctl_ridx = rt2860_rates[ridx].ctl_ridx; + } + } + + if (hasqos) + xflags = 0; + else + xflags = MTW_TX_NSEQ; + + if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && + (!hasqos || + (qos & IEEE80211_QOS_ACKPOLICY) != + IEEE80211_QOS_ACKPOLICY_NOACK)) { + xflags |= MTW_TX_ACK; + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + dur = rt2860_rates[ctl_ridx].sp_ack_dur; + else + dur = rt2860_rates[ctl_ridx].lp_ack_dur; + USETW(wh->i_dur, dur); + } + /* reserve slots for mgmt packets, just in case */ + if (sc->sc_epq[qid].tx_nfree < 3) { + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "tx ring %d is full\n", qid); + return (-1); + } + + data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); + STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); + sc->sc_epq[qid].tx_nfree--; + + txd = (struct mtw_txd *)&data->desc; + txd->flags = qflags; + + txwi = (struct mtw_txwi *)(txd + 1); + txwi->xflags = xflags; + txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ? + + MTW_AID2WCID(ni->ni_associd) : + 0xff; + + /* clear leftover garbage bits */ + txwi->flags = 0; + txwi->txop = 0; + + data->m = m; + data->ni = ni; + data->ridx = ridx; + + mtw_set_tx_desc(sc, data); + + /* + * The chip keeps track of 2 kind of Tx stats, + * * TX_STAT_FIFO, for per WCID stats, and + * * TX_STA_CNT0 for all-TX-in-one stats. + * + * To use FIFO stats, we need to store MCS into the driver-private + * PacketID field. So that, we can tell whose stats when we read them. + * We add 1 to the MCS because setting the PacketID field to 0 means + * that we don't want feedback in TX_STAT_FIFO. + * And, that's what we want for STA mode, since TX_STA_CNT0 does the + * job. + * + * FIFO stats doesn't count Tx with WCID 0xff, so we do this in + * run_tx(). + */ + + if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_MBSS) { + + /* + * Unlike PCI based devices, we don't get any interrupt from + * USB devices, so we simulate FIFO-is-full interrupt here. + * Ralink recommends to drain FIFO stats every 100 ms, but 16 + * slots quickly get fulled. To prevent overflow, increment a + * counter on every FIFO stat request, so we know how many slots + * are left. We do this only in HOSTAP or multiple vap mode + * since FIFO stats are used only in those modes. We just drain + * stats. AMRR gets updated every 1 sec by run_ratectl_cb() via + * callout. Call it early. Otherwise overflow. + */ + if (sc->fifo_cnt++ == 10) { + /* + * With multiple vaps or if_bridge, if_start() is called + * with a non-sleepable lock, tcpinp. So, need to defer. + */ + uint32_t i = MTW_CMDQ_GET(&sc->cmdq_store); + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "cmdq_store=%d\n", i); + sc->cmdq[i].func = mtw_drain_fifo; + sc->cmdq[i].arg0 = sc; + ieee80211_runtask(ic, &sc->cmdq_task); + } + } + + STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); + usbd_transfer_start(sc->sc_xfer[mtw_wme_ac_xfer_map[qid]]); + + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, + "sending data frame len=%d rate=%d qid=%d\n", + m->m_pkthdr.len + + (int)(sizeof(struct mtw_txd) + sizeof(struct mtw_txwi)), + rt2860_rates[ridx].rate, qid); + + return (0); + } + +static int +mtw_tx_mgt(struct mtw_softc *sc, struct mbuf *m, struct ieee80211_node *ni) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct mtw_node *rn = MTW_NODE(ni); + struct mtw_tx_data *data; + struct ieee80211_frame *wh; + struct mtw_txd *txd; + struct mtw_txwi *txwi; + uint8_t type; + uint16_t dur; + uint8_t ridx = rn->mgt_ridx; + uint8_t xflags = 0; + uint8_t wflags = 0; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + wh = mtod(m, struct ieee80211_frame *); + + /* tell hardware to add timestamp for probe responses */ + if ((wh->i_fc[0] & + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == + (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) + wflags |= MTW_TX_TS; + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + xflags |= MTW_TX_ACK; + + dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); + USETW(wh->i_dur, dur); + } + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + if (sc->sc_epq[0].tx_nfree == 0) + /* let caller free mbuf */ + return (EIO); + data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); + STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); + sc->sc_epq[0].tx_nfree--; + + txd = (struct mtw_txd *)&data->desc; + txd->flags = htole16( + MTW_TXD_DATA | MTW_TXD_80211 | MTW_TXD_WLAN | MTW_TXD_QSEL_EDCA); + if (type != IEEE80211_FC0_TYPE_DATA) + txd->flags |= htole16(MTW_TXD_WIV); + + txwi = (struct mtw_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->xflags = xflags; + txwi->flags = wflags; + + txwi->txop = 0; /* clear leftover garbage bits */ + + data->m = m; + data->ni = ni; + data->ridx = ridx; + + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "sending mgt frame len=%d rate=%d\n", + m->m_pkthdr.len + + (int)(sizeof(struct mtw_txd) + sizeof(struct mtw_txwi)), + rt2860_rates[ridx].rate); + + STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); + + usbd_transfer_start(sc->sc_xfer[MTW_BULK_TX_BE]); + + return (0); +} + +static int +mtw_sendprot(struct mtw_softc *sc, const struct mbuf *m, + struct ieee80211_node *ni, int prot, int rate) +{ + struct ieee80211com *ic = ni->ni_ic; + struct mtw_tx_data *data; + struct mtw_txd *txd; + struct mtw_txwi *txwi; + struct mbuf *mprot; + int ridx; + int protrate; + uint8_t wflags = 0; + uint8_t xflags = 0; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + /* check that there are free slots before allocating the mbuf */ + if (sc->sc_epq[0].tx_nfree == 0) + /* let caller free mbuf */ + return (ENOBUFS); + + mprot = ieee80211_alloc_prot(ni, m, rate, prot); + if (mprot == NULL) { + if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "could not allocate mbuf\n"); + return (ENOBUFS); + } + + protrate = ieee80211_ctl_rate(ic->ic_rt, rate); + wflags = MTW_TX_FRAG; + xflags = 0; + if (prot == IEEE80211_PROT_RTSCTS) + xflags |= MTW_TX_ACK; + + data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); + STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); + sc->sc_epq[0].tx_nfree--; + + txd = (struct mtw_txd *)&data->desc; + txd->flags = RT2860_TX_QSEL_EDCA; + txwi = (struct mtw_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->flags = wflags; + txwi->xflags = xflags; + txwi->txop = 0; /* clear leftover garbage bits */ + + data->m = mprot; + data->ni = ieee80211_ref_node(ni); + + /* XXX TODO: methodize with MCS rates */ + for (ridx = 0; ridx < MTW_RIDX_MAX; ridx++) + if (rt2860_rates[ridx].rate == protrate) + break; + data->ridx = ridx; + + mtw_set_tx_desc(sc, data); + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "sending prot len=%u rate=%u\n", + m->m_pkthdr.len, rate); + + STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); + + usbd_transfer_start(sc->sc_xfer[0]); + + return (0); +} + +static int +mtw_tx_param(struct mtw_softc *sc, struct mbuf *m, struct ieee80211_node *ni, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct mtw_tx_data *data; + struct mtw_txd *txd; + struct mtw_txwi *txwi; + uint8_t ridx; + uint8_t rate; + uint8_t opflags = 0; + uint8_t xflags = 0; + int error; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + KASSERT(params != NULL, ("no raw xmit params")); + + rate = params->ibp_rate0; + if (!ieee80211_isratevalid(ic->ic_rt, rate)) { + /* let caller free mbuf */ + return (EINVAL); + } + + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) + xflags |= MTW_TX_ACK; + if (params->ibp_flags & (IEEE80211_BPF_RTS | IEEE80211_BPF_CTS)) { + error = mtw_sendprot(sc, m, ni, + params->ibp_flags & IEEE80211_BPF_RTS ? + IEEE80211_PROT_RTSCTS : + IEEE80211_PROT_CTSONLY, + rate); + if (error) { + device_printf(sc->sc_dev, "%s:%d %d\n", __FILE__, + __LINE__, error); + return (error); + } + opflags |= MTW_TX_TXOP_SIFS; + } + + if (sc->sc_epq[0].tx_nfree == 0) { + /* let caller free mbuf */ + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, + "sending raw frame, but tx ring is full\n"); + return (EIO); + } + data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); + STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); + sc->sc_epq[0].tx_nfree--; + + txd = (struct mtw_txd *)&data->desc; + txd->flags = htole16( + MTW_TXD_DATA | MTW_TXD_80211 | MTW_TXD_WLAN | MTW_TXD_QSEL_EDCA); + // txd->flags = htole16(MTW_TXD_QSEL_EDCA); + txwi = (struct mtw_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->xflags = xflags; + txwi->txop = opflags; + txwi->flags = 0; /* clear leftover garbage bits */ + + data->m = m; + data->ni = ni; + /* XXX TODO: methodize with MCS rates */ + for (ridx = 0; ridx < MTW_RIDX_MAX; ridx++) + if (rt2860_rates[ridx].rate == rate) + break; + data->ridx = ridx; + + mtw_set_tx_desc(sc, data); + + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "sending raw frame len=%u rate=%u\n", + m->m_pkthdr.len, rate); + + STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); + + usbd_transfer_start(sc->sc_xfer[MTW_BULK_RAW_TX]); + + return (0); +} + +static int +mtw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct mtw_softc *sc = ni->ni_ic->ic_softc; + int error = 0; + MTW_LOCK(sc); + /* prevent management frames from being sent if we're not ready */ + if (!(sc->sc_flags & MTW_RUNNING)) { + error = ENETDOWN; + goto done; + } + + if (params == NULL) { + /* tx mgt packet */ + if ((error = mtw_tx_mgt(sc, m, ni)) != 0) { + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, "mgt tx failed\n"); + goto done; + } + } else { + /* tx raw packet with param */ + if ((error = mtw_tx_param(sc, m, ni, params)) != 0) { + MTW_DPRINTF(sc, MTW_DEBUG_XMIT, + "tx with param failed\n"); + goto done; + } + } + +done: + + MTW_UNLOCK(sc); + + if (error != 0) { + if (m != NULL) + m_freem(m); + } + + return (error); +} + +static int +mtw_transmit(struct ieee80211com *ic, struct mbuf *m) +{ + struct mtw_softc *sc = ic->ic_softc; + int error; + MTW_LOCK(sc); + if ((sc->sc_flags & MTW_RUNNING) == 0) { + MTW_UNLOCK(sc); + return (ENXIO); + } + error = mbufq_enqueue(&sc->sc_snd, m); + if (error) { + MTW_UNLOCK(sc); + return (error); + } + mtw_start(sc); + MTW_UNLOCK(sc); + + return (0); +} + +static void +mtw_start(struct mtw_softc *sc) +{ + struct ieee80211_node *ni; + struct mbuf *m; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + if ((sc->sc_flags & MTW_RUNNING) == 0) { + + return; + } + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + if (mtw_tx(sc, m, ni) != 0) { + mbufq_prepend(&sc->sc_snd, m); + break; + } + } +} + +static void +mtw_parent(struct ieee80211com *ic) +{ + + struct mtw_softc *sc = ic->ic_softc; + + MTW_LOCK(sc); + if (sc->sc_detached) { + MTW_UNLOCK(sc); + return; + } + + if (!(sc->sc_flags & MTW_RUNNING) && ic->ic_nrunning > 0) { + mtw_init_locked(sc); + MTW_UNLOCK(sc); + ieee80211_start_all(ic); + return; + } + if (!(sc->sc_flags & MTW_RUNNING) && ic->ic_nrunning > 0) { + mtw_update_promisc_locked(sc); + MTW_UNLOCK(sc); + return; + } + if ((sc->sc_flags & MTW_RUNNING) && sc->rvp_cnt <= 1 && + ic->ic_nrunning == 0) { + mtw_stop(sc); + MTW_UNLOCK(sc); + return; + } + return; +} + +static void +mt7601_set_agc(struct mtw_softc *sc, uint8_t agc) +{ + uint8_t bbp; + + mtw_bbp_write(sc, 66, agc); + mtw_bbp_write(sc, 195, 0x87); + bbp = (agc & 0xf0) | 0x08; + mtw_bbp_write(sc, 196, bbp); +} + +static int +mtw_mcu_calibrate(struct mtw_softc *sc, int func, uint32_t val) +{ + struct mtw_mcu_cmd_8 cmd; + + cmd.func = htole32(func); + cmd.val = htole32(val); + return (mtw_mcu_cmd(sc, 31, &cmd, sizeof(struct mtw_mcu_cmd_8))); +} + +static int +mtw_rf_write(struct mtw_softc *sc, uint8_t bank, uint8_t reg, uint8_t val) +{ + uint32_t tmp; + int error, ntries, shift; + + for (ntries = 0; ntries < 10; ntries++) { + if ((error = mtw_read(sc, MTW_RF_CSR, &tmp)) != 0) + return (error); + if (!(tmp & MTW_RF_CSR_KICK)) + break; + } + if (ntries == 10) + return (ETIMEDOUT); + + if (sc->asic_ver == 0x7601) + shift = MT7601_BANK_SHIFT; + else + shift = MT7610_BANK_SHIFT; + + tmp = MTW_RF_CSR_WRITE | MTW_RF_CSR_KICK | (bank & 0xf) << shift | + reg << 8 | val; + return (mtw_write(sc, MTW_RF_CSR, tmp)); +} + +void +mtw_select_chan_group(struct mtw_softc *sc, int group) +{ + uint32_t tmp; + uint8_t bbp; + + /* Tx band 20MHz 2G */ + mtw_read(sc, MTW_TX_BAND_CFG, &tmp); + tmp &= ~( + MTW_TX_BAND_SEL_2G | MTW_TX_BAND_SEL_5G | MTW_TX_BAND_UPPER_40M); + tmp |= (group == 0) ? MTW_TX_BAND_SEL_2G : MTW_TX_BAND_SEL_5G; + mtw_write(sc, MTW_TX_BAND_CFG, tmp); + + /* select 20 MHz bandwidth */ + mtw_bbp_read(sc, 4, &bbp); + bbp &= ~0x18; + bbp |= 0x40; + mtw_bbp_write(sc, 4, bbp); + + /* calibrate BBP */ + mtw_bbp_write(sc, 69, 0x12); + mtw_bbp_write(sc, 91, 0x07); + mtw_bbp_write(sc, 195, 0x23); + mtw_bbp_write(sc, 196, 0x17); + mtw_bbp_write(sc, 195, 0x24); + mtw_bbp_write(sc, 196, 0x06); + mtw_bbp_write(sc, 195, 0x81); + mtw_bbp_write(sc, 196, 0x12); + mtw_bbp_write(sc, 195, 0x83); + mtw_bbp_write(sc, 196, 0x17); + mtw_rf_write(sc, 5, 8, 0x00); + // mtw_mcu_calibrate(sc, 0x6, 0x10001); + + /* set initial AGC value */ + mt7601_set_agc(sc, 0x14); +} + +static int +mtw_rf_read(struct mtw_softc *sc, uint8_t bank, uint8_t reg, uint8_t *val) +{ + uint32_t tmp; + int error, ntries, shift; + + for (ntries = 0; ntries < 100; ntries++) { + if ((error = mtw_read(sc, MTW_RF_CSR, &tmp)) != 0) + return (error); + if (!(tmp & MTW_RF_CSR_KICK)) + break; + } + if (ntries == 100) + return (ETIMEDOUT); + + if (sc->asic_ver == 0x7601) + shift = MT7601_BANK_SHIFT; + else + shift = MT7610_BANK_SHIFT; + + tmp = MTW_RF_CSR_KICK | (bank & 0xf) << shift | reg << 8; + if ((error = mtw_write(sc, MTW_RF_CSR, tmp)) != 0) + return (error); + + for (ntries = 0; ntries < 100; ntries++) { + if ((error = mtw_read(sc, MTW_RF_CSR, &tmp)) != 0) + return (error); + if (!(tmp & MTW_RF_CSR_KICK)) + break; + } + if (ntries == 100) + return (ETIMEDOUT); + + *val = tmp & 0xff; + return (0); +} +static void +mt7601_set_chan(struct mtw_softc *sc, u_int chan) +{ + uint32_t tmp; + uint8_t bbp, rf, txpow1; + int i; + /* find the settings for this channel */ + for (i = 0; mt7601_rf_chan[i].chan != chan; i++) + ; + + mtw_rf_write(sc, 0, 17, mt7601_rf_chan[i].r17); + mtw_rf_write(sc, 0, 18, mt7601_rf_chan[i].r18); + mtw_rf_write(sc, 0, 19, mt7601_rf_chan[i].r19); + mtw_rf_write(sc, 0, 20, mt7601_rf_chan[i].r20); + + /* use Tx power values from EEPROM */ + txpow1 = sc->txpow1[i]; + + /* Tx automatic level control */ + mtw_read(sc, MTW_TX_ALC_CFG0, &tmp); + tmp &= ~0x3f3f; + tmp |= (txpow1 & 0x3f); + mtw_write(sc, MTW_TX_ALC_CFG0, tmp); + + /* LNA */ + mtw_bbp_write(sc, 62, 0x37 - sc->lna[0]); + mtw_bbp_write(sc, 63, 0x37 - sc->lna[0]); + mtw_bbp_write(sc, 64, 0x37 - sc->lna[0]); + + /* VCO calibration */ + mtw_rf_write(sc, 0, 4, 0x0a); + mtw_rf_write(sc, 0, 5, 0x20); + mtw_rf_read(sc, 0, 4, &rf); + mtw_rf_write(sc, 0, 4, rf | 0x80); + + /* select 20 MHz bandwidth */ + mtw_bbp_read(sc, 4, &bbp); + bbp &= ~0x18; + bbp |= 0x40; + mtw_bbp_write(sc, 4, bbp); + mtw_bbp_write(sc, 178, 0xff); +} + +static int +mtw_set_chan(struct mtw_softc *sc, struct ieee80211_channel *c) +{ + struct ieee80211com *ic = &sc->sc_ic; + u_int chan, group; + + chan = ieee80211_chan2ieee(ic, c); + if (chan == 0 || chan == IEEE80211_CHAN_ANY) + return (EINVAL); + + /* determine channel group */ + if (chan <= 14) + group = 0; + else if (chan <= 64) + group = 1; + else if (chan <= 128) + group = 2; + else + group = 3; + + if (group != sc->sc_chan_group || !sc->sc_bw_calibrated) + mtw_select_chan_group(sc, group); + + sc->sc_chan_group = group; + + /* chipset specific */ + if (sc->asic_ver == 0x7601) + mt7601_set_chan(sc, chan); + + DELAY(1000); + return (0); +} + +static void +mtw_set_channel(struct ieee80211com *ic) +{ + struct mtw_softc *sc = ic->ic_softc; + + MTW_LOCK(sc); + mtw_set_chan(sc, ic->ic_curchan); + MTW_UNLOCK(sc); + + return; +} + +static void +mtw_getradiocaps(struct ieee80211com *ic, int maxchans, int *nchans, + struct ieee80211_channel chans[]) +{ + // struct mtw_softc *sc = ic->ic_softc; + uint8_t bands[IEEE80211_MODE_BYTES]; + + memset(bands, 0, sizeof(bands)); + setbit(bands, IEEE80211_MODE_11B); + setbit(bands, IEEE80211_MODE_11G); + setbit(bands, IEEE80211_MODE_11NG); + + /* Note: for now, only support HT20 channels */ + ieee80211_add_channels_default_2ghz(chans, maxchans, nchans, bands, 0); +} + +static void +mtw_scan_start(struct ieee80211com *ic) +{ + struct mtw_softc *sc = ic->ic_softc; + MTW_LOCK(sc); + /* abort TSF synchronization */ + mtw_abort_tsf_sync(sc); + mtw_set_bssid(sc, ieee80211broadcastaddr); + + MTW_UNLOCK(sc); + + return; +} + +static void +mtw_scan_end(struct ieee80211com *ic) +{ + struct mtw_softc *sc = ic->ic_softc; + + MTW_LOCK(sc); + + mtw_enable_tsf_sync(sc); + mtw_set_bssid(sc, sc->sc_bssid); + + MTW_UNLOCK(sc); + + return; +} + +/* + * Could be called from ieee80211_node_timeout() + * (non-sleepable thread) + */ +static void +mtw_update_beacon(struct ieee80211vap *vap, int item) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; + struct ieee80211_node *ni = vap->iv_bss; + struct mtw_softc *sc = ic->ic_softc; + struct mtw_vap *rvp = MTW_VAP(vap); + int mcast = 0; + uint32_t i; + + switch (item) { + case IEEE80211_BEACON_ERP: + mtw_updateslot(ic); + break; + case IEEE80211_BEACON_HTINFO: + mtw_updateprot(ic); + break; + case IEEE80211_BEACON_TIM: + mcast = 1; /*TODO*/ + break; + default: + break; + } + + setbit(bo->bo_flags, item); + if (rvp->beacon_mbuf == NULL) { + rvp->beacon_mbuf = ieee80211_beacon_alloc(ni); + if (rvp->beacon_mbuf == NULL) + return; + } + ieee80211_beacon_update(ni, rvp->beacon_mbuf, mcast); + + i = MTW_CMDQ_GET(&sc->cmdq_store); + MTW_DPRINTF(sc, MTW_DEBUG_BEACON, "cmdq_store=%d\n", i); + sc->cmdq[i].func = mtw_update_beacon_cb; + sc->cmdq[i].arg0 = vap; + ieee80211_runtask(ic, &sc->cmdq_task); + + return; +} + +static void +mtw_update_beacon_cb(void *arg) +{ + + struct ieee80211vap *vap = arg; + struct ieee80211_node *ni = vap->iv_bss; + struct mtw_vap *rvp = MTW_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct mtw_softc *sc = ic->ic_softc; + struct mtw_txwi txwi; + struct mbuf *m; + uint16_t txwisize; + uint8_t ridx; + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return; + if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) + return; + + /* + * No need to call ieee80211_beacon_update(), mtw_update_beacon() + * is taking care of appropriate calls. + */ + if (rvp->beacon_mbuf == NULL) { + rvp->beacon_mbuf = ieee80211_beacon_alloc(ni); + if (rvp->beacon_mbuf == NULL) + return; + } + m = rvp->beacon_mbuf; + + memset(&txwi, 0, sizeof(txwi)); + txwi.wcid = 0xff; + txwi.len = htole16(m->m_pkthdr.len); + + /* send beacons at the lowest available rate */ + ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? MTW_RIDX_OFDM6 : + MTW_RIDX_CCK1; + txwi.phy = htole16(rt2860_rates[ridx].mcs); + if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) + txwi.phy |= htole16(MTW_PHY_OFDM); + txwi.txop = MTW_TX_TXOP_HT; + txwi.flags = MTW_TX_TS; + txwi.xflags = MTW_TX_NSEQ; + + txwisize = sizeof(txwi); + mtw_write_region_1(sc, MTW_BCN_BASE, (uint8_t *)&txwi, txwisize); + mtw_write_region_1(sc, MTW_BCN_BASE + txwisize, mtod(m, uint8_t *), + (m->m_pkthdr.len + 1) & ~1); +} + +static void +mtw_updateprot(struct ieee80211com *ic) +{ + struct mtw_softc *sc = ic->ic_softc; + uint32_t i; + + i = MTW_CMDQ_GET(&sc->cmdq_store); + MTW_DPRINTF(sc, MTW_DEBUG_BEACON, "test cmdq_store=%d\n", i); + sc->cmdq[i].func = mtw_updateprot_cb; + sc->cmdq[i].arg0 = ic; + ieee80211_runtask(ic, &sc->cmdq_task); +} + +static void +mtw_updateprot_cb(void *arg) +{ + + struct ieee80211com *ic = arg; + struct mtw_softc *sc = ic->ic_softc; + uint32_t tmp; + + tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; + /* setup protection frame rate (MCS code) */ + tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ? + rt2860_rates[MTW_RIDX_OFDM6].mcs | MTW_PHY_OFDM : + rt2860_rates[MTW_RIDX_CCK11].mcs; + + /* CCK frames don't require protection */ + mtw_write(sc, MTW_CCK_PROT_CFG, tmp); + if (ic->ic_flags & IEEE80211_F_USEPROT) { + if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) + tmp |= RT2860_PROT_CTRL_RTS_CTS; + else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) + tmp |= RT2860_PROT_CTRL_CTS; + } + mtw_write(sc, MTW_OFDM_PROT_CFG, tmp); +} + +static void +mtw_usb_timeout_cb(void *arg) +{ + struct ieee80211vap *vap = arg; + struct mtw_softc *sc = vap->iv_ic->ic_softc; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + if (vap->iv_state == IEEE80211_S_SCAN) { + MTW_DPRINTF(sc, MTW_DEBUG_USB | MTW_DEBUG_STATE, + "timeout caused by scan\n"); + /* cancel bgscan */ + ieee80211_cancel_scan(vap); + } else { + MTW_DPRINTF(sc, MTW_DEBUG_USB | MTW_DEBUG_STATE, + "timeout by unknown cause\n"); + } +} +static int mtw_reset(struct mtw_softc *sc) +{ + + usb_device_request_t req; + uint16_t tmp; + uint16_t actlen; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = MTW_RESET; + USETW(req.wValue, 1); + USETW(req.wIndex, 0); + USETW(req.wLength, 0); + return (usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, + &req, &tmp, 0, &actlen, 1000)); + +} + + +static void +mtw_update_promisc_locked(struct mtw_softc *sc) +{ + + uint32_t tmp; + + mtw_read(sc, MTW_RX_FILTR_CFG, &tmp); + + tmp |= MTW_DROP_UC_NOME; + if (sc->sc_ic.ic_promisc > 0) + tmp &= ~MTW_DROP_UC_NOME; + + mtw_write(sc, MTW_RX_FILTR_CFG, tmp); + + MTW_DPRINTF(sc, MTW_DEBUG_RECV, "%s promiscuous mode\n", + (sc->sc_ic.ic_promisc > 0) ? "entering" : "leaving"); +} + +static void +mtw_update_promisc(struct ieee80211com *ic) +{ + struct mtw_softc *sc = ic->ic_softc; + + if ((sc->sc_flags & MTW_RUNNING) == 0) + return; + + MTW_LOCK(sc); + mtw_update_promisc_locked(sc); + MTW_UNLOCK(sc); +} + +static void +mtw_enable_tsf_sync(struct mtw_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + uint32_t tmp; + int error; + mtw_read(sc, MTW_BCN_TIME_CFG, &tmp); + tmp &= ~0x1fffff; + tmp |= vap->iv_bss->ni_intval * 16; + tmp |= MTW_TSF_TIMER_EN | MTW_TBTT_TIMER_EN; + + /* local TSF is always updated with remote TSF on beacon reception */ + tmp |= 1 << MTW_TSF_SYNC_MODE_SHIFT; + error = mtw_write(sc, MTW_BCN_TIME_CFG, tmp); + if (error != 0) { + device_printf(sc->sc_dev, "enable_tsf_sync failed error:%d\n", + error); + } + return; +} + +static void +mtw_enable_mrr(struct mtw_softc *sc) +{ +#define CCK(mcs) (mcs) + +#define OFDM(mcs) (1 << 3 | (mcs)) + mtw_write(sc, MTW_LG_FBK_CFG0, + OFDM(6) << 28 | /* 54->48 */ + OFDM(5) << 24 | /* 48->36 */ + OFDM(4) << 20 | /* 36->24 */ + OFDM(3) << 16 | /* 24->18 */ + OFDM(2) << 12 | /* 18->12 */ + OFDM(1) << 8 | /* 12-> 9 */ + OFDM(0) << 4 | /* 9-> 6 */ + OFDM(0)); /* 6-> 6 */ + + mtw_write(sc, MTW_LG_FBK_CFG1, + CCK(2) << 12 | /* 11->5.5 */ + CCK(1) << 8 | /* 5.5-> 2 */ + CCK(0) << 4 | /* 2-> 1 */ + CCK(0)); /* 1-> 1 */ +#undef OFDM +#undef CCK +} + +static void +mtw_set_txpreamble(struct mtw_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t tmp; + + mtw_read(sc, MTW_AUTO_RSP_CFG, &tmp); + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + tmp |= MTW_CCK_SHORT_EN; + else + tmp &= ~MTW_CCK_SHORT_EN; + mtw_write(sc, MTW_AUTO_RSP_CFG, tmp); +} + +static void +mtw_set_basicrates(struct mtw_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + /* set basic rates mask */ + if (ic->ic_curmode == IEEE80211_MODE_11B) + mtw_write(sc, MTW_LEGACY_BASIC_RATE, 0x003); + else if (ic->ic_curmode == IEEE80211_MODE_11A) + mtw_write(sc, MTW_LEGACY_BASIC_RATE, 0x150); + else /* 11g */ + mtw_write(sc, MTW_LEGACY_BASIC_RATE, 0x17f); +} + +static void +mtw_set_bssid(struct mtw_softc *sc, const uint8_t *bssid) +{ + mtw_write(sc, MTW_MAC_BSSID_DW0, + bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); + mtw_write(sc, MTW_MAC_BSSID_DW1, bssid[4] | bssid[5] << 8); +} + +static void +mtw_set_macaddr(struct mtw_softc *sc, const uint8_t *addr) +{ + mtw_write(sc, MTW_MAC_ADDR_DW0, + addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); + mtw_write(sc, MTW_MAC_ADDR_DW1, addr[4] | addr[5] << 8 | 0xff << 16); +} + +static void +mtw_updateslot(struct ieee80211com *ic) +{ + + struct mtw_softc *sc = ic->ic_softc; + uint32_t i; + + i = MTW_CMDQ_GET(&sc->cmdq_store); + MTW_DPRINTF(sc, MTW_DEBUG_BEACON, "cmdq_store=%d\n", i); + sc->cmdq[i].func = mtw_updateslot_cb; + sc->cmdq[i].arg0 = ic; + ieee80211_runtask(ic, &sc->cmdq_task); + + return; +} + +/* ARGSUSED */ +static void +mtw_updateslot_cb(void *arg) +{ + struct ieee80211com *ic = arg; + struct mtw_softc *sc = ic->ic_softc; + uint32_t tmp; + mtw_read(sc, MTW_BKOFF_SLOT_CFG, &tmp); + tmp &= ~0xff; + tmp |= IEEE80211_GET_SLOTTIME(ic); + mtw_write(sc, MTW_BKOFF_SLOT_CFG, tmp); +} + +static void +mtw_update_mcast(struct ieee80211com *ic) +{ +} + +static int8_t +mtw_rssi2dbm(struct mtw_softc *sc, uint8_t rssi, uint8_t rxchain) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_channel *c = ic->ic_curchan; + int delta; + + if (IEEE80211_IS_CHAN_5GHZ(c)) { + u_int chan = ieee80211_chan2ieee(ic, c); + delta = sc->rssi_5ghz[rxchain]; + + /* determine channel group */ + if (chan <= 64) + delta -= sc->lna[1]; + else if (chan <= 128) + delta -= sc->lna[2]; + else + delta -= sc->lna[3]; + } else + delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; + + return (-12 - delta - rssi); +} +static int +mt7601_bbp_init(struct mtw_softc *sc) +{ + uint8_t bbp; + int i, error, ntries; + + /* wait for BBP to wake up */ + for (ntries = 0; ntries < 20; ntries++) { + if ((error = mtw_bbp_read(sc, 0, &bbp)) != 0) + return (error); + if (bbp != 0 && bbp != 0xff) + break; + } + + if (ntries == 20) + return (ETIMEDOUT); + + mtw_bbp_read(sc, 3, &bbp); + mtw_bbp_write(sc, 3, 0); + mtw_bbp_read(sc, 105, &bbp); + mtw_bbp_write(sc, 105, 0); + + /* initialize BBP registers to default values */ + for (i = 0; i < nitems(mt7601_def_bbp); i++) { + if ((error = mtw_bbp_write(sc, mt7601_def_bbp[i].reg, + mt7601_def_bbp[i].val)) != 0) + return (error); + } + + sc->sc_bw_calibrated = 0; + + return (0); +} + +static int +mt7601_rf_init(struct mtw_softc *sc) +{ + int i, error; + + /* RF bank 0 */ + for (i = 0; i < nitems(mt7601_rf_bank0); i++) { + error = mtw_rf_write(sc, 0, mt7601_rf_bank0[i].reg, + mt7601_rf_bank0[i].val); + if (error != 0) + return (error); + } + /* RF bank 4 */ + for (i = 0; i < nitems(mt7601_rf_bank4); i++) { + error = mtw_rf_write(sc, 4, mt7601_rf_bank4[i].reg, + mt7601_rf_bank4[i].val); + if (error != 0) + return (error); + } + /* RF bank 5 */ + for (i = 0; i < nitems(mt7601_rf_bank5); i++) { + error = mtw_rf_write(sc, 5, mt7601_rf_bank5[i].reg, + mt7601_rf_bank5[i].val); + if (error != 0) + return (error); + } + return (0); +} + +static int +mtw_txrx_enable(struct mtw_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t tmp; + int error, ntries; + mtw_write(sc, MTW_MAC_SYS_CTRL, MTW_MAC_TX_EN); + for (ntries = 0; ntries < 200; ntries++) { + if ((error = mtw_read(sc, MTW_WPDMA_GLO_CFG, &tmp)) != 0) { + return (error); + } + if ((tmp & (MTW_TX_DMA_BUSY | MTW_RX_DMA_BUSY)) == 0) + break; + mtw_delay(sc, 50); + } + if (ntries == 200) { + return (ETIMEDOUT); + } + + DELAY(50); + + tmp |= MTW_RX_DMA_EN | MTW_TX_DMA_EN | MTW_TX_WB_DDONE; + mtw_write(sc, MTW_WPDMA_GLO_CFG, tmp); + + /* enable Rx bulk aggregation (set timeout and limit) */ + tmp = MTW_USB_TX_EN | MTW_USB_RX_EN | MTW_USB_RX_AGG_EN | + MTW_USB_RX_AGG_TO(128) | MTW_USB_RX_AGG_LMT(2); + mtw_write(sc, MTW_USB_DMA_CFG, tmp); + + /* set Rx filter */ + tmp = MTW_DROP_CRC_ERR | MTW_DROP_PHY_ERR; + if (ic->ic_opmode != IEEE80211_M_MONITOR) { + tmp |= MTW_DROP_UC_NOME | MTW_DROP_DUPL | MTW_DROP_CTS | + MTW_DROP_BA | MTW_DROP_ACK | MTW_DROP_VER_ERR | + MTW_DROP_CTRL_RSV | MTW_DROP_CFACK | MTW_DROP_CFEND; + if (ic->ic_opmode == IEEE80211_M_STA) + tmp |= MTW_DROP_RTS | MTW_DROP_PSPOLL; + } + mtw_write(sc, MTW_RX_FILTR_CFG, tmp); + + mtw_write(sc, MTW_MAC_SYS_CTRL, MTW_MAC_RX_EN | MTW_MAC_TX_EN); + return (0); +} +static int +mt7601_rxdc_cal(struct mtw_softc *sc) +{ + uint32_t tmp; + uint8_t bbp; + int ntries; + + mtw_read(sc, MTW_MAC_SYS_CTRL, &tmp); + mtw_write(sc, MTW_MAC_SYS_CTRL, MTW_MAC_RX_EN); + mtw_bbp_write(sc, 158, 0x8d); + mtw_bbp_write(sc, 159, 0xfc); + mtw_bbp_write(sc, 158, 0x8c); + mtw_bbp_write(sc, 159, 0x4c); + + for (ntries = 0; ntries < 20; ntries++) { + DELAY(300); + mtw_bbp_write(sc, 158, 0x8c); + mtw_bbp_read(sc, 159, &bbp); + if (bbp == 0x0c) + break; + } + + if (ntries == 20) + return (ETIMEDOUT); + + mtw_write(sc, MTW_MAC_SYS_CTRL, 0); + mtw_bbp_write(sc, 158, 0x8d); + mtw_bbp_write(sc, 159, 0xe0); + mtw_write(sc, MTW_MAC_SYS_CTRL, tmp); + return (0); +} + +static int +mt7601_r49_read(struct mtw_softc *sc, uint8_t flag, int8_t *val) +{ + uint8_t bbp; + + mtw_bbp_read(sc, 47, &bbp); + bbp = 0x90; + mtw_bbp_write(sc, 47, bbp); + bbp &= ~0x0f; + bbp |= flag; + mtw_bbp_write(sc, 47, bbp); + return (mtw_bbp_read(sc, 49, val)); +} + +static int +mt7601_rf_temperature(struct mtw_softc *sc, int8_t *val) +{ + uint32_t rfb, rfs; + uint8_t bbp; + int ntries; + + mtw_read(sc, MTW_RF_BYPASS0, &rfb); + mtw_read(sc, MTW_RF_SETTING0, &rfs); + mtw_write(sc, MTW_RF_BYPASS0, 0); + mtw_write(sc, MTW_RF_SETTING0, 0x10); + mtw_write(sc, MTW_RF_BYPASS0, 0x10); + + mtw_bbp_read(sc, 47, &bbp); + bbp &= ~0x7f; + bbp |= 0x10; + mtw_bbp_write(sc, 47, bbp); + + mtw_bbp_write(sc, 22, 0x40); + + for (ntries = 0; ntries < 10; ntries++) { + mtw_bbp_read(sc, 47, &bbp); + if ((bbp & 0x10) == 0) + break; + } + if (ntries == 10) + return (ETIMEDOUT); + + mt7601_r49_read(sc, MT7601_R47_TEMP, val); + + mtw_bbp_write(sc, 22, 0); + + mtw_bbp_read(sc, 21, &bbp); + bbp |= 0x02; + mtw_bbp_write(sc, 21, bbp); + bbp &= ~0x02; + mtw_bbp_write(sc, 21, bbp); + + mtw_write(sc, MTW_RF_BYPASS0, 0); + mtw_write(sc, MTW_RF_SETTING0, rfs); + mtw_write(sc, MTW_RF_BYPASS0, rfb); + return (0); +} + +static int +mt7601_rf_setup(struct mtw_softc *sc) +{ + uint32_t tmp; + uint8_t rf; + int error; + + if (sc->sc_rf_calibrated) + return (0); + + /* init RF registers */ + if ((error = mt7601_rf_init(sc)) != 0) + return (error); + + /* init frequency offset */ + mtw_rf_write(sc, 0, 12, sc->rf_freq_offset); + mtw_rf_read(sc, 0, 12, &rf); + + /* read temperature */ + mt7601_rf_temperature(sc, &rf); + sc->bbp_temp = rf; + device_printf(sc->sc_dev, "BBP temp 0x%x\n", rf); + + mtw_rf_read(sc, 0, 7, &rf); + if ((error = mtw_mcu_calibrate(sc, 0x1, 0)) != 0) + return (error); + mtw_delay(sc, 100); + mtw_rf_read(sc, 0, 7, &rf); + + /* Calibrate VCO RF 0/4 */ + mtw_rf_write(sc, 0, 4, 0x0a); + mtw_rf_write(sc, 0, 4, 0x20); + mtw_rf_read(sc, 0, 4, &rf); + mtw_rf_write(sc, 0, 4, rf | 0x80); + + if ((error = mtw_mcu_calibrate(sc, 0x9, 0)) != 0) + return (error); + if ((error = mt7601_rxdc_cal(sc)) != 0) + return (error); + if ((error = mtw_mcu_calibrate(sc, 0x6, 1)) != 0) + return (error); + if ((error = mtw_mcu_calibrate(sc, 0x6, 0)) != 0) + return (error); + if ((error = mtw_mcu_calibrate(sc, 0x4, 0)) != 0) + return (error); + if ((error = mtw_mcu_calibrate(sc, 0x5, 0)) != 0) + return (error); + + mtw_read(sc, MTW_LDO_CFG0, &tmp); + tmp &= ~(1 << 4); + tmp |= (1 << 2); + mtw_write(sc, MTW_LDO_CFG0, tmp); + + if ((error = mtw_mcu_calibrate(sc, 0x8, 0)) != 0) + return (error); + if ((error = mt7601_rxdc_cal(sc)) != 0) + return (error); + + sc->sc_rf_calibrated = 1; + return (0); +} + +static void +mtw_set_txrts(struct mtw_softc *sc) +{ + uint32_t tmp; + + /* set RTS threshold */ + mtw_read(sc, MTW_TX_RTS_CFG, &tmp); + tmp &= ~0xffff00; + tmp |= 0x1000 << MTW_RTS_THRES_SHIFT; + mtw_write(sc, MTW_TX_RTS_CFG, tmp); +} +static int +mtw_mcu_radio(struct mtw_softc *sc, int func, uint32_t val) +{ + struct mtw_mcu_cmd_16 cmd; + + cmd.r1 = htole32(func); + cmd.r2 = htole32(val); + cmd.r3 = 0; + cmd.r4 = 0; + return (mtw_mcu_cmd(sc, 20, &cmd, sizeof(struct mtw_mcu_cmd_16))); +} +static void +mtw_init_locked(struct mtw_softc *sc) +{ + + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + uint32_t tmp; + int i, error, ridx, ntries; + if (ic->ic_nrunning > 1) + return; + mtw_stop(sc); + + for (i = 0; i != MTW_EP_QUEUES; i++) + mtw_setup_tx_list(sc, &sc->sc_epq[i]); + + for (ntries = 0; ntries < 100; ntries++) { + if ((error = mtw_read(sc, MTW_WPDMA_GLO_CFG, &tmp)) != 0) + goto fail; + if ((tmp & (MTW_TX_DMA_BUSY | MTW_RX_DMA_BUSY)) == 0) + break; + DELAY(1000); + } + if (ntries == 100) { + device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); + error = ETIMEDOUT; + goto fail; + } + tmp &= 0xff0; + tmp |= MTW_TX_WB_DDONE; + mtw_write(sc, MTW_WPDMA_GLO_CFG, tmp); + + mtw_set_leds(sc, MTW_LED_MODE_ON); + /* reset MAC and baseband */ + mtw_write(sc, MTW_MAC_SYS_CTRL, MTW_BBP_HRST | MTW_MAC_SRST); + mtw_write(sc, MTW_USB_DMA_CFG, 0); + mtw_write(sc, MTW_MAC_SYS_CTRL, 0); + + /* init MAC values */ + if (sc->asic_ver == 0x7601) { + for (i = 0; i < nitems(mt7601_def_mac); i++) + mtw_write(sc, mt7601_def_mac[i].reg, + mt7601_def_mac[i].val); + } + + /* wait while MAC is busy */ + for (ntries = 0; ntries < 100; ntries++) { + if ((error = mtw_read(sc, MTW_MAC_STATUS_REG, &tmp)) != 0) + goto fail; + if (!(tmp & (MTW_RX_STATUS_BUSY | MTW_TX_STATUS_BUSY))) + break; + DELAY(1000); + } + if (ntries == 100) { + error = ETIMEDOUT; + goto fail; + } + + /* set MAC address */ + + mtw_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); + + /* clear WCID attribute table */ + mtw_set_region_4(sc, MTW_WCID_ATTR(0), 1, 8 * 32); + + mtw_write(sc, 0x1648, 0x00830083); + mtw_read(sc, MTW_FCE_L2_STUFF, &tmp); + tmp &= ~MTW_L2S_WR_MPDU_LEN_EN; + mtw_write(sc, MTW_FCE_L2_STUFF, tmp); + + /* RTS config */ + mtw_set_txrts(sc); + + /* clear Host to MCU mailbox */ + mtw_write(sc, MTW_BBP_CSR, 0); + mtw_write(sc, MTW_H2M_MAILBOX, 0); + + /* clear RX WCID search table */ + mtw_set_region_4(sc, MTW_WCID_ENTRY(0), 0xffffffff, 512); + + /* abort TSF synchronization */ + mtw_abort_tsf_sync(sc); + + mtw_read(sc, MTW_US_CYC_CNT, &tmp); + tmp = (tmp & ~0xff); + if (sc->asic_ver == 0x7601) + tmp |= 0x1e; + mtw_write(sc, MTW_US_CYC_CNT, tmp); + + /* clear shared key table */ + mtw_set_region_4(sc, MTW_SKEY(0, 0), 0, 8 * 32); + + /* clear IV/EIV table */ + mtw_set_region_4(sc, MTW_IVEIV(0), 0, 8 * 32); + + /* clear shared key mode */ + mtw_write(sc, MTW_SKEY_MODE_0_7, 0); + mtw_write(sc, MTW_SKEY_MODE_8_15, 0); + + /* txop truncation */ + mtw_write(sc, MTW_TXOP_CTRL_CFG, 0x0000583f); + + /* init Tx power for all Tx rates */ + for (ridx = 0; ridx < 5; ridx++) { + if (sc->txpow20mhz[ridx] == 0xffffffff) + continue; + mtw_write(sc, MTW_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); + } + mtw_write(sc, MTW_TX_PWR_CFG7, 0); + mtw_write(sc, MTW_TX_PWR_CFG9, 0); + + mtw_read(sc, MTW_CMB_CTRL, &tmp); + tmp &= ~(1 << 18 | 1 << 14); + mtw_write(sc, MTW_CMB_CTRL, tmp); + + /* clear USB DMA */ + mtw_write(sc, MTW_USB_DMA_CFG, + MTW_USB_TX_EN | MTW_USB_RX_EN | MTW_USB_RX_AGG_EN | + MTW_USB_TX_CLEAR | MTW_USB_TXOP_HALT | MTW_USB_RX_WL_DROP); + mtw_delay(sc, 50); + mtw_read(sc, MTW_USB_DMA_CFG, &tmp); + tmp &= ~(MTW_USB_TX_CLEAR | MTW_USB_TXOP_HALT | MTW_USB_RX_WL_DROP); + mtw_write(sc, MTW_USB_DMA_CFG, tmp); + + /* enable radio */ + mtw_mcu_radio(sc, 0x31, 0); + + /* init RF registers */ + if (sc->asic_ver == 0x7601) + mt7601_rf_init(sc); + + /* init baseband registers */ + if (sc->asic_ver == 0x7601) + error = mt7601_bbp_init(sc); + + if (error != 0) { + device_printf(sc->sc_dev, "could not initialize BBP\n"); + goto fail; + } + + /* setup and calibrate RF */ + error = mt7601_rf_setup(sc); + + if (error != 0) { + device_printf(sc->sc_dev, "could not initialize RF\n"); + goto fail; + } + + /* select default channel */ + mtw_set_chan(sc, ic->ic_curchan); + + /* setup initial protection mode */ + mtw_updateprot_cb(ic); + + sc->sc_flags |= MTW_RUNNING; + sc->cmdq_run = MTW_CMDQ_GO; + for (i = 0; i != MTW_N_XFER; i++) + usbd_xfer_set_stall(sc->sc_xfer[i]); + + usbd_transfer_start(sc->sc_xfer[MTW_BULK_RX]); + + error = mtw_txrx_enable(sc); + if (error != 0) { + goto fail; + } + + return; + +fail: + + mtw_stop(sc); + return; +} + +static void +mtw_stop(void *arg) +{ + struct mtw_softc *sc = (struct mtw_softc *)arg; + uint32_t tmp; + int i, ntries, error; + + MTW_LOCK_ASSERT(sc, MA_OWNED); + + sc->sc_flags &= ~MTW_RUNNING; + + sc->ratectl_run = MTW_RATECTL_OFF; + sc->cmdq_run = sc->cmdq_key_set; + + MTW_UNLOCK(sc); + + for (i = 0; i < MTW_N_XFER; i++) + usbd_transfer_drain(sc->sc_xfer[i]); + + MTW_LOCK(sc); + + mtw_drain_mbufq(sc); + + if (sc->rx_m != NULL) { + m_free(sc->rx_m); + sc->rx_m = NULL; + } + + /* Disable Tx/Rx DMA. */ + mtw_read(sc, MTW_WPDMA_GLO_CFG, &tmp); + tmp &= ~(MTW_RX_DMA_EN | MTW_TX_DMA_EN); + mtw_write(sc, MTW_WPDMA_GLO_CFG, tmp); + // mtw_usb_dma_write(sc, 0); + + for (ntries = 0; ntries < 100; ntries++) { + if (mtw_read(sc, MTW_WPDMA_GLO_CFG, &tmp) != 0) + break; + if ((tmp & (MTW_TX_DMA_BUSY | MTW_RX_DMA_BUSY)) == 0) + break; + DELAY(10); + } + if (ntries == 100) { + device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); + } + + /* stop MAC Tx/Rx */ + mtw_read(sc, MTW_MAC_SYS_CTRL, &tmp); + tmp &= ~(MTW_MAC_RX_EN | MTW_MAC_TX_EN); + mtw_write(sc, MTW_MAC_SYS_CTRL, tmp); + + /* disable RTS retry */ + mtw_read(sc, MTW_TX_RTS_CFG, &tmp); + tmp &= ~0xff; + mtw_write(sc, MTW_TX_RTS_CFG, tmp); + + /* US_CYC_CFG */ + mtw_read(sc, MTW_US_CYC_CNT, &tmp); + tmp = (tmp & ~0xff); + mtw_write(sc, MTW_US_CYC_CNT, tmp); + + /* stop PBF */ + mtw_read(sc, MTW_PBF_CFG, &tmp); + tmp &= ~0x3; + mtw_write(sc, MTW_PBF_CFG, tmp); + + /* wait for pending Tx to complete */ + for (ntries = 0; ntries < 100; ntries++) { + if ((error = mtw_read(sc, MTW_TXRXQ_PCNT, &tmp)) != 0) + break; + if ((tmp & MTW_TX2Q_PCNT_MASK) == 0) + break; + } + +} + +static void +mtw_delay(struct mtw_softc *sc, u_int ms) +{ + usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? &sc->sc_mtx : NULL, + USB_MS_TO_TICKS(ms)); +} + +static void +mtw_update_chw(struct ieee80211com *ic) +{ + + printf("%s: TODO\n", __func__); +} + +static int +mtw_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) +{ + + /* For now, no A-MPDU TX support in the driver */ + return (0); +} + +static device_method_t mtw_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, mtw_match), + DEVMETHOD(device_attach, mtw_attach), + DEVMETHOD(device_detach, mtw_detach), DEVMETHOD_END +}; + +static driver_t mtw_driver = { .name = "mtw", + .methods = mtw_methods, + .size = sizeof(struct mtw_softc) }; + +DRIVER_MODULE(mtw, uhub, mtw_driver, mtw_driver_loaded, NULL); +MODULE_DEPEND(mtw, wlan, 1, 1, 1); +MODULE_DEPEND(mtw, usb, 1, 1, 1); +MODULE_DEPEND(mtw, firmware, 1, 1, 1); +MODULE_VERSION(mtw, 1); +USB_PNP_HOST_INFO(mtw_devs); diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtwreg.h b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtwreg.h new file mode 100644 index 0000000000..05af4f4f6c --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtwreg.h @@ -0,0 +1,1439 @@ +/* $OpenBSD: mtwreg.h,v 1.2 2022/07/27 06:41:04 hastings Exp $ */ +/* + * Copyright (c) 2007 Damien Bergamini + * Copyright (c) 2021 James Hastings + * + * 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. + */ + +#define MTW_ASIC_VER 0x0000 +#define MTW_CMB_CTRL 0x0020 +#define MTW_EFUSE_CTRL 0x0024 +#define MTW_EFUSE_DATA0 0x0028 +#define MTW_EFUSE_DATA1 0x002c +#define MTW_EFUSE_DATA2 0x0030 +#define MTW_EFUSE_DATA3 0x0034 +#define MTW_OSC_CTRL 0x0038 +#define MTW_COEX_CFG0 0x0040 +#define MTW_PLL_CTRL 0x0050 +#define MTW_LDO_CFG0 0x006c +#define MTW_LDO_CFG1 0x0070 +#define MTW_WLAN_CTRL 0x0080 + +/* SCH/DMA registers */ +#define MTW_INT_STATUS 0x0200 +#define RT2860_INT_MASK 0x0204 +#define MTW_WPDMA_GLO_CFG 0x0208 +#define RT2860_WPDMA_RST_IDX 0x020c +#define RT2860_DELAY_INT_CFG 0x0210 +#define MTW_WMM_AIFSN_CFG 0x0214 +#define MTW_WMM_CWMIN_CFG 0x0218 +#define MTW_WMM_CWMAX_CFG 0x021c +#define MTW_WMM_TXOP0_CFG 0x0220 +#define MTW_WMM_TXOP1_CFG 0x0224 +#define RT2860_GPIO_CTRL 0x0228 +#define RT2860_MCU_CMD_REG 0x022c +#define MTW_MCU_DMA_ADDR 0x0230 +#define MTW_MCU_DMA_LEN 0x0234 +#define MTW_USB_DMA_CFG 0x0238 +#define RT2860_TX_BASE_PTR(qid) (0x0230 + (qid) * 16) +#define RT2860_TX_MAX_CNT(qid) (0x0234 + (qid) * 16) +#define RT2860_TX_CTX_IDX(qid) (0x0238 + (qid) * 16) +#define RT2860_TX_DTX_IDX(qid) (0x023c + (qid) * 16) +#define MTW_TSO_CTRL 0x0250 +#define MTW_HDR_TRANS_CTRL 0x0260 +#define RT2860_RX_BASE_PTR 0x0290 +#define RT2860_RX_MAX_CNT 0x0294 +#define RT2860_RX_CALC_IDX 0x0298 +#define RT2860_FS_DRX_IDX 0x029c +#define MTW_US_CYC_CNT 0x02a4 + +#define MTW_TX_RING_BASE 0x0300 +#define MTW_RX_RING_BASE 0x03c0 + +/* Packet Buffer registers */ +#define MTW_SYS_CTRL 0x0400 +#define MTW_PBF_CFG 0x0404 +#define MTW_TX_MAX_PCNT 0x0408 +#define MTW_RX_MAX_PCNT 0x040c +#define MTW_PBF_CTRL 0x0410 +#define RT2860_BUF_CTRL 0x0410 +#define RT2860_MCU_INT_STA 0x0414 +#define RT2860_MCU_INT_ENA 0x0418 +#define RT2860_TXQ_IO(qid) (0x041c + (qid) * 4) +#define MTW_BCN_OFFSET0 0x041c +#define MTW_BCN_OFFSET1 0x0420 +#define MTW_BCN_OFFSET2 0x0424 +#define MTW_BCN_OFFSET3 0x0428 +#define RT2860_RX0Q_IO 0x0424 +#define MTW_RXQ_STA 0x0430 +#define MTW_TXQ_STA 0x0434 +#define MTW_TXRXQ_PCNT 0x0438 + +/* RF registers */ +#define MTW_RF_CSR 0x0500 +#define MTW_RF_BYPASS0 0x0504 +#define MTW_RF_BYPASS1 0x0508 +#define MTW_RF_SETTING0 0x050C +#define MTW_RF_MISC 0x0518 +#define MTW_RF_DATA_WR 0x0524 +#define MTW_RF_CTRL 0x0528 +#define MTW_RF_DATA_RD 0x052c + +/* MCU registers */ +#define MTW_MCU_RESET_CTL 0x070c +#define MTW_MCU_INT_LEVEL 0x0718 +#define MTW_MCU_COM_REG0 0x0730 +#define MTW_MCU_COM_REG1 0x0734 +#define MTW_MCU_COM_REG2 0x0738 +#define MTW_MCU_COM_REG3 0x073c +#define MTW_FCE_PSE_CTRL 0x0800 +#define MTW_FCE_PARAMETERS 0x0804 +#define MTW_FCE_CSO 0x0808 +#define MTW_FCE_L2_STUFF 0x080c +#define MTW_FCE_WLAN_FLOW_CTRL 0x0824 +#define MTW_TX_CPU_FCE_BASE 0x09a0 +#define MTW_TX_CPU_FCE_MAX_COUNT 0x09a4 +#define MTW_MCU_FW_IDX 0x09a8 +#define MTW_FCE_PDMA 0x09c4 +#define MTW_FCE_SKIP_FS 0x0a6c + +/* MAC registers */ +#define MTW_MAC_VER_ID 0x1000 +#define MTW_MAC_SYS_CTRL 0x1004 +#define MTW_MAC_ADDR_DW0 0x1008 +#define MTW_MAC_ADDR_DW1 0x100c +#define MTW_MAC_BSSID_DW0 0x1010 +#define MTW_MAC_BSSID_DW1 0x1014 +#define MTW_MAX_LEN_CFG 0x1018 +#define MTW_BBP_CSR 0x101c +#define MTW_LED_CFG 0x102c +#define MTW_AMPDU_MAX_LEN_20M1S 0x1030 +#define MTW_AMPDU_MAX_LEN_20M2S 0x1034 +#define MTW_AMPDU_MAX_LEN_40M1S 0x1038 +#define MTW_AMPDU_MAX_LEN_40M2S 0x103c +#define MTW_AMPDU_MAX_LEN 0x1040 + +/* MAC Timing control registers */ +#define MTW_XIFS_TIME_CFG 0x1100 +#define MTW_BKOFF_SLOT_CFG 0x1104 +#define RT2860_NAV_TIME_CFG 0x1108 +#define RT2860_CH_TIME_CFG 0x110c +#define RT2860_PBF_LIFE_TIMER 0x1110 +#define MTW_BCN_TIME_CFG 0x1114 +#define MTW_TBTT_SYNC_CFG 0x1118 +#define MTW_TSF_TIMER_DW0 0x111c +#define MTW_TSF_TIMER_DW1 0x1120 +#define RT2860_TBTT_TIMER 0x1124 +#define MTW_INT_TIMER_CFG 0x1128 +#define RT2860_INT_TIMER_EN 0x112c +#define RT2860_CH_IDLE_TIME 0x1130 + +/* MAC Power Save configuration registers */ +#define MTW_MAC_STATUS_REG 0x1200 +#define MTW_PWR_PIN_CFG 0x1204 +#define MTW_AUTO_WAKEUP_CFG 0x1208 +#define MTW_AUX_CLK_CFG 0x120c +#define MTW_BBP_PA_MODE_CFG0 0x1214 +#define MTW_BBP_PA_MODE_CFG1 0x1218 +#define MTW_RF_PA_MODE_CFG0 0x121c +#define MTW_RF_PA_MODE_CFG1 0x1220 +#define MTW_RF_PA_MODE_ADJ0 0x1228 +#define MTW_RF_PA_MODE_ADJ1 0x122c +#define MTW_DACCLK_EN_DLY_CFG 0x1264 /* MT7612 */ + +/* MAC TX configuration registers */ +#define MTW_EDCA_AC_CFG(aci) (0x1300 + (aci) * 4) +#define MTW_EDCA_TID_AC_MAP 0x1310 +#define MTW_TX_PWR_CFG(ridx) (0x1314 + (ridx) * 4) +#define MTW_TX_PIN_CFG 0x1328 +#define MTW_TX_BAND_CFG 0x132c +#define MTW_TX_SW_CFG0 0x1330 +#define MTW_TX_SW_CFG1 0x1334 +#define MTW_TX_SW_CFG2 0x1338 +#define RT2860_TXOP_THRES_CFG 0x133c +#define MTW_TXOP_CTRL_CFG 0x1340 +#define MTW_TX_RTS_CFG 0x1344 +#define MTW_TX_TIMEOUT_CFG 0x1348 +#define MTW_TX_RETRY_CFG 0x134c +#define MTW_TX_LINK_CFG 0x1350 +#define MTW_HT_FBK_CFG0 0x1354 +#define MTW_HT_FBK_CFG1 0x1358 +#define MTW_LG_FBK_CFG0 0x135c +#define MTW_LG_FBK_CFG1 0x1360 +#define MTW_CCK_PROT_CFG 0x1364 +#define MTW_OFDM_PROT_CFG 0x1368 +#define MTW_MM20_PROT_CFG 0x136c +#define MTW_MM40_PROT_CFG 0x1370 +#define MTW_GF20_PROT_CFG 0x1374 +#define MTW_GF40_PROT_CFG 0x1378 +#define RT2860_EXP_CTS_TIME 0x137c +#define MTW_EXP_ACK_TIME 0x1380 +#define MTW_TX_PWR_CFG5 0x1384 +#define MTW_TX_PWR_CFG6 0x1388 +#define MTW_TX_PWR_EXT_CFG(ridx) (0x1390 + (ridx) * 4) +#define MTW_TX0_RF_GAIN_CORR 0x13a0 +#define MTW_TX1_RF_GAIN_CORR 0x13a4 +#define MTW_TX0_RF_GAIN_ATTEN 0x13a8 +#define MTW_TX_ALC_CFG3 0x13ac +#define MTW_TX_ALC_CFG0 0x13b0 +#define MTW_TX_ALC_CFG1 0x13b4 +#define MTW_TX_ALC_CFG4 0x13c0 +#define MTW_TX_ALC_VGA3 0x13c8 +#define MTW_TX_PWR_CFG7 0x13d4 +#define MTW_TX_PWR_CFG8 0x13d8 +#define MTW_TX_PWR_CFG9 0x13dc +#define MTW_VHT20_PROT_CFG 0x13e0 +#define MTW_VHT40_PROT_CFG 0x13e4 +#define MTW_VHT80_PROT_CFG 0x13e8 +#define MTW_TX_PIFS_CFG 0x13ec /* MT761X */ + +/* MAC RX configuration registers */ +#define MTW_RX_FILTR_CFG 0x1400 +#define MTW_AUTO_RSP_CFG 0x1404 +#define MTW_LEGACY_BASIC_RATE 0x1408 +#define MTW_HT_BASIC_RATE 0x140c +#define MTW_HT_CTRL_CFG 0x1410 +#define RT2860_SIFS_COST_CFG 0x1414 +#define RT2860_RX_PARSER_CFG 0x1418 + +/* MAC Security configuration registers */ +#define RT2860_TX_SEC_CNT0 0x1500 +#define RT2860_RX_SEC_CNT0 0x1504 +#define RT2860_CCMP_FC_MUTE 0x1508 +#define MTW_PN_PAD_MODE 0x150c /* MT761X */ + +/* MAC HCCA/PSMP configuration registers */ +#define MTW_TXOP_HLDR_ADDR0 0x1600 +#define MTW_TXOP_HLDR_ADDR1 0x1604 +#define MTW_TXOP_HLDR_ET 0x1608 +#define RT2860_QOS_CFPOLL_RA_DW0 0x160c +#define RT2860_QOS_CFPOLL_A1_DW1 0x1610 +#define RT2860_QOS_CFPOLL_QC 0x1614 +#define MTW_PROT_AUTO_TX_CFG 0x1648 + +/* MAC Statistics Counters */ +#define MTW_RX_STA_CNT0 0x1700 +#define MTW_RX_STA_CNT1 0x1704 +#define MTW_RX_STA_CNT2 0x1708 +#define MTW_TX_STA_CNT0 0x170c +#define MTW_TX_STA_CNT1 0x1710 +#define MTW_TX_STA_CNT2 0x1714 +#define MTW_TX_STAT_FIFO 0x1718 + +/* RX WCID search table */ +#define MTW_WCID_ENTRY(wcid) (0x1800 + (wcid) * 8) + +/* MT761x Baseband */ +#define MTW_BBP_CORE(x) (0x2000 + (x) * 4) +#define MTW_BBP_IBI(x) (0x2100 + (x) * 4) +#define MTW_BBP_AGC(x) (0x2300 + (x) * 4) +#define MTW_BBP_TXC(x) (0x2400 + (x) * 4) +#define MTW_BBP_RXC(x) (0x2500 + (x) * 4) +#define MTW_BBP_TXQ(x) (0x2600 + (x) * 4) +#define MTW_BBP_TXBE(x) (0x2700 + (x) * 4) +#define MTW_BBP_RXFE(x) (0x2800 + (x) * 4) +#define MTW_BBP_RXO(x) (0x2900 + (x) * 4) +#define MTW_BBP_DFS(x) (0x2a00 + (x) * 4) +#define MTW_BBP_TR(x) (0x2b00 + (x) * 4) +#define MTW_BBP_CAL(x) (0x2c00 + (x) * 4) +#define MTW_BBP_DSC(x) (0x2e00 + (x) * 4) +#define MTW_BBP_PFMU(x) (0x2f00 + (x) * 4) + +#define MTW_SKEY_MODE_16_23 0x7008 +#define MTW_SKEY_MODE_24_31 0x700c +#define MTW_H2M_MAILBOX 0x7010 + +/* Pair-wise key table */ +#define MTW_PKEY(wcid) (0x8000 + (wcid) * 32) + +/* USB 3.0 DMA */ +#define MTW_USB_U3DMA_CFG 0x9018 + +/* IV/EIV table */ +#define MTW_IVEIV(wcid) (0xa000 + (wcid) * 8) + +/* WCID attribute table */ +#define MTW_WCID_ATTR(wcid) (0xa800 + (wcid) * 4) + +/* Shared Key Table */ +#define MTW_SKEY(vap, kidx) ((vap & 8) ? MTW_SKEY_1(vap, kidx) : \ + MTW_SKEY_0(vap, kidx)) +#define MTW_SKEY_0(vap, kidx) (0xac00 + (4 * (vap) + (kidx)) * 32) +#define MTW_SKEY_1(vap, kidx) (0xb400 + (4 * ((vap) & 7) + (kidx)) * 32) + +/* Shared Key Mode */ +#define MTW_SKEY_MODE_0_7 0xb000 +#define MTW_SKEY_MODE_8_15 0xb004 + +/* Shared Key Mode */ +#define MTW_SKEY_MODE_BASE 0xb000 + +/* Beacon */ +#define MTW_BCN_BASE 0xc000 + +/* possible flags for register CMB_CTRL 0x0020 */ +#define MTW_PLL_LD (1U << 23) +#define MTW_XTAL_RDY (1U << 22) + +/* possible flags for register EFUSE_CTRL 0x0024 */ +#define MTW_SEL_EFUSE (1U << 31) +#define MTW_EFSROM_KICK (1U << 30) +#define MTW_EFSROM_AIN_MASK 0x03ff0000 +#define MTW_EFSROM_AIN_SHIFT 16 +#define MTW_EFSROM_MODE_MASK 0x000000c0 +#define MTW_EFUSE_AOUT_MASK 0x0000003f + +/* possible flags for register OSC_CTRL 0x0038 */ +#define MTW_OSC_EN (1U << 31) +#define MTW_OSC_CAL_REQ (1U << 30) +#define MTW_OSC_CLK_32K_VLD (1U << 29) +#define MTW_OSC_CAL_ACK (1U << 28) +#define MTW_OSC_CAL_CNT (0xfff << 16) +#define MTW_OSC_REF_CYCLE 0x1fff + +/* possible flags for register WLAN_CTRL 0x0080 */ +#define MTW_GPIO_OUT_OE_ALL (0xff << 24) +#define MTW_GPIO_OUT_ALL (0xff << 16) +#define MTW_GPIO_IN_ALL (0xff << 8) +#define MTW_THERM_CKEN (1U << 9) +#define MTW_THERM_RST (1U << 8) +#define MTW_INV_TR_SW0 (1U << 6) +#define MTW_FRC_WL_ANT_SET (1U << 5) +#define MTW_PCIE_APP0_CLK_REQ (1U << 4) +#define MTW_WLAN_RESET (1U << 3) +#define MTW_WLAN_RESET_RF (1U << 2) +#define MTW_WLAN_CLK_EN (1U << 1) +#define MTW_WLAN_EN (1U << 0) + +/* possible flags for registers INT_STATUS/INT_MASK 0x0200 */ +#define RT2860_TX_COHERENT (1 << 17) +#define RT2860_RX_COHERENT (1 << 16) +#define RT2860_MAC_INT_4 (1 << 15) +#define RT2860_MAC_INT_3 (1 << 14) +#define RT2860_MAC_INT_2 (1 << 13) +#define RT2860_MAC_INT_1 (1 << 12) +#define RT2860_MAC_INT_0 (1 << 11) +#define RT2860_TX_RX_COHERENT (1 << 10) +#define RT2860_MCU_CMD_INT (1 << 9) +#define RT2860_TX_DONE_INT5 (1 << 8) +#define RT2860_TX_DONE_INT4 (1 << 7) +#define RT2860_TX_DONE_INT3 (1 << 6) +#define RT2860_TX_DONE_INT2 (1 << 5) +#define RT2860_TX_DONE_INT1 (1 << 4) +#define RT2860_TX_DONE_INT0 (1 << 3) +#define RT2860_RX_DONE_INT (1 << 2) +#define RT2860_TX_DLY_INT (1 << 1) +#define RT2860_RX_DLY_INT (1 << 0) + +/* possible flags for register WPDMA_GLO_CFG 0x0208 */ +#define MTW_HDR_SEG_LEN_SHIFT 8 +#define MTW_BIG_ENDIAN (1 << 7) +#define MTW_TX_WB_DDONE (1 << 6) +#define MTW_WPDMA_BT_SIZE_SHIFT 4 +#define MTW_WPDMA_BT_SIZE16 0 +#define MTW_WPDMA_BT_SIZE32 1 +#define MTW_WPDMA_BT_SIZE64 2 +#define MTW_WPDMA_BT_SIZE128 3 +#define MTW_RX_DMA_BUSY (1 << 3) +#define MTW_RX_DMA_EN (1 << 2) +#define MTW_TX_DMA_BUSY (1 << 1) +#define MTW_TX_DMA_EN (1 << 0) + +/* possible flags for register DELAY_INT_CFG */ +#define RT2860_TXDLY_INT_EN (1U << 31) +#define RT2860_TXMAX_PINT_SHIFT 24 +#define RT2860_TXMAX_PTIME_SHIFT 16 +#define RT2860_RXDLY_INT_EN (1U << 15) +#define RT2860_RXMAX_PINT_SHIFT 8 +#define RT2860_RXMAX_PTIME_SHIFT 0 + +/* possible flags for register GPIO_CTRL */ +#define RT2860_GPIO_D_SHIFT 8 +#define RT2860_GPIO_O_SHIFT 0 + +/* possible flags for register MCU_DMA_ADDR 0x0230 */ +#define MTW_MCU_READY (1U << 0) + +/* possible flags for register USB_DMA_CFG 0x0238 */ +#define MTW_USB_TX_BUSY (1U << 31) +#define MTW_USB_RX_BUSY (1U << 30) +#define MTW_USB_EPOUT_VLD_SHIFT 24 +#define MTW_USB_RX_WL_DROP (1U << 25) +#define MTW_USB_TX_EN (1U << 23) +#define MTW_USB_RX_EN (1U << 22) +#define MTW_USB_RX_AGG_EN (1U << 21) +#define MTW_USB_TXOP_HALT (1U << 20) +#define MTW_USB_TX_CLEAR (1U << 19) +#define MTW_USB_PHY_WD_EN (1U << 16) +#define MTW_USB_PHY_MAN_RST (1U << 15) +#define MTW_USB_RX_AGG_LMT(x) ((x) << 8) /* in unit of 1KB */ +#define MTW_USB_RX_AGG_TO(x) ((x) & 0xff) /* in unit of 33ns */ + +/* possible flags for register US_CYC_CNT 0x02a4 */ +#define RT2860_TEST_EN (1 << 24) +#define RT2860_TEST_SEL_SHIFT 16 +#define RT2860_BT_MODE_EN (1 << 8) +#define RT2860_US_CYC_CNT_SHIFT 0 + +/* possible flags for register PBF_CFG 0x0404 */ +#define MTW_PBF_CFG_RX_DROP (1 << 8) +#define MTW_PBF_CFG_RX0Q_EN (1 << 4) +#define MTW_PBF_CFG_TX3Q_EN (1 << 3) +#define MTW_PBF_CFG_TX2Q_EN (1 << 2) +#define MTW_PBF_CFG_TX1Q_EN (1 << 1) +#define MTW_PBF_CFG_TX0Q_EN (1 << 0) + +/* possible flags for register BUF_CTRL 0x0410 */ +#define RT2860_WRITE_TXQ(qid) (1 << (11 - (qid))) +#define RT2860_NULL0_KICK (1 << 7) +#define RT2860_NULL1_KICK (1 << 6) +#define RT2860_BUF_RESET (1 << 5) +#define RT2860_READ_TXQ(qid) (1 << (3 - (qid)) +#define RT2860_READ_RX0Q (1 << 0) + +/* possible flags for registers MCU_INT_STA/MCU_INT_ENA */ +#define RT2860_MCU_MAC_INT_8 (1 << 24) +#define RT2860_MCU_MAC_INT_7 (1 << 23) +#define RT2860_MCU_MAC_INT_6 (1 << 22) +#define RT2860_MCU_MAC_INT_4 (1 << 20) +#define RT2860_MCU_MAC_INT_3 (1 << 19) +#define RT2860_MCU_MAC_INT_2 (1 << 18) +#define RT2860_MCU_MAC_INT_1 (1 << 17) +#define RT2860_MCU_MAC_INT_0 (1 << 16) +#define RT2860_DTX0_INT (1 << 11) +#define RT2860_DTX1_INT (1 << 10) +#define RT2860_DTX2_INT (1 << 9) +#define RT2860_DRX0_INT (1 << 8) +#define RT2860_HCMD_INT (1 << 7) +#define RT2860_N0TX_INT (1 << 6) +#define RT2860_N1TX_INT (1 << 5) +#define RT2860_BCNTX_INT (1 << 4) +#define RT2860_MTX0_INT (1 << 3) +#define RT2860_MTX1_INT (1 << 2) +#define RT2860_MTX2_INT (1 << 1) +#define RT2860_MRX0_INT (1 << 0) + +/* possible flags for register TXRXQ_PCNT 0x0438 */ +#define MTW_RX0Q_PCNT_MASK 0xff000000 +#define MTW_TX2Q_PCNT_MASK 0x00ff0000 +#define MTW_TX1Q_PCNT_MASK 0x0000ff00 +#define MTW_TX0Q_PCNT_MASK 0x000000ff + +/* possible flags for register RF_CSR_CFG 0x0500 */ +#define MTW_RF_CSR_KICK (1U << 31) +#define MTW_RF_CSR_WRITE (1U << 30) +#define MT7610_BANK_SHIFT 15 +#define MT7601_BANK_SHIFT 14 + +/* possible flags for register FCE_L2_STUFF 0x080c */ +#define MTW_L2S_WR_MPDU_LEN_EN (1 << 4) + +/* possible flag for register DEBUG_INDEX */ +#define RT5592_SEL_XTAL (1U << 31) + +/* possible flags for register MAC_SYS_CTRL 0x1004 */ +#define MTW_RX_TS_EN (1 << 7) +#define MTW_WLAN_HALT_EN (1 << 6) +#define MTW_PBF_LOOP_EN (1 << 5) +#define MTW_CONT_TX_TEST (1 << 4) +#define MTW_MAC_RX_EN (1 << 3) +#define MTW_MAC_TX_EN (1 << 2) +#define MTW_BBP_HRST (1 << 1) +#define MTW_MAC_SRST (1 << 0) + +/* possible flags for register MAC_BSSID_DW1 0x100c */ +#define RT2860_MULTI_BCN_NUM_SHIFT 18 +#define RT2860_MULTI_BSSID_MODE_SHIFT 16 + +/* possible flags for register MAX_LEN_CFG 0x1018 */ +#define RT2860_MIN_MPDU_LEN_SHIFT 16 +#define RT2860_MAX_PSDU_LEN_SHIFT 12 +#define RT2860_MAX_PSDU_LEN8K 0 +#define RT2860_MAX_PSDU_LEN16K 1 +#define RT2860_MAX_PSDU_LEN32K 2 +#define RT2860_MAX_PSDU_LEN64K 3 +#define RT2860_MAX_MPDU_LEN_SHIFT 0 + +/* possible flags for registers BBP_CSR_CFG 0x101c */ +#define MTW_BBP_CSR_KICK (1 << 17) +#define MTW_BBP_CSR_READ (1 << 16) +#define MTW_BBP_ADDR_SHIFT 8 +#define MTW_BBP_DATA_SHIFT 0 + +/* possible flags for register LED_CFG */ +#define MTW_LED_MODE_ON 0 +#define MTW_LED_MODE_DIM 1 +#define MTW_LED_MODE_BLINK_TX 2 +#define MTW_LED_MODE_SLOW_BLINK 3 + +/* possible flags for register XIFS_TIME_CFG 0x1100 */ +#define MTW_BB_RXEND_EN (1 << 29) +#define MTW_EIFS_TIME_SHIFT 20 +#define MTW_OFDM_XIFS_TIME_SHIFT 16 +#define MTW_OFDM_SIFS_TIME_SHIFT 8 +#define MTW_CCK_SIFS_TIME_SHIFT 0 + +/* possible flags for register BKOFF_SLOT_CFG 0x1104 */ +#define MTW_CC_DELAY_TIME_SHIFT 8 +#define MTW_SLOT_TIME 0 + +/* possible flags for register NAV_TIME_CFG */ +#define RT2860_NAV_UPD (1U << 31) +#define RT2860_NAV_UPD_VAL_SHIFT 16 +#define RT2860_NAV_CLR_EN (1U << 15) +#define RT2860_NAV_TIMER_SHIFT 0 + +/* possible flags for register CH_TIME_CFG */ +#define RT2860_EIFS_AS_CH_BUSY (1 << 4) +#define RT2860_NAV_AS_CH_BUSY (1 << 3) +#define RT2860_RX_AS_CH_BUSY (1 << 2) +#define RT2860_TX_AS_CH_BUSY (1 << 1) +#define RT2860_CH_STA_TIMER_EN (1 << 0) + +/* possible values for register BCN_TIME_CFG 0x1114 */ +#define MTW_TSF_INS_COMP_SHIFT 24 +#define MTW_BCN_TX_EN (1 << 20) +#define MTW_TBTT_TIMER_EN (1 << 19) +#define MTW_TSF_SYNC_MODE_SHIFT 17 +#define MTW_TSF_SYNC_MODE_DIS 0 +#define MTW_TSF_SYNC_MODE_STA 1 +#define MTW_TSF_SYNC_MODE_IBSS 2 +#define MTW_TSF_SYNC_MODE_HOSTAP 3 +#define MTW_TSF_TIMER_EN (1 << 16) +#define MTW_BCN_INTVAL_SHIFT 0 + +/* possible flags for register TBTT_SYNC_CFG 0x1118 */ +#define RT2860_BCN_CWMIN_SHIFT 20 +#define RT2860_BCN_AIFSN_SHIFT 16 +#define RT2860_BCN_EXP_WIN_SHIFT 8 +#define RT2860_TBTT_ADJUST_SHIFT 0 + +/* possible flags for register INT_TIMER_CFG 0x1128 */ +#define RT2860_GP_TIMER_SHIFT 16 +#define RT2860_PRE_TBTT_TIMER_SHIFT 0 + +/* possible flags for register INT_TIMER_EN */ +#define RT2860_GP_TIMER_EN (1 << 1) +#define RT2860_PRE_TBTT_INT_EN (1 << 0) + +/* possible flags for register MAC_STATUS_REG 0x1200 */ +#define MTW_RX_STATUS_BUSY (1 << 1) +#define MTW_TX_STATUS_BUSY (1 << 0) + +/* possible flags for register PWR_PIN_CFG 0x1204 */ +#define RT2860_IO_ADDA_PD (1 << 3) +#define RT2860_IO_PLL_PD (1 << 2) +#define RT2860_IO_RA_PE (1 << 1) +#define RT2860_IO_RF_PE (1 << 0) + +/* possible flags for register AUTO_WAKEUP_CFG 0x1208 */ +#define MTW_AUTO_WAKEUP_EN (1 << 15) +#define MTW_SLEEP_TBTT_NUM_SHIFT 8 +#define MTW_WAKEUP_LEAD_TIME_SHIFT 0 + +/* possible flags for register TX_PIN_CFG 0x1328 */ +#define RT2860_TRSW_POL (1U << 19) +#define RT2860_TRSW_EN (1U << 18) +#define RT2860_RFTR_POL (1U << 17) +#define RT2860_RFTR_EN (1U << 16) +#define RT2860_LNA_PE_G1_POL (1U << 15) +#define RT2860_LNA_PE_A1_POL (1U << 14) +#define RT2860_LNA_PE_G0_POL (1U << 13) +#define RT2860_LNA_PE_A0_POL (1U << 12) +#define RT2860_LNA_PE_G1_EN (1U << 11) +#define RT2860_LNA_PE_A1_EN (1U << 10) +#define RT2860_LNA_PE1_EN (RT2860_LNA_PE_A1_EN | RT2860_LNA_PE_G1_EN) +#define RT2860_LNA_PE_G0_EN (1U << 9) +#define RT2860_LNA_PE_A0_EN (1U << 8) +#define RT2860_LNA_PE0_EN (RT2860_LNA_PE_A0_EN | RT2860_LNA_PE_G0_EN) +#define RT2860_PA_PE_G1_POL (1U << 7) +#define RT2860_PA_PE_A1_POL (1U << 6) +#define RT2860_PA_PE_G0_POL (1U << 5) +#define RT2860_PA_PE_A0_POL (1U << 4) +#define RT2860_PA_PE_G1_EN (1U << 3) +#define RT2860_PA_PE_A1_EN (1U << 2) +#define RT2860_PA_PE_G0_EN (1U << 1) +#define RT2860_PA_PE_A0_EN (1U << 0) + +/* possible flags for register TX_BAND_CFG 0x132c */ +#define MTW_TX_BAND_SEL_2G (1 << 2) +#define MTW_TX_BAND_SEL_5G (1 << 1) +#define MTW_TX_BAND_UPPER_40M (1 << 0) + +/* possible flags for register TX_SW_CFG0 0x1330 */ +#define RT2860_DLY_RFTR_EN_SHIFT 24 +#define RT2860_DLY_TRSW_EN_SHIFT 16 +#define RT2860_DLY_PAPE_EN_SHIFT 8 +#define RT2860_DLY_TXPE_EN_SHIFT 0 + +/* possible flags for register TX_SW_CFG1 0x1334 */ +#define RT2860_DLY_RFTR_DIS_SHIFT 16 +#define RT2860_DLY_TRSW_DIS_SHIFT 8 +#define RT2860_DLY_PAPE_DIS SHIFT 0 + +/* possible flags for register TX_SW_CFG2 0x1338 */ +#define RT2860_DLY_LNA_EN_SHIFT 24 +#define RT2860_DLY_LNA_DIS_SHIFT 16 +#define RT2860_DLY_DAC_EN_SHIFT 8 +#define RT2860_DLY_DAC_DIS_SHIFT 0 + +/* possible flags for register TXOP_THRES_CFG 0x133c */ +#define RT2860_TXOP_REM_THRES_SHIFT 24 +#define RT2860_CF_END_THRES_SHIFT 16 +#define RT2860_RDG_IN_THRES 8 +#define RT2860_RDG_OUT_THRES 0 + +/* possible flags for register TXOP_CTRL_CFG 0x1340 */ +#define MTW_TXOP_ED_CCA_EN (1 << 20) +#define MTW_EXT_CW_MIN_SHIFT 16 +#define MTW_EXT_CCA_DLY_SHIFT 8 +#define MTW_EXT_CCA_EN (1 << 7) +#define MTW_LSIG_TXOP_EN (1 << 6) +#define MTW_TXOP_TRUN_EN_MIMOPS (1 << 4) +#define MTW_TXOP_TRUN_EN_TXOP (1 << 3) +#define MTW_TXOP_TRUN_EN_RATE (1 << 2) +#define MTW_TXOP_TRUN_EN_AC (1 << 1) +#define MTW_TXOP_TRUN_EN_TIMEOUT (1 << 0) + +/* possible flags for register TX_RTS_CFG 0x1344 */ +#define MTW_RTS_FBK_EN (1 << 24) +#define MTW_RTS_THRES_SHIFT 8 +#define MTW_RTS_RTY_LIMIT_SHIFT 0 + +/* possible flags for register TX_TIMEOUT_CFG 0x1348 */ +#define MTW_TXOP_TIMEOUT_SHIFT 16 +#define MTW_RX_ACK_TIMEOUT_SHIFT 8 +#define MTW_MPDU_LIFE_TIME_SHIFT 4 + +/* possible flags for register TX_RETRY_CFG 0x134c */ +#define MTW_TX_AUTOFB_EN (1 << 30) +#define MTW_AGG_RTY_MODE_TIMER (1 << 29) +#define MTW_NAG_RTY_MODE_TIMER (1 << 28) +#define MTW_LONG_RTY_THRES_SHIFT 16 +#define MTW_LONG_RTY_LIMIT_SHIFT 8 +#define MTW_SHORT_RTY_LIMIT_SHIFT 0 + +/* possible flags for register TX_LINK_CFG 0x1350 */ +#define MTW_REMOTE_MFS_SHIFT 24 +#define MTW_REMOTE_MFB_SHIFT 16 +#define MTW_TX_CFACK_EN (1 << 12) +#define MTW_TX_RDG_EN (1 << 11) +#define MTW_TX_MRQ_EN (1 << 10) +#define MTW_REMOTE_UMFS_EN (1 << 9) +#define MTW_TX_MFB_EN (1 << 8) +#define MTW_REMOTE_MFB_LT_SHIFT 0 + +/* possible flags for registers *_PROT_CFG */ +#define RT2860_RTSTH_EN (1 << 26) +#define RT2860_TXOP_ALLOW_GF40 (1 << 25) +#define RT2860_TXOP_ALLOW_GF20 (1 << 24) +#define RT2860_TXOP_ALLOW_MM40 (1 << 23) +#define RT2860_TXOP_ALLOW_MM20 (1 << 22) +#define RT2860_TXOP_ALLOW_OFDM (1 << 21) +#define RT2860_TXOP_ALLOW_CCK (1 << 20) +#define RT2860_TXOP_ALLOW_ALL (0x3f << 20) +#define RT2860_PROT_NAV_SHORT (1 << 18) +#define RT2860_PROT_NAV_LONG (2 << 18) +#define RT2860_PROT_CTRL_RTS_CTS (1 << 16) +#define RT2860_PROT_CTRL_CTS (2 << 16) + +/* possible flags for registers EXP_{CTS,ACK}_TIME */ +#define RT2860_EXP_OFDM_TIME_SHIFT 16 +#define RT2860_EXP_CCK_TIME_SHIFT 0 + +/* possible flags for register RX_FILTR_CFG 0x1400 */ +#define MTW_DROP_CTRL_RSV (1 << 16) +#define MTW_DROP_BAR (1 << 15) +#define MTW_DROP_BA (1 << 14) +#define MTW_DROP_PSPOLL (1 << 13) +#define MTW_DROP_RTS (1 << 12) +#define MTW_DROP_CTS (1 << 11) +#define MTW_DROP_ACK (1 << 10) +#define MTW_DROP_CFEND (1 << 9) +#define MTW_DROP_CFACK (1 << 8) +#define MTW_DROP_DUPL (1 << 7) +#define MTW_DROP_BC (1 << 6) +#define MTW_DROP_MC (1 << 5) +#define MTW_DROP_VER_ERR (1 << 4) +#define MTW_DROP_NOT_MYBSS (1 << 3) +#define MTW_DROP_UC_NOME (1 << 2) +#define MTW_DROP_PHY_ERR (1 << 1) +#define MTW_DROP_CRC_ERR (1 << 0) + +/* possible flags for register AUTO_RSP_CFG 0x1404 */ +#define MTW_CTRL_PWR_BIT (1 << 7) +#define MTW_BAC_ACK_POLICY (1 << 6) +#define MTW_CCK_SHORT_EN (1 << 4) +#define MTW_CTS_40M_REF_EN (1 << 3) +#define MTW_CTS_40M_MODE_EN (1 << 2) +#define MTW_BAC_ACKPOLICY_EN (1 << 1) +#define MTW_AUTO_RSP_EN (1 << 0) + +/* possible flags for register SIFS_COST_CFG */ +#define RT2860_OFDM_SIFS_COST_SHIFT 8 +#define RT2860_CCK_SIFS_COST_SHIFT 0 + +/* possible flags for register TXOP_HLDR_ET 0x1608 */ +#define MTW_TXOP_ETM1_EN (1 << 25) +#define MTW_TXOP_ETM0_EN (1 << 24) +#define MTW_TXOP_ETM_THRES_SHIFT 16 +#define MTW_TXOP_ETO_EN (1 << 8) +#define MTW_TXOP_ETO_THRES_SHIFT 1 +#define MTW_PER_RX_RST_EN (1 << 0) + +/* possible flags for register TX_STAT_FIFO 0x1718 */ +#define MTW_TXQ_MCS_SHIFT 16 +#define MTW_TXQ_WCID_SHIFT 8 +#define MTW_TXQ_ACKREQ (1 << 7) +#define MTW_TXQ_AGG (1 << 6) +#define MTW_TXQ_OK (1 << 5) +#define MTW_TXQ_PID_SHIFT 1 +#define MTW_TXQ_VLD (1 << 0) + +/* possible flags for register TX_STAT_FIFO_EXT 0x1798 */ +#define MTW_TXQ_PKTID_SHIFT 8 +#define MTW_TXQ_RETRY_SHIFT 0 + +/* possible flags for register WCID_ATTR 0xa800 */ +#define MTW_MODE_NOSEC 0 +#define MTW_MODE_WEP40 1 +#define MTW_MODE_WEP104 2 +#define MTW_MODE_TKIP 3 +#define MTW_MODE_AES_CCMP 4 +#define MTW_MODE_CKIP40 5 +#define MTW_MODE_CKIP104 6 +#define MTW_MODE_CKIP128 7 +#define MTW_RX_PKEY_EN (1 << 0) + +/* possible flags for MT7601 BBP register 47 */ +#define MT7601_R47_MASK 0x07 +#define MT7601_R47_TSSI (0 << 0) +#define MT7601_R47_PKT (1 << 0) +#define MT7601_R47_TXRATE (1 << 1) +#define MT7601_R47_TEMP (1 << 2) + +#define MTW_RXQ_WLAN 0 +#define MTW_RXQ_MCU 1 +#define MTW_TXQ_MCU 5 + +enum mtw_phy_mode { + MTW_PHY_CCK, + MTW_PHY_OFDM, + MTW_PHY_HT, + MTW_PHY_HT_GF, + MTW_PHY_VHT, +}; + +/* RT2860 TX descriptor */ +struct rt2860_txd { + uint32_t sdp0; /* Segment Data Pointer 0 */ + uint16_t sdl1; /* Segment Data Length 1 */ +#define RT2860_TX_BURST (1 << 15) +#define RT2860_TX_LS1 (1 << 14) /* SDP1 is the last segment */ + + uint16_t sdl0; /* Segment Data Length 0 */ +#define RT2860_TX_DDONE (1 << 15) +#define RT2860_TX_LS0 (1 << 14) /* SDP0 is the last segment */ + + uint32_t sdp1; /* Segment Data Pointer 1 */ + uint8_t reserved[3]; + uint8_t flags; +#define RT2860_TX_QSEL_SHIFT 1 +#define RT2860_TX_QSEL_MGMT (0 << 1) +#define RT2860_TX_QSEL_HCCA (1 << 1) +#define RT2860_TX_QSEL_EDCA (2 << 1) +#define RT2860_TX_WIV (1 << 0) +} __packed; + +/* TX descriptor */ +struct mtw_txd { + uint16_t len; + uint16_t flags; +#define MTW_TXD_CMD (1 << 14) +#define MTW_TXD_DATA (0 << 14) +#define MTW_TXD_MCU (2 << 11) +#define MTW_TXD_WLAN (0 << 11) +#define MTW_TXD_QSEL_EDCA (2 << 9) +#define MTW_TXD_QSEL_HCCA (1 << 9) +#define MTW_TXD_QSEL_MGMT (0 << 9) +#define MTW_TXD_WIV (1 << 8) +#define MTW_TXD_CMD_SHIFT 4 +#define MTW_TXD_80211 (1 << 3) +} __packed; +struct mtw_txd_fw { + uint16_t len; + uint16_t flags; +uint8_t fw[0x2c44]; +} __packed; +/* TX Wireless Information */ +struct mtw_txwi { + uint8_t flags; +#define MTW_TX_MPDU_DSITY_SHIFT 5 +#define MTW_TX_AMPDU (1 << 4) +#define MTW_TX_TS (1 << 3) +#define MTW_TX_CFACK (1 << 2) +#define MTW_TX_MMPS (1 << 1) +#define MTW_TX_FRAG (1 << 0) + + uint8_t txop; +#define MTW_TX_TXOP_HT 0 +#define MTW_TX_TXOP_PIFS 1 +#define MTW_TX_TXOP_SIFS 2 +#define MTW_TX_TXOP_BACKOFF 3 + + uint16_t phy; +#define MT7650_PHY_MODE 0xe000 +#define MT7601_PHY_MODE 0xc000 +#define MT7601_PHY_SHIFT 14 +#define MT7650_PHY_SHIFT 13 +#define MT7650_PHY_SGI (1 << 9) +#define MT7601_PHY_SGI (1 << 8) +#define MTW_PHY_BW20 (0 << 7) +#define MTW_PHY_BW40 (1 << 7) +#define MTW_PHY_BW80 (2 << 7) +#define MTW_PHY_BW160 (3 << 7) +#define MTW_PHY_LDPC (1 << 6) +#define MTW_PHY_MCS 0x3f +#define MTW_PHY_SHPRE (1 << 3) + + uint8_t xflags; +#define MTW_TX_BAWINSIZE_SHIFT 2 +#define MTW_TX_NSEQ (1 << 1) +#define MTW_TX_ACK (1 << 0) + + uint8_t wcid; /* Wireless Client ID */ + uint16_t len; +#define MTW_TX_PID_SHIFT 12 + + uint32_t iv; + uint32_t eiv; + uint32_t reserved1; +} __packed; + +/* RT2860 RX descriptor */ +struct rt2860_rxd { + uint32_t sdp0; + uint16_t sdl1; /* unused */ + uint16_t sdl0; +#define MTW_RX_DDONE (1 << 15) +#define MTW_RX_LS0 (1 << 14) + + uint32_t sdp1; /* unused */ + uint32_t flags; +#define MTW_RX_DEC (1 << 16) +#define MTW_RX_AMPDU (1 << 15) +#define MTW_RX_L2PAD (1 << 14) +#define MTW_RX_RSSI (1 << 13) +#define MTW_RX_HTC (1 << 12) +#define MTW_RX_AMSDU (1 << 11) +#define MTW_RX_MICERR (1 << 10) +#define MTW_RX_ICVERR (1 << 9) +#define MTW_RX_CRCERR (1 << 8) +#define MTW_RX_MYBSS (1 << 7) +#define MTW_RX_BC (1 << 6) +#define MTW_RX_MC (1 << 5) +#define MTW_RX_UC2ME (1 << 4) +#define MTW_RX_FRAG (1 << 3) +#define MTW_RX_NULL (1 << 2) +#define MTW_RX_DATA (1 << 1) +#define MTW_RX_BA (1 << 0) +} __packed; + +/* RX descriptor */ +struct mtw_rxd { + uint16_t len; +#define MTW_RXD_SELF_GEN (1 << 15) +#define MTW_RXD_LEN 0x3fff + + uint16_t flags; +} __packed; + +/* RX Wireless Information */ +struct mtw_rxwi { + uint32_t flags; + uint8_t wcid; + uint8_t keyidx; +#define MTW_RX_UDF_SHIFT 5 +#define MTW_RX_BSS_IDX_SHIFT 2 + + uint16_t len; +#define MTW_RX_TID_SHIFT 12 + + uint16_t seq; + uint16_t phy; + uint8_t rssi[4]; + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; +} __packed __aligned(4); + +/* MCU Command */ +struct mtw_mcu_cmd_8 { + uint32_t func; + uint32_t val; +} __packed __aligned(4); + +struct mtw_mcu_cmd_16 { + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; +} __packed __aligned(4); + +#define MTW_DMA_PAD 4 + +/* first DMA segment contains TXWI + 802.11 header + 32-bit padding */ +#define MTW_TXWI_DMASZ \ + (sizeof (struct mtw_txwi) + \ + sizeof (struct ieee80211_htframe) + \ + sizeof (uint16_t)) + +#define MT7601_RF_7601 0x7601 /* 1T1R */ +#define MT7610_RF_7610 0x7610 /* 1T1R */ +#define MT7612_RF_7612 0x7612 /* 2T2R */ + +#define MTW_CONFIG_NO 1 + +/* USB vendor request */ +#define MTW_RESET 0x1 +#define MTW_WRITE_2 0x2 +#define MTW_WRITE_REGION_1 0x6 +#define MTW_READ_REGION_1 0x7 +#define MTW_EEPROM_READ 0x9 +#define MTW_WRITE_CFG 0x46 +#define MTW_READ_CFG 0x47 + +/* eFUSE ROM */ +#define MTW_EEPROM_CHIPID 0x00 +#define MTW_EEPROM_VERSION 0x01 +#define MTW_EEPROM_MAC01 0x02 +#define MTW_EEPROM_MAC23 0x03 +#define MTW_EEPROM_MAC45 0x04 +#define MTW_EEPROM_ANTENNA 0x1a +#define MTW_EEPROM_CONFIG 0x1b +#define MTW_EEPROM_COUNTRY 0x1c +#define MTW_EEPROM_FREQ_OFFSET 0x1d +#define MTW_EEPROM_LED1 0x1e +#define MTW_EEPROM_LED2 0x1f +#define MTW_EEPROM_LED3 0x20 +#define MTW_EEPROM_LNA 0x22 +#define MTW_EEPROM_RSSI1_2GHZ 0x23 +#define MTW_EEPROM_RSSI2_2GHZ 0x24 +#define MTW_EEPROM_RSSI1_5GHZ 0x25 +#define MTW_EEPROM_RSSI2_5GHZ 0x26 +#define MTW_EEPROM_DELTAPWR 0x28 +#define MTW_EEPROM_PWR2GHZ_BASE1 0x29 +#define MTW_EEPROM_PWR2GHZ_BASE2 0x30 +#define MTW_EEPROM_TSSI1_2GHZ 0x37 +#define MTW_EEPROM_TSSI2_2GHZ 0x38 +#define MTW_EEPROM_TSSI3_2GHZ 0x39 +#define MTW_EEPROM_TSSI4_2GHZ 0x3a +#define MTW_EEPROM_TSSI5_2GHZ 0x3b +#define MTW_EEPROM_PWR5GHZ_BASE1 0x3c +#define MTW_NIC_CONF2 0x42 +#define MTW_EEPROM_PWR5GHZ_BASE2 0x53 +#define MTW_TXPWR_EXT_PA_5G 0x54 +#define MTW_TXPWR_START_2G_0 0x56 +#define MTW_TXPWR_START_2G_1 0x5c +#define MTW_TXPWR_START_5G_0 0x62 +#define RT2860_EEPROM_TSSI1_5GHZ 0x6a +#define RT2860_EEPROM_TSSI2_5GHZ 0x6b +#define RT2860_EEPROM_TSSI3_5GHZ 0x6c +#define RT2860_EEPROM_TSSI4_5GHZ 0x6d +#define RT2860_EEPROM_TSSI5_5GHZ 0x6e +#define MTW_TX_TSSI_SLOPE 0x6e +#define MTW_EEPROM_RPWR 0x6f + +/* led related */ +#define CMD_LED_MODE 0x10 +#define CMD_MODE_ON 0x0 +static const struct rt2860_rate { + uint8_t rate; + uint8_t mcs; + enum ieee80211_phytype phy; + uint8_t ctl_ridx; + uint16_t sp_ack_dur; + uint16_t lp_ack_dur; +} rt2860_rates[] = { + { 2, 0, IEEE80211_T_DS, 0, 314, 314 }, + { 4, 1, IEEE80211_T_DS, 1, 258, 162 }, + { 11, 2, IEEE80211_T_DS, 2, 223, 127 }, + { 22, 3, IEEE80211_T_DS, 3, 213, 117 }, + { 12, 0, IEEE80211_T_OFDM, 4, 60, 60 }, + { 18, 1, IEEE80211_T_OFDM, 4, 52, 52 }, + { 24, 2, IEEE80211_T_OFDM, 6, 48, 48 }, + { 36, 3, IEEE80211_T_OFDM, 6, 44, 44 }, + { 48, 4, IEEE80211_T_OFDM, 8, 44, 44 }, + { 72, 5, IEEE80211_T_OFDM, 8, 40, 40 }, + { 96, 6, IEEE80211_T_OFDM, 8, 40, 40 }, + { 108, 7, IEEE80211_T_OFDM, 8, 40, 40 }, + { 0x80, 0, IEEE80211_T_HT, 4, 60, 60 }, + { 0x81, 1, IEEE80211_T_HT, 4, 60, 60 }, + { 0x82, 2, IEEE80211_T_HT, 4, 60, 60 }, + { 0x83, 3, IEEE80211_T_HT, 4, 60, 60 }, + { 0x84, 4, IEEE80211_T_HT, 4, 60, 60 }, + { 0x85, 5, IEEE80211_T_HT, 4, 60, 60 }, + { 0x86, 6, IEEE80211_T_HT, 4, 60, 60 }, + { 0x87, 7, IEEE80211_T_HT, 4, 60, 60 }, + { 0x88, 8, IEEE80211_T_HT, 4, 60, 60 }, + { 0x89, 9, IEEE80211_T_HT, 4, 60, 60 }, + { 0x8a, 10, IEEE80211_T_HT, 4, 60, 60 }, + { 0x8b, 11, IEEE80211_T_HT, 4, 60, 60 }, + { 0x8c, 12, IEEE80211_T_HT, 4, 60, 60 }, + { 0x8d, 13, IEEE80211_T_HT, 4, 60, 60 }, + { 0x8e, 14, IEEE80211_T_HT, 4, 60, 60 }, + { 0x8f, 15, IEEE80211_T_HT, 4, 60, 60 }, + + /* MCS - 3 streams */ + { 0x90, 16, IEEE80211_T_HT, 4, 60, 60 }, + { 0x91, 17, IEEE80211_T_HT, 4, 60, 60 }, + { 0x92, 18, IEEE80211_T_HT, 4, 60, 60 }, + { 0x93, 19, IEEE80211_T_HT, 4, 60, 60 }, + { 0x94, 20, IEEE80211_T_HT, 4, 60, 60 }, + { 0x95, 21, IEEE80211_T_HT, 4, 60, 60 }, + { 0x96, 22, IEEE80211_T_HT, 4, 60, 60 }, + { 0x97, 23, IEEE80211_T_HT, 4, 60, 60 } +}; +/* These are indexes into the above rt2860_rates[] array */ +#define MTW_RIDX_CCK1 0 +#define MTW_RIDX_CCK11 3 +#define MTW_RIDX_OFDM6 4 +#define MTW_RIDX_MCS0 12 +#define MTW_RIDX_MAX 36 + +#define MT7601_RF_CHAN \ + { 1, 0x99, 0x99, 0x09, 0x50 }, \ + { 2, 0x46, 0x44, 0x0a, 0x50 }, \ + { 3, 0xec, 0xee, 0x0a, 0x50 }, \ + { 4, 0x99, 0x99, 0x0b, 0x50 }, \ + { 5, 0x46, 0x44, 0x08, 0x51 }, \ + { 6, 0xec, 0xee, 0x08, 0x51 }, \ + { 7, 0x99, 0x99, 0x09, 0x51 }, \ + { 8, 0x46, 0x44, 0x0a, 0x51 }, \ + { 9, 0xec, 0xee, 0x0a, 0x51 }, \ + { 10, 0x99, 0x99, 0x0b, 0x51 }, \ + { 11, 0x46, 0x44, 0x08, 0x52 }, \ + { 12, 0xec, 0xee, 0x08, 0x52 }, \ + { 13, 0x99, 0x99, 0x09, 0x52 }, \ + { 14, 0x33, 0x33, 0x0b, 0x52 } + +/* + * Default values for MAC registers. + */ +#define MT7601_DEF_MAC \ + { MTW_BCN_OFFSET0, 0x18100800 }, \ + { MTW_BCN_OFFSET1, 0x38302820 }, \ + { MTW_BCN_OFFSET2, 0x58504840 }, \ + { MTW_BCN_OFFSET3, 0x78706860 }, \ + { MTW_MAC_SYS_CTRL, 0x0000000c }, \ + { MTW_MAX_LEN_CFG, 0x000a3fff }, \ + { MTW_AMPDU_MAX_LEN_20M1S, 0x77777777 }, \ + { MTW_AMPDU_MAX_LEN_20M2S, 0x77777777 }, \ + { MTW_AMPDU_MAX_LEN_40M1S, 0x77777777 }, \ + { MTW_AMPDU_MAX_LEN_40M2S, 0x77777777 }, \ + { MTW_XIFS_TIME_CFG, 0x33a41010 }, \ + { MTW_BKOFF_SLOT_CFG, 0x00000209 }, \ + { MTW_TBTT_SYNC_CFG, 0x00422010 }, \ + { MTW_INT_TIMER_CFG, 0x00000000 }, \ + { MTW_PWR_PIN_CFG, 0x00000000 }, \ + { MTW_AUTO_WAKEUP_CFG, 0x00000014 }, \ + { MTW_EDCA_AC_CFG(0), 0x000a4360 }, \ + { MTW_EDCA_AC_CFG(1), 0x000a4700 }, \ + { MTW_EDCA_AC_CFG(2), 0x00043338 }, \ + { MTW_EDCA_AC_CFG(3), 0x0003222f }, \ + { MTW_TX_PIN_CFG, 0x33150f0f }, \ + { MTW_TX_BAND_CFG, 0x00000005 }, \ + { MTW_TX_SW_CFG0, 0x00000402 }, \ + { MTW_TX_SW_CFG1, 0x00000000 }, \ + { MTW_TX_SW_CFG2, 0x00000000 }, \ + { MTW_TXOP_CTRL_CFG, 0x0000583f }, \ + { MTW_TX_RTS_CFG, 0x01100020 }, \ + { MTW_TX_TIMEOUT_CFG, 0x000a2090 }, \ + { MTW_TX_RETRY_CFG, 0x47d01f0f }, \ + { MTW_TX_LINK_CFG, 0x007f1820 }, \ + { MTW_HT_FBK_CFG1, 0xedcba980 }, \ + { MTW_CCK_PROT_CFG, 0x07f40000 }, \ + { MTW_OFDM_PROT_CFG, 0x07f60000 }, \ + { MTW_MM20_PROT_CFG, 0x01750003 }, \ + { MTW_MM40_PROT_CFG, 0x03f50003 }, \ + { MTW_GF20_PROT_CFG, 0x01750003 }, \ + { MTW_GF40_PROT_CFG, 0x03f50003 }, \ + { MTW_EXP_ACK_TIME, 0x002400ca }, \ + { MTW_TX_PWR_CFG5, 0x00000000 }, \ + { MTW_TX_PWR_CFG6, 0x01010101 }, \ + { MTW_TX0_RF_GAIN_CORR, 0x003b0005 }, \ + { MTW_TX1_RF_GAIN_CORR, 0x00000000 }, \ + { MTW_TX0_RF_GAIN_ATTEN, 0x00006969 }, \ + { MTW_TX_ALC_CFG3, 0x6c6c6c6c }, \ + { MTW_TX_ALC_CFG0, 0x2f2f0005 }, \ + { MTW_TX_ALC_CFG4, 0x00000400 }, \ + { MTW_TX_ALC_VGA3, 0x00060006 }, \ + { MTW_RX_FILTR_CFG, 0x00015f97 }, \ + { MTW_AUTO_RSP_CFG, 0x00000003 }, \ + { MTW_LEGACY_BASIC_RATE, 0x0000015f }, \ + { MTW_HT_BASIC_RATE, 0x00008003 }, \ + { MTW_RX_MAX_PCNT, 0x0000009f }, \ + { MTW_WPDMA_GLO_CFG, 0x00000030 }, \ + { MTW_WMM_AIFSN_CFG, 0x00002273 }, \ + { MTW_WMM_CWMIN_CFG, 0x00002344 }, \ + { MTW_WMM_CWMAX_CFG, 0x000034aa }, \ + { MTW_TSO_CTRL, 0x00000000 }, \ + { MTW_SYS_CTRL, 0x00080c00 }, \ + { MTW_FCE_PSE_CTRL, 0x00000001 }, \ + { MTW_AUX_CLK_CFG, 0x00000000 }, \ + { MTW_BBP_PA_MODE_CFG0, 0x010055ff }, \ + { MTW_BBP_PA_MODE_CFG1, 0x00550055 }, \ + { MTW_RF_PA_MODE_CFG0, 0x010055ff }, \ + { MTW_RF_PA_MODE_CFG1, 0x00550055 }, \ + { 0x0a38, 0x00000000 }, \ + { MTW_BBP_CSR, 0x00000000 }, \ + { MTW_PBF_CFG, 0x7f723c1f } + +/* + * Default values for Baseband registers + */ +#define MT7601_DEF_BBP \ + { 1, 0x04 }, \ + { 4, 0x40 }, \ + { 20, 0x06 }, \ + { 31, 0x08 }, \ + { 178, 0xff }, \ + { 66, 0x14 }, \ + { 68, 0x8b }, \ + { 69, 0x12 }, \ + { 70, 0x09 }, \ + { 73, 0x11 }, \ + { 75, 0x60 }, \ + { 76, 0x44 }, \ + { 84, 0x9a }, \ + { 86, 0x38 }, \ + { 91, 0x07 }, \ + { 92, 0x02 }, \ + { 99, 0x50 }, \ + { 101, 0x00 }, \ + { 103, 0xc0 }, \ + { 104, 0x92 }, \ + { 105, 0x3c }, \ + { 106, 0x03 }, \ + { 128, 0x12 }, \ + { 142, 0x04 }, \ + { 143, 0x37 }, \ + { 142, 0x03 }, \ + { 143, 0x99 }, \ + { 160, 0xeb }, \ + { 161, 0xc4 }, \ + { 162, 0x77 }, \ + { 163, 0xf9 }, \ + { 164, 0x88 }, \ + { 165, 0x80 }, \ + { 166, 0xff }, \ + { 167, 0xe4 }, \ + { 195, 0x00 }, \ + { 196, 0x00 }, \ + { 195, 0x01 }, \ + { 196, 0x04 }, \ + { 195, 0x02 }, \ + { 196, 0x20 }, \ + { 195, 0x03 }, \ + { 196, 0x0a }, \ + { 195, 0x06 }, \ + { 196, 0x16 }, \ + { 195, 0x07 }, \ + { 196, 0x05 }, \ + { 195, 0x08 }, \ + { 196, 0x37 }, \ + { 195, 0x0a }, \ + { 196, 0x15 }, \ + { 195, 0x0b }, \ + { 196, 0x17 }, \ + { 195, 0x0c }, \ + { 196, 0x06 }, \ + { 195, 0x0d }, \ + { 196, 0x09 }, \ + { 195, 0x0e }, \ + { 196, 0x05 }, \ + { 195, 0x0f }, \ + { 196, 0x09 }, \ + { 195, 0x10 }, \ + { 196, 0x20 }, \ + { 195, 0x20 }, \ + { 196, 0x17 }, \ + { 195, 0x21 }, \ + { 196, 0x06 }, \ + { 195, 0x22 }, \ + { 196, 0x09 }, \ + { 195, 0x23 }, \ + { 196, 0x17 }, \ + { 195, 0x24 }, \ + { 196, 0x06 }, \ + { 195, 0x25 }, \ + { 196, 0x09 }, \ + { 195, 0x26 }, \ + { 196, 0x17 }, \ + { 195, 0x27 }, \ + { 196, 0x06 }, \ + { 195, 0x28 }, \ + { 196, 0x09 }, \ + { 195, 0x29 }, \ + { 196, 0x05 }, \ + { 195, 0x2a }, \ + { 196, 0x09 }, \ + { 195, 0x80 }, \ + { 196, 0x8b }, \ + { 195, 0x81 }, \ + { 196, 0x12 }, \ + { 195, 0x82 }, \ + { 196, 0x09 }, \ + { 195, 0x83 }, \ + { 196, 0x17 }, \ + { 195, 0x84 }, \ + { 196, 0x11 }, \ + { 195, 0x85 }, \ + { 196, 0x00 }, \ + { 195, 0x86 }, \ + { 196, 0x00 }, \ + { 195, 0x87 }, \ + { 196, 0x18 }, \ + { 195, 0x88 }, \ + { 196, 0x60 }, \ + { 195, 0x89 }, \ + { 196, 0x44 }, \ + { 195, 0x8a }, \ + { 196, 0x8b }, \ + { 195, 0x8b }, \ + { 196, 0x8b }, \ + { 195, 0x8c }, \ + { 196, 0x8b }, \ + { 195, 0x8d }, \ + { 196, 0x8b }, \ + { 195, 0x8e }, \ + { 196, 0x09 }, \ + { 195, 0x8f }, \ + { 196, 0x09 }, \ + { 195, 0x90 }, \ + { 196, 0x09 }, \ + { 195, 0x91 }, \ + { 196, 0x09 }, \ + { 195, 0x92 }, \ + { 196, 0x11 }, \ + { 195, 0x93 }, \ + { 196, 0x11 }, \ + { 195, 0x94 }, \ + { 196, 0x11 }, \ + { 195, 0x95 }, \ + { 196, 0x11 }, \ + { 47, 0x80 }, \ + { 60, 0x80 }, \ + { 150, 0xd2 }, \ + { 151, 0x32 }, \ + { 152, 0x23 }, \ + { 153, 0x41 }, \ + { 154, 0x00 }, \ + { 155, 0x4f }, \ + { 253, 0x7e }, \ + { 195, 0x30 }, \ + { 196, 0x32 }, \ + { 195, 0x31 }, \ + { 196, 0x23 }, \ + { 195, 0x32 }, \ + { 196, 0x45 }, \ + { 195, 0x35 }, \ + { 196, 0x4a }, \ + { 195, 0x36 }, \ + { 196, 0x5a }, \ + { 195, 0x37 }, \ + { 196, 0x5a } + +/* + * Default values for RF registers + */ +#define MT7601_BANK0_RF \ + { 0, 0x02 }, \ + { 1, 0x01 }, \ + { 2, 0x11 }, \ + { 3, 0xff }, \ + { 4, 0x0a }, \ + { 5, 0x20 }, \ + { 6, 0x00 }, \ + { 7, 0x00 }, \ + { 8, 0x00 }, \ + { 9, 0x00 }, \ + { 10, 0x00 }, \ + { 11, 0x21 }, \ + { 13, 0x00 }, \ + { 14, 0x7c }, \ + { 15, 0x22 }, \ + { 16, 0x80 }, \ + { 17, 0x99 }, \ + { 18, 0x99 }, \ + { 19, 0x09 }, \ + { 20, 0x50 }, \ + { 21, 0xb0 }, \ + { 22, 0x00 }, \ + { 23, 0xc5 }, \ + { 24, 0xfc }, \ + { 25, 0x40 }, \ + { 26, 0x4d }, \ + { 27, 0x02 }, \ + { 28, 0x72 }, \ + { 29, 0x01 }, \ + { 30, 0x00 }, \ + { 31, 0x00 }, \ + { 32, 0x00 }, \ + { 33, 0x00 }, \ + { 34, 0x23 }, \ + { 35, 0x01 }, \ + { 36, 0x00 }, \ + { 37, 0x00 }, \ + { 38, 0x00 }, \ + { 39, 0x20 }, \ + { 40, 0x00 }, \ + { 41, 0xd0 }, \ + { 42, 0x1b }, \ + { 43, 0x02 }, \ + { 44, 0x00 } + +#define MT7601_BANK4_RF \ + { 0, 0x01 }, \ + { 1, 0x00 }, \ + { 2, 0x00 }, \ + { 3, 0x00 }, \ + { 4, 0x00 }, \ + { 5, 0x08 }, \ + { 6, 0x00 }, \ + { 7, 0x5b }, \ + { 8, 0x52 }, \ + { 9, 0xb6 }, \ + { 10, 0x57 }, \ + { 11, 0x33 }, \ + { 12, 0x22 }, \ + { 13, 0x3d }, \ + { 14, 0x3e }, \ + { 15, 0x13 }, \ + { 16, 0x22 }, \ + { 17, 0x23 }, \ + { 18, 0x02 }, \ + { 19, 0xa4 }, \ + { 20, 0x01 }, \ + { 21, 0x12 }, \ + { 22, 0x80 }, \ + { 23, 0xb3 }, \ + { 24, 0x00 }, \ + { 25, 0x00 }, \ + { 26, 0x00 }, \ + { 27, 0x00 }, \ + { 28, 0x18 }, \ + { 29, 0xee }, \ + { 30, 0x6b }, \ + { 31, 0x31 }, \ + { 32, 0x5d }, \ + { 33, 0x00 }, \ + { 34, 0x96 }, \ + { 35, 0x55 }, \ + { 36, 0x08 }, \ + { 37, 0xbb }, \ + { 38, 0xb3 }, \ + { 39, 0xb3 }, \ + { 40, 0x03 }, \ + { 41, 0x00 }, \ + { 42, 0x00 }, \ + { 43, 0xc5 }, \ + { 44, 0xc5 }, \ + { 45, 0xc5 }, \ + { 46, 0x07 }, \ + { 47, 0xa8 }, \ + { 48, 0xef }, \ + { 49, 0x1a }, \ + { 54, 0x07 }, \ + { 55, 0xa7 }, \ + { 56, 0xcc }, \ + { 57, 0x14 }, \ + { 58, 0x07 }, \ + { 59, 0xa8 }, \ + { 60, 0xd7 }, \ + { 61, 0x10 }, \ + { 62, 0x1c }, \ + { 63, 0x00 } + +#define MT7601_BANK5_RF \ + { 0, 0x47 }, \ + { 1, 0x00 }, \ + { 2, 0x00 }, \ + { 3, 0x08 }, \ + { 4, 0x04 }, \ + { 5, 0x20 }, \ + { 6, 0x3a }, \ + { 7, 0x3a }, \ + { 8, 0x00 }, \ + { 9, 0x00 }, \ + { 10, 0x10 }, \ + { 11, 0x10 }, \ + { 12, 0x10 }, \ + { 13, 0x10 }, \ + { 14, 0x10 }, \ + { 15, 0x20 }, \ + { 16, 0x22 }, \ + { 17, 0x7c }, \ + { 18, 0x00 }, \ + { 19, 0x00 }, \ + { 20, 0x00 }, \ + { 21, 0xf1 }, \ + { 22, 0x11 }, \ + { 23, 0x02 }, \ + { 24, 0x41 }, \ + { 25, 0x20 }, \ + { 26, 0x00 }, \ + { 27, 0xd7 }, \ + { 28, 0xa2 }, \ + { 29, 0x20 }, \ + { 30, 0x49 }, \ + { 31, 0x20 }, \ + { 32, 0x04 }, \ + { 33, 0xf1 }, \ + { 34, 0xa1 }, \ + { 35, 0x01 }, \ + { 41, 0x00 }, \ + { 42, 0x00 }, \ + { 43, 0x00 }, \ + { 44, 0x00 }, \ + { 45, 0x00 }, \ + { 46, 0x00 }, \ + { 47, 0x00 }, \ + { 48, 0x00 }, \ + { 49, 0x00 }, \ + { 50, 0x00 }, \ + { 51, 0x00 }, \ + { 52, 0x00 }, \ + { 53, 0x00 }, \ + { 54, 0x00 }, \ + { 55, 0x00 }, \ + { 56, 0x00 }, \ + { 57, 0x00 }, \ + { 58, 0x31 }, \ + { 59, 0x31 }, \ + { 60, 0x0a }, \ + { 61, 0x02 }, \ + { 62, 0x00 }, \ + { 63, 0x00 } +union mtw_stats { + uint32_t raw; + struct { + uint16_t fail; + uint16_t pad; + } error; + struct { + uint16_t success; + uint16_t retry; + } tx; +} __aligned(4); diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtwvar.h b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtwvar.h new file mode 100644 index 0000000000..4e2b013157 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/usb/wlan/if_mtwvar.h @@ -0,0 +1,391 @@ +/* $OpenBSD: if_mtwvar.h,v 1.1 2021/12/20 13:59:02 hastings Exp $ */ +/* + * Copyright (c) 2008,2009 Damien Bergamini + * + * 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. + */ + +#define MTW_MAX_RXSZ \ + 4096 +#if 0 + (sizeof (uint32_t) + \ + sizeof (struct mtw_rxwi) + \ + sizeof (uint16_t) + \ + MCLBYTES + \ + sizeof (struct mtw_rxd)) +#endif + +#define MTW_TX_TIMEOUT 5000 /* ms */ +#define MTW_VAP_MAX 8 +#define MTW_RX_RING_COUNT 1 +#define MTW_TX_RING_COUNT 32 + +#define MTW_RXQ_COUNT 2 +#define MTW_TXQ_COUNT 6 + +#define MTW_WCID_MAX 64 +#define MTW_AID2WCID(aid) (1 + ((aid) & 0x7)) + +struct mtw_rx_radiotap_header { + struct ieee80211_radiotap_header wr_ihdr; + uint64_t wr_tsf; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + uint8_t wr_dbm_antsignal; + uint8_t wr_antenna; + uint8_t wr_antsignal; +} __packed; +#define MTW_RATECTL_OFF 0 +#define MTW_RX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_RATE | \ + 1 << IEEE80211_RADIOTAP_CHANNEL | \ + 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL | \ + 1 << IEEE80211_RADIOTAP_ANTENNA | \ + 1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) +struct mtw_tx_radiotap_header { + struct ieee80211_radiotap_header wt_ihdr; + uint8_t wt_flags; + uint8_t wt_rate; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; + uint8_t wt_hwqueue; +} __packed; + +#define MTW_TX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_RATE | \ + 1 << IEEE80211_RADIOTAP_CHANNEL) + +struct mtw_softc; + +struct mtw_fw_data { + uint16_t len; + uint16_t flags; + + uint8_t *buf; + uint32_t buflen; + +}; +struct mtw_tx_desc { + uint32_t flags; +#define RT2573_TX_BURST (1 << 0) +#define RT2573_TX_VALID (1 << 1) +#define RT2573_TX_MORE_FRAG (1 << 2) +#define RT2573_TX_NEED_ACK (1 << 3) +#define RT2573_TX_TIMESTAMP (1 << 4) +#define RT2573_TX_OFDM (1 << 5) +#define RT2573_TX_IFS_SIFS (1 << 6) +#define RT2573_TX_LONG_RETRY (1 << 7) +#define RT2573_TX_TKIPMIC (1 << 8) +#define RT2573_TX_KEY_PAIR (1 << 9) +#define RT2573_TX_KEY_ID(id) (((id) & 0x3f) << 10) +#define RT2573_TX_CIP_MODE(m) ((m) << 29) + + uint16_t wme; +#define RT2573_QID(v) (v) +#define RT2573_AIFSN(v) ((v) << 4) +#define RT2573_LOGCWMIN(v) ((v) << 8) +#define RT2573_LOGCWMAX(v) ((v) << 12) + + uint8_t hdrlen; + uint8_t xflags; +#define RT2573_TX_HWSEQ (1 << 4) + + uint8_t plcp_signal; + uint8_t plcp_service; +#define RT2573_PLCP_LENGEXT 0x80 + + uint8_t plcp_length_lo; + uint8_t plcp_length_hi; + + uint32_t iv; + uint32_t eiv; + + uint8_t offset; + uint8_t qid; + uint8_t txpower; +#define RT2573_DEFAULT_TXPOWER 0 + + uint8_t reserved; +} __packed; + +struct mtw_tx_data { + STAILQ_ENTRY(mtw_tx_data) next; + struct mbuf *m; + struct mtw_softc *sc; + struct usbd_xfer *xfer; + uint8_t qid; + uint8_t ridx; + uint32_t buflen; + //struct mtw_tx_desc desc; + struct ieee80211_node *ni; + //struct mtw_txd desc; + uint8_t desc[sizeof(struct mtw_txd)+sizeof(struct mtw_txwi)]; + +}; + +struct mtw_rx_data { + STAILQ_ENTRY(mtw_rx_data) next; + struct mtw_softc *sc; + struct usbd_xfer *xfer; + + uint8_t *buf; +}; + +struct mtw_tx_ring { + struct mtw_tx_data data[MTW_TX_RING_COUNT]; + struct usbd_pipe *pipeh; + int cur; + int queued; + uint8_t pipe_no; +}; + +struct mtw_rx_ring { + struct mtw_rx_data data[MTW_RX_RING_COUNT]; + struct usbd_pipe *pipeh; + uint8_t pipe_no; +}; + +struct mtw_vap { + struct ieee80211vap vap; + struct mbuf *beacon_mbuf; + + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); + void (*recv_mgmt)(struct ieee80211_node *, + struct mbuf *, int, + const struct ieee80211_rx_stats *, + int, int); + + uint8_t rvp_id; +}; +#define MTW_VAP(vap) ((struct mtw_vap *)(vap)) +struct mtw_host_cmd { + void (*cb)(struct mtw_softc *, void *); + uint8_t data[256]; +}; + +struct mtw_cmd_newstate { + enum ieee80211_state state; + int arg; +}; + +struct mtw_cmd_key { + struct ieee80211_key key; + struct ieee80211_node *ni; +}; + +#define MTW_HOST_CMD_RING_COUNT 32 +struct mtw_host_cmd_ring { + struct mtw_host_cmd cmd[MTW_HOST_CMD_RING_COUNT]; + int cur; + int next; + int queued; +}; + + + +struct mtw_node { + struct ieee80211_node ni; + uint8_t mgt_ridx; + uint8_t amrr_ridx; + uint8_t fix_ridx; + +}; +#define MTW_NODE(ni) ((struct mtw_node *)(ni)) + +struct mtw_mcu_tx { + struct mtw_softc *sc; + struct usbd_xfer *xfer; + struct usbd_pipe *pipeh; + uint8_t pipe_no; + uint8_t *buf; + int8_t seq; +}; + +#define MTW_MCU_IVB_LEN 0x40 +struct mtw_ucode_hdr { + uint32_t ilm_len; + uint32_t dlm_len; + uint16_t build_ver; + uint16_t fw_ver; + uint8_t pad[4]; + char build_time[16]; +} __packed; + +struct mtw_ucode { + struct mtw_ucode_hdr hdr; + uint8_t ivb[MTW_MCU_IVB_LEN]; + uint8_t data[]; +} __packed; + +STAILQ_HEAD(mtw_tx_data_head, mtw_tx_data); +struct mtw_endpoint_queue { + struct mtw_tx_data tx_data[MTW_TX_RING_COUNT]; + struct mtw_tx_data_head tx_qh; + struct mtw_tx_data_head tx_fh; + uint32_t tx_nfree; +}; + +struct mtw_cmdq { + void *arg0; + void *arg1; + void (*func)(void *); + struct ieee80211_key *k; + struct ieee80211_key key; + uint8_t mac[IEEE80211_ADDR_LEN]; + uint8_t wcid; +}; +enum { + MTW_BULK_RX, /* = WME_AC_BK */ + //MTW_BULK_RX1, + MTW_BULK_TX_BE, /* = WME_AC_BE */ + MTW_BULK_TX_VI, /* = WME_AC_VI */ + MTW_BULK_TX_VO, /* = WME_AC_VO */ + MTW_BULK_TX_HCCA, + MTW_BULK_TX_PRIO, + MTW_BULK_TX_BK, + MTW_BULK_FW_CMD, + MTW_BULK_RAW_TX, + MTW_N_XFER, +}; +#define MTW_TXCNT 0 +#define MTW_SUCCESS 1 +#define MTW_RETRY 2 +#define MTW_EP_QUEUES 6 +#define MTW_FLAG_FWLOAD_NEEDED 0x01 +#define MTW_RUNNING 0x02 +struct mtw_softc { + device_t sc_dev; + int sc_idx; + struct ieee80211com sc_ic; + struct ieee80211_ratectl_tx_stats sc_txs; + int (*sc_newstate)(struct ieee80211com *, + enum ieee80211_state, int); + int (*sc_srom_read)(struct mtw_softc *, + uint16_t, uint16_t *); +#define MTW_CMDQ_MAX 16 +#define MTW_CMDQ_MASQ (MTW_CMDQ_MAX - 1) +#define MTW_CMDQ_ABORT 0 +#define MTW_CMDQ_GO 1 + struct mbuf *rx_m; + uint8_t runbmap; + uint8_t running; + uint8_t ap_running; + uint8_t adhoc_running; + uint8_t sta_running; + uint8_t fwloading; + uint16_t wcid_stats[MTW_WCID_MAX + 1][3]; + struct mbufq sc_snd; + uint8_t cmdq_exec; + uint8_t fifo_cnt; + uint32_t sc_flags; + uint8_t rvp_cnt; + uint8_t cmdq_run; + uint8_t rvp_bmap; + struct mtw_cmdq cmdq[MTW_CMDQ_MAX]; + struct task cmdq_task; + uint8_t cmdq_mtw; + uint8_t cmdq_key_set; + struct usb_device *sc_udev; + struct usb_interface *sc_iface; + uint32_t cmdq_store; + struct mtx sc_mtx; + uint32_t sc_mcu_xferlen; + struct usb_xfer *sc_xfer[MTW_N_XFER]; + uint16_t asic_ver; + uint16_t asic_rev; + uint16_t mac_ver; + uint16_t mac_rev; + uint16_t rf_rev; + int ridx; + int amrr_ridx; + uint8_t freq; + uint8_t ntxchains; + uint8_t nrxchains; + + struct mtw_txd_fw *txd_fw[4]; + int sc_sent; + uint8_t sc_ivb_1[MTW_MCU_IVB_LEN]; +#ifdef __HAIKU__ + struct mtw_endpoint_queue sc_epq[MTW_N_XFER]; +#else + struct mtw_endpoint_queue sc_epq[MTW_BULK_RX]; +#endif + uint8_t rfswitch; + uint8_t ext_2ghz_lna; + uint8_t ext_5ghz_lna; + uint8_t calib_2ghz; + uint8_t calib_5ghz; + uint8_t txmixgain_2ghz; + uint8_t txmixgain_5ghz; + int8_t txpow1[54]; + int8_t txpow2[54]; + int8_t txpow3[54]; + int8_t rssi_2ghz[3]; + int8_t rssi_5ghz[3]; + uint8_t lna[4]; + + uint8_t leds; + uint16_t led[3]; + uint32_t txpow20mhz[5]; + uint32_t txpow40mhz_2ghz[5]; + uint32_t txpow40mhz_5ghz[5]; + + int8_t bbp_temp; + uint8_t rf_freq_offset; + uint32_t rf_pa_mode[2]; + int sc_rf_calibrated; + int sc_bw_calibrated; + int sc_chan_group; + + + + + uint8_t cmd_seq; + uint8_t sc_detached; + struct mtw_tx_ring sc_mcu; + struct mtw_rx_ring rxq[MTW_RXQ_COUNT]; + struct mtw_tx_ring txq[MTW_TXQ_COUNT]; + struct task ratectl_task; + struct usb_callout ratectl_ch; + uint8_t ratectl_run; + //struct mtw_host_cmd_ring cmdq; + uint8_t qfullmsk; + int sc_tx_timer; + + uint8_t sc_bssid[IEEE80211_ADDR_LEN]; + + union { + struct mtw_rx_radiotap_header th; + uint8_t pad[64]; + } sc_rxtapu; +#define sc_rxtap sc_rxtapu.th + int sc_rxtap_len; + + union { + struct mtw_tx_radiotap_header th; + uint8_t pad[64]; + uint8_t wt_hwqueue; + + } sc_txtapu; +#define sc_txtap sc_txtapu.th + int sc_txtap_len; + int sc_key_tasks; +}; +#define MTW_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define MTW_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define MTW_LOCK_ASSERT(sc, t) mtx_assert(&(sc)->sc_mtx, t) diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/glue.c b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/glue.c index 2ab6b0dd87..b6d4ae9b2e 100644 --- a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/glue.c +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/glue.c @@ -33,13 +33,17 @@ HAIKU_FIRMWARE_NAME_MAP({ {"rt2561sfw", "rt2561s.ucode"}, {"rt2661fw", "rt2661.ucode"}, {"rt2860fw", "rt2860.ucode"}, + {"runfw", "rt2870.ucode"}, + + {"/mediatek/mt7601u.bin", "mtw-mt7601u"}, }); NO_HAIKU_FBSD_MII_DRIVER(); NO_HAIKU_REENABLE_INTERRUPTS(); extern driver_t* DRIVER_MODULE_NAME(ral, pci); +extern driver_t* DRIVER_MODULE_NAME(mtw, uhub); extern driver_t* DRIVER_MODULE_NAME(ural, uhub); extern driver_t* DRIVER_MODULE_NAME(run, uhub); extern driver_t* DRIVER_MODULE_NAME(rum, uhub); @@ -53,6 +57,7 @@ __haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[]) NULL }; driver_t *usb_drivers[] = { + DRIVER_MODULE_NAME(mtw, uhub), DRIVER_MODULE_NAME(ural, uhub), DRIVER_MODULE_NAME(run, uhub), DRIVER_MODULE_NAME(rum, uhub), diff --git a/src/libs/compat/freebsd_network/compat/dev/usb/usbdevs b/src/libs/compat/freebsd_network/compat/dev/usb/usbdevs index 5ca40d5385..2770ac9db6 100644 --- a/src/libs/compat/freebsd_network/compat/dev/usb/usbdevs +++ b/src/libs/compat/freebsd_network/compat/dev/usb/usbdevs @@ -777,8 +777,10 @@ vendor ARDUINO 0x2341 Arduino SA vendor TPLINK 0x2357 TP-Link vendor WESTMOUNTAIN 0x2405 West Mountain Radio vendor TRIPPLITE 0x2478 Tripp-Lite +vendor NORELSYS 0x2537 NOREL Systems Ltd. vendor TENDA2 0x2604 Tenda vendor HIROSE 0x2631 Hirose Electric +vendor XIAOMI 0x2717 Xiaomi vendor NHJ 0x2770 NHJ vendor THINGM 0x27b8 ThingM vendor PERASO 0x2932 Peraso Technologies, Inc. @@ -1047,7 +1049,6 @@ product ALCATEL OT535 0x02df One Touch 535/735 /* Alcor Micro, Inc. products */ product ALCOR2 KBD_HUB 0x2802 Kbd Hub -product ALCOR DUMMY 0x0000 Dummy product product ALCOR SDCR_6335 0x6335 SD/MMC Card Reader product ALCOR SDCR_6362 0x6362 SD/MMC Card Reader product ALCOR SDCR_6366 0x6366 SD/MMC Card Reader @@ -1064,6 +1065,7 @@ product ALCOR AU6390 0x6390 AU6390 USB-IDE converter product ALINK DWM652U5 0xce16 DWM-652 product ALINK 3G 0x9000 3G modem product ALINK SIM7600E 0x9001 LTE modem +product ALINK SIM7600G 0x9011 LTE modem product ALINK 3GU 0x9200 3G modem /* Altec Lansing products */ @@ -1097,6 +1099,9 @@ product AMOI H02 0x0802 H02 3G modem /* American Power Conversion products */ product APC UPS 0x0002 Uninterruptible Power Supply +/* American Power Conversion products */ +product APC UPS1000 0x0003 Uninterruptible Power Supply + /* Ambit Microsystems products */ product AMBIT WLAN 0x0302 WLAN product AMBIT NTL_250 0x6098 NTL 250 cable modem @@ -1104,9 +1109,6 @@ product AMBIT NTL_250 0x6098 NTL 250 cable modem /* Apacer products */ product APACER HT202 0xb113 USB 2.0 Flash Drive -/* American Power Conversion products */ -product APC UPS 0x0002 Uninterruptible Power Supply - /* Amigo Technology products */ product AMIGO RT2870_1 0x9031 RT2870 product AMIGO RT2870_2 0x9041 RT2870 @@ -1136,18 +1138,42 @@ product ANYDATA ADU_500A 0x6502 CDMA 2000 EV-DO USB Modem /* AOX, Inc. products */ product AOX USB101 0x0008 Ethernet -/* American Power Conversion products */ -product APC UPS 0x0002 Uninterruptible Power Supply - /* Apple Computer products */ -product APPLE DUMMY 0x0000 Dummy product product APPLE IMAC_KBD 0x0201 USB iMac Keyboard product APPLE KBD 0x0202 USB Keyboard M2452 product APPLE EXT_KBD 0x020c Apple Extended USB Keyboard +/* PowerBooks Feb 2005, iBooks G4 */ +product APPLE FOUNTAIN_ANSI 0x020e Apple Internal Keyboard/Trackpad +product APPLE FOUNTAIN_ISO 0x020f Apple Internal Keyboard/Trackpad +/* 17 inch PowerBook */ +product APPLE GEYSER_17 0x020d Apple Internal Keyboard/Trackpad +/* PowerBooks Oct 2005 */ +product APPLE GEYSER_ANSI 0x0214 Apple Internal Keyboard/Trackpad +product APPLE GEYSER_ISO 0x0215 Apple Internal Keyboard/Trackpad +product APPLE GEYSER_JIS 0x0216 Apple Internal Keyboard/Trackpad +/* Core Duo MacBook & MacBook Pro */ +product APPLE GEYSER3_ANSI 0x0217 Apple Internal Keyboard/Trackpad +product APPLE GEYSER3_ISO 0x0218 Apple Internal Keyboard/Trackpad +product APPLE GEYSER3_JIS 0x0219 Apple Internal Keyboard/Trackpad +/* Core2 Duo MacBook & MacBook Pro */ +product APPLE GEYSER4_ANSI 0x021a Apple Internal Keyboard/Trackpad +product APPLE GEYSER4_ISO 0x021b Apple Internal Keyboard/Trackpad +product APPLE GEYSER4_JIS 0x021c Apple Internal Keyboard/Trackpad +/* External */ +product APPLE ALU_MINI_ANSI 0x021d Apple Keyboard/Trackpad +product APPLE ALU_MINI_ISO 0x021e Apple Keyboard/Trackpad +product APPLE ALU_MINI_JIS 0x021f Apple Keyboard/Trackpad +product APPLE ALU_ANSI 0x0220 Apple Keyboard/Trackpad +product APPLE ALU_ISO 0x0221 Apple Keyboard/Trackpad +product APPLE ALU_JIS 0x0222 Apple Keyboard/Trackpad /* MacbookAir, aka wellspring */ product APPLE WELLSPRING_ANSI 0x0223 Apple Internal Keyboard/Trackpad product APPLE WELLSPRING_ISO 0x0224 Apple Internal Keyboard/Trackpad product APPLE WELLSPRING_JIS 0x0225 Apple Internal Keyboard/Trackpad +/* Core2 Duo MacBook3,1 */ +product APPLE GEYSER4_HF_ANSI 0x0229 Apple Internal Keyboard/Trackpad +product APPLE GEYSER4_HF_ISO 0x022a Apple Internal Keyboard/Trackpad +product APPLE GEYSER4_HF_JIS 0x022b Apple Internal Keyboard/Trackpad /* MacbookProPenryn, aka wellspring2 */ product APPLE WELLSPRING2_ANSI 0x0230 Apple Internal Keyboard/Trackpad product APPLE WELLSPRING2_ISO 0x0231 Apple Internal Keyboard/Trackpad @@ -1176,6 +1202,10 @@ product APPLE WELLSPRING6A_JIS 0x024b Apple Internal Keyboard/Trackpad product APPLE WELLSPRING6_ANSI 0x024c Apple Internal Keyboard/Trackpad product APPLE WELLSPRING6_ISO 0x024d Apple Internal Keyboard/Trackpad product APPLE WELLSPRING6_JIS 0x024e Apple Internal Keyboard/Trackpad +/* External */ +product APPLE ALU_REVB_ANSI 0x024f Apple Keyboard/Trackpad +product APPLE ALU_REVB_ISO 0x0250 Apple Keyboard/Trackpad +product APPLE ALU_REVB_JIS 0x0251 Apple Keyboard/Trackpad /* Macbook8,2 (unibody) */ product APPLE WELLSPRING5A_ANSI 0x0252 Apple Internal Keyboard/Trackpad product APPLE WELLSPRING5A_ISO 0x0253 Apple Internal Keyboard/Trackpad @@ -1196,6 +1226,17 @@ product APPLE WELLSPRING8_JIS 0x0292 Apple Internal Keyboard/Trackpad product APPLE WELLSPRING9_ANSI 0x0272 Apple Internal Keyboard/Trackpad product APPLE WELLSPRING9_ISO 0x0273 Apple Internal Keyboard/Trackpad product APPLE WELLSPRING9_JIS 0x0274 Apple Internal Keyboard/Trackpad +product APPLE WELLSPRINGT2_J140K 0x027a Apple Internal Keyboard/Trackpad +product APPLE WELLSPRINGT2_J132 0x027b Apple Internal Keyboard/Trackpad +product APPLE WELLSPRINGT2_J680 0x027c Apple Internal Keyboard/Trackpad +product APPLE WELLSPRINGT2_J213 0x027d Apple Internal Keyboard/Trackpad +product APPLE WELLSPRINGT2_J214K 0x027e Apple Internal Keyboard/Trackpad +product APPLE WELLSPRINGT2_J223 0x027f Apple Internal Keyboard/Trackpad +product APPLE WELLSPRINGT2_J230K 0x0280 Apple Internal Keyboard/Trackpad +product APPLE WELLSPRINGT2_J152F 0x0340 Apple Internal Keyboard/Trackpad +product APPLE MAGIC_KEYBOARD_2021 0x029c Apple Internal Keyboard/Trackpad +product APPLE MAGIC_KEYBOARD_FINGERPRINT_2021 0x029a Apple Keyboard/Trackpad +product APPLE MAGIC_TRACKPAD2 0x0265 Apple Magic Trackpad 2 product APPLE MOUSE 0x0301 Mouse M4848 product APPLE OPTMOUSE 0x0302 Optical mouse product APPLE MIGHTYMOUSE 0x0304 Mighty Mouse @@ -1337,6 +1378,7 @@ product AZUREWAVE RTL8192SU_5 0x3325 RTL8192SU /* Baltech products */ product BALTECH CARDREADER 0x9999 Card reader +product BALTECH SMARTCARDREADER 0xf019 SmartCard reader /* Bayer products */ product BAYER CONTOUR_CABLE 0x6001 FTDI compatible adapter @@ -1420,8 +1462,26 @@ product BILLIONTON USBE100 0x8511 USBE100 product BILLIONTON USB2AR 0x90ff USB2AR Ethernet /* Brainboxes Limited products */ +product BRAINBOXES US101 0x1011 US-101 USB2Serial 1xRS232 +product BRAINBOXES US159 0x1021 US-159 USB2Serial 1xRS232 +product BRAINBOXES US235 0x1017 US-235 USB2Serial 1xRS232 product BRAINBOXES US257 0x5001 US-257 USB2Serial 2xRS232 product BRAINBOXES US25701 0x5002 US-25701 USB2Serial 2xRS232 +product BRAINBOXES US279_12 0x2021 US-279 USB2Serial 8xRS232 (Port 1 and 2) +product BRAINBOXES US279_34 0x2022 US-279 USB2Serial 8xRS232 (Port 3 and 4) +product BRAINBOXES US279_56 0x2023 US-279 USB2Serial 8xRS232 (Port 5 and 6) +product BRAINBOXES US279_78 0x2024 US-279 USB2Serial 8xRS232 (Port 7 and 8) +product BRAINBOXES US313 0x6001 US-313 USB2Serial 2xRS422/485 +product BRAINBOXES US320 0x1019 US-320 USB2Serial 1xRS422/485 +product BRAINBOXES US324 0x1013 US-324 USB2Serial 1xRS422/485 +product BRAINBOXES US346_12 0x3011 US-346 USB2Serial 4xRS422/485 (Port 1 and 2) +product BRAINBOXES US346_34 0x3012 US-346 USB2Serial 4xRS422/485 (Port 3 and 4) +product BRAINBOXES US701_12 0x2011 US-701 USB2Serial 4xRS232 (Port 1 and 2) +product BRAINBOXES US701_34 0x2012 US-701 USB2Serial 4xRS232 (Port 3 and 4) +product BRAINBOXES US842_12 0x8001 US-842 USB2Serial 8xRS-422/485 (Port 1 and 2) +product BRAINBOXES US842_34 0x8002 US-842 USB2Serial 8xRS-422/485 (Port 3 and 4) +product BRAINBOXES US842_56 0x8003 US-842 USB2Serial 8xRS-422/485 (Port 5 and 6) +product BRAINBOXES US842_78 0x8004 US-842 USB2Serial 8xRS-422/485 (Port 7 and 8) /* Broadcom products */ product BROADCOM BCM2033 0x2033 BCM2033 Bluetooth USB dongle @@ -1679,6 +1739,14 @@ product DELL U5520_3 0x8138 Dell 5520 3G product DELL U5730 0x8180 Dell 5730 3G product DELL U5730_2 0x8181 Dell 5730 3G product DELL U5730_3 0x8182 Dell 5730 3G +product DELL DW5809 0x81b1 Dell DW5809e Snapdragon X7 LTE/GPS +product DELL DW5809_2 0x81b3 Dell DW5809e Snapdragon X7 LTE/GPS +product DELL DW5811 0x81b5 Dell DW5811e Snapdragon X7 LTE/GPS +product DELL DW5811_2 0x81b6 Dell DW5811e Snapdragon X7 LTE/GPS +product DELL DW5816 0x81cb Dell DW5816e Snapdragon X7 LTE/GPS +product DELL DW5816_2 0x81cc Dell DW5816e Snapdragon X7 LTE/GPS +product DELL DW5818 0x81d0 Dell DW5818 Snapdragon X7 LTE +product DELL DW5818_2 0x81d2 Dell DW5819 Snapdragon X7 LTE product DELL DW700 0x9500 Dell DW700 GPS product DELL2 VARIOUS_UPS 0xffff Various UPS Models @@ -1721,6 +1789,8 @@ product DLINK DWA182C1 0x3315 DWA-182 rev C1 product DLINK DWA180A1 0x3316 DWA-180 rev A1 product DLINK DWA172A1 0x3318 DWA-172 rev A1 product DLINK DWA131E1 0x3319 DWA-131 rev E1 +product DLINK DWA182D1 0x331c DWA-182 rev D1 +product DLINK DWA181A1 0x331e DWA-181 rev A1 product DLINK DWL122 0x3700 DWL-122 product DLINK DWLG120 0x3701 DWL-G120 product DLINK DWL120F 0x3702 DWL-120 rev F @@ -1752,10 +1822,12 @@ product DLINK DWM157 0x7d02 DWM-157 product DLINK DWM157_2 0x7d0e DWM-157 product DLINK DWR510 0x7e12 DWR-510 product DLINK DWM222 0x7e35 DWM-222 +product DLINK DWM222_2 0x7e3d DWM-222 product DLINK DWM157_CD_2 0xa407 DWM-157 CD-ROM Mode product DLINK DWM157_CD 0xa707 DWM-157 CD-ROM Mode product DLINK DWR510_CD 0xa805 DWR-510 CD-ROM Mode product DLINK DWM222_CD 0xab00 DWM-222 CD-ROM Mode +product DLINK DWM222_CD_2 0xac01 DWM-222 CD-ROM Mode product DLINK DSB650 0xabc1 10/100 Ethernet product DLINK DUBH7 0xf103 DUB-H7 USB 2.0 7-Port Hub product DLINK2 RTL8192SU_1 0x3300 RTL8192SU @@ -1835,6 +1907,7 @@ product EDIMAX EW7318USG 0x7318 USB Wireless dongle product EDIMAX RTL8192SU_1 0x7611 RTL8192SU product EDIMAX RTL8192SU_2 0x7612 RTL8192SU product EDIMAX EW7622UMN 0x7622 EW-7622UMn +product EDIMAX MT7601U 0x7710 MT7601U product EDIMAX RT2870_1 0x7711 RT2870 product EDIMAX EW7717 0x7717 EW-7717 product EDIMAX EW7718 0x7718 EW-7718 @@ -1852,7 +1925,6 @@ product EGALAX TPANEL2 0x0002 Touch Panel product EGALAX2 TPANEL 0x0001 Touch Panel /* EGO Products */ -product EGO DUMMY 0x0000 Dummy Product product EGO M4U 0x1020 ESI M4U /* Eicon Networks */ @@ -1874,6 +1946,7 @@ product ELECOM WDC150SU2M 0x4008 WDC-150SU2M product ELECOM LDUSBTX2 0x400b LD-USB/TX product ELECOM WDB433SU2M2 0x400f WDB-433SU2M2 product ELECOM LDUSB20 0x4010 LD-USB20 +product ELECOM EDCQUA3C 0x4017 EDC-QUA3C product ELECOM UCSGT 0x5003 UC-SGT product ELECOM UCSGT0 0x5004 UC-SGT product ELECOM LDUSBTX3 0xabc1 LD-USB/TX @@ -1939,6 +2012,7 @@ product EPSON 1270 0x0120 Perfection 1270 scanner product EPSON 2480 0x0121 Perfection 2480 scanner product EPSON 3590 0x0122 Perfection 3590 scanner product EPSON 4990 0x012a Perfection 4990 Photo scanner +product EPSON TMU220B 0x0202 TM-U220B product EPSON CRESSI_EDY 0x0521 Cressi Edy diving computer product EPSON N2ITION3 0x0522 Zeagle N2iTion3 diving computer product EPSON STYLUS_875DC 0x0601 Stylus Photo 875DC Card Reader @@ -1975,7 +2049,6 @@ product FALCOM TWIST 0x0001 USB GSM/GPRS Modem product FALCOM SAMBA 0x0005 FTDI compatible adapter /* FEIYA products */ -product FEIYA DUMMY 0x0000 Dummy product product FEIYA 5IN1 0x1132 5-in-1 Card Reader product FEIYA ELANGO 0x6200 MicroSDHC Card Reader product FEIYA AC110 0x6300 AC-110 Card Reader @@ -2285,6 +2358,7 @@ product GENESYS GL3520_SS 0x0616 GL3520 4-Port USB 3.0 DataPath product GENESYS GL641USB 0x0700 GL641USB CompactFlash Card Reader product GENESYS GL641USB2IDE_2 0x0701 GL641USB USB-IDE Bridge No 2 product GENESYS GL641USB2IDE 0x0702 GL641USB USB-IDE Bridge +product GENESYS GL3220 0x0732 GL3220 USB 3.1 AiO Card Reader product GENESYS GL3233 0x0743 GL3233 USB 3.0 AiO Card Reader product GENESYS GL641USB_2 0x0760 GL641USB 6-in-1 Card Reader @@ -2539,9 +2613,7 @@ product HUAWEI K3770 0x14c9 3G modem product HUAWEI K3771 0x14ca K3771 product HUAWEI K3772 0x14cf K3772 product HUAWEI K3770_INIT 0x14d1 K3770 Initial -product HUAWEI E3131_INIT 0x14fe 3G modem initial product HUAWEI E392 0x1505 LTE modem -product HUAWEI E3131 0x1506 3G modem product HUAWEI K3765_INIT 0x1520 K3765 Initial product HUAWEI K4505_INIT 0x1521 K4505 Initial product HUAWEI K3772_INIT 0x1526 K3772 Initial @@ -2554,6 +2626,13 @@ product HUAWEI ETS2055 0x1803 CDMA modem product HUAWEI E173 0x1c05 3G modem product HUAWEI E173_INIT 0x1c0b 3G modem initial product HUAWEI E3272 0x1c1e LTE modem +product HUAWEI E3372_INIT 0x1f01 LTE modem initial +product HUAWEI E3372_NCM 0x1506 LTE modem in NCM mode +product HUAWEI E3372v153_INIT 0x14fe LTE modem initial +product HUAWEI E3372v153_NCM 0x155f LTE modem in NCM mode +product HUAWEI E5573Cs322_NCM 0x155e LTE AP modem NCM mode +product HUAWEI E5573Cs322_ECM 0x14db LTE AP modem ECM mode +product HUAWEI E5573Cs322_ACM 0x1442 LTE AP modem ACM mode /* HUAWEI 3com products */ product HUAWEI3COM WUB320G 0x0009 Aolynk WUB320g @@ -2584,7 +2663,6 @@ product IDTECH IDT1221U 0x0300 FTDI compatible adapter product IMAGINATION DBX1 0x2107 DBX1 DSP core /* Initio Corporation products */ -product INITIO DUMMY 0x0000 Dummy product product INITIO INIC_1610P 0x1e40 USB to SATA Bridge /* Inside Out Networks products */ @@ -2697,6 +2775,7 @@ product KEISOKUGIKEN USBDAQ 0x0068 HKS-0200 USBDAQ /* Kensington products */ product KENSINGTON ORBIT 0x1003 Orbit USB/PS2 trackball product KENSINGTON TURBOBALL 0x1005 TurboBall +product KENSINGTON SLIMBLADE 0x2041 Slimblade Trackball /* Synaptics products */ product SYNAPTICS FPR9A 0x009a Fingerprint Reader @@ -2811,10 +2890,13 @@ product LENOVO GIGALAN 0x304b USB 3.0 Ethernet product LENOVO ETHERNET 0x7203 USB 2.0 Ethernet product LENOVO RTL8153 0x7205 USB 3.0 Ethernet product LENOVO ONELINK 0x720a USB 3.0 Ethernet +product LENOVO RTL8153_04 0x720c USB 3.0 Ethernet +product LENOVO ONELINKPLUS 0x3054 LAN port in Thinkpad OneLink+ dock product LENOVO TBT3LAN 0x3069 LAN port in Thinkpad TB3 dock product LENOVO USBCLAN 0x3062 LAN port in Thinkpad USB-C dock product LENOVO TBT3LANGEN2 0x3082 LAN port in Thinkpad TB3 dock gen2 -product LENOVO USBCLANGEN2 0xa387 LAN port in Thinkpad UBS-C dock gen2 +product LENOVO USBCLANGEN2 0xa387 LAN port in Thinkpad USB-C dock gen2 +product LENOVO USBCLANHYBRID 0xa359 LAN port in Thinkpad Hybrid USB-C with USB-A dock /* Lexar products */ product LEXAR JUMPSHOT 0x0001 jumpSHOT CompactFlash Reader @@ -2854,7 +2936,6 @@ product LINKSYS4 RT3070 0x0078 RT3070 product LINKSYS4 WUSB600NV2 0x0079 WUSB600N v2 /* Logilink products */ -product LOGILINK DUMMY 0x0000 Dummy product product LOGILINK U2M 0x0101 LogiLink USB MIDI Cable /* Logitech products */ @@ -3292,6 +3373,7 @@ product MICROSOFT WLNOTEBOOK3 0x00d2 Wireless Optical Mouse 3000 (Model 1049) product MICROSOFT NATURAL4000 0x00db Natural Ergonomic Keyboard 4000 product MICROSOFT WLNOTEBOOK2 0x00e1 Wireless Optical Mouse 3000 (Model 1056) product MICROSOFT XBOX360 0x0292 XBOX 360 WLAN +product MICROSOFT WINDEVETH 0x0c5e Windows Dev Kit 2023 Ethernet /* Microtech products */ product MICROTECH SCSIDB25 0x0004 USB-SCSI-DB25 @@ -3483,6 +3565,9 @@ product NOVATECH RTL8188CU 0x9071 RTL8188CU product NOKIA N958GB 0x0070 Nokia N95 8GBc product NOKIA2 CA42 0x1234 CA-42 cable +/* NOREL Systems Ltd. products */ +product NORELSYS NS1081 0x1081 NS1081 USB 3.0 Flash Card Reader + /* Novatel Wireless products */ product NOVATEL V640 0x1100 Merlin V620 product NOVATEL CDMA_MODEM 0x1110 Novatel Wireless Merlin CDMA @@ -3533,6 +3618,20 @@ product OLIMEX ARM_USB_OCD_H 0x002b FTDI compatible adapter /* Olympus products */ product OLYMPUS C1 0x0102 C-1 Digital Camera product OLYMPUS C700 0x0105 C-700 Ultra Zoom +/* Current Olympus DSLRs and EVIL cameras reuse the same product code and + * bcdDevice for multiple models. This may result in problems with newer + * cameras. */ +/* Olympus DSLRs */ +product OLYMPUS E_1 0x0102 +product OLYMPUS E_300 0x0118 +product OLYMPUS E_330 0x0118 +product OLYMPUS E_30 0x0118 +/* Olympus EVIL cameras */ +product OLYMPUS E_PM1 0x012c +product OLYMPUS E_PM2 0x012e +product OLYMPUS E_M1 0x012e +product OLYMPUS E_M1MarkII 0x012e +product OLYMPUS E_M5MarkIII 0x012e /* OmniVision Technologies, Inc. products */ product OMNIVISION OV511 0x0511 OV511 Camera @@ -3952,9 +4051,27 @@ product QUANTA GLE 0xea06 HSDPA modem product QUANTA RW6815R 0xf003 HP iPAQ rw6815 RNDIS /* Quectel products */ -product QUECTEL EC25 0x0125 LTE modem -product QUECTEL EM05 0x0127 LTE modem -product QUECTEL EM12_G 0x0512 LTE modem +product QUECTEL EC21 0x0121 Quectel EC21 +product QUECTEL EC25 0x0125 Quectel EC20(MDM9x07)/EC25/EG25 +product QUECTEL EM05 0x0127 Quectel EM05 +product QUECTEL EG91 0x0191 Quectel EG91 +product QUECTEL EG95 0x0195 Quectel EG95 +product QUECTEL BG96 0x0296 Quectel BG96 +product QUECTEL EP06 0x0306 Quectel EG06/EP06/EM06 +product QUECTEL EG065K 0x030B Quectel EG065K/EG060K +product QUECTEL AG15 0x0415 Quectel AG15 +product QUECTEL AG35 0x0435 Quectel AG35 +product QUECTEL AG520 0x0452 Quectel AG520 +product QUECTEL AG550 0x0455 Quectel AG550 +product QUECTEL EM12 0x0512 Quectel EG12/EP12/EM12/EG16/EG18 +product QUECTEL EM160R 0x0620 Quectel EM160R/EG20 +product QUECTEL BG95 0x0700 Quectel BG95/BG77/BG600L-M3/BC69 +product QUECTEL RG500 0x0800 Quectel RG500/RM500/RG510/RM510 +product QUECTEL RG520 0x0801 Quectel RG520/RM520/SG520 +product QUECTEL EC200 0x6000 Quectel EC200/UC200 +product QUECTEL EC200S 0x6002 Quectel EC200S +product QUECTEL EC200T 0x6026 Quectel EC200T +product QUECTEL UC200 0x6120 Quectel UC200 /* Quickshot products */ product QUICKSHOT STRIKEPAD 0x6238 USB StrikePad @@ -3986,6 +4103,7 @@ product RALINK RT3573 0x3573 RT3573 product RALINK RT5370 0x5370 RT5370 product RALINK RT5372 0x5372 RT5372 product RALINK RT5572 0x5572 RT5572 +product RALINK MT7601U 0x7601 MT7601 Mediatek Wireless Adpater product RALINK RT8070 0x8070 RT8070 product RALINK RT2570_3 0x9020 RT2500USB Wireless Adapter product RALINK RT2573_2 0x9021 RT2501USB Wireless Adapter @@ -3996,11 +4114,11 @@ product RATOC REXUSB60F 0xb020 USB serial adapter REX-USB60F /* Realtek products */ /* Green House and CompUSA OEM this part */ -product REALTEK DUMMY 0x0000 Dummy product product REALTEK USB20CRW 0x0158 USB20CRW Card Reader product REALTEK RTL8188ETV 0x0179 RTL8188ETV product REALTEK RTL8188CTV 0x018a RTL8188CTV product REALTEK RTL8821AU_2 0x0811 RTL8821AU +product REALTEK RTW8821CU_CD 0x1a2b RTW8821CU_CD product REALTEK RTL8188RU_2 0x317f RTL8188RU product REALTEK USBKR100 0x8150 USBKR100 USB Ethernet product REALTEK RTL8152 0x8152 RTL8152 USB Ethernet @@ -4032,14 +4150,14 @@ product REALTEK RTL8187B_2 0x8198 RTL8187B Wireless Adapter product REALTEK RTL8712 0x8712 RTL8712 product REALTEK RTL8713 0x8713 RTL8713 product REALTEK RTL8188CU_COMBO 0x8754 RTL8188CU +product REALTEK RTL8812AU_1 0x8812 RTL8812AU Wireless Adapter +product REALTEK RTL8812AU_2 0x881a RTL8812AU Wireless Adapter product REALTEK RTL8821AU_1 0xa811 RTL8821AU product REALTEK RTL8723BU 0xb720 RTL8723BU product REALTEK RTL8192SU 0xc512 RTL8192SU -product REALTEK RTL8812AU_1 0x8812 RTL8812AU Wireless Adapter -product REALTEK RTL8812AU_2 0x881a RTL8812AU Wireless Adapter +product REALTEK RTW8821CU 0xc811 RTW8821CU /* RedOctane products */ -product REDOCTANE DUMMY 0x0000 Dummy product product REDOCTANE GHMIDI 0x474b GH MIDI INTERFACE /* Renesas products */ @@ -4303,9 +4421,16 @@ product SIERRA E6893 0x6893 E6893 product SIERRA MC8700 0x68A3 MC8700 product SIERRA MC7354 0x68C0 MC7354 product SIERRA MC7355 0x9041 MC7355 +product SIERRA AC340U 0x9051 Sierra Wireless AirCard 340U product SIERRA MC7430 0x9071 Sierra Wireless MC7430 Qualcomm Snapdragon X7 LTE-A product SIERRA AC313U 0x68aa Sierra Wireless AirCard 313U product SIERRA TRUINSTALL 0x0fff Aircard Tru Installer +product SIERRA EM7430 0x81cb Sierra Wireless EM7430 Qualcomm Snapdragon X7 LTE-A +product SIERRA EM7430_2 0x81cc Sierra Wireless EM7430 Qualcomm Snapdragon X7 LTE-A +product SIERRA EM7455 0x9078 Sierra Wireless EM7455 Qualcomm Snapdragon X7 LTE-A +product SIERRA EM7455_2 0x9079 Sierra Wireless EM7455 Qualcomm Snapdragon X7 LTE-A +product SIERRA EM7565 0x9090 Sierra Wireless EM7565 Qualcomm Snapdragon X7 LTE-A +product SIERRA EM7565_2 0x9091 Sierra Wireless EM7565 Qualcomm Snapdragon X7 LTE-A /* Sigmatel products */ product SIGMATEL WBT_3052 0x4200 WBT-3052 IrDA/USB Bridge @@ -4603,7 +4728,6 @@ product TECLAST TLC300 0x3203 USB Media Player product TESTO USB_INTERFACE 0x0001 FTDI compatible adapter /* TexTech products */ -product TEXTECH DUMMY 0x0000 Dummy product product TEXTECH U2M_1 0x0101 Textech USB MIDI cable product TEXTECH U2M_2 0x1806 Textech USB MIDI cable @@ -4703,8 +4827,8 @@ product TOSHIBA HSDPA 0x1302 G450 modem product TOSHIBA TRANSMEMORY 0x6545 USB ThumbDrive /* TP-Link products */ -product TPLINK T4U 0x0101 Archer T4U product TPLINK RTL8192CU 0x0100 RTL8192CU +product TPLINK T4U 0x0101 Archer T4U product TPLINK WN821NV5 0x0107 TL-WN821N v5 product TPLINK WN822NV4 0x0108 TL-WN822N v4 product TPLINK WN823NV2 0x0109 TL-WN823N v2 @@ -4757,6 +4881,9 @@ product TWINMOS MDIV 0x1325 Memory Disk IV /* Ubiquam products */ product UBIQUAM UALL 0x3100 CDMA 1xRTT USB Modem (U-100/105/200/300/520) +/* u-blox products */ +product UBLOX XPLR_M9 0x0501 M9 GNSS Explorer Kit + /* Ultima products */ product ULTIMA 1200UBPLUS 0x4002 1200 UB Plus scanner @@ -4842,7 +4969,6 @@ product WAVESENSE JAZZ 0xaaaa Jazz blood glucose meter /* WCH products */ product WCH CH341SER 0x5523 CH341/CH340 USB-Serial Bridge -product WCH2 DUMMY 0x0000 Dummy product product WCH2 CH341SER_2 0x5523 CH341/CH340 USB-Serial Bridge product WCH2 CH341SER_3 0x7522 CH341/CH340 USB-Serial Bridge product WCH2 CH341SER 0x7523 CH341/CH340 USB-Serial Bridge @@ -4878,6 +5004,7 @@ product WESTERN MYPASSPORTES_06 0x0750 MyPassport Essential External HDD product WESTERN MYPASSPORTES_07 0x0752 MyPassport Essential External HDD product WESTERN MYPASSPORTES_08 0x07A0 MyPassport Essential External HDD product WESTERN MYPASSPORTES_09 0x07A2 MyPassport Essential External HDD +product WESTERN MYPASSPORTUL_00 0x0743 MyPassport Ultra External HDD /* WeTelecom products */ product WETELECOM WM_D200 0x6801 WM-D200 @@ -4902,12 +5029,16 @@ product WISTRONNEWEB UR055G 0x0711 UR055G product WISTRONNEWEB O8494 0x0804 ORiNOCO 802.11n product WISTRONNEWEB AR5523_1 0x0826 AR5523 product WISTRONNEWEB AR5523_1_NF 0x0827 AR5523 (no firmware) -product WISTRONNEWEB AR5523_2 0x082a AR5523 +product WISTRONNEWEB AR5523_2 0x0828 AR5523 +product WISTRONNEWEB AR5523_2_ALT 0x082a AR5523 product WISTRONNEWEB AR5523_2_NF 0x0829 AR5523 (no firmware) /* Xerox products */ product XEROX WCM15 0xffef WorkCenter M15 +/* Xiaomi products */ +product XIAOMI MT7601U 0x4106 MT7601U + /* Xirlink products */ product XIRLINK PCCAM 0x8080 IBM PC Camera