RTL8188FU/FTV USB网卡驱动编译与DKMS避坑

发布时间:2026/10/24 6:48:57
RTL8188FU/FTV USB网卡驱动编译与DKMS避坑

简介:面向 Linux 与 Android 平台的 Realtek RTL8188FU、RTL8188FTV USB 无线网卡驱动合集,适合具备一定内核基础、从事嵌入式驱动开发与系统移植的工程人员,用于排查无线网卡编译、加载、连接及兼容性问题。压缩包共五十六个文件、约二十四点三二 MB,内含驱动源码包、覆盖安卓四点二至八点零各版本的无线网络开发参考代码、认证与热点工具、配置文件、内核补丁以及安装脚本,并附多份技术说明文档。目前已有九千六百零三人学习下载。读者可据此完成驱动编译安装与模块加载,参考各版本代码开展安卓平台移植,了解站点模式、软热点、桥接、点对点投屏、省电、规范支持和调试日志等功能的配置方法,也能借助版本说明与快速入门资料定位差异、减少反复试错。

1. 一块十几块钱的 USB 网卡插上没反应:RTL8188FU/FTV 驱动到底补了哪块短板

电商平台搜 USB WIFI REALTE 8188FT,出来的大多是十几块钱的 2.4GHz 单频小网卡,拆开看芯片基本是 RTL8188FU 或它的 TV 变体 RTL8188FTV:USB 2.0 接口、802.11n、标称 150Mbps、只有 2.4G。插到工控机、树莓派或者安卓盒子上,lsusb能看见0bda:f179、0bda:c820、0bda:a729这类 ID,ip link里却空荡荡。内核自带的rtl8xxxu对这两个型号支持时有时无,较新的内核分支干脆不认,dmesg里连个 wlan 设备名都不给。这份驱动源码包补的就是这块:一整套 C 代码,Linux 与 Android 两套编译入口,编出来的8188fu.ko直接insmod就能起接口。适合手上有几台设备要批量铺无线链路、又不想为每台机器换一张"Linux 免驱"卡的人。

2. 拆开源码包:RTL8188FU 与 RTL8188FTV 共用一套 802.11 状态机

2.1 目录骨架与两个芯片变体的宏开关

拿到包先别急着make,用tree -L 2扫一遍,心里有张地图比什么都强。这类原厂驱动包的目录组织高度一致,看懂了这一份,后面遇到同系列的 8188FS、8192FU 迁移成本很低。

路径作用实际改动频率
os_dep/linux/usb_intf.cUSB 探测、VID/PID 表、电源管理回调、probe 入口高
os_dep/linux/ioctl_cfg80211.ccfg80211_ops 注册,扫描/连接/密钥下发中
os_dep/linux/ioctl_linux.cwext 私有 ioctl,老工具链靠它低
os_dep/linux/xmit_linux.cskb 收发、netdev_ops、队列映射低
os_dep/android/安卓平台适配、框架层对接中
core/rtw_*.c802.11 管理帧、扫描、关联、加密、AP 模式低
hal/、halrf/PHY 参数、射频校准、功率表、信道表低
include/autoconf.h编译期总开关,全篇最关键的一个头文件高
firmware/rtl8188fufw.bin运行时由request_firmware拉起的固件不改

RTL8188FU 和 RTL8188FTV 在这份源码里不是两套代码。二者共用同一个core与hal,差异集中在 USB PID 表、部分射频功率参数表和电源管理的默认值上,靠autoconf.h里的CONFIG_RTL8188F宏统一打开。这意味着你不需要为两个型号维护两份工程,只要把 PID 表补齐、把 RF 参数按型号选对,一个.ko能同时覆盖两种料。我一般会在usb_intf.c的 ID 表上方加一行注释,把现场见过的 PID 都记下来,下次换批次不用重新查。

2.2 autoconf.h 与 Makefile:编译期真正影响行为的七个开关

autoconf.h是这套驱动的中枢,里面几十个CONFIG_宏,但真正会咬人的就那几个。新手最容易犯的错是把所有宏都打开图省事,结果编出来的模块又大又不稳,还找不到原因。

