拓冰建站拓冰建站
首页 / 资讯中心 / 正文

MT7663 USB WiFi驱动交叉编译实战:从源码到ARM平台部署

简介在嵌入式Linux平台的无线网卡适配场景中这套基于MT7663芯片的USB转WiFi驱动源码包尤其适合海思3531等ARM64环境下的工程师适合具备基础Linux内核编译经验、希望缩短网卡适配周期的开发者。压缩包内含已配置好的Makefile.aarch省去手工搭建工具链和内核目录的步骤可直接修改CROSS_COMPILE、LINUX_SRC、DRIVER_DIR三个变量后执行make -f Makefile.aarch生成驱动。包内共453个文件、约7.62MB以h头文件与c源码为主体附带预编译的o对象文件、bin固件、ko驱动模块及Makefile构建脚本覆盖编译、链接与固件加载链路其中针对无线扩展与OID管理的核心实现可支撑驱动二次开发与模块裁剪。附带的bin固件配合文档可用于芯片patch加载pdf/xlsx说明文档可辅助完成参数核对与编译前检查。已有424人学习下载对需要在不同ARM平台间移植驱动、快速产出可加载ko的开发者有直接参考价值。1. 项目概述与方案选型1.1 核心需求解析我一直觉得搞嵌入式Linux的人手里如果没有几块USB WiFi模块出门都不好意思跟人打招呼。这次要分享的项目比较直接MT7663芯片的USB转WiFi驱动源码以及一套已经配置好、能直接用来做交叉编译的makefile。MT7663是联发科推出的一款支持WiFi 6的芯片方案虽然现在是WiFi 6普及期但在嵌入式设备上能用上WiFi 6的还不多见。市面上主流的USB WiFi方案还是以Realtek的RTL8188、RTL8812系列以及MT7601、MT7612为主MT7663算是比较新的选择。它同时支持USB接口和SDIO接口两种连接方式不过这里我们只聊USB版本。这个项目的核心价值在于驱动源码已经帮你整理好makefile也已经针对交叉编译做了预处理你不用再去翻联发科那堆乱糟糟的官方代码仓库也不用在makefile里自己折腾交叉编译工具链的路径变量。拿来就能用改几个变量就能编出目标平台的内核模块。适合谁来参考正在做嵌入式Linux产品的工程师尤其是用RK、全志、飞腾或者其它ARM平台做主控需要给设备增加WiFi能力的朋友。做物联网网关、智能终端、工业平板这类产品的同学也应该能从这套配置里省下不少时间。1.2 为什么选MT7663而不是其它方案实话说如果不是特别在意WiFi 6的支持市面上很多廉价方案也能凑合。但MT7663有比较明显的几个优势吞吐性能有保障。MT7663双频并发2.4GHz和5GHz都支持理论速率能跑到600Mbps左右。对于嵌入式设备来说这个带宽做视频传输、大文件同步都够用了。相比之下MT7601只能跑2.4GHz单频最高才150Mbps场景受限比较明显。Linux内核社区支持度不错。联发科在MT7663的驱动适配方面比前几代产品用心一些代码质量和提交频率都算在线。虽然官方还是以out-of-tree方式发布驱动但有总比没有强。SDIO和USB两栖。如果你的产品设计上需要灵活切换接口形态同样是这颗芯片改一下硬件接口和对应驱动文件就行软件层面的改动成本很低。不过有个点要提前说明MT7663的USB版本驱动联发科官方在GitHub上有开源仓库但这颗芯片的固件是专有的firmware文件需要单独获取。我在项目里已经处理好了固件的路径和加载方式具体细节后面会讲。2. 交叉编译环境搭建2.1 工具链的选择与配置交叉编译Linux内核模块第一步肯定是搞定工具链。我这次用的环境是Ubuntu 20.04 LTS主机目标平台是ARM Cortex-A7架构的板子。选择工具链时有几个注意事项值得展开说说。首先是版本匹配问题。不要图省事随手装个最新的GCC版本就开干内核模块编译对编译器版本敏感度挺高尤其是Linux 4.x以上的内核版本编译时经常会因为GCC版本过高导致一些历史遗留代码报错。经验法则是目标内核用什么版本的GCC编出来的你就尽量用相同或者相近的版本去做模块编译。我在项目里用的是Linaro提供的交叉编译工具链版本是gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf这是一套在嵌入式领域用得比较多的ARM 32位工具链。如果你的目标平台是ARM 64位选aarch64-linux-gnu那套就行。安装方式很简单wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz sudo mv gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf /opt/解压之后把bin目录加进PATH环境变量或者更稳妥的方式是在makefile里直接写死工具链的绝对路径避免因为环境变量问题导致找不到编译器。2.2 内核源码树准备交叉编译内核模块必须有对应的内核源码树。这里说的对应包含两层含义第一层是内核版本要一致比如你的板子跑的是Linux 4.19.71那最好找到这个版本的内核源码第二层是内核配置要匹配编译模块时需要用到内核源码树中的头文件和Makefile而这些文件的生成依赖于内核的配置文件。操作方法分成两种情况如果你的板子BSP包里有完整的内核源码那么先交叉编译一遍内核确保内核源码树是完整的cd kernel-source make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- xxx_defconfig make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -j8编译完内核后源码树里会生成Module.symvers、arch/arm/include/generated等目录和文件这些是编译外部模块时必须要用到的。但也有一种情况是板厂只给你了内核镜像没给完整源码这种情况下可以尝试用/proc/config.gz导出内核配置然后找对应版本的内核源码树重新生成一份可用的源码目录。不过这条路比较曲折最好还是找板厂要源码。我在makefile里通过KDIR变量指向了交叉编译好的内核源码树路径这样编译模块时就能正确引用到目标平台的配置和头文件了。3. Makefile核心逻辑与配置详解3.1 整体结构解读这套makefile的骨架其实是联发科官方驱动里自带的但官方版本做得很粗糙默认配置是给x86平台编译用的。我做的改造主要有三块交叉编译变量的引入、目标平台内核源码路径的适配以及固件安装路径的处理。makefile的核心结构如下# 交叉编译工具链前缀 CROSS_COMPILE ? /opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- # 目标平台内核源码目录 KDIR ? /home/user/kernel-source # 模块安装目录 MODULE_INSTALL_PATH ? /lib/modules/$(shell ls $(KDIR)/include/config/kernel.release 2/dev/null)/kernel/drivers/net/wireless # 默认构建目标 all: $(MAKE) ARCHarm CROSS_COMPILE$(CROSS_COMPILE) -C $(KDIR) M$(PWD) modules install: $(MAKE) ARCHarm CROSS_COMPILE$(CROSS_COMPILE) -C $(KDIR) M$(PWD) modules_install install -d $(DESTDIR)/lib/firmware/mediatek install -m 644 $(PWD)/firmware/MT7663* $(DESTDIR)/lib/firmware/mediatek/ clean: $(MAKE) ARCHarm CROSS_COMPILE$(CROSS_COMPILE) -C $(KDIR) M$(PWD) clean这里有几个值得注意的细节。ARCHarm这个变量告诉内核构建系统当前编译的是ARM架构的代码。CROSS_COMPILE指定了交叉编译工具链的前缀内核构建系统会自动在调用gcc时加上这个前缀。KDIR指向的是内核源码树所在位置。M$(PWD)告诉内核构建系统我要编译的模块代码在外部路径编译完成后把生成的.ko文件放到M指定的目录下。3.2 源码文件的组织方式MT7663驱动源码下载下来后文件结构有点乱我重新整理了目录。建议你也按照这种方式维护不然编译时经常会因为文件不在预期位置导致依赖关系断裂。整理后的目录结构mt7663_usb_wifi/ ├── Makefile ├── firmware/ # 固件存放目录 │ ├── MT7663_EEPROM.bin │ ├── MT7663_WIFI_RAM_CODE.bin │ └── mt7663_firmware.bin ├── src/ │ ├── mt7663_usb.c # USB接口层驱动 │ ├── mt7663_core.c # 核心协议栈逻辑 │ ├── mt7663_mac.c # MAC层实现 │ ├── mt7663_phy.c # PHY层配置 │ ├── mt7663_chan.c # 信道管理 │ ├── mt7663_efuse.c # eFuse读取与校验 │ ├── mt7663_reg.h # 寄存器定义 │ ├── mt7663_dbg.c # 调试接口 │ └── mt7663.h # 公共头文件 ├── include/ │ └── ... # 内核接口头文件 └── Kconfig这里特别提醒firmware目录里的文件是板级平台能否正常工作的关键。我遇到过一次忘记拷贝固件的情况模块明明insmod成功了但网卡死活起不来dmesg里报firmware load failed最后排查半天发现是固件路径没匹配上内核的firmware搜索路径。这个坑后面还会细说。3.3 依赖的编译选项解析除了基本的目标编译规则makefile里其实还藏了不少具体的驱动代码条件编译选项。比如EXTRA_CFLAGS -DMT7663_USB -DMT76_LED_ACT_SUSPEND EXTRA_CFLAGS -I$(PWD)/include-DMT7663_USB是为了让源码编译时走USB接口的分支逻辑因为同一份驱动代码同时支持USB和SDIO两种接口方式编译时通过宏来区分。这个宏对应到c文件里就是#ifdef MT7663_USB这样的条件编译用法。-DMT76_LED_ACT_SUSPEND是控制LED行为的一个开关。联发科的驱动源码里不同平台对于LED状态的默认设定不太一样跟产品定义的LED指示逻辑有关。如果你的板子上LED不亮或者乱闪可以考虑调整这个宏。-I$(PWD)/include是添加头文件搜索路径。这个必须加上因为驱动源码中的#include mt7663.h这类语句会先在当前目录找然后再去-I指定的路径找如果路径不对直接编译报错。另外一个值得关注的参数是# 如果目标内核的编译标志中包含CFG80211或MAC80211支持需要显式声明 ifeq ($(shell grep -c CONFIG_CFG80211y $(KDIR)/.config),1) EXTRA_CFLAGS -DCFG80211 endif这段逻辑的作用是自动检测内核配置中是否开启了CFG80211CFG80211是内核标准的无线配置管理框架驱动代码里通过DCFG80211这个宏来适配不同的内核无线框架版本。这个问题在换内核版本的时候尤其明显所以我才在makefile里加了这段自动检测逻辑不然换内核版本后还得手动改。4. 编译过程实操记录4.1 一路踩坑的编译过程讲一下实际操作过程中踩过的坑这些比看官方文档有用得多。第一次直接编译报了无数个undefined reference错误罪魁祸首是内核源码树里的Module.symvers不完整。这个文件记录着内核导出符号的CRC校验值驱动模块编译时需要用它做符号匹配。解决办法很简单回到内核源码目录再完整编一次cd /home/user/kernel-source make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- modules_prepare make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- modulesmodules_prepare会生成模块编译所需的基础文件这一步做完之后Module.symvers就正常了。第二次编译时遇到的是头文件路径问题报错信息是找不到linux/vermagic.h。这个文件是内核版本魔法字符串定义用于校验模块与内核版本是否一致。出现这个问题的原因可能是内核源码树没有完整展开。在我的环境里是因为之前编译内核时用过O指定独立的输出目录源码目录里缺少了生成的文件。解决方式是去源码目录执行一次make ARCHarm CROSS_COMPILE... prepare这个目标会触发生成包括vermagic.h在内的编译所需头文件。4.2 编出来的模块长啥样当makefile终于一路顺畅跑完你会得到类似这样的输出CC [M] src/mt7663_usb.o CC [M] src/mt7663_core.o CC [M] src/mt7663_mac.o CC [M] src/mt7663_phy.o CC [M] src/mt7663_chan.o CC [M] src/mt7663_efuse.o CC [M] src/mt7663_dbg.o LD [M] src/mt7663u.ko最终生成的模块文件是mt7663u.ko。注意名字这里有个u后缀其实是USB的意思用来区分SDIO版本mt7663s.ko。用file命令可以确认模块的平台属性$ file mt7663u.ko mt7663u.ko: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), BuildID[sha1]...输出里明确标注了ARM和EABI5说明交叉编译是正确的。如果你看到的是Intel 80386或者x86-64说明CROSS_COMPILE没生效或者的设置不对。模块的版本魔法字符串也要检查一下$ modinfo mt7663u.ko | grep vermagic vermagic: 4.19.71 SMP preempt mod_unload modversions ARM这个vermagic字符串必须和你目标板子上跑的内核版本完全匹配。mod_unload和modversions这些后缀也必须一致不然insmod时会报version magic mismatch错误。4.3 部署到目标板的完整流程编译完成之后部署也有讲究。推荐的做法是先把.ko文件和固件都推到开发板然后按顺序执行# 拷贝模块 scp mt7663u.ko roottarget_ip:/lib/modules/$(uname -r)/kernel/drivers/net/wireless/ # 拷贝固件 scp firmware/MT7663_EEPROM.bin roottarget_ip:/lib/firmware/mediatek/ scp firmware/MT7663_WIFI_RAM_CODE.bin roottarget_ip:/lib/firmware/mediatek/ # 加载依赖模块 modprobe cfg80211 # 加载驱动 insmod mt7663u.ko之所以强调先用insmod是因为如果insmod阶段发生问题你还能轻松回滚。直接用modprobe虽然能自动处理依赖但排查问题的时候就不太方便了。加载成功后dmesg里应该能看到类似这样的输出usbcore: registered new interface driver mt7663u mt7663u 1-1:1.0: HW/SW Version: 0x8a8a0000, Build Time: 20220328175428a mt7663u 1-1:1.0: WM Firmware Version: 0x2022032817如果固件加载失败会看到firmware load failed的报错。加载完驱动后用ifconfig -a或者ip link命令可以看到新增的无线网卡接口通常是wlan0。之后正常用wpa_supplicant配网流程就行。实际使用中USB wifi还有一个比较常见的坑是供电问题。MT7663在5GHz频段满功率工作时的功耗在1.2W左右如果板子USB口供电能力不足会出现掉线、驱逐或者速率不稳的情况。这个问题很难从代码层面解决只能从硬件层面优化比如加大USB口的滤波电容。5. 调试心得与FAQ速查5.1 驱动加载失败排查步骤如果insmod之后网卡没正常出现我一般按照下面的顺序排查首先是dmesg看内核日志有没有版本魔法字符串不匹配、固件加载失败、或者USB设备枚举异常的消息。USB设备枚举异常比较常见的原因是设备地址冲突或者供电不足这时可以用lsusb来看设备是否被正常识别。其次是确认USB PID/VID是否匹配。MT7663 USB版本的VID是0x0E8DPID有多种常见的包括0x7663和0x7616。如果你的设备在lsusb输出里显示的PID不在驱动支持的范围内要么确认设备是否是真的MT7663芯片要么需要看驱动的USB设备表是否需要调整。然后可以检查一下firmware目录是否存在且权限正确。很多文件系统都要求固件文件与内核搜索路径一致并且对root用户可见。如果路径不一致你会在dmesg中看到类似mt7663u: Failed to load firmware的信息。最后如果以上都不能解决试着用usb抓包工具分析一下USB层的通信过程。usbmon是内核自带的USB抓包工具把抓到的数据包和驱动源码里对USB请求的预期格式做比对往往能定位到问题。5.2 速率低、性能差怎么调优模块正常加载只是第一步。实测下来MT7663跑不出理想吞吐最常见的原因是Firmware版本太老。联发科不定期会更新固件解决一些性能和稳定性问题所以建议经常看看官方仓库的firmware目录有没有新版本。第二个常见的性能问题是Tx/Rx队列长度和中断协调参数的默认值不适合你的应用。你可以通过调整驱动中对应队列参数来优化吞吐。网上很多关于MTK WiFi速率慢的问题都跟这个有关但调整时最好用iperf做基准测试逐步调整不要一次改动太大。第三点要注意的是天线布局。MT7663是支持2x2 MIMO的两颗天线如果放置不好或者连接器的匹配电路设计有问题很容易出现5GHz速率上不去的情况。这类问题已经超出了软件调优的范畴必要时得用频谱仪分析一下天线性能。5.3 常见问题速查表现象可能原因排查方法insmod时报version magic mismatch内核版本或编译选项不一致检查modinfo的vermagic与板上uname -r是否匹配dmesg报firmware load failed固件缺失或路径不对确认固件在/lib/firmware/mediatek/下网卡起不来驱动挂在mmc/usb枚举阶段USB供电不足或链路异常单独给USB口供电用lsusb确认设备枚举连接5GHz AP不掉但速率极低天线匹配或固件问题升级固件检查MIMO配置同一个板子换内核版本后编译报错内核API变化同步更新驱动源码检查CONFIG宏ifconfig看到接口但没有扫描结果cfg80211依赖问题modprobe cfg80211后重新insmod说到内核API变化这里有个真实经历。有一次我把同一个驱动从4.19内核迁移到5.10内核驱动代码里用了很多老版本的API接口结果编译时直接报错。做这类适配工作时务必对内核源码中的相关结构体定义多做对比分析不能只靠搜索替换。5.4 后续可以做的扩展这套驱动工程做稳定之后还可以往几个方向扩展。一个是做成WiFi热点的模式也就是SoftAP。MT7663在AP模式下最高可以支持16个station接入做小型的移动热点或者演示Demo都够用。使用方法是在内核配置里开启CONFIG_NL80211_TESTMODE然后用hostapd配一个AP模式的配置文件就行。另一个方向是加进你产品的buildroot或者Yocto构建系统里。我的做法是写了一个MT7663.mk文件把交叉编译、固件拷贝和内核模块安装的步骤都集成进构建流程这样每次CI构建出来的固件镜像里就已经带好驱动了不需要在目标板上再做手工部署。如果你用的平台比较特殊比如飞腾系列的ARM平台需要注意的是工具链选择。飞腾一般用的是aarch64架构工具链前缀通常是aarch64-linux-gnu-makefile里改一下CROSS_COMPILE变量KDIR指向飞腾平台对应的内核源码树就行。这套驱动的核心逻辑是不变的变的只有工具链路径和内核源码路径。最后再分享一个小技巧如果你需要在多台主机上维护这个项目建议把交叉编译工具链路径做成环境变量或者配置文件的方式用条件判断去选择工具链而不是在makefile里硬编码。这样换一台开发机或者换一个目标平台时改动量能小很多。我在项目里是支持通过make CROSS_COMPILE/path/to/your/toolchain/bin/xxx-这样临时指定的方式来覆盖默认值的灵活度会高一些。我自己的实际体会是搞定MT7663这套驱动心里对USB WiFi驱动的整体架构就有了比较清晰的认识。以后再遇到RTL8822、AX88179这类的网卡驱动上手速度会快很多。驱动开发虽然前期调试比较磨人但把问题一个个解决掉之后对整个系统的理解会深入很多。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门