前几天给一台闲置笔记本装 Ubuntu 20.04,系统装完了,网卡却变成了一块废铁。lspci里清清楚楚写着Realtek Semiconductor Co., Ltd. Device b852,也就是很常见的 RTL8852BE Wi-Fi 6 网卡,可 Ubuntu 20.04 默认的 5.4 内核压根不认识它。更要命的是这台机器没有有线网口,想联网装驱动又必须先有网,直接陷入"先有鸡还是先有蛋"的死局。这篇文章把我这次离线装 b852 驱动的完整过程写下来,包括依赖包怎么获取、dkms 怎么注册、Secure Boot 和固件缺失这几个大坑怎么跳,给正在折腾同样网卡的朋友一份能直接照着抄的作业。不管你是刚接触 Linux 的新手,还是第一次碰 Realtek 离线驱动的老手,这篇都能帮你省下至少半天排查时间。
1. 先别急着编译,搞清楚 b852 的芯片身份和驱动来源
1.1 用 lspci 一句话锁定网卡型号
很多朋友拿到一张不认的网卡,第一反应是去网上搜"Ubuntu 无线网卡驱动",结果下载了一堆不知道能不能用的东西。我的习惯是先在终端里执行:
lspci -nn | grep -i network输出大概是这样的:
02:00.0 Network controller [0280]: Realtek Semiconductor Co., Ltd. Device [10ec:b852]10ec是 Realtek 的厂商 ID,b852是设备 ID。拿这个设备 ID 去查资料就非常明确了:它是 RTL8852BE,Wi-Fi 6 标准的 PCIe 无线网卡,联想 IdeaPad、戴尔 Inspiron、HP Pavilion 这些中端笔记本上出镜率很高。
这里有个细节要提醒:lspci 显示的是Device b852,而不是RTL8852BE这种通俗名字。这是很正常的,因为设备 ID 才是内核和驱动真正用来匹配硬件的依据。不要看到 b852 就觉得是"某个未知杂牌",它就是 RTL8852BE 的 PCIe 版本编号。后面编译驱动、查固件文件,全部要围绕这个 ID 展开。
RTL8852BE 还有几个近亲兄弟,比如 RTL8852AE 是另一个接口版本,RTL8852CE 是更新的型号,它们的设备 ID 各不相同,固件文件也不通用。如果你不确认型号就随便拿一个仓库来编译,大概率会在加载模块时报unknown symbol或者固件加载失败。所以第一步花三十秒跑一条命令,后面所有工作都不会白做。
1.2 为什么 Ubuntu 20.04 默认内核"不认账"
Ubuntu 20.04 发布时用的是 5.4 内核,那时候 Realtek 的 Wi-Fi 6 网卡驱动还是一片空白。内核社区到 5.12 版本才第一次合入rtw89驱动,最初的版本只支持 RTL8852AE,RTL8852BE 被正式支持又晚了好几个版本。所以你在 5.4 内核下看不到无线网卡,ip link里没有任何 wlan 接口,nmcli dev status里只有一个 ethernet,这些现象都是预期内的。
有一个例外情况:如果你装 Ubuntu 20.04 时选了安装 HWE 内核,也就是 Hardware Enablement 内核,uname -r会显示 5.15 甚至更高。新内核里可能已经自带了rtw89_8852be模块,直接执行modprobe rtw89_8852be就可能生效。不过我实测下来,HWE 内核本身也会带来头文件版本不匹配的坑,而且如果你用的是个纯离线环境,还是会卡在依赖获取上。所以无论旧内核新内核,把离线依赖准备这一关踏踏实实做好,才是最稳的路线。
1.3 能驱动 b852 的三条路径,我为什么选它
目前社区能驱动 RTL8852BE 的方案大概有三条:
| 方案 | 模块名 | 维护状态 | 我的推荐度 |
|---|---|---|---|
| 内核主线自带 rtw89 | rtw89_8852be | 持续合入 | 首选 |
| lwfinger/rtw89 GitHub 仓库 | rtw89_8852be | 更新频繁,支持旧内核 | 离线安装首选 |
| HRex39/rtl8852be 老仓库 | 8852be | 更新较慢,内核兼容性有限 | 备用 |
内核主线自带驱动是最理想的,但 Ubuntu 20.04 默认 5.4 内核没法直接享受。lwfinger 的 rtw89 仓库是社区里维护质量比较高的,源码里带了固件文件和 DKMS 脚本,编译安装的路径很完整,这也是我最后实际采用的方案。HRex39 那个老仓库在更早的时候救过不少人,但在新内核上会出现 API 不兼容的编译报错,所以只把它当成备胎。
2. 离线环境的物资准备:把所有依赖包提前囤齐
2.1 源码包的选择与获取
先讲驱动源码。如果你在能上网的机器上,直接访问 GitHub 的 lwfinger/rtw89 仓库,把主分支打包下载成 zip 文件,或者用 git clone 拉下来。源码包大概几兆字节,里面包含了驱动源码、固件目录和一个 DKMS 安装脚本。
这里有个很关键的经验:不要在目标离线的 Ubuntu 机器上直接git clone,因为大多数离线环境根本没有 git 和网络。你要把源码包放在 U 盘或移动硬盘里再带过去。U 盘文件系统建议用 FAT32 或 exFAT,避免 NTFS 在某些 Linux 环境下需要额外安装 ntfs-3g 才能读写。虽然 20.04 默认已经能读 NTFS,但 FAT32 是最省心的。
如果你用的是 rtw89 仓库,需要在有网机器上确认源码树里是否包含firmware/rtw8852b_fw.bin这个文件。我在实际下载的版本里是有的,安装脚本会把它复制到/lib/firmware/rtw89/目录。如果没有这个文件,后面加载模块时就会报固件缺失,那又要多折腾一轮。
2.2 编译链依赖清单:比想象中更费心
驱动源码编译需要一套完整的工具链和内核头文件。我把这次用到的依赖包整理成了一张表,你在准备阶段可以直接照抄:
| 软件包 | 作用 | 离线安装方式 | 必须性 |
|---|---|---|---|
| build-essential | gcc、g++、make 等编译工具 | dpkg -i 安装 deb | 必须 |
| linux-headers-$(uname -r) | 与当前内核匹配的头文件 | dpkg -i 安装 deb | 必须 |
| dkms | 注册驱动模块,内核升级后自动重新编译 | dpkg -i 安装 deb | 强烈建议 |
| bc | 内核编译脚本需要的计算器工具 | dpkg -i 安装 deb | 必须 |
| flex、bison | 内核模块的语法分析器 | dpkg -i 安装 deb | 常见必须 |
| pkg-config | 编译时获取库信息 | dpkg -i 安装 deb | 视版本而定 |
很多教程只提 build-essential 和 linux-headers,结果编译到一半报flex: command not found或者bc: command not found。对于 rtw89 仓库的代码,flex、bison、bc 这几个工具基本绕不开。所以我的建议是干脆一次性全备齐,别抱着省事的心态,缺一个小工具就能卡住整个编译流程。
2.3 用 apt 打包下载 deb 依赖的正确姿势
在有网络的 Ubuntu 20.04 机器上,准备依赖包的方式有两种,我个人推荐第二种。
第一种是直接执行apt download 包名,但它只会下载你指定的那一个包,不会自动下载依赖。如果你需要 20 个关联包,手写命令会非常痛苦。
第二种是我实际用的方法,利用apt install --download-only:
mkdir -p ~/offline-packages cd ~/offline-packages sudo apt update sudo apt install --download-only build-essential dkms bc flex bison pkg-config # 再回过头来把具体版本的内核头文件下载下来 apt download linux-headers-$(uname -r)执行完之后,所有下载好的 deb 文件都在/var/cache/apt/archives/目录里。把它们复制到 U 盘:
mkdir -p ~/offline-packages sudo cp /var/cache/apt/archives/*.deb ~/offline-packages/需要注意一个问题:uname -r是"当前这台有网机器"的内核版本,如果你是在另一台机器上给目标机准备依赖,不能直接照搬。你必须先知道目标机的内核版本号,然后手动指定:
apt download linux-headers-5.4.0-26-generic linux-headers-5.4.0-26这里的5.4.0-26是目标机uname -r的输出。版本号对不上,编译出的模块根本无法加载。
2.4 传输文件的几种实用方案
依赖包装好之后,怎么把它弄到离线的目标机器上也有讲究。最简单的是 U 盘拷贝,但我在实际操作中发现,如果你手头有一台可以开网络的临时设备,比如手机开 USB 网络共享,那目标机器就能短暂联网,此时直接用scp从局域网另一台机器拉取 deb 包会快得多。
手机 USB 网络共享这个技巧值得单独说一下。很多安卓手机通过 USB 线连上电脑后,在设置里打开"USB 网络共享",Ubuntu 就能自动识别出一个有线网络接口,目标机立刻就能访问互联网。这个方法不依赖任何网卡驱动,因为 RNDIS 协议在 Ubuntu 20.04 里是原生支持的。如果你的网络环境允许,这是解决离线死局的最高效手段;如果彻底没有外部网络,那 U 盘方案就是兜底。
3. 把地基打好:内核头文件与工具链的离线安装
3.1 版本匹配是头等大事
在目标机器上,首先要确认内核版本。执行:
uname -r假如输出是5.4.0-26-generic,那么你需要的头文件包就是linux-headers-5.4.0-26-generic和linux-headers-5.4.0-26。这两个 deb 通常配套安装,缺一不可。如果只装了linux-headers-5.4.0-26-generic而没装公共头文件目录,编译时一样会报找不到linux/version.h这类错误。
判断头文件是否已安装,可以看目录:
ls /usr/src/正常情况下会出现linux-headers-5.4.0-26-generic这样的文件夹。如果目录里空空如也,或者只有linux-headers-5.4.0-26没有-generic后缀的那部分,都说明头文件不完整,重装一遍最省事。
3.2 按顺序 dpkg 安装,依赖错误怎么处理
把 U 盘里的 deb 包目录挂载到目标机后,我习惯先不急着dpkg -i *.deb一把梭,因为如果 deb 包的加载顺序不对,dpkg 会抱怨依赖不满足。虽然很多情况下 apt 会自动解析,但在离线环境里dpkg -i不会处理依赖关系。
我的做法是先安装 linux-headers 相关的包:
cd <你的deb目录> sudo dpkg -i linux-headers-5.4.0-26_*.deb sudo dpkg -i linux-headers-5.4.0-26-generic_*.deb然后再安装工具链和辅助工具:
sudo dpkg -i build-essential_*.deb dkms_*.deb bc_*.deb flex_*.deb bison_*.deb pkg-config_*.deb如果中途报依赖缺失,比如gcc-9-base没装上,不要慌。去 deb 目录里找对应的包,先把它装上,然后再重新执行一次 dpkg 命令。所有 deb 都在同一个目录下时,最简单的方式是:
sudo dpkg -i *.deb这个命令会自动重试安装目录里所有未安装的包,你只需要多执行两次,等它不再报错为止。这也是离线安装 deb 的一个通用经验:不要期待一次成功,多跑几遍,直到 dpkg 把所有依赖关系都理顺。
3.3 验证编译环境是否可用
依赖装完,一定要主动验证一下,而不是直接去编译驱动。我的验证命令如下:
gcc --version make --version dkms --version ls /usr/src/linux-headers-$(uname -r)如果 gcc 能输出版本号,/usr/src 下也有对应的头文件目录,那编译环境就基本到位了。这里还有一个容易忽略的点:gcc版本需要与内核头文件期望的版本兼容。Ubuntu 20.04 官方源里的 gcc-9 搭配 5.4 内核是没有问题的。如果你为了编译其他东西装了 gcc-12,某些内核模块可能会因编译器版本过新而告警,但一般不影响最终结果。
4. 编译并安装驱动:从源码到 modprobe 的完整动作
4.1 解压源码,先看 README
把 rtw89 源码包传到目标机后,我建议先解压,然后打开 README 或 INSTALL 文件看一看。lwfinger 的 rtw89 仓库会在文档里写明当前支持的内核范围、编译命令和 DKMS 安装方式。这个动作花不了两分钟,但能避免你因为仓库分支不同而用了错误的安装方式。
tar -zxvf rtw89-master.tar.gz cd rtw89-master4.2 编译安装的完整命令流程
在源码目录里依次执行:
make -j$(nproc)-j$(nproc)会让 make 根据 CPU 核心数并行编译,速度快不少,如果你的机器只有两个核心,建议直接用make,避免内存不足。
编译完成后看到rtw89_8852be.ko这样的.ko模块文件,说明编译成功。然后执行安装:
sudo make install这个命令会把模块复制到/lib/modules/$(uname -r)/kernel/drivers/net/wireless/realtek/rtw89/目录,如果固件文件存在,也会一并复制到/lib/firmware/rtw89/。最后刷新模块依赖并加载:
sudo depmod -a sudo modprobe rtw89_8852be如果你没有报错,终端会安静地回到提示符。这时执行lsmod | grep rtw89,能看到rtw89_8852be和rtw89_core等模块列表,基本就成功了。
4.3 通过 DKMS 注册,让驱动在内核升级后依然存活
直接make install有一个隐患:你以后只要升级内核,新内核目录下的驱动模块目录是全新的,之前手动安装的.ko文件不会自动过去,无线网卡又会消失。解决这个问题的方法就是 DKMS。
lwfinger/rtw89 仓库里提供了 DKMS 集成脚本,最简单的方式是:
sudo make dkms_install或者手动用 dkms 命令注册:
sudo dkms add . sudo dkms build rtw89/1.0 sudo dkms install rtw89/1.0这里的1.0是 dkms.conf 里定义的版本号,以你仓库里的实际内容为准。注册完成后,以后每次内核升级,dkms 都会自动为新内核重新编译这个模块,省去你重复make install的麻烦。我在实际体验中非常推荐这一步,尤其是经常追新内核的用户。
4.4 加载后的验证动作
模块加载成功并不代表网卡一定可用,还要确认网络层是否识别到了设备:
ip link iwconfig nmcli device status如果能看到wlan0或类似名称的无线接口,且 NetworkManager 把它标记为 disconnected/available,那说明驱动已经完全工作,剩下就是通过图形界面或命令行连接 WiFi 了。nmcli device wifi list能列出附近的无线网络,nmcli device wifi connect "SSID" password "密码"可以直接命令行连上。
5. 装完依然连不上?按这条链路排查最容易出问题的地方
5.1 Secure Boot 导致模块被签名验证拦截
这是我在多台机器上遇到的最常见障碍。如果你的笔记本出厂开启了 Secure Boot,而内核配置了模块签名验证,那么modprobe rtw89_8852be时可能会出现:
modprobe: ERROR: could not insert 'rtw89_8852be': Operation not permitted或者在 dmesg 里看到:
Lockdown: modprobe: unsigned module loading is restricted; see man kernel_lockdown.7最直接的解决办法是进 BIOS 关闭 Secure Boot。不同品牌路径不一样,联想笔记本一般是开机按 F2 进入 Setup,在 Security 菜单里找到 Secure Boot 选项,设为 Disabled 保存退出。关闭后再次modprobe,一般就能正常加载。我这里不讨论 MOK 签名流程,因为它比较复杂,对新手不友好;如果你的机器不允许关闭 Secure Boot,再考虑用内核的mokutil做签名导入,但那是另一个话题了。
5.2 固件文件缺失:dmesg 会明确告诉你
模块加载成功但网卡不工作,先看内核日志:
sudo dmesg | grep rtw89如果出现:
rtw89_8852be: Direct firmware load for rtw89/rtw8852b_fw.bin failed with error -2那就说明驱动模块找到了,但固件缺失。解决办法是把rtw8852b_fw.bin文件放到/lib/firmware/rtw89/目录下。这个文件可以从 linux-firmware 仓库获取,也可以直接从 lwfinger/rtw89 源码包的 firmware 目录里复制。放好之后执行:
sudo modprobe -r rtw89_8852be sudo modprobe rtw89_8852be再查 dmesg,固件加载错误应该消失。这里要特别注意:不同芯片对应的固件文件后缀不同,8852BE 对应的是rtw8852b_fw.bin,别拿成 8852A 的文件,否则会一直报同样的错误。
5.3 与内核自带驱动或旧驱动的冲突
如果你之前用 HRex39 的旧仓库装过8852be模块,后来又换 rtw89,两个驱动会同时存在并争抢同一个设备。这种情况下建议把旧驱动列入黑名单。黑名单文件的路径是/etc/modprobe.d/blacklist.conf,在末尾加一行:
blacklist 8852be然后重新生成模块依赖并重启网络服务:
sudo update-initramfs -u sudo modprobe -r 8852be sudo modprobe rtw89_8852be另一个冲突来源是内核自带的rtw88驱动。5.4 内核的 rtw88 还不支持 b852 设备,所以你一般不会遇到,但如果你后来把内核升级到较高版本,rtw88_8852be可能已经存在。此时同样用黑名单把它禁掉,确保 rtw89 优先加载即可。
5.4 信号列表为空或者连不上:rfkill 和网络管理器
驱动正常、固件正常,也能看到 wlan0,但扫描不到任何 Wi-Fi 信号,这时先检查是不是无线网卡被软件禁用了:
rfkill list如果某项显示Soft blocked: yes或Hard blocked: yes,执行:
rfkill unblock all硬件开关和功能键(比如 Fn+F2)也可能把无线网卡关掉,Ubuntu 里常常不显示明显的提示。另一个常见原因是 NetworkManager 没有接管这个新出现的无线设备。你可以通过nmcli device set wlan0 managed yes让 NetworkManager 管理它,然后再用图形界面连接。把这几项检查完整,绝大多数"装完看不到信号"的问题都能定位到具体原因。
6. 一点经验总结:这次踩坑之后,我沉淀下来的通用离线装驱动流程
回到文章开头那个死局,这次成功解决之后,我复盘出的一套通用流程,以后再遇到其他离线网卡或者离线装内核模块的场景,基本都能套用:
首先,离线机器先想尽一切办法拿到临时网络,无论是手机 USB 共享还是借一个免驱的 USB 无线网卡。只要有一次联网机会,就立刻把编译链、内核头文件、dkms 以及目标驱动源码全部囤到本地。其次,如果实在没有网络,就用另一台同版本、同架构的机器把 deb 包下载好,靠 U 盘拷贝进去。关键点在于内核头文件版本必须和uname -r严格一致,这是最容易翻车的地方。
依赖安装顺序上也形成了一个固定套路:先头文件,再工具链,再辅助工具,最后驱动源码编译。遇到依赖错误不要慌,把dpkg -i *.deb多跑两遍,直到输出清清爽爽。驱动装上后不要急着高兴,把lsmod、dmesg、rfkill、nmcli四个命令挨个过一遍,基本就能覆盖绝大多数问题。
如果你正在折腾的也是 Realtek b852 网卡,我的建议很明确:优先走 rtw89 仓库加 DKMS 注册这条路,不要浪费时间在来路不明的所谓"一键安装脚本"上。把上面每一步走完,你的 Ubuntu 20.04 就会在离线状态下彻底认识这块网卡。后续即使系统升级内核,驱动也能自动跟着重编译,再不用重复今天这一步。