Skip site navigation (1)Skip section navigation (2)
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>