/* include/autoconf.h 节选,按需开启,不要全开 */ #define CONFIG_RTL8188F /* 芯片型号,8188FU/FTV 共用 */ #define CONFIG_USB_HCI /* USB 总线接口 */ #define CONFIG_CFG80211 /* 提供 nl80211 接口,iw/hostapd 要用 */ #define CONFIG_WEXT_PRIV /* 保留 wext,老工具链兜底 */ /* #define CONFIG_POWER_SAVING */ /* 默认开,会掉速、会断流,桌面端建议关 */ #define CONFIG_LPS_32K /* 低功耗睡眠,和 POWER_SAVING 二选一 */ /* #define CONFIG_MP_INCLUDED */ /* 产测模式,量产固件必须关掉 */ /* #define CONFIG_CONCURRENT_MODE */ /* 双接口并发,单网卡场景开了纯属浪费内存 */ #define CONFIG_RFKILL /* 有硬件 rfkill 开关的机器要开 */

每个宏背后都是实打实的行为差异。CONFIG_POWER_SAVING打开后,空载时驱动会把射频打进休眠,省电是真省,但配合某些 USB HUB 会出现"闲置三分钟必掉线"的玄学问题,桌面和工控场景我一般直接注释掉。CONFIG_MP_INCLUDED会把产测命令通道编进去,能通过 ioctl 直接发裸包改功率,产线用得上,出货固件留着就是个后门。CONFIG_CFG80211关掉的话,iw直接报nl80211 not found,只有iwconfig还能用,新系统上基本等于残废。

Makefile 那边负责的是平台分支,原理是给不同目标板预设ARCH、CROSS_COMPILE、KSRC三个变量。典型的写法长这样:

ifeq ($(CONFIG_PLATFORM_I386_PC), y) EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ARCH := x86_64 CROSS_COMPILE := KSRC := /lib/modules/$(shell uname -r)/build endif ifeq ($(CONFIG_PLATFORM_ARM_RPI), y) EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_IOCTL_CFG80211 ARCH := arm CROSS_COMPILE := arm-linux-gnueabihf- KSRC := /lib/modules/$(shell uname -r)/build endif

KSRC指向的是"已经配置并编译过一次"的内核源码树或头文件包,不是随便一个/usr/src/linux目录。判断标准很简单:目录下同时存在.config、Module.symvers、include/generated/autoconf.h三个文件。缺Module.symvers会报符号未定义,缺.config会按默认配置编,产出的 vermagic 和你正在跑的内核对不上,insmod时一句version magic should be就把你挡在门外。

2.3 它不走 mac80211:自带全栈对编译和抓包意味着什么

这一点决定了后面所有的排错思路,必须说清楚。这份驱动没有依赖内核的mac80211软栈,它自己实现了 802.11 状态机,直接注册net_device,再挂一组自己的cfg80211_ops。业内的说法叫 fullmac 风格,虽然这颗芯片本身是 softmac 硬件,但驱动把 MAC 层的大部分活儿揽到了自己身上。

好处在 Android 上体现得最明显。很多设备内核根本没编mac80211,或者只把它作为 GKI 的受限符号导出,这时候任何依赖mac80211的驱动都加载不了,而这份驱动只要内核有cfg80211就能跑。坏处有两个:一是hostapd的 nl80211 路径只实现了一部分,开 AP 模式经常要配驱动自带的补丁版hostapd,标准版可能卡在nl80211: Could not configure driver mode;二是抓包不能靠mac80211的 monitor 接口,得用驱动自己的 monitor 模式,iw dev wlan0 interface add mon0 type monitor有时候不生效,得改源码里的CONFIG_MONITOR_MODE再重编。

理解了这层架构,你就不会在modprobe mac80211上浪费时间,也不会指望它和iwlwifi那种驱动一样听话。它就是一套自带生态的东西,能用、能连、能跑吞吐,但边界很清楚。

3. Linux 侧编译实录:从 make 到 iw dev 里冒出 wlan1

3.1 依赖装载与内核头路径自检

先解决"能编"的问题。桌面发行版上标准动作就三条命令,装编译链、装当前内核的头文件、确认build软链指对了地方。

sudo apt update sudo apt install -y build-essential bc kmod git "linux-headers-$(uname -r)" # 确认 build 软链和关键文件都在 ls -l /lib/modules/$(uname -r)/build ls /lib/modules/$(uname -r)/build/{.config,Module.symvers}

