简介AP6212 驱动资料包面向在 Linux 平台适配 Broadcom AP6212 无线芯片的开发者与系统集成者聚焦 WiFi 与蓝牙驱动的编译、移植和调试适合具备一定内核基础、需要解决硬件识别、驱动加载及网络连接稳定性问题的人群。压缩包共 14 个文件、约 5.31MB以 txt 说明、pdf 手册、jpg 版本对比图为主并包含源码压缩包、补丁脚本及 C 源码等便于按移植流程查阅与取用。已有 2038 人学习下载说明其在同类芯片适配场景中具有一定参考价值。内容覆盖驱动源码、内核移植步骤、设备树与编译配置说明、蓝牙应用库编译设置、WiFi/蓝牙用户指南及固件与 nvram 资源还整理了个人移植中遇到的问题与解决办法可帮助读者理解 AP6212 的版本差异、排查加载失败与连接异常并完成 WiFi Direct、A2DP 等功能的启用与优化。1. AP6212 驱动在 Linux 上的第一道坎SDIO 认不到卡比编译失败常见得多手上有一块带 AP6212 的板子内核 4.19编译 AP6212 Linux 驱动一次就过insmod也不报错可ip link里死活看不到 wlan0——这种事我在板卡移植现场见过太多次。AP6212 是 WiFi 走 SDIO、蓝牙走 UART 的双模模组硬件上还多出 WL_REG_ON、BT_REG_ON 两根使能脚任何一处没配好表现出来的都是“驱动没装好”实际坏的地方可能在内核配置、设备树、固件文件名甚至在电源上电时序。装不好轻则开机多等半分钟、扫描不到 5G 频段重则 2.4G 一连就掉、蓝牙连一次断一次调试时没有任何黑匣子可看只能靠 dmesg 一行行猜。这篇写给正在板卡上移植这颗模组的人从版本怎么选、源码怎么编、固件怎么放一直写到装崩了怎么救。2. 环境与版本核对AP6212 驱动选哪套分支、配哪份固件AP6212 的坑有一半是版本没对齐埋下的。同样一份驱动源码放在 3.10 的厂商 SDK 里能编过挪到 5.10 上就是一堆unknown field报错同样一份 nvrama0 版芯片用着正常换成 a1 版芯片就下载固件超时。所以动手之前先把三件事定下来内核版本、驱动形态、固件文件名。2.1 内核版本决定驱动形态bcmdhd 外挂还是 brcmfmac 内置这套模组的驱动在 Linux 下有两条完全不同的路。第一条是模组厂随 SDK 发出来的 bcmdhd 源码包编译产物是dhd.ko走的是它自己的一套 netdev 实现跟 cfg80211 只做半对接第二条是内核主线里的 brcmfmac从 4.9 开始对 43438 这颗芯片的支持就基本可用了4.19 之后我一般直接用它能省掉一大半维护成本。内核版本推荐驱动形态固件存放位置典型场景3.10 ~ 4.4bcmdhddhd.ko/system/vendor/firmware或/lib/firmware厂商 SDK、老 Android BSP4.9 ~ 4.14brcmfmac 少量厂商补丁/lib/firmware/brcm主线化过渡期4.19 及以上brcmfmac首选/lib/firmware/brcm新项目、长期维护选 brcmfmac 就要把内核配置项开对这几个是最容易漏的# 内核 .config 里必须打开的一组项 CONFIG_CFG80211m CONFIG_MAC80211m CONFIG_BRCMUTILm CONFIG_BRCMFMACm CONFIG_BRCMFMAC_SDIOy CONFIG_BRCMFMAC_PROTO_BCDCy # 43438 不支持 msgbuf 协议这一项保持关闭 # CONFIG_BRCMFMAC_PROTO_MSGBUF is not set CONFIG_BT_HCIUARTm CONFIG_BT_HCIUART_BCMyBRCMFMAC_PROTO_BCDC和PROTO_MSGBUF这两个协议选项是分水岭。43438 这颗芯片只支持 BCDC如果 menuconfig 里手滑把 msgbuf 打开编译不报错加载时固件也能下去但初始化阶段会卡在brcmf_proto_msgbuf_attach上日志只留一句failed to attach msgbuf很容易被误判成固件问题。BT_HCIUART_BCM则是给蓝牙用的蓝牙 H4 协议要靠它识别 bcm 的下载协议缺了这项hciattach会一直停在bcm43xx_init。如果项目必须留在 bcmdhd 上比如要跑厂商定制的 P2P 或某个私有 ioctl那就把驱动源码和内核版本严格绑定。判断标准很简单驱动包里include/目录下的头文件和内核树里同名头文件的字段能对上。对不上就别硬编换分支比改代码快。2.2 先确认硬件怎么挂的SDIO 总线号、串口、使能脚驱动之前先看硬件。把板子启动到能进 shell 的程度哪怕 WiFi 完全不通SDIO 控制器和串口也应该在工作# 看 mmc 控制器有没有枚举到设备 dmesg | grep -i -E mmc[0-9]|sdio # 看 SDIO 设备节点正常应该出现类似 mmc1:0001:1 的目录 ls -l /sys/bus/sdio/devices/ # 看当前 mmc 控制器的时钟与位宽 cat /sys/kernel/debug/mmc1/iosdmesg里出现mmc1: new high speed SDIO card at address 0001这一行说明硬件链路是通的剩下的都是软件问题如果只有mmc1: SDHCI controller on ... using ADMA之后再无下文那多半是 WL_REG_ON 没拉起来、供电没到位或者bus-width写错。使能脚的定义每家板子不一样但套路固定WiFi 一根 WL_REG_ON蓝牙一根 BT_REG_ON有的板子还有一根共用的 WL_HOST_WAKE 中断脚。这三根脚在设备树里必须描述清楚否则驱动再对模块也不上电。常见的 mmc-pwrseq 写法/* SDIO WiFi 供电与复位时序 */ mmc1 { status okay; bus-width 4; non-removable; keep-power-in-suspend; cap-power-off-card; max-frequency 50000000; mmc-pwrseq wifi_pwrseq; brcmf: wifi1 { reg 1; compatible brcm,bcm4329-fmac; }; }; wifi_pwrseq: wifi-pwrseq { compatible mmc-pwrseq-simple; /* WL_REG_ON低电平有效具体 GPIO 号按板子原理图改 */ reset-gpios gpio1 12 GPIO_ACTIVE_LOW; /* 上电后等 200ms 再枚举短了会认不到卡 */ post-power-on-delay-ms 200; };non-removable表示卡是焊死的不能让 mmc 子系统去做插拔探测cap-power-off-card允许在挂起时断电post-power-on-delay-ms是最容易被忽略的一行模组内部稳压和晶振起振需要时间很多板子给 50ms 能认出卡但跑一会儿就掉改成 200ms 就稳了。compatible brcm,bcm4329-fmac是 brcmfmac 认 SDIO 设备的通用匹配串写错就只是枚举到设备、不绑定驱动。蓝牙那侧走的是 UART/* 蓝牙挂在 uart1 上波特率上限由 max-speed 决定 */ uart1 { status okay; pinctrl-names default; pinctrl-0 uart1_pins; bluetooth { compatible brcm,bcm43438-bt; max-speed 1500000; /* BT_REG_ON高电平有效 */ shutdown-gpios gpio1 13 GPIO_ACTIVE_HIGH; }; };max-speed是协商后的最高波特率1500000 是这颗芯片的常用档但有些板子的 UART 时钟分频除不尽实测只能用 115200 或 921600硬上高波特率会得到一堆乱码和hci0: command tx timeout。shutdown-gpios在高版本内核里由 hci_bcm 驱动接管加载时会自动拉高老内核没有这个节点就得自己在hciattach前用脚本把 GPIO 拉起来。2.3 固件与 nvram 准备文件名对不上驱动装了也白装brcmfmac 是按文件名找固件的名字错一个字符就加载失败。它认的规则是brcmfmacchipid-sdio.bin和brcmfmacchipid-sdio.txt43438 对应brcmfmac43430-sdio.bin。而厂商给的原始文件名通常是fw_bcm43438a1.bin和nvram_ap6212a.txt中间需要一层改名或者软链。# 固件统一放到 brcm 子目录下权限 644 sudo mkdir -p /lib/firmware/brcm sudo cp fw_bcm43438a1.bin /lib/firmware/brcm/brcmfmac43430-sdio.bin sudo cp nvram_ap6212a.txt /lib/firmware/brcm/brcmfmac43430-sdio.txt sudo chmod 644 /lib/firmware/brcm/brcmfmac43430-sdio.* # 用 bcmdhd 的话保留原名路径由模块参数指定不用改名 sudo cp fw_bcm43438a1.bin /lib/firmware/brcm/ sudo cp nvram_ap6212a.txt /lib/firmware/brcm/ # 校验一下文件是不是拷贝过程被截断了 md5sum /lib/firmware/brcm/brcmfmac43430-sdio.bin ls -l /lib/firmware/brcm/固件版本要和芯片版本对应。AP6212 常见两种芯片a0 和 a1。a0 用fw_bcm43438a0.bin配nvram_ap6212.txta1 用fw_bcm43438a1.bin配nvram_ap6212a.txt。这两个组合不能交叉交叉的典型症状是固件能下载进去但brcmf_chip_recognition阶段读回 chipid 对不上日志打印brcmf_chip_set_passive: unsupported chip。判断芯片版本最省事的办法是看模组丝印其次是挨个试试错成本就是一次重启。nvram 文件里还有几个参数决定实际体验值得单独看一眼# nvram_ap6212a.txt 里需要关注的几行 macaddr00:90:4c:xx:xx:xx # 出厂 MAC缺失会导致每次开机 MAC 变化 boardtype0x0b3 # 板型标识跟天线匹配有关 btc_mode1 # 蓝牙共存模式不开 2.4G 会和蓝牙互抢 btc_params400x0f # 共存参数不同板子取值不同macaddr缺失是最常见的一类问题。brcmfmac 找不到 MAC 时会用随机地址表现就是每次重启 wlan0 的 MAC 都变路由器上的 DHCP 租约表越积越长某些做了 MAC 绑定的环境直接连不上。这种字段如果驱动包里没带就得在产线工装里写进去。3. 编译与加载 AP6212 驱动从源码到 insmod 的落地步骤版本和固件都对齐之后才轮到编译。这一步在 x86 主机上交叉编译产物拿到板子上insmod。看着简单实际最容易翻车的是内核树不完整、符号版本对不上、加载顺序错。3.1 准备内核树与交叉工具链交叉编译模块要求主机上有一份配置和板上内核完全一致的内核树包括.config和Module.symvers。只拷头文件不够缺Module.symvers会在加载时报disagrees about version of symbol。# 主机上确认工具链可用 arm-linux-gnueabihf-gcc -v # 内核树必须是板上跑的同一版本、同一配置 cd /home/dev/kernel/linux-4.19 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- modules_prepare # 检查这两个文件是否存在缺一个都别往下走 ls -l .config Module.symversmodules_prepare会生成编译外部模块所需的脚本和头文件。如果手上只有板上/lib/modules/$(uname -r)/build那个软链把它指到完整内核树或者干脆把板上/proc/config.gz拿回来重新配一遍。.config不一致的后果很隐蔽编译能过加载能过跑起来偶尔 oops查起来毫无头绪。3.2 改 Makefile 和三个关键宏bcmdhd 的 Makefile 一般把内核路径写成宿主机默认值交叉编译必须改。核心是三个变量ARCH、CROSS_COMPILE、KERNELDIR外加一组DHDCFLAGS。# 驱动源码目录下的 Makefile 关键片段 ARCH ? arm CROSS_COMPILE ? arm-linux-gnueabihf- KERNELDIR ? /home/dev/kernel/linux-4.19 # 告诉驱动走 SDIO 总线而不是 USB 或 PCIe CONFIG_BCMDHD_SDIO : y # 固件与 nvram 的默认路径和 2.3 节放的位置保持一致 CONFIG_BCMDHD_FW_PATH : /lib/firmware/brcm/fw_bcm43438a1.bin CONFIG_BCMDHD_NVRAM_PATH : /lib/firmware/brcm/nvram_ap6212a.txt # 走 cfg80211 框架上层才能用 wpa_supplicant 的 nl80211 驱动 DHDCFLAGS -DUSE_CFG80211 # 打开 PNO休眠唤醒后的被动扫描要靠它 DHDCFLAGS -DPNO_SUPPORTCONFIG_BCMDHD_SDIO决定编译哪套总线适配代码选错会得到一堆dhdsdio_*未定义符号。FW_PATH和NVRAM_PATH是编进模块的默认值运行时也能用模块参数覆盖但产线上一般直接编死省得启动脚本里再传。USE_CFG80211影响的是上层接口开了走 cfg80211iw和wpa_supplicant -Dnl80211都能用不开就只能用它私有的 wireless extensions新发行版基本已经移除了。改完直接编export ARCHarm export CROSS_COMPILEarm-linux-gnueabihf- export KERNELDIR/home/dev/kernel/linux-4.19 make -C $KERNELDIR M$PWD modules -j4 # 产物确认正常会生成 dhd.ko file dhd.ko modinfo dhd.ko | head -20-C $KERNELDIR让 make 先切到内核树读顶层 MakefileM$PWD再指回驱动目录这是编译外部模块的标准写法。modinfo输出的vermagic必须和板上uname -r完全一致不一致就说明内核树选错了别抱侥幸心理硬加载。3.3 insmod 加载顺序与 dmesg 观察模块之间是有依赖的。bcmdhd 依赖 cfg80211cfg80211 又依赖内核里已经编进去的部分brcmfmac 依赖 brcmutil。顺序错了就是Unknown symbol in module。# bcmdhd 路线先依赖后主体 insmod /lib/modules/$(uname -r)/cfg80211.ko insmod /lib/modules/$(uname -r)/dhd.ko \ firmware_path/lib/firmware/brcm/fw_bcm43438a1.bin \ nvram_path/lib/firmware/brcm/nvram_ap6212a.txt # brcmfmac 路线一条 modprobe 就够依赖自动处理 modprobe brcmfmac # 无论哪条路加载完先看这一段日志 dmesg | tail -40成功的日志长这样先是mmc1: new high speed SDIO card at address 0001完成枚举接着dhd_module_init in或brcmfmac: brcmf_sdio_probe: firmware ready然后打印固件版本和 MAC最后出现wl0: Broadcom BCM43438 WLAN found之类的一行。只要看到 MAC 地址那一行链路层就通了。失败时日志停在哪个阶段指向的问题是不一样的。停在枚举之前回去查设备树和供电停在固件下载查文件名、芯片版本、nvram停在wl0注册之前但固件已经下去多半是 MAC 或者板型参数有问题。模块参数除了firmware_path/nvram_path还有几个常用# 打开调试级别日志更啰嗦但定位更准 insmod dhd.ko dhd_msg_level0x1 # 强制指定 MAC临时绕开 nvram 缺 macaddr 的问题 insmod dhd.ko mac00:11:22:33:44:55dhd_msg_level是按位掩码的0x1是错误0x7是错误加警告加信息产线调试期开大一点量产必须关掉否则串口日志会被刷屏拖慢启动。4. 配置双模AP6212 的 wpa_supplicant 与蓝牙 HCI 初始化wlan0 出现只是第一步能连上 AP 才算 WiFi 通了蓝牙那侧hci0出现也只是第一步能扫到设备才算通。这两条路互不依赖可以分开调但共用一套电源和共存参数调好一个再去动另一个。4.1 wlan0 起来之后wpa_supplicant 与 nl80211 的配置如果驱动走的是 cfg80211上层就用 wpa_supplicant 的nl80211驱动后端如果走的是老私有接口就得用wext。判断方式是看iw dev有没有输出有就是 cfg80211。# /etc/wpa_supplicant.conf ctrl_interface/var/run/wpa_supplicant update_config1 countryCN network{ ssidtest-ap psk12345678 key_mgmtWPA-PSK protoRSN pairwiseCCMP scan_ssid1 }countryCN不是摆设它决定驱动下发的监管域进而决定哪些信道可用。这一行缺失时某些内核版本会把 12、13 信道标成 no-IR表现是能扫到 AP 但连不上。scan_ssid1是给隐藏 SSID 用的正常 AP 开着也无妨只是每次扫描多花一点时间。# 前台起一次看握手过程调通了再改 -B 后台 wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf -dd # 拿到 IP udhcpc -i wlan0 # 或发行版自带客户端 dhclient wlan0 # 确认接口状态 iw dev wlan0 link-Dnl80211指定驱动后端写错成wext会报Failed to initialize driver interface。-dd是调试级别会打印每一步的 EAPOL 交互排查密码错、四次握手失败时非常有用。连上之后iw dev wlan0 link会显示当前 BSSID、信号强度和速率这几项是判断链路质量的直接依据。4.2 蓝牙走 UARThciattach 与内核 hci_bcm 两条路蓝牙这块分老新两套机制。4.9 之前基本靠用户态hciattach手动下载固件4.9 之后内核里的 hci_bcm 能自己处理前提是设备树写对。老路子# 先把 BT_REG_ON 拉高具体 gpio 号按板子改 gpioset gpiochip1 131 sleep 0.2 # bcm43xx 协议先低速协商再切高速 hciattach /dev/ttyS1 bcm43xx 1500000 flow -t 30 # 起来了之后 hciconfig hci0 up hciconfig -abcm43xx是协议名它会先按 115200 发下载命令把BCM43438A1.hcd固件灌进去再切到1500000。flow表示启用硬件流控不写这参数在高速率下必然丢包。-t 30是超时秒数默认值偏小固件大的时候会误判失败。这个.hcd文件要放在/etc/firmware/或--bd_addr指定的路径下路径不对就卡在bcm43xx_init不动。新路子4.19 及以上modprobe bluetooth modprobe hci_uart modprobe btbcm # 设备树里 bluetooth 节点写对的话hci0 会自动出现 hciconfig -a rfkill list rfkill unblock bluetoothrfkill是个容易被忘掉的开关。有些板子的默认状态下蓝牙是 soft blockedhciconfig hci0 up会报Operation not possible due to RF-kill这时候rfkill unblock bluetooth一下就通了跟驱动一点关系没有。蓝牙固件文件名通常要求是BCM43438A1.hcd从厂商包里拷过来放到/lib/firmware/brcm/或/etc/firmware/两个路径不同发行版认的不一样都放一份最省事。文件版本同样要和芯片版本对上。5. 常见问题排查AP6212 驱动装完不认卡、固件超时、蓝牙 110下面这几条都是我在板子上真实撞过的按现象、原因、解决三段记遇到同类问题时可以直接对号。现象一dmesg里 mmc1 只有控制器初始化没有new high speed SDIO card/sys/bus/sdio/devices/是空的。原因通常是电源或时序。WL_REG_ON 没拉起来、reset-gpios的极性写反、post-power-on-delay-ms给得太短都会导致枚举阶段读不到卡。也有一种情况是bus-width写成14 线模组按 1 线枚举运气好能认到但速率极低运气不好直接超时。解决办法是把万用表或示波器搭到 WL_REG_ON 上确认上电后确实被拉高然后把延时从 50ms 加到 200ms 再试同时核对设备树里bus-width 4和non-removable两行。现象二卡认到了固件下载阶段报brcmf_sdio_download_firmware: dongle is not responding或FW download failed。原因基本是固件和芯片版本不匹配或者 nvram 用错了。a0 芯片灌 a1 的固件、nvram_ap6212.txt和nvram_ap6212a.txt混用都会卡在这一步。另一类原因是 SDIO 时钟太快max-frequency给到 50MHz 时某些板子的走线撑不住。解决办法是先换固件组合两组都试一遍排除版本问题还不行就把max-frequency降到 25MHz 验证能过就说明是信号完整性问题回去改 layout 或加串阻而不是继续折腾驱动。现象三wlan0 出现了iw dev wlan0 scan一条结果都没有或者 MAC 每次重启都变。MAC 每次变说明 nvram 里没有macaddr驱动用了随机地址。扫描无结果则多半是监管域或天线问题country没设导致信道全被禁或者天线没接、阻抗不匹配导致灵敏度极差。解决办法是先补macaddr把出厂 MAC 写进 nvram 或者产线工装再用iw reg get看当前监管域手工iw reg set CN验证一下是不是这个原因。如果设了监管域还是扫不到那就是射频侧的问题跟软件无关了。现象四insmod报disagrees about version of symbol或Invalid module format。内核树和板上内核不是同一份。vermagic里包含内核版本、SMP 标志、抢占模式、模块版本校验任何一项不一致都加载不了。常见于板上内核是厂商改过的主机上用的却是官方源码。解决办法是把板上/proc/version和/proc/config.gz拿回来用同一份配置重新编内核树再编模块实在拿不到配置就在内核树里把CONFIG_MODVERSIONS关掉重编能绕过符号校验但这只是应急长期用会掩盖真正的不兼容。现象五hciattach报Cant init device hci0: Connection timed out (110)。110 是超时错误码含义是发了 HCI Reset 命令但没收到回应。原因有三个方向BT_REG_ON 没拉高、串口引脚复用没配对、波特率不对。排查顺序是先量 BT_REG_ON 电平再用stty -F /dev/ttyS1 115200加回环测试确认串口本身通最后才怀疑波特率。很多板子的 UART 时钟源是 24MHz1500000 除不尽实际协商出来的波特率有偏差降到 921600 或 115200 就正常了。6. 装完怎么验证AP6212 的三层验证法驱动装完最忌讳的是“看到 wlan0 就以为成了”。我一般按三层走一遍每层不过就不往下走这样出问题时能立刻定位在哪一层。#!/bin/sh # ap6212_check.sh —— 三层验证每层不过就退出 echo 第一层链路层SDIO 枚举 固件下载 ls /sys/bus/sdio/devices/ || { echo SDIO 未枚举查供电与设备树; exit 1; } dmesg | grep -E brcmfmac|dhd | tail -20 echo 第二层接口层wlan0 与 MAC ip link show wlan0 || { echo wlan0 未创建查固件与 nvram; exit 2; } cat /sys/class/net/wlan0/address iw dev wlan0 info echo 第三层业务层扫描与关联 iw dev wlan0 scan | grep -c SSID || { echo 扫描为空查监管域与天线; exit 3; } wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf -B sleep 5 udhcpc -i wlan0 ping -c 4 -W 2 223.5.5.5 || { echo 连通性失败查关联与路由; exit 4; } echo 蓝牙 hciconfig hci0 || { echo hci0 未创建查 BT_REG_ON 与串口; exit 5; } hciconfig hci0 up hcitool scan这个脚本的价值在于它把“哪一层坏了”变成了一个退出码。exit 1是硬件和枚举exit 2是驱动和固件exit 3是射频和配置exit 4是关联和路由exit 5是蓝牙链路。产线上一批板子跑下来统计退出码分布就知道该改哪一环。第三层的ping只是最粗的连通性判断真要压一遍链路质量还得看吞吐# 板子做客户端主机起服务端 iperf3 -c 192.168.1.100 -t 30 -i 5 # 关注重传和信号这两个数比吞吐更能说明问题 iw dev wlan0 station dump | grep -E signal|tx retries|tx failed2.4G 单天线在干净环境下 20~30Mbps 是正常区间低于 10Mbps 就该怀疑天线或共存参数了。tx retries持续偏高说明空口干扰严重这时候回去看 nvram 里的btc_mode有没有开蓝牙和 WiFi 同时工作时的共存参数是不是默认值。三层全过我才会把驱动固化进镜像。有一次图省事跳过了第三层只验证到 wlan0 出现就发了版结果现场一批板子扫描正常、关联也正常就是拿不到 IP最后查出来是 nvram 里的板型参数和这批板子的天线不匹配射频校准数据不对。从那以后我每次出镜像前都强制走一遍这个脚本三层全绿才算数。希望这套流程能帮到你少走几次回头路。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?