简介:这份资源是MT7663 USB转WiFi驱动的完整源码包,面向嵌入式Linux开发者和无线网卡移植人员,尤其适合需要在海思等ARM64平台上集成WiFi功能的工程师。包内已配置好交叉编译用的Makefile.aarch,工具链为aarch64-linux-gnu-,在海思3531上编译通过,生成的wlan_mt7663_usb.ko约3MB。若目标平台不同,只需修改Makefile.aarch中的CROSS_COMPILE、LINUX_SRC、DRIVER_DIR路径,非arm64平台再调整ARCH参数,执行make -f Makefile.aarch即可生成驱动。资源共453个文件,以137个h头文件、117个c源文件、87个cmd脚本、86个o目标文件为主,另含bin固件、cfg配置、makefile及说明文档,压缩包7.62MB。已有429人学习下载。读者可获得可直接编译的驱动源码、固件与配置参考,以及跨平台移植的排错思路,省去从零搭建编译环境的时间。
1. mt7663 USB转WiFi驱动交叉编译:从源码到跑通的完整环境搭建
手上有一块 mt7663 的 USB WiFi 模块,想在嵌入式板子上跑起来,结果翻遍官方 SDK 发现驱动源码散落在好几个目录,Makefile 还得自己拼交叉编译工具链。这不是个例——mt7663 这颗芯片在 USB WiFi 模块里出货量不小,但原厂给的驱动包往往只带一个默认 Makefile,编译主机一换、内核版本一变,直接报错。更麻烦的是,很多人拿到源码后直接make编译,编出来的 ko 文件架构不对,insmod 时报invalid module format,查半天才发现是交叉编译器没配对。这篇记录的是我实际搭这套环境的过程:从确认内核版本、选交叉工具链,到改 Makefile、编译、加载、验证联网,每一步都落到具体命令和参数。适合手里有 mt7663 USB 模块、需要在 ARM 或 MIPS 板子上跑 WiFi 的开发者,新手照着走能通,熟手可以看版本取舍和参数差异。
2. 环境准备:内核版本、工具链与源码目录的对应关系
2.1 先确认目标板的内核版本和架构
交叉编译驱动最怕的就是主机内核和目标板内核不一致。mt7663 驱动里会引用内核头文件中的结构体定义,比如struct usb_device_id、struct ieee80211_ops,这些在不同内核版本间可能有变化。所以第一步不是急着编译,而是登录目标板,确认三件事:
# 在目标板上执行 uname -r # 输出示例:4.19.90 uname -m # 输出示例:aarch64 cat /proc/version # 确认编译器版本和内核构建信息uname -r给出内核版本号,这个号必须和编译驱动时用的内核源码树版本一致。uname -m给出 CPU 架构,决定了交叉编译器前缀是aarch64-linux-gnu-还是arm-linux-gnueabihf-。/proc/version里还能看到内核是用哪个 GCC 版本编的,如果差异太大,编译出的 ko 可能加载失败。
常见做法是:在编译主机上准备一份和目标板完全同版本的内核源码,路径记下来,后面改 Makefile 要用。如果目标板是厂商定制的内核,源码通常由厂商提供,不要用主线内核替代。
2.2 交叉编译工具链的选择与验证
mt7663 驱动是内核模块,必须用交叉编译器编译。工具链的选择取决于目标板架构:
| 目标架构 | 工具链前缀 | 常见来源 |
|---|---|---|
| ARM 32位 | arm-linux-gnueabihf- | Linaro、厂商 SDK |
| ARM 64位 | aarch64-linux-gnu- | Linaro、厂商 SDK |
| MIPS | mips-linux-gnu- | 厂商 SDK |
安装完工具链后,先验证它能不能正常工作:
# 检查交叉编译器版本 aarch64-linux-gnu-gcc --version # 检查是否支持目标内核的配置 aarch64-linux-gnu-gcc -v我一般会把工具链路径加到PATH里,或者在 Makefile 里写绝对路径。用export PATH=$PATH:/opt/toolchain/bin这种方式最省事,但要注意别和主机自带的 GCC 冲突。验证方法是which aarch64-linux-gnu-gcc能正确指向工具链目录。
提示:工具链的 GCC 版本最好和目标内核编译时用的版本接近。如果目标内核是 GCC 7.5 编的,你用 GCC 12 编驱动,可能出现
struct布局差异导致加载后崩溃。
2.3 源码目录结构确认
拿到 mt7663 USB WiFi 源码后,先看目录里有什么。典型的驱动源码包会包含:
# 查看源码目录 ls -la # 常见输出: # Makefile # os/linux/ # 平台相关代码 # include/ # 头文件 # sta/ # station 模式相关 # ap/ # AP 模式相关 # common/ # 公共代码 # chips/ # 芯片相关代码 # mt7663/ # 芯片专属目录关键是找到os/linux/下的config.mk或类似文件,里面通常有CONFIG_MT7663_USB之类的开关。如果源码包里已经带了一个配置好的 Makefile,先别改,直接看它引用了哪些变量,再对照自己的环境改。
3. 配置与编译:Makefile 关键参数逐项拆解
3.1 Makefile 里必须改的四个变量
mt7663 驱动源码自带的 Makefile 通常长这样:
# 原始 Makefile 片段 ifeq ($(PLATFORM),) PLATFORM = PC endif ifeq ($(PLATFORM),PC) LINUX_SRC = /lib/modules/$(shell uname -r)/build CROSS_COMPILE = endif ifeq ($(PLATFORM),ARM) LINUX_SRC = /path/to/arm/kernel CROSS_COMPILE = arm-linux-gnueabihf- endif要交叉编译,至少改四个地方:
# 修改后的 Makefile 片段 PLATFORM = ARM LINUX_SRC = /home/dev/kernel/linux-4.19.90 CROSS_COMPILE = aarch64-linux-gnu- ARCH = arm64PLATFORM决定走哪个分支,LINUX_SRC指向目标板内核源码的绝对路径,CROSS_COMPILE是工具链前缀,ARCH告诉内核构建系统目标架构。这四个变量缺一个,编译就会出问题。
常见坑是LINUX_SRC指向了主机当前内核的/lib/modules/$(uname -r)/build,结果编出来的是 x86 模块。另一个坑是ARCH没设,内核 Makefile 默认用主机架构。
3.2 内核源码树必须先编译过
交叉编译外部模块时,内核源码树必须已经执行过make modules_prepare,否则会报missing generated/autoconf.h之类的错误。操作步骤:
# 进入目标板内核源码目录 cd /home/dev/kernel/linux-4.19.90 # 使用目标板的配置文件 cp /path/to/target_config .config # 准备模块编译环境 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules_preparemodules_prepare会生成编译外部模块所需的头文件和脚本。如果目标内核是厂商定制的,.config文件可以从目标板的/proc/config.gz提取:
# 在目标板上 zcat /proc/config.gz > target_config然后把这个文件拷到编译主机,作为内核源码的.config。
3.3 编译命令与常见报错处理
配置改好后,编译命令很简单:
# 在驱动源码目录执行 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j4-j4是并行编译,加快速度。编译成功后会在当前目录生成mt7663_usb.ko或类似名称的 ko 文件。
如果报错error: implicit declaration of function 'xxx',通常是内核版本差异导致某个函数签名变了。比如cfg80211相关接口在不同内核版本间有调整。解决办法是找到对应头文件,确认函数原型,然后在驱动代码里做条件编译。
如果报错ERROR: modpost: "xxx" undefined,说明驱动引用了内核没导出的符号。常见做法是检查内核.config里是否开启了对应的CONFIG_选项,比如CONFIG_CFG80211、CONFIG_MAC80211。
注意:编译前先
make clean清一下,避免上次编译的残留对象文件干扰。尤其是改了LINUX_SRC之后,必须重新编译。
3.4 编译产物检查
编译完成后,用file命令确认 ko 文件的架构:
file mt7663_usb.ko # 正确输出示例: # mt7663_usb.ko: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), BuildID[sha1]=xxx, not stripped如果显示x86-64,说明交叉编译没生效,回去检查CROSS_COMPILE和ARCH。如果显示ARM但位数不对,检查工具链前缀是否匹配目标板。
还可以用modinfo查看模块信息:
modinfo mt7663_usb.ko # 查看 vermagic 是否和目标内核一致vermagic里包含内核版本和 SMP 等配置信息,必须和目标板内核完全匹配,否则 insmod 会报invalid module format。
4. 部署与加载:把 ko 文件放到板子上跑起来
4.1 传输 ko 文件到目标板
编译主机和目标板之间传文件,常用几种方式:
# 方式一:scp scp mt7663_usb.ko root@192.168.1.100:/lib/modules/4.19.90/ # 方式二:U盘挂载 mount /dev/sda1 /mnt cp mt7663_usb.ko /mnt/ # 然后在目标板上挂载U盘拷贝 # 方式三:tftp tftp -g -r mt7663_usb.ko 192.168.1.50传输前确认目标板的/lib/modules/$(uname -r)/目录存在,没有就手动创建。
4.2 加载驱动与固件依赖
mt7663 驱动加载时需要固件文件,通常是mt7663.bin或类似名称。固件要放到目标板的/lib/firmware/目录下:
# 在目标板上 mkdir -p /lib/firmware # 把固件文件拷进去 cp mt7663.bin /lib/firmware/ # 加载驱动 insmod mt7663_usb.ko # 查看加载日志 dmesg | tail -30如果dmesg里出现firmware: failed to load mt7663.bin,说明固件路径不对或文件缺失。如果出现usb 1-1: new high-speed USB device但后面没有 WiFi 接口注册,可能是固件版本不匹配。
常见做法是先用lsusb确认模块的 VID/PID 被识别:
lsusb # 查看是否有 MediaTek 相关设备4.3 验证 WiFi 接口是否生成
驱动加载成功后,用ifconfig -a或ip link查看是否多了一个wlan0或ra0接口:
ip link show # 输出中应该有 wlan0 或类似名称如果没有,检查dmesg里是否有register netdev相关日志。有时候驱动加载了但接口没起来,是因为cfg80211没初始化完成,可以尝试modprobe cfg80211先加载依赖模块。
5. 避坑与排查:mt7663 交叉编译最常见的五个翻车点
5.1 现象:insmod 报 invalid module format
原因:编译时用的内核源码版本和目标板内核不一致,或者CROSS_COMPILE没生效编成了 x86 模块。
解决:用modinfo对比 ko 文件和目标内核的vermagic,确保完全一致。重新编译前先make clean,并确认LINUX_SRC指向正确。
5.2 现象:编译报错 “missing generated/autoconf.h”
原因:内核源码树没有执行make modules_prepare,或者.config文件缺失。
解决:进入内核源码目录,执行make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules_prepare。如果.config不存在,从目标板/proc/config.gz提取。
5.3 现象:驱动加载后没有 wlan0 接口
原因:固件文件缺失或路径不对,或者cfg80211模块没加载。
解决:确认/lib/firmware/下有对应固件文件,dmesg里搜firmware关键字。先modprobe cfg80211再insmod mt7663_usb.ko。
5.4 现象:编译通过但加载后内核 panic
原因:驱动代码里引用了不兼容的内核 API,或者结构体布局差异导致内存越界。
解决:检查内核版本差异,在驱动代码里加条件编译。常见做法是找厂商提供的对应内核版本驱动补丁,不要混用不同版本的源码。
5.5 现象:make 报错 “No rule to make target”
原因:Makefile 里的LINUX_SRC路径写错,或者内核源码树不完整。
解决:用绝对路径,确认$(LINUX_SRC)/Makefile存在。如果内核源码是从别处拷贝的,检查是否缺少scripts/目录。
6. 装完怎么验证:三个命令确认驱动真正跑通
驱动加载成功不等于 WiFi 能用。我一般会走一遍完整的验证流程,确认从驱动加载到联网都正常。
第一步,确认接口存在且状态正常:
ip link show wlan0 # 输出中 state UP 表示接口已启用 # 如果 state DOWN,执行 ip link set wlan0 up第二步,扫描周围 WiFi:
iwlist wlan0 scan | grep ESSID # 或者用 iw dev wlan0 scan | grep SSID能扫到 SSID 说明射频部分工作正常。如果报Interface doesn't support scanning,可能是驱动没注册cfg80211扫描接口,检查驱动编译时是否开启了CONFIG_CFG80211。
第三步,连接一个测试热点并获取 IP:
# 使用 wpa_supplicant 连接 wpa_passphrase "TestSSID" "TestPassword" > /etc/wpa_supplicant.conf wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf udhcpc -i wlan0 # 或者用 dhclient wlan0获取到 IP 后ping一下网关,能通就说明整条链路都通了。
| 验证项 | 命令 | 预期结果 |
|---|---|---|
| 接口存在 | ip link show wlan0 | 显示 wlan0 接口 |
| 射频正常 | iwlist wlan0 scan | 列出周围 SSID |
| 连接正常 | udhcpc -i wlan0 | 获取到 IP 地址 |
| 数据通路 | ping -c 3 网关IP | 有回包 |
从那以后我每次交叉编译完驱动,都强制走一遍file看架构、modinfo看 vermagic、dmesg看加载日志这三步,确认没问题再上板子。希望帮到你。
本文还有配套的精品资源,点击获取