linux-headers-$(uname -r)这个包名在 Debian/Ubuntu 系成立,Fedora 系对应kernel-devel,Arch 系是linux-headers,名字不同但本质一样:一份预配置好的头文件树加上Module.symvers。如果第二条ls报No such file,说明你装的头和跑的内核不是同一个版本,或者内核是自己编的但没执行make modules_install。自己编内核的场景要特别注意,Module.symvers必须来自那次编译的输出目录,不能从别处拷,否则符号 CRC 对不上,加载时报disagrees about version of symbol。

树莓派这类 ARM 板子上还有一个坑:官方内核的build软链指向/usr/src/linux-headers-xxx-v8+,但这棵树的.config里CONFIG_CFG80211可能是模块而非内建,insmod前得先modprobe cfg80211,不然驱动加载时会报一堆unknown symbol in module,新手很容易误判成代码问题。

3.2 改平台宏、指定 KSRC,把 8188fu.ko 编出来

平台宏和KSRC都改对之后,编译本身很快,几十秒的事。x86 本地编译最省事,因为uname -r直接给出了正确的内核版本。

cd rtl8188fu-driver # 只留 x86 平台分支,其余关掉,避免多个 KSRC 互相覆盖 sed -i 's/^CONFIG_PLATFORM_I386_PC = y/CONFIG_PLATFORM_I386_PC = y/' Makefile sed -i 's|^KSRC :=.*|KSRC := /lib/modules/$(shell uname -r)/build|' Makefile make clean make -j"$(nproc)" 2>&1 | tee build.log ls -lh 8188fu.ko

tee build.log这个习惯救过我很多次,编译报错动辄几百行,滚屏之后想回头找第一条 error 基本靠翻日志。make clean也别省,这套驱动的依赖关系写得不算严谨,改了autoconf.h不 clean 直接编,经常出现宏没生效的假象。

交叉编译换三个变量就行,以树莓派 32 位系统为例:

make clean make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \ KSRC=/lib/modules/$(uname -r)/build \ -j"$(nproc)" # 验证产物架构,别把 aarch64 的 ko 拷到 armhf 机器上 file 8188fu.ko

ARCH要和目标内核的架构严格一致,CROSS_COMPILE末尾那个短横线不能丢,丢了会拼出arm-linux-gnueabihf-gcc变成arm-linux-gnueubihfgcc这种不存在的名字。KSRC如果是在 x86 主机上给树莓派编,要指向树莓派的内核头文件树,不能指本机的,这一步搞错了,file一看架构就露馅。

3.3 固件落位、depmod 与 insmod 后的第一轮 dmesg 检查

模块编出来不等于能跑,固件没放对位置,驱动照样起不来或者起来后扫不到任何 AP。

# 固件有两个常见搜索路径,两个都放一份最稳妥 sudo cp firmware/rtl8188fufw.bin /lib/firmware/ sudo cp firmware/rtl8188fufw.bin /lib/firmware/rtlwifi/ 2>/dev/null || true sudo depmod -a sudo modprobe cfg80211 sudo insmod ./8188fu.ko dmesg | tail -40

depmod -a的作用是刷新模块依赖索引,只有你打算用modprobe 8188fu而不是insmod时才必须,但养成习惯没坏处。真正要看的是dmesg尾部那几十行,正常的加载序列会依次出现 USB 设备枚举、厂商与产品 ID、固件加载成功、wlan0或wlan1注册。如果只看到枚举没有注册,八成是 PID 没匹配上;如果看到request_firmware failed,就是固件路径问题;如果看到rtw_cfg80211_init_wiphy之类的失败,那多半是cfg80211没提前加载。

ip link里出现新接口后,先别急着连网,iw dev看一遍能力集:

ip link show iw dev iw phy | grep -A5 "Supported interface modes"

确认managed模式在列,Supported bands里只有 2.4GHz,信道 1 到 13,这就对上了。如果iw phy报No such device,说明cfg80211注册失败,回头翻dmesg。

3.4 用 wpa_supplicant 打通一条链路并量化吞吐

验证驱动能不能用,最快的办法是拿wpa_supplicant连一个已知能用的 AP,别一上来就折腾 AP 模式。

cat > /tmp/wpa-2g.conf <<'EOF' ctrl_interface=/var/run/wpa_supplicant network={ ssid="lab-2g" psk="12345678" key_mgmt=WPA-PSK proto=RSN pairwise=CCMP scan_ssid=1 } EOF sudo ip link set wlan0 up sudo wpa_supplicant -i wlan0 -c /tmp/wpa-2g.conf -B sudo dhclient -v wlan0 iw dev wlan0 link ping -c 20 -i 0.2 192.168.1.1 iperf3 -c 192.168.1.100 -t 30 -P 4

