Date: Mon, 3 Feb 2025 19:29:43 GMT From: Jesper Schmitz Mouridsen <jsm@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: c14b01624261 - main - mt7601U: Importing if_mtw from OpenBSD Message-ID: <202502031929.513JThFp036311@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by jsm: URL: https://cgit.FreeBSD.org/src/commit/?id=c14b016242613da79516e83fc6faef35d827cc18 commit c14b016242613da79516e83fc6faef35d827cc18 Author: Jesper Schmitz Mouridsen <jsm@FreeBSD.org> AuthorDate: 2025-02-03 19:20:52 +0000 Commit: Jesper Schmitz Mouridsen <jsm@FreeBSD.org> CommitDate: 2025-02-03 19:20:52 +0000 mt7601U: Importing if_mtw from OpenBSD Added ht20 mode, based on if_run from FreeBSD, and if_mtw.c from OpenBSD. PR: 247545 Approved by: adrian, wireless Differential Revision: https://reviews.freebsd.org/D45179 --- sbin/devd/devd.conf | 2 +- share/man/man4/Makefile | 1 + share/man/man4/mtw.4 | 74 + sys/dev/usb/usbdevs | 3 +- sys/dev/usb/wlan/if_mtw.c | 4675 ++++++++++++++++++++++++++++++++++++++++++ sys/dev/usb/wlan/if_mtwreg.h | 1439 +++++++++++++ sys/dev/usb/wlan/if_mtwvar.h | 387 ++++ sys/modules/usb/Makefile | 2 +- sys/modules/usb/mtw/Makefile | 9 + 9 files changed, 6589 insertions(+), 3 deletions(-) diff --git a/sbin/devd/devd.conf b/sbin/devd/devd.conf index 08cbeb840b2f..86faf2f30722 100644 --- a/sbin/devd/devd.conf +++ b/sbin/devd/devd.conf @@ -18,7 +18,7 @@ options { # Setup some shorthand for regex that we use later in the file. #XXX Yes, this is gross -- imp set wifi-driver-regex - "(ath|ath[0-9]+k|bwi|bwn|ipw|iwlwifi|iwi|iwm|iwn|malo|mwl|mt79|otus|\ + "(ath|ath[0-9]+k|bwi|bwn|ipw|iwlwifi|iwi|iwm|iwn|malo|mwl|mt79|mtw|otus|\ ral|rsu|rtw|rtwn|rum|run|uath|upgt|ural|urtw|wpi|wtap|zyd)[0-9]+"; }; diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 9dc1c7f9bc12..600b4dfd9504 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -338,6 +338,7 @@ MAN= aac.4 \ msdosfs.4 \ msk.4 \ mtio.4 \ + mtw.4 \ multicast.4 \ muge.4 \ mvs.4 \ diff --git a/share/man/man4/mtw.4 b/share/man/man4/mtw.4 new file mode 100644 index 000000000000..17722be73203 --- /dev/null +++ b/share/man/man4/mtw.4 @@ -0,0 +1,74 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2024 Jesper Schmitz Mouridsen <jsm@freebsd.org> +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd Feb 03, 2025 +.Dt MTW 4 +.Os +.Sh NAME +.Nm if_mtw +.Nd "Mediatek MT7601U" +.Ed +.Sh DESCRIPTION +This module provides support for Mediatek MT7601U with the firmware from net/wifi-firmware-mtw-kmod + +.Sh HARDWARE +The +.Nm +driver supports Mediatek MT7601U +based USB wireless network adapters including (but not all of them tested): +.Pp +.Bl -column -compact +.It +ASUS USB-N10 v2 +.It +D-Link DWA-127 rev B1 +.It +Edimax EW-7711UAn v2 +.It +Foxconn WFU03 +.It +Tenda U2 +.It +Tenda W311MI v2 +.It +TP-LINK TL-WN727N v4 (tested working) +.It +Yealink WF40 +.El +.Sh SEE ALSO +.Xr usb 4 +.Sh BUGS +The +.Nm +only works in station mode and monitor mode. The firmware does not always reinitialize when reloading the module, or when rebooting, without first unplugging the device. +.Sh History +The mtw driver first appeared in OpenBSD 7.1. The mtw driver was ported to FreeBSD in FreeBSD 15.0. +.Sh AUTHORS +.An -nosplit +The mtw driver was written by +.An James Hastings Aq Mt hastings@openbsd.org +ported to FreeBSD by +.An Jesper Schmitz Mouridsen Aq Mt jsm@FreeBSD.org diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 61f563ca1aa6..0dc99526d991 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -1906,6 +1906,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 @@ -4101,7 +4102,7 @@ product RALINK RT3573 0x3573 RT3573 product RALINK RT5370 0x5370 RT5370 product RALINK RT5372 0x5372 RT5372 product RALINK RT5572 0x5572 RT5572 -product RALINK RT7601 0x7601 RT7601 +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 diff --git a/sys/dev/usb/wlan/if_mtw.c b/sys/dev/usb/wlan/if_mtw.c new file mode 100644 index 000000000000..ecd4693e2361 --- /dev/null +++ b/sys/dev/usb/wlan/if_mtw.c @@ -0,0 +1,4675 @@ +/*- + * Copyright (c) 2008-2010 Damien Bergamini <damien.bergamini@free.fr> + * 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/eventhandler.h> +#include <sys/firmware.h> +#include <sys/kdb.h> +#include <sys/kernel.h> +#include <sys/linker.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> + +#include <net/bpf.h> +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <net/if_var.h> +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_ratectl.h> +#include <net80211/ieee80211_regdomain.h> +#include <netinet/if_ether.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include "usbdevs.h" + +#define USB_DEBUG_VAR mtw_debug +#include <dev/usb/usb_debug.h> +#include <dev/usb/usb_msctest.h> + +#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) +{ + 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; +} + +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); + } + firmware_unregister("/mediatek/mt7601u"); + 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; + } + *** 5717 LINES SKIPPED ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502031929.513JThFp036311>