
简介面向嵌入式开发人员的USB WiFi模块驱动资源包主要针对RTL8733BU并兼容RTL8733与RTL8731芯片已适配mc6810平台及Linux 4.9.138内核。包内含1098个文件以485个h头文件、221个c驱动源文件、188个o编译中间文件为主并附带mk/makefile、ko驱动模块、cmd编译脚本以及wlan0dhcp、runwpa等网络配置脚本压缩包整体约11.06MB。从内容预览可见核心驱动源码包括hal8733b_fw.c、rtw_mlme_ext.c、ioctl_cfg80211.c、hal_btcoex.c等便于开发者理解USB WiFi模块在Linux下的驱动实现与适配过程。已有671人学习适合需要为嵌入式Linux设备添加无线网络功能或研究RTL8733系列驱动移植的技术人员。驱动源码与编译配置体系较为完整可辅助快速完成模块集成、内核编译及网络连通调试。 做嵌入式Linux平台上的无线功能最绕不开的一件事就是USB WiFi模块的驱动适配。我最近在mc6810平台上做项目内核固定在Linux 4.9.138需要把一个USB WiFi模块跑起来选型最终定了Realtek的rtl8733bu。这个芯片的官方驱动源码同时覆盖了rtl8733和rtl8731两个系列一套代码可以兼容好几个硬件版本对于量产备料和后续换型都很方便。整个适配过程从交叉编译到模块加载再到wlan0出来并成功联网中间踩了不少坑。这篇文章我就把整个流程和排查经验整理出来给准备在老内核上做USB WiFi模块开发的同学一个参考。这篇内容适合三类人看一是正在嵌入式ARM平台上移植Realtek USB WiFi驱动的工程师二是手里有mc6810或类似平台、想把无线功能快速跑通的项目开发者三是刚开始接触Linux无线子系统、想弄明白驱动源码结构、视频和编译配置关系的同学。1. 项目概述在mc6810上把rtl8733bu跑起来的整体思路1.1 为什么选rtl8733bu这个USB WiFi模块项目需求很简单板子上预留了USB Host口需要一个能稳定跑STA模式连接路由器上网的无线模块。刚开始我在SDIO接口WiFi和USB接口WiFi之间纠结后来考虑到USB接口调试方便、插拔替换容易而且平台侧USB Host驱动已经很成熟就把方向定在了USB WiFi上。rtl8733bu是Realtek面向USB接口的2.4G单频WiFi芯片支持802.11b/g/nUSB 2.0接口就能满足带宽需求。这颗芯片在市面上有不少现成模块散热和天线设计也比较成熟。最关键的是Realtek官方驱动源码包通常会把这颗芯片和同家族的rtl8733、rtl8731统一放到一套代码里管理编译一次就能识别多个USB设备ID。这意味着后续即使因为供货原因换了不同封装的同系列模块驱动也不用重新移植这是选型时很加分的点。另外要说明一点Realtek这颗芯片的官方驱动是自带协议栈的它通过内核的cfg80211框架向上注册无线接口并不依赖mac80211。这个特点在老内核上其实是优势因为mac80211的API版本和内核版本强绑定驱动跟着内核版本走容易出问题而自带协议栈的驱动只要cfg80211接口稳定跨内核版本适配就相对轻松。1.2 mc6810平台的约束和前期确认项mc6810平台的内核是Linux 4.9.138。这个内核版本不算新但也绝对不算老刚好处于cfg80211已经完全替代WEXT、但某些API和最新内核还有差异的阶段。Realtek官方驱动在开发时往往以较新内核为基准拿到4.9内核上编译最常见的报错就是cfg80211结构体成员对不上、函数签名不一样这一类。所以在动手之前我先把平台侧的几个关键条件确认了一遍USB Host控制器驱动是否已经正常插上U盘能不能识别这决定了WiFi模块枚举是否顺畅。内核是否已经打开CFG80211支持如果没开驱动编了也注册不了无线接口。板子上有没有现成的2.4G天线接口天线没接好会带来扫描不到信号、吞吐量偏低等一堆假故障。文件系统里有没有/lib/firmware目录固件加载路径是否正常。这些确认完才进入正式的驱动移植流程。很多问题其实不是出在驱动本身而是平台侧的基础环境没准备好。2. 动手之前驱动源码结构和3个必须改的配置点2.1 看懂Realtek驱动源码的目录逻辑Realtek官方驱动包解压后往往是一大包代码里面按芯片系列分成不同目录。以rtl8733bu为例你需要找到对应的芯片型号目录比如rtl8733B核心代码在下面几个子目录里hal硬件抽象层包括RF、MAC、PHY的初始化寄存器配置这部分基本不用动。os_dep操作系统依赖层是驱动和内核对接的部分也是适配时改动最多的地方。platform平台相关配置部分驱动版本会在这里面放不同开发板的配置脚本。main驱动主逻辑包括协议栈核心实现。驱动整体是以内核模块方式编译的不要尝试把整个源码包塞进内核树编译而是单独作为一个外部模块通过Makefile指定内核源码路径来构建。这样可以保持内核源码干净也方便后续换内核版本时重新编译驱动。这套目录结构本身就像一个分层框架你在适配时要记住一个原则能不动hal层就不动重点在os_dep和Makefile里做平台适配。驱动跑不起来九成问题出在编译配置和设备ID匹配上而不是芯片寄存器配置上。2.2 三个必须确认的配置点第一个是Makefile里的平台宏和工具链路径。Realtek驱动通过Makefile里的CONFIG_PLATFORM_xxx开关来选择不同的平台配置。默认可能是x86平台必须改成ARM平台并指定对应的交叉编译工具链、内核版本号和内核源码路径。我的配置大概是这样的CONFIG_PLATFORM_IOT_PC n CONFIG_PLATFORM_ARM_MC6810 y ifeq ($(CONFIG_PLATFORM_ARM_MC6810), y) EXTRA_CFLAGS -DCONFIG_LITTLE_ENDIAN ARCH : arm64 CROSS_COMPILE : /opt/toolchains/aarch64-linux-gnu/bin/aarch64-linux-gnu- KVER : 4.9.138 KSRC : /opt/linux-4.9.138 endif注意4.9内核时代模块编译的附加编译参数一般用EXTRA_CFLAGS新内核内核才推荐用ccflags-y。如果你看到一篇教程让你用ccflags-y在4.9内核上不一定有效。这条细节就够劝退一拨人了。第二个是芯片型号宏和USB VID/PID匹配表。在驱动源码中搜索芯片目录下的Makefile或autoconf.h确认CONFIG_RTL8733B这个宏已经被打开。然后去os_dep/usb_intf.c里找USB设备ID表把模块铭牌上或lsusb看到的VID/PID填进去。rtl8733bu的默认ID通常是0bda:b733但不同厂家做的模块可能会改ID量产时一定要以实物为准。第三个是cfg80211和WEXT的选择。4.9内核上建议直接用CFG80211把驱动配置里的CONFIG_CFG80211设为y同时把CONFIG_WIRELESS_EXT关掉。WEXT在后续内核里已经被标记为弃用而且Realtek驱动的WEXT路径更新更少没必要在这上面折腾。2.3 内核侧需要提前开启的配置驱动要正常工作内核侧也有几个配置项要打开。我整理了一个核对表内核配置项建议值用途说明CONFIG_USByUSB核心支持CONFIG_USB_XHCI_HCD / CONFIG_USB_EHCI_HCDyUSB Host控制器驱动按平台实际情况选择CONFIG_CFG80211yWiFi配置管理框架驱动注册无线接口的基础CONFIG_WIRELESS_EXTn老接口不建议使用CONFIG_FW_LOADERy固件加载机制驱动运行必须要固件CONFIG_NETDEVICESy网络设备支持CONFIG_WLANy无线局域网设备分类这里要注意不少教程会让你开CONFIG_MAC80211但对于rtl8733bu这类自带协议栈的Realtek驱动来说它并不依赖mac80211开不开都不影响。真正决定驱动能否注册无线接口的是CFG80211。3. 交叉编译与部署从make到wlan0出现的完整过程3.1 准备编译环境和内核源码整个移植过程中最重要的一条铁律是编译驱动用的内核源码路径必须和板子上实际运行内核的版本严格一致。否则即使编译通过insmod的时候也会报一堆Unknown symbol。我建议在编译服务器上把内核源码解压到固定路径比如/opt/linux-4.9.138然后先编译一次内核至少执行过make modules_prepare确保内核源码目录里有完整的头文件、Module.symvers和编译配置文件。如果你拿到的内核源码是没编译过的驱动模块编译时会连linux/version.h都找不到。交叉编译工具链也要确认好。现在很多平台已经是arm64架构工具链前缀通常是aarch64-linux-gnu-。在Makefile里指定好这个前缀后驱动编译时就会自动使用交叉编译器。3.2 修改Makefile并执行编译按前面说的修改完Makefile后执行make clean make编译过程正常情况下会持续几分钟期间会输出大量编译信息。看到最后生成了rtl8733bu.ko这个文件第一步就算成功了。你可以用modinfo查看一下模块信息确认没有明显的编译错误modinfo ./rtl8733bu.ko如果编译卡住或报错不要急着一行行看错误先用make clean清掉之前的中间文件再重新编因为Realtek驱动的Makefile有时会缓存一些过时的.o文件导致改了配置不生效。3.3 拷贝驱动和固件到目标板编译产物是rtl8733bu.ko但驱动运行还缺一个固件文件。Realtek驱动的固件在源码包里的firmware目录下rtl8733bu对应的固件文件名称因驱动版本而异一般类似rtl8733bu_fw.bin。把这个文件拷贝到板子文件系统的/lib/firmware/rtlwifi/目录下驱动加载时会从这个路径读取固件。具体拷贝命令视你的开发板传输方式而定NFS挂载、adb push、scp都可以。核心是确保目标板文件系统里有这两个文件/root/rtl8733bu.ko /lib/firmware/rtlwifi/rtl8733bu_fw.bin3.4 加载驱动并确认wlan0出现在目标板终端上执行insmod cfg80211.ko # 如果cfg80211编成了模块需要先加载 insmod rtl8733bu.ko dmesg | tail -n 50正常的情况下dmesg里会出现类似下面的关键日志usb 1-1: new high-speed USB device number 3 using xhci-hcd rtl8733bu: Chip Version: 00H rtl8733bu: Firmware Version: ... rtl8733bu: wlan0: IEEE 802.11b/g/n然后执行ifconfig -a能看到wlan0这个网络接口就说明驱动加载成功了。如果看不到wlan0优先检查两个地方模块是否加载成功lsmod | grep rtl以及USB设备ID是否被驱动识别lsusb。这里有个小技巧如果使用insmod加载时报“unknown symbol”说明有依赖模块没先加载用modprobe替代insmod会自动处理依赖关系。3.5 快速联网验证整个链路wlan0只是底层驱动注册成功真正要验证整个链路通没通还得连上路由器。我在目标板上放了一个wpa_supplicant的配置文件ctrl_interface/var/run/wpa_supplicant network{ ssidMyAP psk12345678 key_mgmtWPA-PSK }然后依次执行wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf -D nl80211 udhcpc -i wlan0 ping -I wlan0 192.168.1.1能ping通网关说明USB枚举、驱动加载、固件运行、无线连接、IP获取这整条链路全部OK。到了这一步rtl8733bu在mc6810平台上的移植工作就算基本完成了。4. 问题排查实录加载失败、扫描不到、网速低怎么办4.1 编译报错找不到version.h或cfg80211类型不匹配这两个问题是老内核适配里出现频率最高的。找不到linux/version.h基本可以断定内核源码没有先执行过编译准备步骤。解决方法是先进入内核源码目录执行make modules_prepare如果还不行就完整编译一次内核。cfg80211相关的类型不匹配比如struct cfg80211_ops has no member named ...说明你的驱动版本面向的新内核和4.9.138的API有差异。Realtek驱动在源码里通常已经做了内核版本宏适配核心思路就是根据LINUX_VERSION_CODE来判断在旧内核上走旧代码分支。你需要检查驱动里的#if (LINUX_VERSION_CODE KERNEL_VERSION(4, 10, 0))这类条件编译确认4.9.138对应的分支存在。如果确实没有适配你内核版本的代码就需要手动把新API替换成旧API工作量比较大这种情况建议直接换一个更老的驱动版本。4.2 模块加载失败Unknown symbolinsmod时报Unknown symbol最常见的原因是编译驱动时用的内核源码路径和板子上运行的内核不是同一份。比如板子跑的内核是4.9.138但Makefile里的KSRC指着另一个版本的目录驱动就会引用错误的内核符号。排查方法很简单在板子上执行uname -r拿到准确的版本号回到编译服务器确认KSRC路径下的源码确实是这个版本。另外还要确认内核是否真的编译过cfg80211模块如果没有即使符号表匹配驱动也同样会加载失败需要先在板子上把cfg80211模块加载起来。4.3 lsusb能看到设备但没有wlan0这种情况最让人抓狂USB层面已经枚举出设备了但网络接口就是不出来。我的排查顺序是先dmesg | grep rtl看驱动日志。如果驱动提示固件加载失败优先确认固件文件的路径和文件名是否正确。Realtek驱动对固件路径敏感/lib/firmware/rtlwifi/目录下面缺文件或文件名对不上都会静默失败。如果固件没问题再查VID/PID。用lsusb查看实际设备ID然后和驱动源码里的USB设备ID表比对。很多小厂模块会写自己的PID导致官方驱动认不出。这时候在usb_intf.c的ID表里加上你自己的PID重新编译即可。还有一次排查经历是USB接口被其他驱动占用了比如板子上的4G模块和WiFi模块用同一个USB Host控制器导致WiFi模块枚举失败。这种问题在dmesg里通常有USB注册失败的痕迹先把其他设备断开再测试就能定位。这些常见问题我整理成了速查表现象可能原因快速解决办法编译报version.h缺失内核未modules_prepare进入内核目录执行make modules_prepare编译报cfg80211成员不存在驱动版本过新不兼容4.9查看版本宏分支是否匹配4.9.xinsmod报Unknown symbolKSRC路径和内核实版本不一致uname -r核对内核版本和源码路径lsusb有设备但无wlan0VID/PID未在驱动ID表中lsusb看实际ID并添加到usb_intf.c固件加载失败固件缺失或路径不对确认/lib/firmware/rtlwifi/下文件名扫描不到任何WiFi天线没接或省电模式检查天线连接并关闭power save4.4 连上了但吞吐量偏低最后联网成功后我发现iperf测速结果比预期低不少。排查发现是USB枚举跑在了Full-Speed而不是High-Speed。用lsusb -t查看设备速度看到12M就说明USB工作在Full-Speed正常应该是480M。这个问题往往出在USB线材质量差或板子USB Host控制器配置上换一根好一点USB线就能解决。另外一个影响吞吐量的因素是2.4G频段的干扰。板子附近如果有大量WiFi设备或者USB 3.0设备2.4G信号很容易被干扰。我建议做吞吐量测试时先把AP和板子放在同一个房间排除远距离和穿墙因素再逐步排查。还有一个很实用的调优点就是用iw dev wlan0 set power_save off关闭WiFi省电模式。省电模式在手机上是省电利器但在嵌入式设备上做持续数据传输时会明显拉低吞吐量关掉之后iperf成绩通常会有明显提升。到这里rtl8733bu在mc6810平台上的适配工作就算完整走了一遍。回头来看整个移植过程最核心的经验有三条第一驱动移植之前一定先把内核环境核对清楚版本不一致引起的诡异问题最浪费时间第二Realtek的Makefile配置直接决定了编译是否成功平台宏、工具链、内核路径这三点改完就成功了一大半第三遇到问题先看dmesg和lsusb用这两条命令定位比瞎猜快得多。希望这篇实操记录能帮你在自己的平台上少踩几个坑顺利把USB WiFi模块跑起来。本文还有配套的精品资源点击获取