配置里key_mgmt=WPA-PSK加proto=RSN加pairwise=CCMP是最稳的组合,这颗芯片不支持 WPA3-SAE,proto里写RSN但密码套件用 TKIP 也会连不上。scan_ssid=1对隐藏 SSID 有必要,普通网络加了也无害。

iw dev wlan0 link输出里的signal和bitrate是两个关键指标,信号低于 -70dBm 时 2.4G 的重传率会明显上升。iperf3实测能到 40 到 70Mbps 属于正常区间,150Mbps 是理论物理层速率,单天线 20MHz 带宽下实际吞吐打对折是常态。如果只有几 Mbps 且iw dev显示tx failed计数器一直涨,先换 USB 口,再换短一点的线,最后才怀疑驱动。

4. Android 侧交叉编译:让 vendor 分区里的 .ko 真被加载

4.1 安卓内核与桌面内核在这份驱动上的三处硬差异

同样一套代码,在桌面上编完就能用,在安卓上往往卡在三个地方,而且每一处都不会给你明确报错。

第一是符号导出。安卓设备内核为了精简,会把cfg80211的部分函数改成不导出,驱动里调用的cfg80211_*只要有一个不在Module.symvers里,insmod就直接报unknown symbol。第二是模块签名,很多量产内核开了CONFIG_MODULE_SIG_FORCE,没签名的.ko一律拒绝加载,报module verification failed。第三是 SELinux,就算insmod成功了,wpa_supplicant去操作接口时也可能被策略挡掉,dmesg里一串avc: denied。这三处不是代码问题,是构建体系和策略问题,得分别处理。

GKI 之后情况更微妙一些。5.10 以上的通用内核镜像只允许供应商模块使用 KMI 白名单里的符号,白名单外的符号即使导出也会被裁掉。这份驱动用的cfg80211接口大部分在列,但wext相关的那部分不一定,所以安卓侧优先走 nl80211 路径,把CONFIG_WEXT_PRIV当兜底而不是首选。

4.2 交叉工具链与 KSRC:命令行长什么样

安卓的编译命令和 Linux 只差环境变量,但每个变量的来路都得说清楚。

export ARCH=arm64 export CROSS_COMPILE=/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android- export KSRC=/path/to/device-kernel # 编译该设备 boot.img 时用的那棵树 export CLANG_TRIPLE=aarch64-linux-gnu- make clean make -j"$(nproc)" \ ARCH=$ARCH \ CROSS_COMPILE=$CROSS_COMPILE \ KSRC=$KSRC \ 2>&1 | tee build-android.log

KSRC是整件事的命门。它必须是编译该设备内核时用过的那棵源码树,目录下要有.config、Module.symvers、include/generated/、scripts/。随便下一份同版本内核源码是没用的,.config里的CONFIG_LOCALVERSION、编译时间戳、符号 CRC 全都不一样,编出来的模块一insmod就是version magic不匹配。我一般会在设备树目录里留一个build.sh,把KSRC写死,避免几个月后回来找不到对应关系。

工具链版本也要贴。用 4.9 的 GCC 编 5.10 内核的模块,大概率报unrecognized command line option。更稳的做法是直接用内核树里prebuilts自带的那个交叉编译器,路径从设备内核的构建脚本里抄,别自己另找。

4.3 模块签名、modules.load 与 SELinux 上下文

模块编出来了,怎么塞进去、塞进去怎么被系统认,这一段是最容易前功尽弃的地方。

adb root adb remount adb push 8188fu.ko /vendor/lib/modules/8188fu.ko adb shell chmod 644 /vendor/lib/modules/8188fu.ko adb shell restorecon -v /vendor/lib/modules/8188fu.ko # 开机自动加载的清单,不同安卓版本路径不同 adb shell "grep -q 8188fu /vendor/lib/modules/modules.load || \ echo 8188fu.ko >> /vendor/lib/modules/modules.load"

restorecon那一步不能省。/vendor/lib/modules/下的文件默认上下文是u:object_r:vendor_file:sbl,手动adb push进去的文件继承的是adb进程的上下文,init加载时会因为策略拒绝而静默失败。modules.load只对 first stage 加载有效,Android 11 之后 vendor 模块清单可能被编进vendor_boot镜像,改文件不生效,这种机器上手动insmod验证最省事,验证通过再考虑改镜像。

