ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

hi3516cv610移植AIC8800D80 USB Wi-Fi 6驱动实战

hi3516cv610移植AIC8800D80 USB Wi-Fi 6驱动实战 1. 项目背景与整体设计思路1.1 为什么要在 hi3516cv610 上折腾 AIC8800D80hi3516cv610 这颗 SoC 在视频监控、智能视觉、低功耗 IPC 这类场景里出镜率非常高它本身集成的外设接口比较克制很多板子出厂时只留了 USB 2.0 Host 和一路 SDIOWi-Fi 方案要么走 SDIO要么走 USB。AIC8800D80 是一颗 Wi-Fi 6 蓝牙二合一的芯片走 USB 接口支持 802.11ax在带宽和并发上比老一代 8800 系列有明显提升价格也压得住所以拿它给 cv610 做联网能力扩展是很自然的选择。但“自然”不等于“顺利”。AIC8800D80 的官方驱动包通常默认面向通用 Linux 内核或者某些主流 ARM 平台直接丢到 hi3516cv610 的 SDK 里编译十有八九会报错。原因不复杂海思这套 SDK 的内核是深度裁剪过的很多标准内核里默认打开的配置项被关掉了USB 子系统、cfg80211、mac80211 的版本也可能和驱动包预期的不一致。所以这个项目的核心不是“写驱动”而是“把一颗为通用环境准备的 USB Wi-Fi 驱动移植到一颗高度定制化的嵌入式 SoC 上并让它稳定跑起来”。我先把结论摆在这整个移植工作可以拆成四块——内核配置对齐、驱动源码适配、固件部署、上电验证与问题排查。四块里最容易翻车的是内核配置和固件路径驱动源码本身反而改动不大。下面我按实际操作的顺序把每一块的思路、细节和踩过的坑都摊开讲。1.2 整体方案选型与取舍移植 USB Wi-Fi 驱动摆在面前的路其实有三条。第一条是直接用芯片原厂提供的完整驱动包里面通常包含aic8800_fdrvFullMAC 驱动和aic8800_btlpm、aic8800_btusb这类蓝牙相关模块。这条路最省事前提是驱动包版本和你的内核版本对得上。第二条是走 mac80211 框架把芯片当成一个标准的 softMAC 设备来驱动。AIC8800D80 实际上提供的是 FullMAC 风格的接口走这条路需要大量改动不现实。第三条是自己写一个最简的 USB 探测 固件加载框架只保证能识别、能加载固件、能起 wlan 口。这条路适合调试阶段定位问题但不适合量产。实际项目里我选的是第一条也就是原厂驱动包 针对性适配。理由很直接AIC8800D80 的固件和驱动是强耦合的固件里跑着协议栈的大部分逻辑驱动只负责 USB 传输和固件下载自己重写等于把原厂已经调好的东西推倒重来投入产出比极低。选型确定之后真正的工作量集中在“让原厂驱动能在 cv610 的内核里编译通过并正确加载”。这里有个关键判断先确认内核版本和 USB 子系统状态再动驱动源码。很多人一上来就改驱动结果发现是内核里CONFIG_USB相关的选项没开白忙半天。1.3 移植工作的影响范围这个移植不只是“让 Wi-Fi 能用”这么简单它会牵动整块板子的几个层面。从系统层面看加载 Wi-Fi 驱动会引入 cfg80211、mac80211 这两个内核模块如果驱动依赖它们会占用额外的内存cv610 这种内存通常只有 64MB 到 128MB 的板子内存预算要重新算。从启动流程看如果 Wi-Fi 要在开机时自动起来就要考虑固件加载的时机、根文件系统里固件文件的位置、以及 USB 枚举和 rootfs 挂载的先后顺序。从功耗角度看USB Wi-Fi 芯片的供电和时钟管理如果没配好待机功耗会明显偏高这对电池供电的 IPC 是致命的。所以我在做这个项目时习惯先把影响范围列清楚再动手。下面这张表是我实际用的检查清单你可以直接拿去对照。影响层面具体项检查要点内核USB Host、cfg80211、mac80211、firmware loader配置项是否打开版本是否匹配内存驱动模块 固件运行时占用预留至少 8-16MB 余量存储固件文件、驱动 ko 文件路径正确、权限正确启动模块加载顺序、固件加载时机避免在 rootfs 就绪前加载功耗USB 供电、时钟门控待机电流实测2. 内核配置与驱动源码适配细节2.1 内核配置项逐条核对hi3516cv610 的 SDK 内核配置一般放在arch/arm/configs/下的某个 defconfig 里或者用menuconfig交互配置。我建议先跑一遍make menuconfig把下面这些项逐个确认。注意不同 SDK 版本菜单路径可能略有差异但核心项是一致的。# USB 子系统基础 CONFIG_USBy CONFIG_USB_SUPPORTy CONFIG_USB_ARCH_HAS_HCDy CONFIG_USB_ARCH_HAS_OHCIy CONFIG_USB_ARCH_HAS_EHCIy # USB Host 控制器cv610 通常是 EHCI/OHCI 或 dwc2 CONFIG_USB_EHCI_HCDy CONFIG_USB_EHCI_ROOT_HUB_TTy CONFIG_USB_OHCI_HCDy # USB 设备类支持 CONFIG_USB_STORAGEy CONFIG_USB_ACMy # 无线子系统 CONFIG_CFG80211y CONFIG_MAC80211y CONFIG_WIRELESSy CONFIG_WLANy # 固件加载 CONFIG_FW_LOADERy CONFIG_FW_LOADER_USER_HELPERy CONFIG_EXTRA_FIRMWARE这里有几个点必须展开说。CONFIG_FW_LOADER_USER_HELPER这个选项很关键。AIC8800D80 的驱动在加载固件时如果内核的 direct firmware loader 找不到文件会回退到用户态 helper也就是通过/sys/class/firmware/接口让用户程序把固件喂进去。如果你的 rootfs 里没有对应的 helper 程序或者固件路径不对加载就会失败。我一般建议把固件直接编译进内核或者放在标准路径/lib/firmware/下走 direct loader省掉用户态这一环。CONFIG_CFG80211和CONFIG_MAC80211是否必须取决于驱动包。AIC8800D80 的 FullMAC 驱动有些版本不依赖 mac80211只依赖 cfg80211有些版本两者都要。最稳妥的办法是看驱动源码里的Makefile和Kconfig里面会写清楚依赖。如果驱动包里带了cfg80211的兼容层那内核里这两个选项可以不开但我不推荐这么做兼容层往往有坑。还有一个容易被忽略的项是CONFIG_USB_EHCI_ROOT_HUB_TT。cv610 的 USB 控制器如果是 EHCI且你后面要接 USB Hub 扩展多个设备这个 TTTransaction Translator支持必须打开否则 Hub 后面的低速/全速设备枚举会出问题。虽然 Wi-Fi 芯片本身是高速设备但板子上如果有其他 USB 设备共用 Hub这个选项就绕不开。2.2 驱动源码的适配改动原厂驱动包解压后目录结构通常是这样aic8800/ ├── drivers/ │ ├── aic8800_fdrv/ # FullMAC Wi-Fi 驱动 │ ├── aic8800_btlpm/ # 蓝牙 LPM │ └── aic8800_btusb/ # 蓝牙 USB ├── firmware/ │ └── aic8800d80/ │ ├── fw_patch_table.bin │ ├── fw_adid.bin │ └── ... └── Makefile把aic8800_fdrv拷到内核源码树的drivers/net/wireless/下然后在drivers/net/wireless/Kconfig和Makefile里加一行引用。这一步是标准操作但有几个细节要注意。第一驱动源码里的Makefile通常写死了obj-m也就是编译成模块。如果你想编译进内核obj-y要改这里。我一般先编成模块方便调试时反复insmod/rmmod等稳定了再考虑是否内置。第二驱动里可能有针对特定内核版本的宏判断比如#if LINUX_VERSION_CODE KERNEL_VERSION(5, 10, 0)。cv610 SDK 的内核版本如果是 4.9 或 4.19这些分支就会走到老代码路径可能和驱动包预期不符。我遇到过一次驱动里用了cfg80211_register_wdev的新签名但内核是 4.9编译直接报参数不匹配。解决办法是在驱动源码里加一层版本兼容宏或者把内核里对应的函数签名补丁打上。后者风险大前者更可控。第三USB 设备的 VID/PID 匹配表。AIC8800D80 的 VID/PID 在驱动里是写死的如果板子上用的是定制模块PID 可能被改过这时候要么改驱动里的usb_device_id表要么在new_id里动态添加。我建议直接改驱动表因为动态添加在每次上电后都要重新做不适合量产。static const struct usb_device_id aic8800_usb_ids[] { { USB_DEVICE(0x368B, 0x8800) }, // 常见 VID/PID以实际模块为准 { USB_DEVICE(0x368B, 0x8D80) }, { } }; MODULE_DEVICE_TABLE(usb, aic8800_usb_ids);改完这些make modules应该能过。如果报错先看是不是缺头文件再看是不是内核配置项没开导致某些结构体不完整。编译错误的信息通常很直接顺着改就行。2.3 固件文件的处理固件是 AIC8800D80 移植里最容易被低估的一环。芯片上电后USB 枚举成功只是第一步驱动 probe 时会通过 USB 控制传输把固件下载到芯片里下载完成后芯片才会重新枚举成一个正常的 Wi-Fi 设备。如果固件文件缺失、路径不对、或者版本和驱动不匹配probe 就会失败dmesg里会看到类似firmware download failed或者usb probe failed的报错。固件文件一般包括fw_patch_table.bin、fw_adid.bin、fw_patch.bin这几个具体名字以驱动包为准。放置路径有两个选择/lib/firmware/aic8800d80/或者驱动里指定的其他路径。我建议统一放/lib/firmware/下因为这是内核 direct firmware loader 的默认搜索路径省得改驱动里的路径宏。注意固件文件的权限要设成 644属主 root。如果 rootfs 是只读的要确保固件在制作镜像时就打进去了不能等运行时再拷。还有一个坑是固件版本和驱动版本的匹配。原厂驱动包里的固件和驱动是配套的如果你从别处下载了一个“更新”的固件很可能和当前驱动不兼容表现为能加载但连不上 AP或者连上后频繁掉线。我吃过这个亏后来养成习惯驱动和固件永远用同一个发布包里的不混用。3. 实操过程与核心环节实现3.1 从零开始的完整操作流程假设你拿到了一块 cv610 的板子SDK 已经能正常编译出固件现在要把 AIC8800D80 跑起来。下面是我实际走通的流程按顺序执行即可。第一步确认内核版本和当前配置。cd /path/to/sdk/linux-4.9.y make ARCHarm CROSS_COMPILEarm-himix100-linux- menuconfig在 menuconfig 里按 2.1 节的清单逐项确认。确认完保存退出重新编译内核。第二步把驱动源码放进内核树。cp -r aic8800/drivers/aic8800_fdrv drivers/net/wireless/编辑drivers/net/wireless/Kconfig在末尾加source drivers/net/wireless/aic8800_fdrv/Kconfig编辑drivers/net/wireless/Makefile加obj-$(CONFIG_AIC8800_FDRV) aic8800_fdrv/然后在 menuconfig 里找到AIC8800_FDRV选项设成M模块或Y内置。第三步编译模块。make ARCHarm CROSS_COMPILEarm-himix100-linux- modules -j8编译产物在drivers/net/wireless/aic8800_fdrv/aic8800_fdrv.ko。第四步部署固件和模块到板子。# 固件 mkdir -p /rootfs/lib/firmware/aic8800d80 cp aic8800/firmware/aic8800d80/* /rootfs/lib/firmware/aic8800d80/ chmod 644 /rootfs/lib/firmware/aic8800d80/* # 模块 mkdir -p /rootfs/lib/modules/$(uname -r)/extra cp aic8800_fdrv.ko /rootfs/lib/modules/$(uname -r)/extra/第五步板子上电加载模块。insmod /lib/modules/$(uname -r)/extra/aic8800_fdrv.ko如果一切正常dmesg里会看到 USB 枚举、固件下载、wlan 口注册的完整日志ifconfig -a能看到wlan0。第六步起 wlan 口连 AP。ifconfig wlan0 up iwlist wlan0 scan wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf udhcpc -i wlan0到这里Wi-Fi 应该能正常工作了。3.2 关键参数的计算与选择有几个参数在实际操作中需要根据板子情况调整不能照抄。USB 供电电流。AIC8800D80 在固件下载和射频工作时峰值电流可能到 400mA 以上。cv610 板子的 USB 供电如果只给了 500mA 的限流余量很小。我一般会在硬件上确认 USB VBUS 的供电路径如果是直接来自 SoC 的 USB PHY 供电要查 PHY 的驱动能力如果是外部 LDO要确认 LDO 的额定电流。软件层面可以在驱动里调整 USB 的bMaxPower描述符但更根本的是硬件供电要够。固件下载超时。驱动里通常有个fw_download_timeout之类的参数默认可能是 3000ms 或 5000ms。如果板子的 USB 枚举慢或者固件文件大这个超时要适当放大。我遇到过一块板子因为 USB 时钟不稳枚举花了 2 秒多固件下载超时直接失败把超时改成 10000ms 就过了。内存预留。FullMAC 驱动加载后固件在芯片里跑但驱动侧也要分配 USB 传输缓冲、netdev 结构、cfg80211 的 wiphy 结构。实测下来aic8800_fdrv.ko加载后内核内存占用增加约 6-8MB加上固件运行时通过 USB 传输的数据缓冲整体预留 16MB 比较稳妥。cv610 如果只有 64MB 内存跑 Wi-Fi 视频编码会比较紧张建议至少 128MB。3.3 上电验证的完整日志解读正常加载的dmesg日志大概长这样我按阶段拆开讲。# 阶段一USB 枚举 usb 1-1: new high-speed USB device number 2 using ehci-hcd usb 1-1: New USB device found, idVendor368b, idProduct8d80 usb 1-1: Product: AIC8800D80 usb 1-1: Manufacturer: AIC # 阶段二驱动 probe aic8800_fdrv: probe start aic8800_fdrv: firmware download start aic8800_fdrv: firmware download done # 阶段三芯片重新枚举 usb 1-1: USB disconnect, device number 2 usb 1-1: new high-speed USB device number 3 using ehci-hcd usb 1-1: New USB device found, idVendor368b, idProduct8d80 # 阶段四wlan 注册 aic8800_fdrv: wlan0 registered cfg80211: Regulatory domain changed to country: CN这里有个关键现象芯片会重新枚举一次。第一次枚举时芯片处于固件下载模式PID 可能是0x8800之类的 bootloader PID固件下载完成后芯片复位以正常模式重新枚举PID 变成0x8D80。所以驱动里要同时匹配这两个 PID否则第二次枚举时驱动认不出来wlan 口就起不来。这是新手最容易卡住的地方日志里看到USB disconnect就以为出问题了其实是正常流程。如果卡在阶段二firmware download failed先查固件路径和权限再查固件版本。如果卡在阶段四wlan0 registered没出现查 cfg80211 配置和驱动里的注册流程。4. 常见问题与排查技巧实录4.1 典型问题速查表下面这张表是我在实际项目中遇到过的、以及同行反馈过的高频问题按现象、可能原因、排查方法整理可以直接当手册用。现象可能原因排查方法insmod 报 unknown symbol内核配置项缺失cfg80211/mac80211 未编译modinfo aic8800_fdrv.ko看依赖补内核配置probe 失败firmware download failed固件路径错、权限错、版本不匹配查/lib/firmware/对比驱动包版本芯片不重新枚举固件下载后复位失败或 PID 表没匹配查 dmesg 完整日志确认 PID 表wlan0 起不来cfg80211 未注册或驱动注册流程报错iw dev看设备查 dmesg 报错能扫描但连不上 AP固件与驱动不匹配或加密方式不支持换配套固件确认 wpa_supplicant 配置连上后频繁掉线USB 供电不足或射频干扰测 USB VBUS 电流换信道待机功耗偏高USB 时钟未门控或驱动未进低功耗模式查驱动电源管理测待机电流编译报结构体不匹配内核版本与驱动预期不符加版本兼容宏或换驱动版本4.2 几个我踩过的坑和独家技巧坑一固件路径的“隐藏”搜索顺序。内核 direct firmware loader 搜索固件的路径不止/lib/firmware/还有/lib/firmware/updates/、/lib/firmware/kernel_version/等。如果你在多个路径下放了不同版本的固件内核可能加载了旧的那个。我的做法是只保留一个路径其他路径清空避免歧义。坑二USB Hub 的电源管理。如果板子上 Wi-Fi 模块接在 USB Hub 后面Hub 的电源管理如果没配好Wi-Fi 工作时 Hub 可能因为电流波动而复位导致 Wi-Fi 掉线。解决办法是在 Hub 的驱动里关掉CONFIG_USB_HUB_PORT_POWER_CTRL相关的自动挂起或者硬件上给 Hub 独立供电。坑三cfg80211 的 regulatory domain。默认情况下cfg80211 的 regulatory domain 是00世界域很多信道不能用。如果你在中国区用要设置CN否则 5G 频段的高信道扫不到。设置方法是在 rootfs 里放/lib/firmware/regulatory.db或者用iw reg set CN动态设置。我建议在启动脚本里固定设置避免每次手动。技巧一用usbmon抓 USB 传输。如果固件下载失败但日志信息不够可以用usbmon抓 USB 控制传输的原始数据看驱动到底发了什么、芯片回了什么。这个工具在内核里要开CONFIG_USB_MON用起来稍微麻烦但定位固件下载问题非常有效。技巧二先编模块再内置。调试阶段一定编成模块insmod/rmmod反复试改一次驱动重新编译加载只要几十秒。等稳定了再考虑内置进内核减少启动时的模块加载依赖。技巧三保留一份“已知能工作”的配置。移植过程中会反复改内核配置和驱动源码很容易改着改着就回不去了。我的习惯是每走通一个阶段就把当时的.config和驱动源码打个包存起来出问题可以快速回退对比。4.3 稳定性验证与长时间跑测驱动能加载、能连 AP只是第一步。真正要量产还得做稳定性验证。我一般会跑这几项。第一项是长时间 ping 测试。连上 AP 后ping -i 0.2 -c 100000跑几个小时看丢包率和延迟抖动。如果丢包率超过 1%或者延迟抖动超过 50ms就要查射频干扰或 USB 传输稳定性。第二项是反复insmod/rmmod测试。连续加载卸载 100 次看有没有内存泄漏或资源未释放。rmmod后free看内存是否回到初始值lsmod确认模块已卸载干净。第三项是低功耗测试。如果板子支持待机让系统进待机测 Wi-Fi 模块的待机电流。正常情况下驱动应该让芯片进低功耗模式电流降到几毫安。如果待机电流还是几十毫安说明电源管理没生效要查驱动里的suspend/resume回调。第四项是温度测试。Wi-Fi 芯片在满速传输时发热明显如果板子散热不好芯片可能因为过热而降速或掉线。我遇到过一块板子Wi-Fi 跑满 10 分钟就掉线后来发现是芯片温度到了 85 度以上加了散热片才解决。这些测试跑下来如果都过了这个移植基本就算稳了。剩下的就是根据具体产品需求做定制比如自动连接、漫游、蓝牙共存这些那些是另一个层面的工作不在这次移植的核心范围内。我个人在实际操作中的体会是嵌入式 Wi-Fi 驱动移植这件事难点从来不在“写代码”而在“对齐环境”。内核配置、固件版本、USB 时序、供电能力任何一个环节对不上都会表现为“驱动加载失败”但根因可能差得很远。所以排查时一定要从底层往上查先确认 USB 枚举正常再确认固件下载正常最后才看 wlan 口注册。顺序反了就会在错误的方向上浪费大量时间。
返回列表