FNOS 安装 MT7921U USB WiFi 6 驱动说明
这份文档整理的是本次在飞牛 OS 上实际跑通的方案,目标是给 MT7921U / MT7921AU / MT7921BU 这类 USB WiFi 6 网卡安装驱动。
参考飞牛社区帖子:https://club.fnnas.com/forum.php?mod=viewthread&tid=623681
适用环境:
- 系统:
fnOS 1.1.3107
- 内核:
6.18.18-trim
- 架构:
x86_64
- 实测设备:
MT7921U
这次成功的关键不是“直接用论坛现成 .ko”,而是:
- 用
openwrt/mt76 源码
- 按
FNOS 6.18.18-trim 的 headers 打兼容补丁
- 在本机重新编译
先说结论
https://club.fnnas.com/forum.php?mod=viewthread&tid=62368l里论坛分享的预编译包 mt76_backup.tar.gz 在这台机器上不能直接用。
虽然它表面上也是给 6.18.18-trim,但直接安装后会报:
modprobe: ERROR: could not insert 'mt7921u': Exec format error
mt76: disagrees about version of symbol module_layout
所以正确做法是重新编译,而不是直接复制旧 .ko。
支持的 USB ID
本次编译出的 mt7921u.ko 支持这些 ID:
0e8d:7961
3574:6211
0846:9060
0846:9065
35bc:0107
插上网卡后可先检查:
lsusb
重要提醒
1. modprobe 可能不是没安装,而是不在 PATH
FNOS 上 登录 用户默认 PATH 里没有 /usr/sbin,所以你会看到:
modprobe: command not found
这不一定代表系统没装 kmod。直接用完整路径即可:
/usr/sbin/modprobe mt7921u
/usr/sbin/modinfo mt7921u
/usr/sbin/depmod -a
2. 这套方案是给 6.18.18-trim 的
如果以后飞牛 OS 升级内核,比如不是 6.18.18-trim 了,需要重新编译一遍,不能直接沿用旧模块。
先确认:
uname -r
安装前检查
uname -r
uname -m
ls /usr/src/ | grep linux-headers
docker version
预期:
uname -r 是 6.18.18-trim
uname -m 是 x86_64
- 存在
linux-headers-6.18.18-trim
- Docker 可用
本次实际成功的最小方案
和常见教程相比,这次没有去编整套 mt76 全家桶,而是只编 MT7921U 真正需要的那几个模块:
mt76.ko
mt76-usb.ko
mt76-connac-lib.ko
mt792x-lib.ko
mt792x-usb.ko
mt7921-common.ko
mt7921u.ko
这样可以避开 mt7603、mt7615、mt76x0、mt76x2 那些不相关模块的兼容性报错。
安装步骤
步骤 1:准备源码目录
cd /tmp
rm -rf mt76-build
git clone --depth 1 https://github.com/openwrt/mt76 mt76-build
cd mt76-build
步骤 2:打兼容补丁
这次实际需要的补丁点有 3 个:
- 给
mt76.h 补 linux/version.h 和 LINUX_VERSION_CODE
- 把旧路径
asm/unaligned.h 改成 linux/unaligned.h
- 把
ieee80211_txq_aql_pending() 改成旧 headers 也支持的 ieee80211_txq_get_depth()
执行:
cd /tmp/mt76-build
python3 <<'PY'
from pathlib import Path
p = Path('mt76.h')
text = p.read_text()
needle = '#define __MT76_H\n\n'
insert = '#define __MT76_H\n\n#include <linux/version.h>\n#ifndef LINUX_VERSION_CODE\n#define LINUX_VERSION_CODE KERNEL_VERSION(6,18,18)\n#endif\n\n'
if '#include <linux/version.h>' not in text:
text = text.replace(needle, insert, 1)
p.write_text(text)
PY
find . -type f \( -name "*.c" -o -name "*.h" \) -exec sed -i 's|<asm/unaligned.h>|<linux/unaligned.h>|g' {} +
python3 <<'PY'
from pathlib import Path
p = Path('tx.c')
text = p.read_text()
old = """\t\tif (ieee80211_txq_aql_pending(phy->hw, txq))\n\t\t\treturn 0;\n"""
new = """\t\t{\n\t\t\tunsigned long frame_cnt, byte_cnt;\n\n\t\t\tieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt);\n\t\t\tif (frame_cnt || byte_cnt)\n\t\t\t\treturn 0;\n\t\t}\n"""
if old not in text:
raise SystemExit('tx.c patch target not found')
text = text.replace(old, new, 1)
p.write_text(text)
PY
说明:
- 常见教程里提到的
hrtimer 补丁,这次没有用到
- 因为我们没有编
mt76x02_usb_core.c 那条无关分支
步骤 3:用 Docker 编译
宿主机没有现成 gcc,所以这次用 Docker 编译,避免往系统里装一堆编译工具。
cd /
sudo docker run --rm \
-v /tmp/mt76-build:/src \
-v /usr/src/linux-headers-$(uname -r):/kbuild \
-w /src \
gcc:12-bookworm \
bash -lc 'set -e; make -C /kbuild M=/src \
CONFI**T7601U=n CONFI**T7603E=n CONFI**T7615_COMMON=n CONFI**T7615E=n \
CONFI**T7663S=n CONFI**T7663U=n CONFI**T7663_USB_SDIO_COMMON=n \
CONFI**T76_SDIO=n CONFI**T76x02_LIB=n CONFI**T76x02_USB=n \
CONFI**T76x0_COMMON=n CONFI**T76x0E=n CONFI**T76x0U=n \
CONFI**T76x2_COMMON=n CONFI**T76x2E=n CONFI**T76x2U=n \
CONFI**T7915E=n CONFI**T7921E=n CONFI**T7921S=n \
CONFI**T7996E=n CONFI**T7925_COMMON=n \
CONFI**T76_USB=m CONFI**T76_CONNAC_LIB=m CONFI**T7921_COMMON=m \
CONFI**T792x_LIB=m CONFI**T792x_USB=m CONFI**T7921U=m \
modules -j$(nproc)'
编译成功后应生成这些文件:
/tmp/mt76-build/mt76.ko
/tmp/mt76-build/mt76-usb.ko
/tmp/mt76-build/mt76-connac-lib.ko
/tmp/mt76-build/mt792x-lib.ko
/tmp/mt76-build/mt792x-usb.ko
/tmp/mt76-build/mt7921/mt7921-common.ko
/tmp/mt76-build/mt7921/mt7921u.ko
步骤 4:安装到系统模块目录
KVER=$(uname -r)
TARGET=/lib/modules/$KVER/updates/wireless/mt76
sudo mkdir -p "$TARGET"
sudo install -m 644 /tmp/mt76-build/mt76.ko "$TARGET/"
sudo install -m 644 /tmp/mt76-build/mt76-usb.ko "$TARGET/"
sudo install -m 644 /tmp/mt76-build/mt76-connac-lib.ko "$TARGET/"
sudo install -m 644 /tmp/mt76-build/mt792x-lib.ko "$TARGET/"
sudo install -m 644 /tmp/mt76-build/mt792x-usb.ko "$TARGET/"
sudo install -m 644 /tmp/mt76-build/mt7921/mt7921-common.ko "$TARGET/"
sudo install -m 644 /tmp/mt76-build/mt7921/mt7921u.ko "$TARGET/"
sudo chown -R root:root "$TARGET"
sudo /usr/sbin/depmod -a
步骤 5:加载驱动
sudo /usr/sbin/modprobe -r mt7921u mt7921_common mt792x_usb mt792x_lib mt76_usb mt76_connac_lib mt76 2>/dev/null || true
sudo /usr/sbin/modprobe mt7921u
步骤 6:验证
看模块信息:
/usr/sbin/modinfo mt7921u
看是否已加载:
lsmod | grep -E 'mt76|mt7921u|mt792'
看驱动文件是否在:
find /lib/modules/$(uname -r)/updates/wireless/mt76 -maxdepth 1 -type f
如果一切正常,lsmod 应该至少能看到:
mt7921u
mt792x_usb
mt7921_common
mt792x_lib
mt76_usb
mt76_connac_lib
mt76
步骤 7:插上 USB 网卡后检查
lsusb
ip link show
sudo dmesg | tail -n 100
如果识别成功,lsusb 里应出现你的无线网卡 ID,ip link show 里会出现 wl* 或 wlan* 接口。
常见问题
1. modprobe: command not found
直接用:
/usr/sbin/modprobe mt7921u
2. Exec format error
如果你是直接用了别人分享的 .ko,很容易遇到这个错。
通常说明模块和你当前 FNOS 内核 ABI 不匹配,需要按这份文档重新编译。
3. asm/unaligned.h: No such file or directory
说明源码和你当前 headers 不兼容,需要把:
#include <asm/unaligned.h>
改成:
#include <linux/unaligned.h>
4. LINUX_VERSION_CODE / KERNEL_VERSION 报错
说明 mt76.h 缺 linux/version.h,需要补:
#include <linux/version.h>
#define LINUX_VERSION_CODE KERNEL_VERSION(6,18,18)
5. ieee80211_txq_aql_pending 未定义
说明 openwrt/mt76 当前源码比 FNOS 的 mac80211 头文件更新,需要改成 ieee80211_txq_get_depth() 的兼容写法,这份文档里的补丁已经处理。
6. 驱动已加载,但没有无线接口
先确认网卡是否真的插上了:
lsusb
这次安装完成后,我们检查到的系统状态就是:
- 驱动模块已加载
- 但当时 NAS 上并没有插着兼容的
MT7921U USB 网卡
- 所以不会出现
wlan 接口
安装后清理临时文件
如果确认驱动已经装好,可以清理:
sudo rm -rf /tmp/mt76-build
如果你还想顺手清理 Docker 拉下来的编译镜像:
sudo docker image rm gcc:12-bookworm
当前已安装的驱动检查命令
/usr/sbin/modinfo mt7921u
lsmod | grep -E 'mt76|mt7921u|mt792'
find /lib/modules/$(uname -r)/updates/wireless/mt76 -maxdepth 1 -type f
不建议的做法
- 不建议直接复制论坛预编译的
mt76_backup.tar.gz
- 不建议只复制单个
mt7921u.ko
- 不建议在内核升级后继续沿用旧
.ko
备注
本次成功方案的核心是“补兼容点 + 本机重编”,不是“改模块签名”。
之前确认过本机内核:
CONFI**ODULE_SIG_FORCE is not set
所以这次能成功,靠的是模块和 6.18.18-trim 的符号版本、vermagic、依赖链对上,而不是靠签名放行。