签名问题在测试阶段可以先绕过:内核里关掉CONFIG_MODULE_SIG_FORCE重编 boot,或者把公钥编进内核的 keyring。量产机上这两条路都走不通,只能拿到厂商签名通道,这一点得提前评估,别等到产线才发现。

4.4 adb 侧验证:从 insmod 到拿到 IP

安卓上没有dhclient,网络配置走的是dhcpcd或者ndc,wpa_supplicant的参数也和桌面不太一样。

adb shell insmod /vendor/lib/modules/8188fu.ko adb shell dmesg | tail -50 adb shell ip link adb shell "wpa_supplicant -i wlan0 -c /data/local/tmp/wpa.conf -B -Dnl80211" adb shell "dhcpcd wlan0" || adb shell "ndc network interface add wlan0" adb shell ifconfig wlan0 adb shell ping -c 5 192.168.1.1

-Dnl80211优先,如果wpa_supplicant报Failed to initialize driver interface,换成-Dwext再试,这一步能快速区分是 cfg80211 注册失败还是驱动本身没起来。dhcpcd在部分精简系统里被裁掉了,ndc是备选,命令语法随安卓版本变化,跑之前先ndc help看一眼。

dmesg里的关键行和桌面上一致,唯一要注意的是安卓的dmesg权限,非 root 看不到内核日志,adb root是前提。整个链路打通之后,把/data/local/tmp/wpa.conf里的密码删掉,别留在测试机上。

5. 避坑与排查:五类让驱动编不过、跑不稳的现场

5.1 编译期一片 implicit declaration:内核 API 断裂

现象:make跑到一半开始刷屏,strlcpy未声明、struct cfg80211_ops has no member named 'mgmt_frame_register'、kernel_write参数个数不对、set_fs找不到。

原因:这份驱动的代码基线大概停在 4.x 到 5.4 之间,而 5.15、6.1、6.6 这几个 LTS 把一批老 API 删了或者改了签名。strlcpy在 5.15 之后被strscpy取代,set_fs/get_fs在 5.10 移除,cfg80211_ops里好几个回调合并进了struct cfg80211_ops的新字段,usb_control_msg在 5.16 之后多了个timeout参数位置变化。

解决:不推荐逐个文件手改,容易越改越乱。在include/osdep_service_linux.h顶部加一层版本垫片,把差异收敛到一个地方:

/* 兼容垫片:按内核版本选择实现,改一处比改十处稳 */ #include <linux/version.h> #include <linux/string.h> #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) #define rtw_strlcpy(dst, src, len) strscpy(dst, src, len) #else #define rtw_strlcpy(dst, src, len) strlcpy(dst, src, len) #endif /* 6.1 之后 usb_control_msg 的超时参数位置有变,封装一层 */ static inline int rtw_usb_ctrl_msg(struct usb_device *dev, unsigned int pipe, u8 req, u8 type, u16 val, u16 idx, void *buf, size_t len, int timeout) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) return usb_control_msg(dev, pipe, req, type, val, idx, buf, len, timeout); #else return usb_control_msg(dev, pipe, req, type, val, idx, buf, len, timeout); #endif }

然后在报错的调用点把strlcpy换成rtw_strlcpy,把老的cfg80211_ops回调字段注释掉、改用cfg80211_ops里对应的新字段。改完一定要make clean再编,这套驱动的依赖文件写得松,增量编译会骗你。剩下一两个实在对不上的,用EXTRA_CFLAGS += -Wno-error=implicit-function-declaration先放过去,但要记在清单上,别当没看见。

5.2 模块加载成功但没有 wlan 接口:VID/PID 没匹配上

现象:lsmod能看到8188fu,dmesg里也有 USB 设备枚举的记录,但ip link里没有任何新增接口,dmesg里找不到 probe 成功的行。

原因:os_dep/linux/usb_intf.c里的rtw_usb_id_tbl是白名单匹配,不在表里的设备驱动根本不会去 probe。市面上同一颗芯片的成品网卡换过好几轮 PID,源码包里的表不一定覆盖你手上这一批。

解决:先在宿主机上看清楚设备的 VID/PID 和接口类:

