ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

嵌入式Linux下RTL8189FS SDIO WiFi驱动移植实战

嵌入式Linux下RTL8189FS SDIO WiFi驱动移植实战 简介这是一份针对 RTL8189FS 无线网卡的 Linux 驱动资源包适用于嵌入式驱动开发、海思平台移植以及 Android/Linux 系统 Wi-Fi 功能调试等场景面向需要源码级适配的驱动工程师、系统集成人员和有一定 Linux 开发基础的学习者。压缩包共 45 个文件约 15.53MB以 PDF 文档、GZ 源码包和 diff 补丁为主另有 conf 配置、txt 说明和安装脚本等。其中 PDF 涵盖编译安装指南及 SoftAP、Station、P2P、WOW 等功能的快速开始文档GZ 包内含驱动源码、wpa_supplicant/hostapd 及多版本 Android SDKdiff 文件则用于内核补丁集成。包内内容覆盖从内核模块编译到无线工具移植的完整流程同时包含 Android KK/L/O/P 多版本的 SDK 与配置示例可帮助开发者在海思等平台上快速完成 RTL8189FS 的驱动集成、功能调试与性能调优。目前已有 995 人下载学习是嵌入式 Wi-Fi 开发中一套较完整且可直接落地的参考资源。 做嵌入式Linux的应该都有过这种经历从客户或板子厂商手里拿到一个zip包文件名写着一长串比如RTL8189FS_linux_v5.7.9_35795.20191128.zip打开一看全是C源码没有README没有install.sh。第一反应是这东西怎么编译第二反应是它能不能跑我手里的板子。文件名里的含义其实已经很清楚了RTL8189FS一颗Realtek的SDIO WiFi芯片v5.7.9是驱动版本35795.20191128是构建号和发布日期。也就是说这是一份2019年11月底发布的官方Linux驱动源码目标平台就是RTL8189FS这颗芯片。这篇文章我按自己实际移植的经验来讲从芯片定位、驱动包结构、编译前的环境对齐到交叉编译、装载调试再到移植中容易翻车的问题和排查思路尽量把能走的弯路都提前指出来。无论你是拿着它给全志、瑞芯微、三星Exynos之类的方案适配还是只是想在某个开发板上把一个SDIO WiFi模块跑起来都可以直接对着这篇文章操作。1. RTL8189FS是什么芯片这个驱动包到底用在哪些板子上1.1 芯片定位SDIO接口的2.4G WiFi专为嵌入式场景服务RTL8189FS是Realtek面向嵌入式场景推出的一颗SDIO接口WiFi芯片2.4GHz单频802.11n标准1T1R一根天线理论速率150Mbps。它和PC上常见的USB口WiFi芯片RTL8188EUS是亲戚关系协议栈几乎同源但接口从USB换成了SDIO所以完全不能用同一个驱动。常见的卡片式模块长得很小块板上一般是邮票孔或者焊盘形式天线通过IPEX座子外接很多自带WiFi的全志、瑞芯微工控板背面就焊着这么一颗。跟同门师兄RTL8188E系列对比8189FS把USB换成了SDIO硬件上更省一个USB口对很多只有一路USB的SoC来说意义很大比RTL8189FTV略早FTV是它的小改版驱动基本通用。如果你在另一个项目里看到RTL8189ES那是SDIO接口的另一个变体区别主要体现在流片版本和寄存器细节驱动源码不能完全等价替换。1.2 驱动包目录结构Realtek式跨平台套件的典型布局把zip解压后很多人第一次接触Realtek驱动源码时都会懵目录组织不像普通Linux驱动那样是一个简单的module加Kconfig而是分成core/、hal/、os_dep/、include/、platform/等好几个目录看起来特别古老。实际上这是Realtek驱动一贯的跨平台套件写法——同一份源码可以通过makefile里的平台开关面向Windows、Linux、RTOS等不同环境产出不同模块。对Linux来说真正负责操作系统适配的代码集中在os_dep/linux/下面core/是相对通用的协议栈和MLME逻辑hal/才是根据不同芯片型号编写的硬件寄存器操作层。后面编译时需要关心的是根目录的Makefile而不是什么Kconfig。嵌入式的板级BSP里看到这类目录结构基本都是Realtek系驱动比如RTL8189、RTL8723、RTL8821等套路是一样的。Realtek这套老驱动最大的特点就是大而全core目录里从低层的MP/MLME到高层的P2P、WFD、TDLS都有代码即使你没用到这些功能它们也会参与编译。刚开始会觉得啰嗦但这也意味着大部分和WiFi协议有关的东西都能在这套源码里找到参考比很多只做了模块封装的闭源驱动好调。1.3 版本号的真实含义v5.7.9和20191128分别代表什么文件名的v5.7.9是驱动自身版本。Realtek官方发布历史里这个版本在2019年11月28日构建对应的是2019年底的主线树。它适配Linux 4.19、5.4问题不大但直接拿到Linux 5.10/5.15内核上用不打个补丁或者不改代码大概率编译不过。记住这个日期节点很重要后面很多编译报错根源都能追溯到内核API的变化。另外如果你在下载页面还看到过RTL8189FTV_linux_xxx.zip这种包名别以为它换了一个完全不同的芯片。RTL8189FTV是8189FS的改版pin-to-pin兼容功耗特性略好驱动代码也基本公用这套源码。很多方案商会直接拿FS的驱动去跑FTV的模块也能工作。包名末尾的35795是构建号20191128是构建日期对官方来说构建号标志着一次发布日期则说明这个驱动基于哪个时间点的代码。后面如果你看到更新版本比如RTL8189FS_linux_v5.10.x_xxxxx.20220701.zip版本号高适配新内核会更容易。2. 老驱动适配新内核编译前必须对齐的三件事2.1 内核版本与API兼容性边界现实情况是很多人的开发板内核并不是2019年的4.14或4.19而是厂商新一点的5.4、5.10甚至6.1 LTS。而Realtek这种老驱动是自包含的、不走内核Kconfig它内部大量使用了Linux较老的接口比如旧的proc_create、register_netdevice、set_memory_*、内核的signal函数等。随着内核更新这些API一直在调整导致老驱动在不同内核版本上的表现差异很大。我在实际编译中遇到过不少典型问题下面这个表基本代表了这个驱动在不同内核版本上的兼容性边界内核版本常见问题是否容易处理4.19基本直接能编译过简单5.4偶见struct net_device成员变化简单5.10出现kuid_t、proc_create等报错中等5.15proc、cfg80211接口变化频繁较麻烦6.1有较多API不再兼容需要较大改动处理方法一般是两种要么把内核固定到驱动能接受的版本这也是板级BSP最省事的选择要么在驱动代码里加宏判断按内核版本走不同分支。我推荐后者因为一旦把补丁写清楚后面换内核版本可以复用。2.2 Makefile里的平台配置该怎么改Realtek驱动在Makefile里有一堆平台开关如CONFIG_PLATFORM_I386_PC、CONFIG_PLATFORM_ARM_RPI等。默认状态通常是把I386_PC设为y其他平台设为n。拿到交叉编译环境后要做的第一件事就是取消默认平台然后把接近目标平台的配置打开。比如在ARM开发板上就编辑MakefileCONFIG_PLATFORM_I386_PC n CONFIG_PLATFORM_ARM_RPI y如果是arm64平台还要看驱动是否支持AARCH64不支持的可能要自己加一段平台描述然后在对应的平台分支里把交叉编译工具链路径和内核源码路径填对ifeq ($(CONFIG_PLATFORM_ARM_RPI), y) EXTRA_CFLAGS -DCONFIG_LITTLE_ENDIAN ARCH : arm CROSS_COMPILE : arm-linux-gnueabihf- KVER : 4.19.57 KSRC : /home/user/linux-4.19.57 endif这里的KSRC必须指向已经配置过的内核源码也就是至少编译过、生成了Module.symvers和include/config目录的内核源码树否则后续模块链接会报一堆symbol未定义。2.3 设备树与SDIO接口绑定的细节内核侧光有驱动模块不行还得让系统知道这颗WiFi芯片挂在哪个SDIO控制器上、上电顺序是什么、复位脚接到哪个GPIO。这个过程由设备树完成。全志平台常见的写法是在mmc1节点上加上non-removable属性并配置pinctrlmmc1 { pinctrl-names default; pinctrl-0 mmc1_pins_a; bus-width 4; non-removable; status okay; };瑞芯微平台还会单独定义一个sdio_pwrseq节点控制WiFi的电源和复位脚sdio_pwrseq { reset-gpios gpio3 RK_PB3 GPIO_ACTIVE_LOW; status okay; }; sdmmc1 { bus-width 4; sd-uhs-sdr104; status okay; };需要注意的是SDIO WiFi不是插拔的SD卡所以大部分厂商会加non-removable同时保证mmc控制器开启了SDIO支持。判断SDIO是否被枚举成功最直接的办法是开机时看串口日志里有没有“new high speed SDIO card at address 0001”这种打印。如果完全没有这个打印驱动模块再完整也白搭——芯片根本没在总线上被发现。3. 交叉编译实战从修改Makefile到得到8189fs.ko3.1 环境准备与编译命令假设目标系统是32位ARM我用的是arm-linux-gnueabihf-工具链。在最开始强烈建议对Makefile做一次备份然后按照上一节的方式配置平台参数。修改完成后编译命令只需要一行make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- KSRC/home/user/linux-4.19.57首次编译输出会有大量rtw_开头的C文件编译信息最终在当前目录生成8189fs.ko。看到这个ko文件只说明源码编译过了还不能说明它一定能跑。随后必要时可以先用make clean清理中间文件避免之前干扰。如果内核主线里已经编译过驱动直接在目标机上insmod 8189fs.ko可能因为内核配置问题出现版本魔术不匹配或依赖的cfg80211没开。建议先确认内核里CONFIG_CFG80211是什么状态把cfg80211编成模块或编进核心都可以但必须存在否则模块加载时会出现unknown symbol。3.2 构建报错与对策一份可以直接对照的排查表把每种编译报错单独拿出来讲清楚效果最好。下面是我在实际移植中整理过的典型报错对照表报错表现可能原因处理方式unknown type name kuid_t内核5.12后缺少旧头文件结构在驱动头文件里为高版本内核补一个struct kuid_t替身或移植旧头文件struct net_device has no member named destructor内核4.16起移除该字段找到对应代码处加#elif LINUX_VERSION_CODE版本分支multiple definition of rtw_xxx驱动代码默认包含了多个同构文件make clean后重新编译确认没有重复编译undefined reference to cfg80211_xxx内核对cfg80211相关符号导出不足内核开启CONFIG_CFG80211并重新编译后再编译驱动undefined reference to wireless_ext_xxx内核没使能无线扩展开启CONFIG_WIRELESS_EXT比如kuid_t这种报错本质是驱动作者在2019年写代码时没有预料到内核很快改掉了内部类型。可以在驱动中找一个公共头文件像下面这样加一段版本兼容代码#if LINUX_VERSION_CODE KERNEL_VERSION(5, 12, 0) typedef struct kuid_t { uid_t val; } kuid_t; #endif不过这种做法只能让编译通过真正能不能运行还得看驱动是否还有其它隐式依赖所以更保险的思路是尽量选择与驱动同年代的内核然后单独打少量兼容补丁。3.3 固件文件该放到哪里RTL8189FS是softmac芯片硬件逻辑需要加载一块固件。驱动代码里会通过request_firmware请求名为rtl8189fs.bin的文件而这个文件通常就在驱动包的fw目录下。把它复制到目标系统的/lib/firmware/下即可有些版本的源码可能会从/lib/firmware/rtlwifi/读取保险起见两个位置都放一份。如果你在dmesg里看到类似rtl8189fs: Direct firmware load for rtl8189fs.bin failed with status -2就是固件路径不对或者文件缺失装完固件重新装载一次模块即可。这条错误我经常遇到很多人把源码包里的bin文件漏拷导致驱动一直加载不起来。4. 从insmod到连上路由器模块装载与无线调试全流程4.1 装载模块与启动日志解读把编译好的8189fs.ko和固件文件通过nfs或者scp拷到目标板执行insmod 8189fs.ko成功的情况下dmesg里会出现大量驱动初始化日志比如“rtw_drv_init”、芯片ID识别信息、MAC地址等。随后用ifconfig -a应该能看到wlan0接口。看不到wlan0基本可以判断是SDIO枚举没成功或者固件加载失败回到前面排查。装载时要留意依赖顺序。如果cfg80211是模块方式存在8189fs.ko在加载时会自动拉依赖但前提是内核模块目录里的modules.dep是正确的。嵌入式板子如果手工放内核模块忘了跑depmod就可能在insmod时报unknown symbol或自动依赖缺失这个问题很常见但容易被忽略。4.2 STA模式扫描热点与连接路由器wlan0出现以后先做一次扫描确认芯片射频工作正常ifconfig wlan0 up iwlist wlan0 scan | grep -E ESSID|Encryption如果能找到周边热点说明射频、MAC层、协议栈基本正常。然后配置wpa_supplicant连接路由器ctrl_interface/var/run/wpa_supplicant network{ ssidMyWiFi pskmyPassw0rd key_mgmtWPA-PSK }后台启动连接进程并拿DHCP地址wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf -D nl80211 udhcpc -i wlan0ping一下路由器IP通了就说明STA模式正常。这一步做一次就知道驱动是否真正能进入正常收发状态。4.3 AP模式用手机连上开发板验证很多项目需要把设备作为热点比如配网阶段。RTL8189FS支持AP模式用hostapd加dnsmasq就能实现。hostapd配置如下interfacewlan0 drivernl80211 ssidTestAP hw_modeg channel6 wpa2 wpa_passphrase12345678 rsn_pairwiseCCMP启动后手机会搜到TestAP能连上就说明硬件支持AP模式。不过要注意嵌入式设备做AP时吞吐量和并发连接数都很有限别拿它跟路由器比。如果hostapd启动失败先看内核是否配置了CONFIG_NF_NAT、CONFIG_NETFILTER_XT_TARGET_MASQUERADE这些跟转发有关的选项虽然AP本身不一定需要NAT但在做完整配网场景时缺了它们会很难排查。5. 移植路上最容易翻车的几个坑与排查思路5.1 信号弱、吞吐量低天线和mmc模式优先排查最常见的原因是天线没有接好或用了干扰严重的排线。RTL8189FS模块上一根IPEX天线和板载蓝牙、SD卡等共用走线时信号很容易劣化。排除硬件问题后可以试着把设备树里mmc控制器的sd-uhs-sdr104等高速模式关掉使用默认的high speed模式。如果还是不行把mmc控制器频率上限降下来有时能立刻改善吞吐。5.2 MAC地址漂移和不可用一些模块的efuse里没有写入MAC地址驱动起来后wlan0会得到一个全F或随机生成的MAC。临时处理方法ifconfig wlan0 down ifconfig wlan0 hw ether 00:11:22:33:44:55 ifconfig wlan0 up如果希望开机自动设置可以写一个脚本或systemd服务。另外有些批次模块的efuse也会因为静电损坏表现为通电后偶尔识别不到WiFi这种硬件问题只能换模块。5.3 运行时不稳定、掉线和mmc error的排查顺序感觉驱动跑起来了但偶尔掉线、ping不通dmesg里不断出现mmc1相关的error或者timeout。这时一般不是WiFi驱动本身的问题而是SDIO总线的电源纹波、时钟质量或SoC的SDIO控制器驱动配置出了问题。排查顺序我一般这样来先查供电WiFi模块的VIO、VDD是否稳定有没有用示波器看纹波再查mmc信号线走线长度和串阻然后看内核里mmc控制器的时钟频率是否太高最后怀疑驱动里的电源管理比如CONFIG_POWER_SAVING没有关导致进入休眠后恢复异常把驱动里省电相关的配置关掉在有些板子上会稳定不少。具体在Makefile里把CONFIG_POWER_SAVING设为n重新编译再实测对比。5.4 换个思路新内核直接找社区适配分支如果你用的是比较新的内核版本Realtek官方老驱动确实麻烦那还有另一条路可走找社区维护的分支比如rtl8189fs-esd或者各厂商在GitHub上的镜像。这些通常是对官方驱动做了新内核适配的拿来直接改Makefile平台参数即可。当然其中部分分支对芯片型号区分不严格拿到后最好确认p2p、tdls等相关代码是否被注释掉。提示不管用哪份源码编译之前都把Makefile通读一遍特别是平台开关、电源管理、调试开关这几个部分。尽量关闭调试打印减少驱动在部署时的性能和日志开销。移植这类Realtek老驱动真正的难点往往不在驱动本身而在它和内核版本、设备树、供电设计三者的配合。驱动代码能本文还有配套的精品资源点击获取
返回列表