前言
近期在Zynq嵌入式Linux平台完成了AIC8800D80 USB WiFi模组的驱动移植与调试,过程中踩遍了内核配置、模块编译、加载顺序、符号报错等各类坑点。网上多数教程流程残缺、关键报错无解决方案,因此本文整理一套可直接落地、零废话、带完整排错方案的Zynq AIC8800 WiFi驱动移植教程。
本文适配:Zynq全系列开发板、Linux4.19内核、自定义内核编译环境,同时解决Unknown symbol、模块加载失败、固件下载异常、USB枚举报错等经典问题。
一、环境与硬件说明
1.1 硬件环境
- 主控:Xilinx ZynqF6P-7015开发板
- 外设:AIC8800D80 USB WiFi/蓝牙二合一模组
- 接口:USB2.0 高速接口
1.2 软件环境
- 内核版本:Linux 4.19-xilinx
- 编译环境:Ubuntu 交叉编译环境
- 系统:Debian Buster ARMHF
二、核心原理:必须搞懂的WiFi内核架构
很多人驱动加载失败,根本原因是分不清内核WiFi子系统层级,切记三个核心目录的区别:
1. kernel/drivers/net/wireless:厂商硬件驱动目录(存放aic8800、realtek、broadcom等私有驱动)
2. kernel/net/wireless:系统核心子系统,存放 cfg80211 源码
3. kernel/net/mac80211:802.11协议栈核心
重中之重:AIC8800第三方驱动绝对不能依赖内置内核符号,因此 cfg80211 和 mac80211 必须编译为 模块(M),不能编译为内置(*)!
三、内核关键配置(解决90%报错)
3.1 打开内核配置界面
make menuconfig
3.2 开启无线子系统模块
路径:Networking support ---> Wireless
<M> cfg80211 - wireless configuration API
<M> Generic IEEE 802.11 Networking Stack (mac80211)
图1 Networking>Wireless配置界面(cfg80211无线子系统)
正确状态:M(编译为模块)
错误状态:*(编译进内核)
报错根源解释:如果设为*内置,内核不会生成cfg80211.ko、mac80211.ko,且核心符号不会对外导出,加载aic8800驱动必然报 Unknown symbol 错误。
3.3 开启AIC8800厂商驱动选项(必做)
在内核配置界面同步开启AIC8800厂商驱动、WiFi主驱动与固件加载支持,否则编译时不会生成对应的驱动模块,路径为:
路径:Device Drivers ---> Network device support ---> Wireless LAN
AIC wireless Support (NEW)
AIC8800 wlan Support
AIC8800 Load Firmware Support
图2 Wireless LAN界面开启AIC8800驱动与固件支持
辅助配置:建议同时开启RF switch子系统支持(RF switch input support选内置、GPIO RFKILL driver选模块),避免无线开关控制异常:
Networking support ---> RF switch subsystem support
[*] RF switch input support
<M> GPIO RFKILL driver
图3 RF switch辅助配置(可选,建议开启)
四、内核模块编译(生成ko文件)
4.1 完整编译命令
进入内核源码根目录,先加载交叉编译环境,再执行编译:
source scripts/mz7xcf.sh
make ARCH=arm modules -j$(nproc)
make ARCH=arm modules_install INSTALL_MOD_PATH=../../output
图4 加载交叉编译环境
制作系统:将 fsbl.elf、system_wrapper.bit 及设备树文件拷贝到 output/files 目录(覆盖时选择Merge),依次执行 move_files.sh、make_uboot.sh、make_kernel.sh、create_image.sh 生成启动镜像,制作完成后插入TF卡,执行 make_parted.sh(格式化分区)、deploy_image.sh(烧写系统):
move_files.sh # 移动文件到指定位置
make_uboot.sh # 制作 uboot
make_kernel.sh # 制作 Linux 内核
create_image.sh # 制作镜像
make_parted.sh # 格式化并分区,输入盘符 sdb
deploy_image.sh # 烧写启动文件与系统文件,输入盘符 sdb
图5 拷贝启动文件到output/files目录
4.2 查找编译产物
很多新手找不到ko文件,是因为路径错误,正确查找命令:
find ../../output -name "cfg80211.ko"
find ../../output -name "mac80211.ko"
find ../../output -name "aic8800_fdrv.ko"
find ../../output -name "aic_load_fw.ko"
图6 aic8800_fdrv.ko编译产物位置
图7 aic_load_fw.ko编译产物位置
4.3 汇总全部驱动ko
最终需要4个核心模块,缺一不可:
1. cfg80211.ko(无线核心子系统)
2. mac80211.ko(802.11协议栈)
3. aic_load_fw.ko(固件加载驱动)
4. aic8800_fdrv.ko(WiFi功能主驱动)
五、开发板驱动加载(严格顺序,必看)
加载顺序绝对不能乱:核心子系统 → 固件加载 → 主驱动
5.1 清空旧模块
rmmod aic8800_fdrv 2>/dev/null
rmmod aic_load_fw 2>/dev/null
rmmod mac80211 2>/dev/null
rmmod cfg80211 2>/dev/null
5.2 上传并准备驱动与固件
将编译好的 aic8800_fdrv.ko、aic_load_fw.ko 及固件文件夹 aic8800D80 上传至开发板用户目录,确认文件传输成功:
ls
图8 上传驱动与固件并确认文件
创建固件存放目录,并将固件芯片文件拷贝到 /vendor/etc/firmware(加载固件驱动时会从该目录读取固件bin):
sudo mkdir -p /vendor/etc/firmware
sudo cp -r aic8800D80/* /vendor/etc/firmware/
图9 拷贝固件到/vendor/etc/firmware目录
5.3 按顺序加载模块
insmod cfg80211.ko
insmod mac80211.ko
insmod aic_load_fw.ko
sleep 3
insmod aic8800_fdrv.ko
图10 加载aic_load_fw固件驱动(自动下载固件)
图11 加载aic8800_fdrv主驱动
关键细节:加载aic_load_fw后必须休眠3秒,等待USB设备重新枚举(PID切换),否则主驱动加载失败。
六、加载成功日志与状态验证
6.1 正常加载现象
- aic_load_fw 自动下载全部固件bin文件,md5校验通过
- USB设备PID从 0xA69C:0x8D80 切换为工作态 0xA69C:0x8D81
- 系统自动生成无线网卡设备:wlx8c7ab3f81771
6.2 查看模块加载状态
lsmod
正常输出:四个模块全部挂载,无报错依赖
aic8800_fdrv 389120 0
aic_load_fw 53248 1 aic8800_fdrv
mac80211 319488 0
cfg80211 237568 2 mac80211,aic8800_fdrv
6.3 查看USB设备与网卡
lsusb
iw dev
ip link
图12 ifconfig查看wifi网卡(wlx8c7ab3f81689)
七、关键报错详解与解决方案
报错1:aic8800_fdrv: Unknown symbol cfg80211_xxx
原因:cfg80211/mac80211未编译为模块、未加载、编译版本不匹配
解决方案:内核配置改为M、重新编译模块、严格按顺序加载
报错2:aic_load_fw: probe failed with error -1
原因:正常现象!固件加载完成后USB设备断开重枚举,旧设备探针失效
解决方案:无需处理,等待3秒加载主驱动即可
报错3:invalid module format .o文件无法加载
原因:加载了编译中间文件.o,而非正式模块.ko
解决方案:删除.o文件,使用output目录下正式ko模块
报错4:regulatory.db failed with error -2
原因:缺少无线国家区域数据库文件
解决方案:不影响WiFi基础扫描、连接功能,可忽略;需完善功能可拷贝regulatory.db到板子/vendor/etc/firmware/
八、WiFi功能测试(扫描+联网)
8.1 扫描周边WiFi
iw dev wlx8c7ab3f81771 scan | grep SSID
8.2 安装wpa_supplicant(Debian buster需换源)
Debian 10(buster)已于2024年6月停止维护(EOL),华为云等镜像仓库已下线,apt update会报404导致wpa_supplicant安装失败:
apt update
apt install wpa_supplicant
图13 apt update报404(buster仓库已下线)
更换为阿里云debian-archive镜像源后重新安装:
cat > /etc/apt/sources.list <<'EOF'
deb http://mirrors.aliyun.com/debian-archive/debian buster main contrib non-free
deb http://mirrors.aliyun.com/debian-archive/debian buster-updates main contrib non-free
deb http://mirrors.aliyun.com/debian-archive/debian-security buster/updates main contrib non-free
EOF
apt update
apt install -y wpa_supplicant iw
图14 更换阿里云源并安装wpa_supplicant/iw
8.3 连接WiFi(wpa_supplicant)
新建wifi.conf配置文件:
network={
ssid="你的WiFi名称"
psk="你的WiFi密码"
}
启动连接并获取IP:
wpa_supplicant -B -i wlx8c7ab3f81771 -c ./wifi.conf
udhcpc -i wlx8c7ab3f81771
8.4 联网测试
获取IP成功后,执行ping测试网络连通性:
dhclient wlx8c7ab3f81771
ping -c3 www.baidu.com
图15 获取IP并ping百度测试成功
九、开机自启优化(进阶)
手动insmod重启失效,可配置开机自动加载:
1. 将4个ko模块拷贝至板子 /lib/modules/$(uname -r)/extra
2. 执行 depmod -a 更新模块依赖
3. 在/etc/modules按顺序写入模块名,实现开机自动加载
部署示意:将 aic8800D80 固件文件夹、aic8800_fdrv.ko、aic_load_fw.ko 一并放置于 rootfs 的 home/uisrc 目录下(也可配合startup.sh实现自启动):
图16 部署驱动与固件到rootfs home/uisrc目录