简介:这份资源是一套面向嵌入式开发者的 USB WiFi 模块驱动源码包,型号为 RTL8733BU,兼容 RTL8733、RTL8731 芯片,并已适配 MC6810 平台及 Linux 4.9.138 内核,解决开发者在特定硬件与内核版本下获取稳定无线驱动的问题。压缩包共 1098 个文件,大小约 11.06MB,核心内容以 C 语言源码与头文件为主(221 个 .c、485 个 .h),同时包含编译脚本、配置命令、模块文件等辅助材料,适合用来理解驱动移植、编译和加载流程。文件命名中的版本号与日期可供判断驱动的新旧与更新节奏。已有 678 人学习下载。对正在基于 Linux 4.9.138 进行嵌入式 WiFi 功能开发或需要参考 RTL8733BU 驱动移植思路的工程师来说,这份源码提供了一套完整的代码结构和模块化目录,便于直接开展驱动适配、内核编译与无线功能调试。
1. USB WiFi 模块 RTL8733BU 在 MC6810 平台:这份适配包能省你多少事
做嵌入式开发的经常会遇到这种状况:主板画好了、系统能起来,USB WiFi 模组插上去却没反应,dmesg 里只有一段 USB 枚举信息,之后就没有下文。手头这块 MC6810 板子跑 Linux 4.9.138 内核,WiFi 模块用的是 RTL8733BU,它和 RTL8733、RTL8731 系列共用同一套驱动源码。这套资料的价值在于,它已经按 4.9.138 这个内核版本做过逐项手工适配,包含驱动源码、固件布局、NVRAM 配置和编译脚本,能把 USB 枚举、固件加载、双频扫描这条路一次走通。适合板卡 BSP 开发、系统集成验证,以及换了主控平台后需要把老 WiFi 模组重新救回来的场景。
2. 内核配置与驱动编译:先让 USB 枚举不再玄学
2.1 为什么 RTL8733BU 不能靠内核自带驱动直接工作
Linux 4.9.138 内核里其实已经有 rtlwifi 目录,mac80211 框架和 cfg80211 也都是现成的,但 RTL8733BU、RTL8733、RTL8731 这一批较新的 USB 芯片默认不在主线支持列表里。内核源码树里只有 rtl8xxxu 这类覆盖老 USB 网卡的驱动,新芯片要靠厂商驱动的 out-of-tree 编译方式加进来。这也是刚接触的人最容易翻车的地方:以为内核开了某个通用 USB WiFi 驱动选项就行,实际芯片完全不识别。
out-of-tree 编译的意思是,把厂商驱动源码放在内核源码目录之外,通过内核提供的 Kbuild 机制编出 .ko,再用 insmod 或拷贝进 rootfs 自动加载。这么做的最大好处是,不用改动内核源码本身,平台 SDK 换内核小版本时驱动目录可以独立维护;坏处是,vermagic 校验和内核版本强相关,4.9.138 环境编出来的 .ko 拿到 4.9.172 的板子上基本不能用。
适配包里通常会有 README 说明它基于哪个驱动基线。MC6810 的 BSP 用 4.9.138 内核,编译这个驱动时要注意内核源码里的scripts/mod/mk_elfconfig和 modpost 工具版本,必须和编内核时用的是同一套,否则后面 modinfo 查 vermagic 会对不上。
2.2 内核侧需要提前确认的配置项
在介入驱动之前,先把内核基础打开。MC6810 的 BSP 通常自带能启动的 defconfig,但“能启动”和“能把 WiFi 跑起来”之间还隔着几个配置开关。下面这几个必须确认是=y而不是=m,否则模块加载顺序会乱,嵌入式场景下不建议把无线协议栈编成模块再依赖自动加载。
| 配置项 | 菜单路径 | 本场景建议 |
|---|---|---|
| CONFIG_USB=y | Device Drivers -> USB support | 必须,否则芯片无法枚举 |
| CONFIG_NET_RADIO=y | Networking -> Wireless | 必须,无线子系统入口 |
| CONFIG_CFG80211=y | Networking -> Wireless | 必须,提供无线配置管理 |
| CONFIG_MAC80211=y | Networking -> Wireless | 必须,驱动依赖的协议栈 |
| CONFIG_WIRELESS_EXT=y | Networking -> Wireless | 建议,兼容旧式无线工具 |
| CONFIG_CRYPTO_AES | Cryptographic API | 建议确认,WPA2 握手需要 AES |
按 4.9.138 的 menuconfig 路径操作一遍:
cd /opt/kernel-4.9.138 make ARCH=arm menuconfig进入 Networking support -> Wireless,把 cfg80211 和 mac80211 都编进内核。脚本化构建的环境可以直接查 .config:
grep -E "CONFIG_USB=|CONFIG_CFG80211=|CONFIG_MAC80211=" /opt/kernel-4.9.138/.config这行命令的含义是快速核对三个关键配置。如果输出是=m,说明还是模块,需要改成=y重新编译内核。我做项目时习惯先把内核编好并固化,再单独编 WiFi 驱动,这样排查问题时只需要盯住驱动目录,不用每次连带内核一起重来。
2.3 用适配包里的 Makefile 交叉编译
驱动适配包顶层结构按芯片厂商标准目录展开,包含 include、hal、os_dep、core、platform 这些子目录,顶层有 Makefile。它支持自动探测内核目录,也支持手动指定。在 MC6810 上我习惯手动指定,把配置写进环境变量:
export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabihf- export KERNELDIR=/opt/kernel-4.9.138 cd /path/to/rtl8733bu_driver make clean make -j8简单说明这几个环境变量的作用:ARCH 告诉 Kbuild 目标体系结构是 ARM,CROSS_COMPILE 指定用哪套交叉工具链,KERNELDIR 指向 4.9.138 的内核源码目录。如果 BSP 用的是 64 位工具链,把前缀换成对应 aarch64 前缀即可,不要混用 32 位和 64 位工具链编 arm 内核模块。
编完后确认模块信息:
file 8733bu.ko modinfo 8733bu.ko | head -20驱动器的主模块名常见是 8733bu.ko,不同适配包命名可能不一样,以顶层 Makefile 的obj-m输出为准。modinfo 里看 vermagic,应该和内核的 vermagic 一致,包括 SMP、preempt、ARM 的 p2v8 这些后缀,缺一项都说明编译环境不匹配。
模块编出来之后放到 rootfs:
mkdir -p /target/rootfs/lib/modules/4.9.138/ cp 8733bu.ko /target/rootfs/lib/modules/4.9.138/ cd /target/rootfs find . -name "*.ko" -exec arm-linux-gnueabihf-strip --strip-debug {} \;strip 这一步的目的是减小镜像体积。注意只剥离 debug 段,不要用--strip-all把符号表全部剥掉,否则模块加载时无法解析依赖关系。目标板空间紧张时,在开发机上做 strip 更合适,不要在已经部署的板子上执行。
2.4 模块加载顺序与可调参数
驱动自动加载时,要保证 usbcore、mac80211、cfg80211 都先于 8733bu 就位。用 modprobe 时系统会通过 modules.dep 处理依赖,但直接 insmod 的场景下顺序写错会报 “Unknown symbol”。适配包一般附带加载脚本,典型内容如下:
#!/bin/sh insmod /lib/modules/4.9.138/cfg80211.ko insmod /lib/modules/4.9.138/mac80211.ko insmod /lib/modules/4.9.138/8733bu.ko rtw_drv_log_level=1rtw_drv_log_level是驱动日志级别参数,0 表示只输出错误,1 带警告,2 起包含调试信息。第一次调试建议开到 1 或 2,稳定后改回 0。日志级别开太高,在低端 CPU 平台上连续打日志反而会拖累网络吞吐。如果驱动在加载时提示参数不存在,说明该适配包用的驱动基线里没有开启CONFIG_DRV_LOG_LEVEL,需要在 Makefile 里打开后重新编译。
3. 固件与 NVRAM:信号差异和认证失败都藏在这些文件里
3.1 芯片固件加载机制与文件放置
RTL8733BU 这类 USB WiFi 芯片内部只有 Boot ROM,完整的 802.11 协议处理固件是主机侧通过 USB 批量传输写进芯片内存的。驱动枚举成功后,会从/lib/firmware/rtlwifi/下读取对应 bin 文件,一次性下载到芯片。固件版本和驱动编译时的预期要匹配,否则 dmesg 里会给出固件版本不匹配的警告,功能上表现为连不上 AP 或扫描列表为空。
驱动适配包里 firmware 目录一般包含这几个文件:rtl8733bu 的 WiFi 固件、蓝牙固件、NVRAM 配置。放到目标板的正确做法是:
mkdir -p /target/rootfs/lib/firmware/rtlwifi/ cp firmware/rtl8733bu_fw.bin /target/rootfs/lib/firmware/rtlwifi/ cp firmware/rtl8733bu_bt.bin /target/rootfs/lib/firmware/rtlwifi/ chmod 644 /target/rootfs/lib/firmware/rtlwifi/*.bin拷贝固件后建议做一次 md5 校验,防止压缩工具或 Windows 换行符把 bin 文件改坏。文件名和内核版本强相关,这个路径里的rtlwifi子目录是驱动内部硬编码的,不能随便改。如果目标板是只读 rootfs,可以把固件放到独立分区再通过符号链接指过来,注意符号链接在 ramfs 里不会自动生效。
驱动请求固件失败时,dmesg 里常见request_firmware failed,但定位时不要只查这一条。先用ls -l /lib/firmware/rtlwifi/确认文件真实存在,再用strings 8733bu.ko | grep rtlwifi确认驱动编译时写入的固件路径。有些适配包会用-DDBG编译选项输出固件名,实际路径和文件名以驱动的字符串表为准。
3.2 NVRAM 参数决定天线配置与信号强度
NVRAM 里存的是射频校准和板级配置,包括 MAC 地址、天线数量、增益、信道规划。同一颗 RTL8733BU 在不同主板上,天线数量和天线走线不一样,直接照搬别人的配置,信号强度可能差一截。驱动读取 NVRAM 的优先顺序是:先查目标板上/lib/firmware/rtlwifi/下的同名配置,再查驱动内置默认值。适配包自带的是公版天线的通用模板,自己做板子时至少要把三个参数核对清楚。
| 参数 | 作用 | 本场景建议 |
|---|---|---|
| ant_num | 天线数量,与 PCB 实际天线走线对应 | 1 或 2 |
| tx_power | 发射功率限制 | 按模块认证值设置,别乱调高 |
| country_code | 决定可用信道和功率上限 | CN / US / EU / 00 |
修改 NVRAM 后要重新加载驱动才会生效:
ifconfig wlan0 down rmmod 8733bu modprobe 8733bu注意 NVRAM 里有一部分和校准数据相关,量产的模组出厂时会烧录到芯片 OTP 区域,驱动加载时会优先读 OTP。如果外部 NVRAM 和 OTP 冲突,以 OTP 为准。碰到信号弱的问题,先把外部 NVRAM 临时改名,让驱动走 OTP 默认值,对比一下差异,再决定要不要覆盖。
还需要注意 Linux 4.9 内核上 crda 的行为。如果 rootfs 里没装 wireless-regdb,即使 NVRAM 写了 CN,实际生效的监管域可能还是 00,5G 信道会被屏蔽。常见做法是在启动脚本里显式执行iw reg set CN,并把 regulatory.bin 装进/lib/crda/目录。这一步不做,后面排查 5G 频段问题时大概率会浪费半天时间。
3.3 蓝牙与 WiFi 共存依赖的固件加载顺序
RTL8733BU 是 WiFi 和蓝牙双模 combo 芯片。WiFi 驱动会顺带把蓝牙的 USB HCI 口初始化,但这个初始化依赖特定时序。加载顺序乱了,蓝牙可能起不来,或者 WiFi 吞吐被蓝牙抢占。适配包里的启动脚本一般把蓝牙固件加载放在 WiFi 固件之后,再通过厂商私有 HCI 命令配置共存参数。
判定共存是否正常,看两处:hciconfig hci0 up能成功,且iw dev wlan0 scan不出现频繁扫描中断。如果先 up 蓝牙再 up WiFi 时出现互相踢掉对方的现象,把加载顺序改成 WiFi 先起来,再启动蓝牙协议栈,稳定性会明显改善。WiFi 驱动里和 HCI 命令相关的实现集中在 hal 目录,不要手动去改里面的 opcode 枚举,除非你已经拿到对应芯片的蓝牙固件 release note。
实际项目中遇到过蓝牙只扫到少量设备、WiFi 同时掉速的情况,原因就是 HCI 固件版本和 WiFi 驱动里 lock 的版本不匹配。这种情况下优先换固件文件,而不是改驱动代码。固件版本号一般写在 bin 文件的头部,可以用hexdump -C查看前 16 字节,和 dmesg 打印的版本号对照。
4. 适配 MC6810 平台的关键改动:电源、端点与 USB 挂起策略
4.1 电源时序与复位脚控制
MC6810 主板给 WiFi 模组供电,很少是简单对接 USB 5V 就完事,实际项目里常见 LDO 加 GPIO 做使能,还有复位脚控制。硬件设计上复位脚极性有高有效也有低有效,驱动里的输出电平和设备树里的 GPIO 配置必须对齐。
先看原理图上 EN 和 RESET 是否独立,再决定时序怎么写。常见做法是设备树里申请 GPIO,然后在驱动加载阶段按顺序拉电平:
&usb1 { status = "okay"; }; &gpio { wifi_en { gpio = <&gpio 88 GPIO_ACTIVE_HIGH>; }; };这是示意性写法,实际落地时驱动会通过 gpiod 接口控制输出,时序建议:先拉高 PWREN,延时 10ms,再拉高 CHIP_EN,再延时 10ms 等待内部稳压器稳定。如果省略这段延时,芯片上电未稳,USB 枚举时表现是第一次获取描述符失败。这种问题很难直接定位,因为 dmesg 里只显示cannot enable. Maybe the USB cable is bad?这类误导性信息。看到这个错误先怀疑电源时序,再查线材和 VBUS。
调试电源时序时,用示波器同时抓两路:GPIO 和模组电源输出。如果 GPIO 拉高后电源有毛刺,说明 LDO 的 EN 脚滤波没做好。板子上空间紧张时,很多人会省掉 EN 脚的 RC 滤波,结果就是低温或快速上下电时 WiFi 间歇性枚举失败,这类问题用软件是很难绕过去的。
4.2 USB 端点带宽与传输模式配置
驱动默认会按芯片标准的端点配置做匹配,但 MC6810 的 USB Host 控制器在某些 SoC 实现上只支持有限的端点速率,需要把驱动中的端点设置与实际设备描述符对齐。在板子上用 lsusb 确认:
lsusb -t lsusb -v | grep -E "bInterfaceClass|bEndpointAddress|wMaxPacketSize"从输出里找到 RTL8733BU 对应的设备描述符,记录各端点的 bEndpointAddress 和 wMaxPacketSize,然后对比驱动源码里初始化 USB 配置的数组。常见差异是在 High-Speed 模式下 isoc 端点的最大包长被缩小,导致上行吞吐掉到 20Mbps 左右。调整方式是修改驱动中控制 isoc 单次传输最大包长的宏:
grep -R "MAX_ISOC" include/ | head找到宏定义后,在合理范围内把值调大,重新编译驱动。这个宏控制单次 isoc 传输的载荷大小,数值越大吞吐越高,但受 SoC USB 控制器预算限制。带宽不足时收包丢包率会明显上升,通过cat /proc/net/dev看 drop 列能判断。我一般会在 512 和 1024 两个档位各试一遍,选择丢包最少的一个,而不是盲目拉到最大。
另外注意 USB 描述符里如果报告的是 Full-Speed 而不是 High-Speed,问题出在 ID 脚检测。RTL8733BU 的 USB 识别依赖 ID 电阻,量产板把 ID 脚悬空或接错,芯片会降级到 Full-Speed。这种问题在驱动里怎么调都没用,必须回到硬件确认 ID 引脚的上下拉电阻。
4.3 关闭 USB Autosuspend,防止睡眠后掉线
MC6810 这类带电源管理的平台,默认会对 USB 设备做 autosuspend。WiFi 网卡在空闲时进入挂起,唤醒后网络栈没有完整恢复,表现是网卡还在,但 ping 不通 AP。有两种处理方式,推荐直接用内核参数禁掉:
usbcore.autosuspend=-1把这一项加到目标板 cmdline 或 U-Boot 的 bootargs,重启后确认:
cat /sys/module/usbcore/parameters/autosuspend_delay_ms输出 -1 表示已经禁用自动挂起。如果不想动内核启动参数,可以在运行时对设备单独关闭:
echo on > /sys/bus/usb/devices/1-1/power/control cat /sys/bus/usb/devices/1-1/power/runtime_status注意设备路径要按实际总线拓扑找到。主板 USB 端口如果是 1-1,Hub 下接的 WiFi 可能是 1-1.2,不要只改根端口。runtime_status 输出 active 而不是 suspended,说明已经生效。
项目里如果既想省电又不希望掉线,可以做带超时的保活机制:每 30 秒发一次空数据包,或者在驱动电源管理回调里把 USB 设备标记为不可挂起。我自己的习惯是嵌入式 WiFi 场景直接关掉 autosuspend,省得后面测试团队报低概率掉线问题。
5. 移植踩坑实录:5 个常见问题的现象、原因与处理
5.1 insmod 报 version magic mismatch
现象:拿着适配包预编译好的 8733bu.ko,往同一内核版本的板子上 insmod,却报version magic '4.9.138 SMP mod_unload ARMv7' should be '4.9.138 SMP preempt mod_unload ARMv7 p2v8'。
原因:vermagic 不只看内核版本号,还包含抢占模式、ARM 的 p2v8 重定位特性等编译选项。不同 SDK 对同一个 4.9.138 编译出来的内核,preempt 状态可能不同。预编译 .ko 在这个场景下最容易栽跟头。
解决:不要试图用 modprobe 的--force绕过版本检查,那是给自己埋雷。回到开发机,用与内核源码相同工具链、相同内核目录重新编译一次,编完用 modinfo 对比 vermagic 关键字段,完全一致后再部署。
5.2 wlan0 起不来或扫描列表为空
现象:ifconfig wlan0 up不报错,但iw dev wlan0 scan永远返回空列表,dmesg 里出现Firmware Request failed之类的信息。
原因:固件文件没放到位,或文件名和驱动预期不一致。驱动在 request_firmware 时用的是它内部硬编码的相对路径,文件不在这条路径下就直接跳过,不会给默认值。
解决:先按驱动二进制里的字符串表找到预期的固件路径,检查 rootfs 下文件是否真实存在,再检查权限是否为 644。如果文件是从 Windows 拷贝进去的,确认 bin 没有被工具转成文本格式,用file命令看一眼就能确认。
5.3 WiFi 正常但蓝牙扫描不到广播
现象:hciconfig hci0 up成功,但扫描列表始终为空,广播包完全抓不到。
原因:RTL8733BU 的蓝牙固件加载有时序要求,WiFi 驱动先上电后,蓝牙固件下载时序被共存初始化打断,HCI 命令被芯片丢弃。
解决:把加载顺序固定为 WiFi 先、蓝牙后,检查驱动里的 coex 开关是否被编译选项关闭。如果适配包默认顺序是正常的,就不要自己改启动脚本里的 insmod 顺序,乱改顺序是典型的自找麻烦。
5.4 睡眠唤醒后 ping 不通,ifconfig 看 wlan0 还在
现象:平台进入 suspend 再唤醒后,WiFi 指示灯正常,但 ping 网关 100% 丢包,必须 rmmod 再 modprobe 一次才能恢复。
原因:USB autosuspend 把 WiFi 设备挂起后,恢复时驱动没有重新走 802.11 关联流程,或者 AP 侧已经把该 client 踢掉而驱动仍保留旧状态。
解决:先按 4.3 节的处理关掉 usbcore autosuspend。如果问题依旧,在驱动源码的 suspend 和 resume 回调里加日志,确认 suspend 时是否进入了 disconnect 分支。特别注意某些 define 被错误打开时,驱动会把挂起当成断开处理。
5.5 5G 频段一个 AP 都搜不到,2.4G 正常
现象:同一块板子,2.4G 热点正常连,5G 列表全空,NVRAM 里country_code已经改成 CN。
原因:5G 受监管域限制,Linux 的 cfg80211 加载监管域数据库失败时会默认禁用所有 5G 频道,而 2.4G 的 1~11 信道不受影响。另一种可能是天线没接好,5G 信号衰减比 2.4G 严重得多,看起来也是搜不到任何热点。
解决:先在启动阶段确认iw reg set CN执行成功,再用iw phy phy0 info查看 Band 2 的可用信道列表。两个都正常后再怀疑天线座虚焊、天线阻抗不匹配。不要一上来就改 NVRAM,那只会掩盖真正的问题。
6. 验证与信号调优:从驱动日志到吞吐实测
6.1 启动后先确认四件事
驱动移植是否真正落地,不看你编译有没有报错,而是看启动日志和无线接口状态。我每次上板都按固定顺序检查四步:
dmesg | grep -i rtl8733 iw dev iw phy phy0 info | head -20 cat /proc/net/dev第一步看芯片是否完成枚举和固件加载,dmesg 里会打印固件版本和 MAC 地址;第二步确认 wlan0 接口存在,如果只有 phy 没有接口,说明驱动没有创建默认 STA 接口,需要手动执行iw phy phy0 interface add wlan0 type managed;第三步看 phy 支持的频段,Band 1 是 2.4G,Band 2 是 5G,缺一个就从 NVRAM 和 regdb 入手;第四步看 drop 字段,接收丢包率持续大于 1% 就要查端点和电源。
这四步走完,驱动层面的状态基本透明了,再往下才谈得上信号调优。
6.2 连上 AP 之后的吞吐与天线调优
连接和吞吐验证我一般用 wpa_supplicant 加 iperf3:
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf iw dev wlan0 link iperf3 -siperf3 在板子上跑 server,电脑端跑 client,测 TCP 吞吐时先连续跑 60 秒,看平均值而不是峰值。达不到预期吞吐时,按优先级排查三件事:
一是天线。RTL8733BU 这类芯片的射频前端对天线净空区很敏感,天线走线要保证 50 欧姆阻抗,净空区不要铺铜。同一块板子,天线位置挪 5mm,吞吐可能差 30%,这不是玄学,是射频仿真里能看到的差异。
二是供电。模组瞬间发射电流比较大,LDO 输出能力不足时会在高功率档位掉吞吐。用示波器抓 3.3V 在打流时的跌落,低于 3.15V 就要加大储能电容或换成 DCDC 供电。
三是 NVRAM 的 tx_power 限幅。量产模组出厂有认证功率值,不要为追求信号强度盲目调高,天线匹配不好时调高功率只会增加误码率,不会提升实际吞吐。
第一次在这个平台调 RTL8733BU 时,我被“看起来一切正常但 5G 扫描为空”折腾了整整两天,最后发现只是 regdb 没装、iw reg set CN没执行。从那以后我每次换平台都会强制按 6.1 的四步清单走一遍,再谈吞吐验证,这个习惯帮我省下了很多重复排障的时间。这份适配包里的编译脚本和 NVRAM 我已经整理好放进了下载区,需要的直接取,希望帮到你。
本文还有配套的精品资源,点击获取