lsusb # 典型输出:Bus 001 Device 004: ID 0bda:f179 Realtek ... lsusb -v -d 0bda:f179 | grep -E "bInterfaceClass|bInterfaceSubClass|bDeviceClass"

拿到 ID 之后补进表里,注意匹配宏要用USB_DEVICE_AND_INTERFACE_INFO而不是简单的USB_DEVICE,因为这颗芯片的接口类通常是0xff厂商自定义,用USB_DEVICE匹配 class 为 0 的通用设备会漏掉:

static struct usb_device_id rtw_usb_id_tbl[] = { {USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xf179, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xc820, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xa729, 0xff, 0xff, 0xff)}, {} /* 必须有这个空项收尾,否则内核会越界读表 */ };

补完重编重载,dmesg里应该能看到rtw_usb_probe相关的行。如果bInterfaceClass是0xe0(无线控制器)而不是0xff,匹配宏第三个参数要相应改成0xe0,这一点lsusb -v一查便知。

5.3 能连上但传大流量就断:USB 自动挂起和低功耗模式

现象:ping通,小文件下载正常,iperf3跑二三十秒链路直接掉,dmesg里偶尔有usb 1-1: reset high-speed USB device,重连后一切正常,过一会儿再断。

原因:两个叠加因素。一是内核的 USB 自动挂起,空闲时把设备送进 suspend,这颗芯片的唤醒时序做得不严,醒来后状态机没恢复干净。二是驱动自己的CONFIG_POWER_SAVING,射频间歇休眠和 USB autosuspend 撞在一起,重传率飙升直到链路被判死。

解决:分三层关掉。

# 第一层:内核启动参数,全局关掉 USB 自动挂起 sudo sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="usbcore.autosuspend=-1 /' /etc/default/grub sudo update-grub # 第二层:驱动编译期关掉省电 sed -i 's/^#define CONFIG_POWER_SAVING/#undef CONFIG_POWER_SAVING/' include/autoconf.h make clean && make -j"$(nproc)" # 第三层:运行时再确认一遍 sudo iw dev wlan0 set power_save off cat /sys/module/usbcore/parameters/autosuspend

三层都做,基本能根治。只做第三层的话,重启或者重新插拔就失效了。如果关掉之后还断,检查供电:USB 2.0 口带这颗芯片加外置天线,峰值电流能到 400mA 以上,前面接个不带电源的 HUB 很容易掉压,换个主板直出的口试试。

5.4 接口起来了但扫不到任何 AP:固件没加载

现象:ip link能看到wlan0,iw dev wlan0 scan返回空列表或者Operation not permitted,dmesg里有一行request_firmware failed或者rtl8188fu: download firmware failed。

原因:固件文件名或路径不对。驱动里request_firmware用的名字是写死的,不同版本的源码包可能写成rtl8188fufw.bin,也可能带子目录rtlwifi/rtl8188fufw.bin,路径对不上就加载失败。固件加载失败时驱动往往还是会注册接口,只是射频起不来,表现就是能看见设备但扫不到东西。

解决:先确认驱动里用的确切名字:

strings 8188fu.ko | grep -i "\.bin" # 输出通常是 rtl8188fufw.bin,看有没有前缀目录

然后按名字放到对应位置,两个常见路径都放一份不占多少空间:

sudo cp firmware/rtl8188fufw.bin /lib/firmware/ sudo cp firmware/rtl8188fufw.bin /lib/firmware/rtlwifi/ sudo rmmod 8188fu && sudo insmod ./8188fu.ko dmesg | grep -i firmware

安卓上对应路径是/vendor/firmware/,权限 644,SELinux 上下文u:object_r:vendor_firmware_file:sbl,同样要restorecon。固件版本和驱动版本最好配对,混用不同批次的 bin 会出现能连但速率只有 1Mbps 的怪现象。

5.5 能连但速度只有几 Mbps:信道、带宽和天线

现象:iw dev wlan0 link显示bitrate只有 6.5Mbps 或者 1Mbps,iperf3跑出来个位数,重传计数一直涨。

原因:三个常见源头。2.4G 频段本来就挤,周围十几个 AP 叠在同一信道;驱动默认开了 40MHz 共存检测,检测到邻居就退回 20MHz 甚至更低;USB 小网卡自带的天线增益极低,插在金属机箱背面基本等于屏蔽。

解决:固定信道避开拥堵,关掉 40MHz 共存,改善物理位置。

