简介:AP6212 驱动包面向需要在 Linux 系统上启用 Broadcom AP6212 无线芯片 Wi-Fi 与蓝牙功能的开发者、系统集成者及驱动学习人员,核心提供驱动源码、移植说明与问题排查参考。压缩包共 14 个文件,约 5.31MB,包含 c 源码、txt 移植与操作说明、pdf 用户指南、jpg 版本对比图,以及 bz2、tgz、rar 等驱动与固件压缩件,便于按模块查阅。已有 2035 人学习,说明其在相关硬件适配场景中具有一定参考需求。读者可从中获取 AP6212 Wi-Fi/蓝牙驱动整合思路、设备树与内核配置相关指引、bluez 编译设置、固件自动检测资料,以及个人移植中遇到的问题与解决办法汇总,适合用于功能调试、版本核对和排错借鉴。
1. 首发固件对不上:AP6212 在 Linux 下装驱动最容易翻车的地方
AP6212 是不少开发板上的常客,正基的 WiFi、蓝牙二合一模块,SDIO 接 WiFi、UART 接蓝牙,一块核心板焊上去,系统起来lsusb什么都看不到,ifconfig -a也只有 lo 和有线网口。这时候很多人第一反应是“驱动没装”,直接去编译一个网上的 bcmdhd 源码往内核里塞,结果模块是加载了,dmesg里一串sdio probe failed,或者 WiFi 能扫到信号、蓝牙死活起不来。AP6212 的 Linux 驱动不是装一个.ko就完事,它牵扯到内核 SDIO 支持、设备树描述、固件与 NVRAM 文件、以及 WiFi/蓝牙两条独立的驱动链路。装得不对,最典型的后果是板子每次上电都要手动insmod,WiFi 隔几分钟掉线,蓝牙变成“能配对不能传数据”。这篇是我自己在一套嵌入式环境里把 AP6212 Linux 驱动从零跑通的记录,面向手里有板子、有内核源码、需要它稳定联网传数据的开发者。
2. 装之前先对齐环境:内核版本、SDIO 与固件的三件套
AP6212 这类 combo 模块的驱动从来不是独立的第三方包,Linux 主线里brcmfmac就覆盖了博通的 SDIO WiFi 芯片族,AP6212 通常在支持列表内。真正决定装什么的,是你手上内核的版本和板子设备树里的描述。我开始动手之前,会先把这三件事查清楚,不查清楚后面全是白费功夫。
2.1 先确认内核支不支持 brcmfmac
登录板子,先看内核版本和配置里两个关键项:CONFIG_BRCMFMAC和CONFIG_MMC(SDIO 走 MMC 子系统)。
# 我一般用这三条确认现状,比翻 .config 快 uname -r # 内核版本,决定驱动源码位置 zcat /proc/config.gz | grep -E "BRCMFMAC|MMC_SDHCI" # 没有 config.gz 就看 /boot/config-$(uname -r) ls /sys/bus/sdio/devices/ # 模块被识别到时这里会有 02d0:a9a6 之类的目录/sys/bus/sdio/devices/这个目录是关键判断点。如果里面有02d0:a9a6(博通的 vendor/device ID,AP6212 常见标识),说明 SDIO 总线已经把模块枚举出来了,剩下只是驱动绑不绑的问题;如果目录是空的,问题在硬件或设备树,往内核里加驱动源码一点用没有。CONFIG_BRCMFMAC建议编成模块=m,方便单独替换;CONFIG_BRCMFMAC_SDIO必须打开,否则只有 USB 那条路。
2.2 设备树里 SDIO 节点和电源使能不能漏
AP6212 的 SDIO 接口不是插上就能用的,设备树里得把这个 mmc 控制器配出来,还要有 GPIO 控制模块的WL_REG_ON复位脚。常见做法是这样写:
&mmc1 { status = "okay"; bus-width = <4>; /* AP6212 走 4-bit SDIO */ non-removable; /* 焊死的模块,不是插拔卡 */ keep-power-in-suspend; /* 休眠不断电,否则唤醒后 WiFi 掉 */ mmc-pwrseq = <&sdio_pwrseq>; brcmf: wifi@1 { reg = <1>; /* SDIO function 1 是 WiFi */ compatible = "brcm,bcm4329-fmac"; }; }; sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; reset-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; /* 对应模块 WL_REG_ON,脚号按板子原理图改 */ };non-removable不加,MMC 子系统会当成可插拔卡去轮询,表现为探测时好时坏;mmc-pwrseq不加,WL_REG_ON一直为低,SDIO 枚举直接失败,/sys/bus/sdio/devices/永远是空的。reset-gpios的脚号必须对着原理图核实,这是最常见的写错点,抄别人的设备树基本必错。
2.3 固件和 NVRAM 文件的位置与命名
brcmfmac加载时会去/lib/firmware/brcm/找两个文件:brcmfmac43430-sdio.bin(固件)和brcmfmac43430-sdio.txt(NVRAM 参数,包含 MAC 地址、功率表、天线配置)。AP6212 的芯片标识是 BCM43430,文件名不能随意改,驱动是按 compatible 字符串推导文件名的。
# 放入固件,命名必须是驱动能推出来的那个 sudo mkdir -p /lib/firmware/brcm sudo cp fw_bcm43438a1.bin /lib/firmware/brcm/brcmfmac43430-sdio.bin sudo cp nvram_ap6212.txt /lib/firmware/brcm/brcmfmac43430-sdio.txt sudo cp brcmfmac43430-sdio.bin /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob # 法规限制表,可缺省 # 验证驱动有没有把固件吃进去 dmesg | grep -i brcmfmacclm_blob是通道限制表,缺了驱动会打印警告但通常还能用,只是某些信道功率受限。NVRAM 里如果用macaddr=指定的地址全 0,会出现两个板子 MAC 冲突,同一个局域网里互相抢 IP,这种故障排查起来很耗时间,我一般刷机后顺手把 NVRAM 里的 MAC 改成唯一值。这一步做完,WiFi 侧的环境就算齐了。
3. 编译与加载:把 brcmfmac 驱动装进内核的正确顺序
环境对齐之后,编译并不复杂,麻烦在于模块依赖顺序和加载时机。SDIO 驱动必须在 MMC 控制器就绪之后才能 probe,顺序错了就是一堆-ENODEV。
3.1 用内核树内编译,别从外网拉源码
如果内核配置里CONFIG_BRCMFMAC=m,最稳的方式是直接在内核树里编,不要去拉什么独立仓库的 bcmdhd——那套是安卓全志时代的私有驱动,接口跟主线内核差得远,编出来也绑不上。
# 在内核源码根目录,确保 .config 里 BRCMFMAC 系列已开启 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_prepare make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- M=drivers/net/wireless/broadcom/brcm80211/brcmfmac modulesmodules_prepare不能省,它会生成Module.symvers和头文件依赖,少了这一步编译时找不到sdio_register_driver这类符号。编完产物落在drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko。交叉编译工具链前缀必须和板子上跑的内核一致,编出来的.ko用modinfo brcmfmac.ko | grep vermagic看一眼,内核版本对不上会直接拒绝加载。
# 拷到板子并安装 scp brcmfmac.ko root@<board-ip>:/lib/modules/$(uname -r)/kernel/drivers/net/wireless/ depmod -a modprobe brcmfmacmodprobe比insmod好在于它会自动处理cfg80211、mac80211这两个依赖模块,insmod遇到依赖缺失只报一句Unknown symbol,不告诉你缺谁。如果板子上没有modprobe,就先insmod cfg80211.ko、再insmod mac80211.ko、最后insmod brcmfmac.ko,顺序不能反。
3.2 蓝牙是另一条链路,UART 加 hciattach
WiFi 起来了不代表蓝牙就好了,AP6212 的蓝牙走 UART,靠hciattach把串口包成 HCI 设备,还多一根BT_REG_ON使能脚。
# 1. 确认串口设备存在,通常是 ttyS1 或 ttyAMA1 ls /dev/ttyS* # 2. 拉起蓝牙,-s 指定波特率,-t 指定协议类型 hciattach -s 1500000 /dev/ttyS1 bcm43xx 1500000 flow # 3. 验证 HCI 设备 hciconfig -a # 应该看到 hci0,UP RUNNINGbcm43xx这个协议名对应博通系蓝牙的初始化流程,波特率 AP6212 常用 1500000,flow表示启用硬件流控,不加的话高速率下丢包严重。BT_REG_ON如果没在设备树里拉高,hciattach会卡住几秒然后报Can't initialize device,这时候别怀疑波特率,先量一下那个使能脚的电压。蓝牙的固件BCM43430A1.hcd放在/lib/firmware/brcm/,文件名同样随芯片型号,放错了会打印BCM: patch file not found。
3.3 配置开机自动加载参数
跑通之后要让它开机即用,模块参数写在/etc/modprobe.d/brcmfmac.conf:
options brcmfmac roamoff=1 feature_disable=0x82000roamoff=1关掉自动漫游,单 AP 场景下能减少无谓的扫描导致短暂丢包;feature_disable是位掩码,按需关掉不用的特性。改完执行update-initramfs -u(Debian 系)或重建 initramfs,否则早期启动阶段参数不生效。这一步踩过坑:以为写了参数文件就完事,结果 initramfs 里是旧的模块配置,开机加载的还是默认值。
4. 踩坑记录:AP6212 驱动加载失败的五个典型现场
这套东西装下来,报错五花八门,但重复率极高。下面五条是我实际遇到过、并且网上问得最多的,每条按“看到什么、为什么、怎么修”来说。
4.1 现象:brcmf_sdio_probe: failed to power on
原因:mmc-pwrseq没配或reset-gpios脚号写错,WL_REG_ON没拉起来,模块根本没上电。解决:对照原理图确认使能脚,改设备树后重新编译 dtb,ls /sys/bus/sdio/devices/确认有设备再加载驱动。还有一种情况是 GPIO 被别的驱动先占了,cat /sys/kernel/debug/gpio能看到占用者。
4.2 现象:固件加载报Direct firmware load for brcm/brcmfmac43430-sdio.bin failed
原因:文件不存在、名字不对、或者权限不对。解决:ls -l /lib/firmware/brcm/核对文件名大小写,dmesg里驱动打印的候选路径照着创;/lib/firmware在部分精简系统上是软链到/usr/lib/firmware,放错地方驱动找不到。注意文件名里的43430是芯片标识,不能改成模块名ap6212。
4.3 现象:WiFi 连上后每隔几十秒断一次
原因:电源管理把 SDIO 时钟关了,或者keep-power-in-suspend没配。解决:设备树加上keep-power-in-suspend,模块参数加power_save=0关掉省电;另外确认 AP 侧不是开着某种强制重关联机制。这个故障很隐蔽,因为断线后很快重连,日志里只有一行deauthenticating。
4.4 现象:hciattach报Can't initialize device: Connection timed out
原因:蓝牙使能脚BT_REG_ON没拉高,或串口被getty占着。解决:设备树补使能脚控制,systemctl disable serial-getty@ttyS1;也可能波特率不匹配,先用 115200 慢速试一遍,通了再提速到 1500000。
4.5 现象:加载模块后dmesg报Unknown symbol in module
原因:cfg80211或mac80211没先加载,或者vermagic与当前内核不匹配。解决:用modprobe自动解决依赖;vermagic不一致说明.ko是给另一个内核编的,modinfo核对后重编,别硬insmod -f,强制加载上去大概率内核崩。
5. 装完怎么验证:三条命令确认 WiFi 和蓝牙真的跑通了
驱动加载成功不等于业务可用,我验收这套环境的习惯是走一遍“枚举 → 出接口 → 传数据”三级验证,每一级都留一条可复现的命令,出问题时能立刻定位到是哪一层。
第一级看 SDIO 枚举和驱动绑定。ls /sys/bus/sdio/devices/下面有设备目录,并且ls /sys/bus/sdio/devices/*/driver能软链到brcmfmac,说明总线和驱动都对上了。这一级不过,别往下看,回去查设备树和上电时序。
# 一级:枚举与绑定 ls /sys/bus/sdio/devices/ # 有无 02d0:xxxx 设备 readlink /sys/bus/sdio/devices/*/driver # 是否指向 brcmfmac # 二级:网络接口与射频 ip link show wlan0 iw dev wlan0 info # 看 channel、txpower 是否正常 rfkill list # 有没有被软/硬阻塞 # 三级:实际收发 iw dev wlan0 scan | grep SSID | head -5 ping -I wlan0 -c 4 <网关IP>三级验证里最容易忽略的是rfkill list,很多板子出厂时 WiFi 被 soft block,wlan0存在但扫不到任何信号,看日志全是空的,以为是驱动问题,其实一句rfkill unblock wlan就好。iw dev看txpower能侧面判断 NVRAM 有没有正确加载——功率表没读到的话 txpower 通常是 0 dBm 或固定值,实际发射很弱。
蓝牙侧对应两级:hciconfig -a看到UP RUNNING,再用hcitool lescan或bluetoothctl scan on确认能扫到周边设备。能扫到但连不上,问题通常在配对流程或 NVRAM 里蓝牙部分的参数,不在驱动本身。
| 验证层级 | 命令 | 正常表现 | 失败指向 |
|---|---|---|---|
| SDIO 枚举 | ls /sys/bus/sdio/devices/ | 出现设备目录 | 设备树、供电 |
| 驱动绑定 | readlink .../driver | 指向 brcmfmac | 内核配置、模块 |
| 接口存在 | ip link show wlan0 | wlan0 处于 DOWN/UP | 固件加载失败 |
| 射频可用 | rfkill list | 无阻塞 | 被 rfkill 拦 |
| 收发正常 | ping -I wlan0 | 有回应 | NVRAM、天线 |
整张表走一遍,基本能把故障锁在某一层,不会出现“感觉驱动没装好”这种模糊判断。还有个小技巧核对固件是否真的生效:cat /sys/kernel/debug/brcmfmac/*/fw_version之类路径在部分内核上有,能直接读到固件版本号,和放进/lib/firmware的文件对上就说明没有缓存旧固件。
从那以后我每次给新板子装 AP6212 驱动,都强制先跑一遍ls /sys/bus/sdio/devices/再看代码,这一条命令能省掉大约一半的无效编译时间。希望帮到你。
本文还有配套的精品资源,点击获取