1. 为什么Ubuntu用户总在“编译驱动”这件事上反复踩坑你有没有过这样的经历新买了块RTX 4090显卡插进Ubuntu 22.04机器系统启动后桌面卡成幻灯片或者实验室刚配的某款工业级USB3 Vision相机在lsusb里能看见设备ID但dmesg | grep -i usb里全是“device descriptor read/64, error -71”又或者某天内核自动升级到6.5.0-xx重启后WiFi模块直接消失lspci -k | grep -A 3 Network显示驱动栏空空如也——连iwlwifi都加载失败。这不是玄学是Ubuntu驱动生态里最真实、最高频的“断层现场”。它背后藏着三个被多数人忽略的硬事实第一Ubuntu官方仓库里的驱动本质是“时间快照”而非“实时镜像”。比如linux-firmware包在22.04 LTS中默认搭载的是2022年Q3的固件集合而某款2023年Q4发布的网卡芯片其固件文件iwlwifi-ty-a0-gf-a0-77.ucode压根不在其中。你apt install firmware-iwlwifi再多次也补不上这个时间差。第二“编译安装”不是替代apt的备选方案而是Linux内核模块加载机制的底层刚需。内核模块.ko文件必须与当前运行内核的精确版本号编译配置符号表三重匹配。Ubuntu的linux-image-6.5.0-28-generic和你自己用make -j$(nproc)编译出的6.5.0-28-custom哪怕只差一个CONFIG_MODULE_SIGy的开关insmod就会报Invalid module format——这跟Windows里DLL版本不兼容是一个逻辑层级的问题只是表现更冷酷。第三所谓“新驱动”90%以上其实指的不是从零写的驱动而是上游主线内核已合入、但尚未进入Ubuntu当前内核分支的补丁集。比如NVIDIA的nvidia-uvm模块对CUDA 12.4的内存管理优化在主线5.19中已存在但Ubuntu 22.04的5.15内核需要手动cherry-pick 3个commit并解决符号冲突。这时候dkms build不是魔法是精密外科手术。我去年帮某高校实验室调试一套多光谱成像系统核心传感器驱动在主线6.1中才完成DMA缓冲区对齐修复而他们用的Ubuntu 20.04内核是5.4。我们没重装系统也没等Ubuntu发布新内核而是用git checkout v6.1 make menuconfig裁剪掉无关模块把编译时间从47分钟压到11分钟最终让整套系统在原有硬件上跑通了实时图像流。这件事让我彻底明白编译驱动不是炫技是绕过发行版节奏限制的生存技能。所以这篇内容不讲“如何下载NVIDIA.run”也不教“怎么禁用nouveau”而是带你拆解Ubuntu下驱动编译安装的完整决策链什么时候必须自己编译哪些步骤绝对不能跳过为什么make modules_install之后还要depmod -a以及——最关键的是如何在不破坏系统稳定性的前提下让新驱动和旧内核和平共处。2. 编译前的四重校验比写代码更重要的前置动作很多人一上来就git clone、./configure结果卡在ERROR: Kernel headers not found上两小时。其实真正的编译工作70%在开始之前。我把它拆成四个不可跳过的校验环节每个环节都有明确的命令和预期输出缺一不可。2.1 校验当前内核版本与头文件一致性先执行uname -r # 输出示例6.5.0-28-generic然后检查对应头文件包是否已安装dpkg -l | grep linux-headers-$(uname -r) # 必须看到状态为iiinstalled的条目 # 如果没有立即执行 sudo apt update sudo apt install linux-headers-$(uname -r)提示linux-headers-6.5.0-28-generic包里包含/usr/src/linux-headers-6.5.0-28-generic/目录这是编译模块的绝对路径依赖。很多教程说“装好headers就行”但没告诉你如果系统有多个内核版本比如你保留了旧内核用于回滚uname -r返回的版本必须和/lib/modules/$(uname -r)/build软链接指向的路径完全一致。我见过三次故障都是因为/lib/modules/6.5.0-28-generic/build被手动指向了/usr/src/linux-headers-6.5.0-25-generic——编译出来的模块加载时会因vermagic不匹配而静默失败。2.2 校验内核配置.config的完整性驱动编译时会读取内核源码根目录下的.config文件里面定义了所有CONFIG_*宏。如果某个驱动依赖CONFIG_PCI_MSIy但你的.config里是CONFIG_PCI_MSIn编译器会在预处理阶段直接跳过相关代码导致模块功能残缺。验证方法zcat /proc/config.gz /tmp/current_config 2/dev/null || \ cp /boot/config-$(uname -r) /tmp/current_config grep CONFIG_PCI_MSI /tmp/current_config # 必须输出 CONFIG_PCI_MSIy如果你要编译的驱动需要特定配置比如Realtek RTL8125B网卡驱动要求CONFIG_R8169m而当前配置是n就必须重新生成.config。安全做法是cd /usr/src/linux-headers-$(uname -r) cp /boot/config-$(uname -r) .config make olddefconfig # 自动填充新选项为默认值 # 然后手动检查关键项 make menuconfig # 进入图形界面定位到 Device Drivers → Network device support → Ethernet driver support → Realtek devices → R8169 # 确保其状态为M模块或*内置2.3 校验构建工具链的完备性Ubuntu默认不安装完整的编译工具链。执行以下命令一次性补齐sudo apt install build-essential libssl-dev libelf-dev libdw-dev zlib1g-dev binutils-dev libncurses5-dev flex bison重点解释两个易被忽略的包libdw-dev提供DWARF调试信息解析库perf和部分驱动调试工具依赖它。没有它make可能在链接阶段报undefined reference to dwfl_begin。binutils-dev包含ld链接器的开发头文件某些驱动Makefile里会调用$(CC) -Wl,--build-id缺少此包会导致链接失败。验证GCC版本兼容性gcc --version # Ubuntu 22.04默认GCC 11.4而内核6.5要求GCC 11.1 # 如果你升级过GCC到12.x需注意内核6.5不支持GCC 13的某些新特性 # 此时应临时切换 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 11 --slave /usr/bin/g g /usr/bin/g-11 sudo update-alternatives --config gcc2.4 校验源码树结构的规范性很多开发者从GitHub克隆驱动源码后直接make却忘了Linux内核模块编译有严格路径约定。以经典的rtl8192eu-aircrack-ng驱动为例它的Makefile里有KDIR ? /lib/modules/$(shell uname -r)/build PWD : $(shell pwd)这意味着KDIR必须指向一个完整可编译的内核源码树且该树中必须包含Makefile、scripts/Makefile.build等核心文件。验证方法ls -l /lib/modules/$(uname -r)/build # 正确输出应为build - /usr/src/linux-headers-6.5.0-28-generic # 如果是 broken link 或指向不存在路径必须修复 sudo rm /lib/modules/$(uname -r)/build sudo ln -s /usr/src/linux-headers-$(uname -r) /lib/modules/$(uname -r)/build注意不要用make prepare代替这个步骤。make prepare只生成include/generated/等临时文件不解决源码树路径问题。我曾在一个客户现场花3小时排查最后发现/lib/modules/6.5.0-28-generic/build软链接指向了/home/user/linux-src——而那个目录是用户自己git clone的主线内核版本号却是6.6-rc1与当前运行内核完全不匹配。3. 驱动源码的三种来源与选择策略别在第一步就走错方向拿到“新驱动”这个词第一反应不该是git clone而是问这个“新”到底新在哪里不同来源的驱动编译流程、风险等级、维护成本天差地别。我按优先级从高到低列出三种来源并附上真实案例说明。3.1 来源一上游主线内核已合入仅需更新内核版本最低风险这是最理想的情况。比如你遇到Intel AX210 WiFi在Ubuntu 20.04上无法启用蓝牙查dmesg发现btusb: failed to send firmware。搜索内核邮件列表会发现修复补丁已于2022年9月合入主线5.19。此时最优解不是编译驱动而是升级内核# Ubuntu 20.04用户可安全升级到HWE内核 sudo apt install --install-recommends linux-generic-hwe-20.04 # 重启后uname -r应显示5.15.0-xx-genericHWE内核 # 若仍需更新可手动安装UKUU工具 sudo add-apt-repository ppa:teejee2008/ppa sudo apt update sudo apt install ukuu # 在GUI中选择5.19.x内核安装优势无需编译无兼容性风险固件自动更新apt upgrade可维护。风险点HWE内核虽经Ubuntu测试但某些定制硬件如OEM笔记本的EC固件可能与新内核存在时序冲突。我的经验是升级前先用boot-repair创建GRUB恢复项且首次启动时加acpi_enforce_resourceslax参数规避ACPI资源争用。3.2 来源二厂商提供独立驱动包中等风险需深度审计典型如NVIDIA.run文件、Realtek官方rtl88x2bu-aircrack-ng。这类包的优点是开箱即用缺点是闭源组件多、更新滞后、与Ubuntu安全策略冲突。以Realtek RTL8822BU WiFi驱动为例其官方GitHub仓库的README写着“This driver is based on the official Realtek driver v5.6.4.2_30363.20180719”但实际解压RTL8822BU_WiFi_linux_v5.6.4.2_30363.20180719.tar.gz会发现core/rtw_cmd.c里有硬编码MAC地址过滤逻辑if (memcmp(pattrib-dst, \x01\x00\x5e, 3) 0)这违反Ubuntu的网络命名空间隔离原则os_dep/linux/ioctl_cfg80211.c中cfg80211_inform_bss_frame()调用方式与内核6.5的API不兼容需手动修改struct cfg80211_bss *bss cfg80211_inform_bss_frame(...)为struct cfg80211_bss *bss cfg80211_inform_bss(...)。我的处理流程先用diff -ruN对比官方驱动与社区维护版如aircrack-ng/rtl8812au-aircrack-ng的差异重点关注os_dep/linux/目录下的ioctl_*.c和usb_intf.c这些是API变更高发区对修改点添加注释说明内核版本适配逻辑例如// Kernel 6.5 uses cfg80211_inform_bss() instead of cfg80211_inform_bss_frame() // See commit 3a7b1c2 in mainline kernel #if LINUX_VERSION_CODE KERNEL_VERSION(6,5,0) bss cfg80211_inform_bss(...); #else bss cfg80211_inform_bss_frame(...); #endif提示永远不要直接运行厂商提供的sudo ./install.sh。先用bash -x ./install.sh跟踪脚本执行流确认它不会覆盖/lib/firmware/中的关键固件。我曾因某款摄像头驱动脚本清空了/lib/firmware/mediatek/导致板载WiFi永久失效最终靠Live USB挂载分区恢复。3.3 来源三社区维护的第三方驱动最高风险但灵活性最强如https://github.com/morrownr/8821au_air.git这类仓库。它们的优势是持续适配新内核劣势是代码质量参差、缺乏厂商支持、可能引入安全漏洞。选择策略我总结为“三看”看提交频率近3个月是否有合并记录如果最新commit是2022年说明项目已停滞看Issue处理搜索关键词“ubuntu 22.04”或“kernel 6.5”看作者是否积极回复看编译日志克隆后执行make -C /lib/modules/$(uname -r)/build M$(pwd) modules观察警告数量。超过5个warning: ‘xxx’ defined but not used说明代码未清理可能存在逻辑缺陷。实战案例某医疗设备公司使用的USB转RS485适配器芯片为CH340G。Ubuntu 22.04自带ch341驱动不支持其特殊波特率模式。我们采用社区驱动https://github.com/juliagoda/ch341-serial但发现其ch341.c中ch341_set_termios()函数未处理c_cflag CBAUD的扩展波特率掩码。解决方案是在Makefile中添加EXTRA_CFLAGS -DCONFIG_CH341_EXT_BAUDRATE修改ch341_set_termios()当检测到c_cflag CBAUD BOTHER时调用ch341_write_reg(dev, 0x13, baud_divisor 0xFF)设置分频寄存器。这个修改让设备在1.5Mbps波特率下误码率从10^-3降至10^-6但代价是每次内核更新都要重新patch。因此我建议对生产环境将patch固化为DKMS模块对开发环境用git apply管理补丁。4. 编译与安装的七步精准操作每一步都决定成败现在进入实操环节。这里不讲泛泛的make sudo make install而是拆解为七个原子步骤每个步骤标注必做理由、常见错误和验证命令。以编译rtl8192eu-aircrack-ng驱动为例因其覆盖PCIe/USB双接口、含firmware加载、需签名验证最具代表性。4.1 步骤一创建独立构建目录并初始化mkdir ~/driver-build cd ~/driver-build git clone https://github.com/aircrack-ng/rtl8192eu-aircrack-ng.git cd rtl8192eu-aircrack-ng必做理由避免在源码根目录执行make clean误删.gitUbuntu的/tmp可能被systemd-tmpfiles定期清理独立目录保障过程可追溯。常见错误在/tmp中克隆后直接编译某次apt autoremove后整个驱动源码消失重编耗时2小时。4.2 步骤二修正Makefile中的内核路径硬编码打开Makefile找到# KVER ? $(shell uname -r) # KSRC ? /lib/modules/$(KVER)/build取消注释并确保KSRC指向正确路径KVER ? 6.5.0-28-generic KSRC ? /usr/src/linux-headers-$(KVER)必做理由某些驱动Makefile用$(shell uname -r)获取版本但在交叉编译或容器环境中可能返回错误值。硬编码可锁定目标内核。验证命令make -n | head -5 # 查看预执行命令确认-KSRC路径正确4.3 步骤三预编译检查与依赖注入执行make -C /lib/modules/$(uname -r)/build M$(pwd) modules_prepare必做理由modules_prepare会生成Module.symvers符号版本表这是模块间调用如usb_register_driver()的契约文件。缺少它insmod会报Unknown symbol in module。常见错误跳过此步直接make编译成功但加载失败。错误日志中dmesg显示usb_register_driver: Unknown symbol根源在此。4.4 步骤四执行模块编译并捕获警告make -C /lib/modules/$(uname -r)/build M$(pwd) modules 21 | tee build.log关键观察点检查build.log末尾是否有Building modules, stage 2.字样搜索warning:重点关注implicit declaration of function未声明函数和assignment from incompatible pointer type指针类型不匹配若出现error: too few arguments to function ‘usb_control_msg’说明内核API已变更需查include/linux/usb.h中该函数签名。我的技巧用grep -E (warning|error) build.log | grep -v unused过滤有效警告比肉眼扫描快10倍。4.5 步骤五固件文件的合规放置rtl8192eu驱动需要rtl8192eu_nic.bin固件。Ubuntu要求固件必须放在/lib/firmware/且权限为644sudo cp firmware/rtl8192eu_nic.bin /lib/firmware/ sudo chmod 644 /lib/firmware/rtl8192eu_nic.bin sudo update-initramfs -u必做理由update-initramfs -u会将固件打包进initrd确保系统启动早期就能加载。否则可能出现dmesg | grep firmware显示Failed to load rtl8192eu_nic.bin。验证命令lsinitramfs /boot/initrd.img-$(uname -r) | grep rtl8192eu # 应输出 firmware/rtl8192eu_nic.bin4.6 步骤六模块签名与安全启动兼容如果你的系统启用了Secure Boot未签名模块会被拒绝加载# 生成密钥对仅首次需要 openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj /CNMy Module Key/ # 注册密钥到MOKMachine Owner Key数据库 sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der ./8192eu.ko # 加载模块 sudo insmod ./8192eu.ko必做理由Ubuntu 22.04默认启用Secure Bootinsmod会静默失败。dmesg中只有PKCS#7 signature not signed with a trusted key一行提示极易被忽略。验证命令sudo dmesg | tail -10 | grep -i signature\|trusted # 成功时应无输出失败时显示签名错误4.7 步骤七持久化加载与冲突规避创建/etc/modprobe.d/rtl8192eu.conf# 黑名单冲突驱动 blacklist rtl8192cu blacklist rtl8192c_common # 设置模块参数 options 8192eu rtw_power_mgnt0 rtw_enusbss0 # 永久加载 install 8192eu /sbin/modprobe --ignore-install 8192eu $CMDLINE_OPTS; /sbin/modprobe --quiet --use-blacklist usbcore必做理由install指令确保modprobe 8192eu时自动加载依赖usbcorertw_power_mgnt0关闭省电模式解决USB断连问题实测使设备在线率从92%提升至99.8%。验证最终状态sudo modprobe 8192eu lsmod | grep 8192eu # 应显示模块名、大小、使用计数 ip link show | grep wlan # 应出现wlan0接口5. 加载失败的五级排查法从dmesg到objdump的完整链路即使严格按上述步骤操作仍有约15%的概率遇到insmod失败。此时不能盲目重试而应按以下五级顺序排查每级提供具体命令和判断逻辑。5.1 一级排查dmesg实时日志分析sudo dmesg -C # 清空日志缓冲区 sudo insmod ./8192eu.ko sudo dmesg -H | tail -20 # -H开启人类可读时间戳关键线索识别Invalid module format→ vermagic不匹配内核版本/配置不一致Unknown symbol→Module.symvers缺失或符号未导出No such device→ 硬件未被PCIe/USB子系统识别检查lspci -vv -s xx:xx.x或lsusb -v -d vid:pidOperation not permitted→ Secure Boot未签名或SELinux阻止。我的实战经验某次dmesg显示8192eu: disagrees about version of symbol module_layout表面是符号问题实则是/lib/modules/$(uname -r)/build指向了错误内核源码。用readelf -S ./8192eu.ko | grep -A2 .modinfo查看模块内嵌的vermagic字符串与cat /lib/modules/$(uname -r)/build/include/generated/compile.h | grep UTS_RELEASE对比即可定位偏差。5.2 二级排查模块依赖关系验证modinfo ./8192eu.ko | grep -E (depends|vermagic|srcversion) # 输出示例 # depends: usbcore,usb-common,cfg80211 # vermagic: 6.5.0-28-generic SMP mod_unload modversions # srcversion: 1A2B3C4D5E6F7G8H9I0J1K交叉验证# 检查依赖模块是否已加载 for dep in $(modinfo ./8192eu.ko | grep depends | cut -d: -f2 | tr , ); do echo Checking $dep: $(lsmod | grep ^$dep | wc -l) done # 应全部输出1致命陷阱modinfo显示depends: usbcore但lsmod | grep usbcore为空。这是因为usbcore是内置模块built-in不显示在lsmod中。此时需确认内核配置CONFIG_USBy非m否则模块无法链接。5.3 三级排查符号表精确比对当dmesg报Unknown symbol usb_register_driver时需确认该符号是否在usbcore模块中导出# 查看usbcore导出的符号 sudo modprobe usbcore cat /proc/kallsyms | grep usb_register_driver # 应输出类似0000000000000000 T usb_register_driver # 如果无输出说明usbcore未加载或符号未导出深度验证用nm检查模块符号nm -D /lib/modules/$(uname -r)/kernel/drivers/usb/core/usbcore.ko | grep usb_register_driver # -D参数只显示动态符号即可供其他模块调用的5.4 四级排查内核日志级别调优默认dmesg日志级别可能过滤关键信息。临时提升sudo dmesg -n 8 # 设置日志级别为8debug sudo insmod ./8192eu.ko sudo dmesg -H | tail -50关键日志特征8192eu: loading out-of-tree module taints kernel→ 模块被标记为“污染”属正常现象8192eu: module verification failed: signature and/or required key missing→ Secure Boot问题8192eu: probe of 1-1:1.0 failed with error -22→ 设备probe失败错误码-22对应EINVAL需检查probe()函数中参数校验逻辑。5.5 五级排查反汇编定位崩溃点当insmod导致内核panic系统冻结需用objdump分析模块# 反汇编模块 arm-linux-gnueabihf-objdump -d ./8192eu.ko disasm.txt # 搜索panic相关字符串 grep -A5 -B5 panic\|oops\|BUG disasm.txt实战案例某次insmod后系统立即重启dmesg无有效日志。用objdump发现8192eu_probe()函数末尾有call __stack_chk_fail指令——这是栈保护失败的标志。根源是驱动中char buffer[256]被memset(buffer, 0, 512)越界写入。修复后问题消失。最后提醒所有排查必须在干净内核日志下进行sudo dmesg -C否则历史错误会干扰判断。我习惯在每次insmod前执行sudo dmesg -C echo $(date) 让日志有清晰时间锚点。6. 生产环境的长期维护方案让驱动随内核升级自动重建编译一次驱动只是开始真正的挑战是维护。Ubuntu内核每6周更新一次手动重编不现实。我推荐基于DKMSDynamic Kernel Module Support的自动化方案它能在apt upgrade安装新内核后自动触发驱动重建。6.1 DKMS标准目录结构搭建sudo mkdir -p /usr/src/8192eu-5.6.4.2 sudo cp -r ~/driver-build/rtl8192eu-aircrack-ng/* /usr/src/8192eu-5.6.4.2/ # 创建dkms.conf文件 sudo tee /usr/src/8192eu-5.6.4.2/dkms.conf EOF PACKAGE_NAME8192eu PACKAGE_VERSION5.6.4.2 CLEANmake clean MAKEmake -C \${kernel_source_dir} M\${dkms_tree}/\${PACKAGE_NAME}/\${PACKAGE_VERSION} modules BUILT_MODULE_NAME[0]8192eu BUILT_MODULE_LOCATION. DEST_MODULE_LOCATION[0]/updates/dkms DEST_MODULE_NAME[0]8192eu AUTOINSTALLyes EOF关键字段说明PACKAGE_VERSION必须是纯数字点号格式如5.6.4.2不能含-git等字符BUILT_MODULE_LOCATION.表示模块在源码根目录生成与Makefile中obj-m : 8192eu.o对应AUTOINSTALLyes启用自动安装新内核安装后自动构建。6.2 DKMS注册与验证sudo dkms add -m 8192eu -v 5.6.4.2 sudo dkms build -m 8192eu -v 5.6.4.2 sudo dkms install -m 8192eu -v 5.6.4.2验证是否生效dkms status | grep 8192eu # 应输出8192eu, 5.6.4.2, 6.5.0-28-generic, x86_64: installed6.3 内核升级后的自动重建机制当apt install linux-image-6.5.0-29-generic时DKMS会自动触发检测到新内核6.5.0-29-generic执行dkms build -m 8192eu -v 5.6.4.2 -k 6.5.0-29-generic将生成的/var/lib/dkms/8192eu/5.6.4.2/6.5.0-29-generic/x86_64/8192eu.ko复制到/lib/modules/6.5.0-29-generic/updates/dkms/运行depmod -a 6.5.0-29-generic更新模块依赖。故障自愈若某次自动构建失败DKMS会记录日志在/var/lib/dkms/8192eu/5.6.4.2/build/make.log。修复后执行sudo dkms remove -m 8192eu -v 5.6.4.2 --all # 清理失败状态 sudo dkms install -m 8192eu -v 5.6.4.2 # 重新安装6.4 安全加固限制DKMS构建范围默认DKMS对所有内核版本构建可能浪费磁盘空间。通过/etc/dkms/framework.conf限制# 只为当前运行内核和最新内核构建 BUILDTARGETSuname -r $(ls /usr/src | grep linux-headers- | sort -V | tail -2 | xargs)磁盘空间监控DKMS模块默认存于/var/lib/dkms/单个模块约20MB。用以下命令监控sudo du -sh /var/lib/dkms/* | sort -hr | head -5 # 若超过1GB执行清理 sudo dkms remove -m 8192eu -v 5.6.4.2 --all sudo dkms autoinstall我的运维心得在某边缘计算节点部署时因未限制DKMS构建范围/var/lib/dkms/占用12GB磁盘导致系统日志写入失败。此后所有生产环境都加入BUILDTARGETS限制并用cron每日执行find /var/lib/dkms -name make.log -mtime 7 -delete清理旧日志。7. 不同场景下的替代方案什么情况下不该编译驱动编译驱动是终极手段但不是万能解药。根据我的十年经验以下五种场景应优先考虑替代方案避免无谓投入。7.1 场景一硬件本身不被Linux支持某客户采购的“工业级4G模组”型号为Quectel EC25-AU。lsusb显示ID 2c7c:0125但内核drivers/net/wwan/中无对应驱动。此时编译无意义因为厂商未提供Linux驱动源码仅提供Windows.inf文件USB描述符中bInterfaceClassffVendor Specific无标准CDC ACM协议支持。正确做法联系厂商索要Linux SDK或更换为Sierra Wireless EM7455内核原生支持。我曾为此类问题向三家模组厂商发邮件仅一家在2周后提供了qmi_wwan兼容驱动。7.2 场景二固件缺失且无法合法获取dmesg显示Failed to load i915/kbl_dmc_ver1_04.bin但/lib/firmware/i915/中无此文件。Intel官网明确声明该固件仅随Windows驱动分发Linux用户需自行提取。此时从Windows驱动包中提取固件违反EULA