# 看周围信道占用,挑一个干扰最少的 sudo iw dev wlan0 scan | grep -E "DS Parameter set|signal" | head -40 # 路由器侧固定 1/6/11 之一,带宽强制 20MHz # 驱动侧关掉 40MHz 相关开关,减少协商抖动 sudo iw dev wlan0 set bitrates legacy-2.4 1 2 5.5 11 6 9 12 18 24 36 48 54

信道选 1、6、11 这三个互不重叠的,别选中间那些看着空闲实际上被邻道挤爆的。天线方面,把网卡从机箱背面挪到前面板或者用一根短的 USB 延长线架高,实测信号能差 10dBm 以上。这几条看着像玄学,但 2.4G 这个频段的物理特性就是这样,改完再测一遍iperf3,前后对比一目了然。

6. 用 DKMS 把编译固化:内核一升级不用重新翻笔记

前面所有步骤都是手工的,手工的东西注定会忘。系统内核一升级,/lib/modules/$(uname -r)/build指向新版本,之前编的8188fu.kovermagic 对不上,开机insmod失败,网卡消失,然后你又要从头来一遍。DKMS 解决的正是这个问题:把源码登记进去,每次内核更新自动重编重装。

先在源码目录里放一个dkms.conf,关键是MAKE[0]那行要显式传KSRC,不然 DKMS 默认拿/lib/modules/${kernelver}/build,某些发行版上这个路径和实际头文件树不一致:

PACKAGE_NAME="rtl8188fu" PACKAGE_VERSION="1.0.0" BUILT_MODULE_NAME[0]="8188fu" BUILT_MODULE_LOCATION[0]="." DEST_MODULE_LOCATION[0]="/kernel/drivers/net/wireless" MAKE[0]="make -j$(nproc) KSRC=/lib/modules/${kernelver}/build" CLEAN="make clean" AUTOINSTALL="yes"

BUILT_MODULE_LOCATION指的是make之后.ko落在源码树的哪个子目录,这份驱动编完就在根目录,所以写.。DEST_MODULE_LOCATION是安装到/lib/modules/${kernelver}/下的相对路径,写updates也行,写kernel/drivers/net/wireless更符合传统布局。

登记和安装的命令不多,顺序别搞反:

sudo mkdir -p /usr/src/rtl8188fu-1.0.0 sudo cp -r ./rtl8188fu-driver/* /usr/src/rtl8188fu-1.0.0/ sudo cp dkms.conf /usr/src/rtl8188fu-1.0.0/ sudo dkms add -m rtl8188fu -v 1.0.0 sudo dkms build -m rtl8188fu -v 1.0.0 sudo dkms install -m rtl8188fu -v 1.0.0 dkms status

dkms status输出rtl8188fu/1.0.0, <kernel>, x86_64: installed才算成功。之后apt upgrade拉了新内核,DKMS 会在安装阶段自动编一遍,编失败的话会在dpkg日志里留记录,/var/lib/dkms/rtl8188fu/1.0.0/build/make.log是排查入口。

安卓侧没法用 DKMS,但有替代习惯:把KSRC、CROSS_COMPILE、内核版本号写进一个build.env,跟源码一起提交,换机器的时候source build.env && make就行。我还会在仓库根目录放一个自检脚本,新机器上跑一遍就知道环境齐不齐:

#!/usr/bin/env bash # check-env.sh:三板斧自检,缺哪条补哪条 set -u KV=$(uname -r) echo "[1] 内核头文件树" test -f "/lib/modules/${KV}/build/.config" && echo " OK" || echo " MISSING .config" test -f "/lib/modules/${KV}/build/Module.symvers" && echo " OK" || echo " MISSING Module.symvers" echo "[2] 固件" ls /lib/firmware/rtl8188fufw.bin 2>/dev/null && echo " OK" || echo " MISSING firmware" echo "[3] 设备枚举" lsusb | grep -iE "0bda:(f179|c820|a729)" || echo " NO DEVICE"

最后说个血泪教训。我之前在一台工控机上图快,手工编完insmod就交付了,没登记 DKMS。三个月后系统自动更新内核,现场断网,运维打电话过来,我只能远程让人家把旧内核从 GRUB 里选回来。从那以后我每次给这类外挂驱动做交付,第一件事就是把 DKMS 配好、把check-env.sh留一份在/root/,然后才去测吞吐。希望帮到你。

本文还有配套的精品资源,点击获取