
简介面向ARM64架构如AGX Orin平台Ubuntu22.04系统的PL2303 USB转串口驱动安装教程资源包专门解决新系统下驱动兼容性差、编译环境配置繁琐等问题适合嵌入式工程师与Linux运维人员参考。压缩包共111个文件以30个C源码、28个头文件和27个Makefile为主体同时提供可加载内核模块ko、符号表symvers、图片及命令脚本等辅助材料整体仅671KB内容紧凑且便于快速部署。资源聚焦PL2303G驱动v1.0.6完整覆盖从环境准备、依赖安装、源码编译到内核模块加载与设备识别验证的流程针对加载失败、权限不足、设备节点未生成等常见问题也给出了基于dmesg日志的排查思路。配合minicom、screen等串口工具的配置说明读者可在AGX Orin等ARM64设备上快速恢复PL2303串口通信能力。该教程已有1094人学习下载对于在ARM64平台维护串口外设的开发者具有直接参考价值。1. ARM64 架构下串口 PL2303 驱动为什么“插上就有 ttyUSB”在 AGX Orin 上不成立一根 USB 转串口线插到 AGX Orin 的 Ubuntu 22.04 上lsusb能看到067b:2303但ls /dev/ttyUSB*就是什么都没有。这是我在 ARM64 平台上做串口调试时遇到的最典型翻车现场而且十次里有七次不是硬件坏了。PL2303 驱动在 Linux 里不是一个“装上就有”的普通软件包它由内核模块承载在内核引导或者热插拔时被动态加载而很多现成的驱动包、编译脚本都是面向 x86_64 架构的到了 ARM64 上要么直接拒绝安装要么装进去也跑不起来。AGX Orin 这类设备跑的是 Ubuntu 22.04但内核通常是定制过的硬件平台又不是常规 PC所以驱动安装的路径完全是另一套。这篇笔记会带你走完从排查设备枚举、确认模块状态、准备内核头文件到用 DKMS 编译安装 pl2303 驱动的全过程并把识别不了芯片、端口漂移、权限不足这些常见坑一次说清。适合正在 ARM64 设备上做串口外设接入、机器人底盘通信或者工业设备调试的开发者。2. PL2303 的驱动体系先搞懂 usbserial、pl2303 和 ttyUSB 三者关系2.1 Linux 里 PL2303 驱动不是“一个文件”而是一条链路很多教程把 PL2303 驱动简化成“下载一个 .ko 然后 modprobe”但实际驱动加载是分层的。USB 转串口设备被主机识别后先由 USB core 枚举然后匹配到 USB 串口适配驱动层。在 Linux 内核里usbserial是通用串口转换层负责把 USB 端点和 tty 层对接pl2303则是针对 PL2303 系列芯片的具体驱动负责讲芯片的寄存器协议。设备最终注册成一个/dev/ttyUSB0节点上层应用读写这个节点和读写普通串口几乎没有区别。内核自带的pl2303.ko一般位于/lib/modules/$(uname -r)/kernel/drivers/usb/serial/pl2303.ko它依赖usbserial.ko。当你插入 PL2303 设备时usb core 通过 VID/PID 匹配到pl2303驱动驱动 probe 成功后再调用usb_serial_register注册 tty 设备。这个链路里任何一环断了结果都是“lsusb 有设备但 /dev/ttyUSB0 不存在”。这里有个容易误解的地方看到 NULL谁都会怀疑“驱动没装”。但更常见的状况是驱动确实存在、也加载了却在 probe 阶段主动拒绝设备。PL2303 芯片版本杂老的 HXA、中间过渡型号和新款芯片的寄存器行为并不完全一致内核驱动对某些克隆芯片或者过新版本会直接返回错误。所以排查时要同时看模块加载状态和内核日志而不是只盯着lsmod的输出。2.2 用三条命令快速判断设备状态先把最基础的三条命令跑一遍每一步输出的含义都值得看清楚。代码如下# 查看 USB 总线是否枚举到设备记下 VID:PID lsusb # 查看内核打印的 USB 和串口相关日志重点看最后 50 行 dmesg | tail -n 50 # 查看 pl2303 和 usbserial 模块是否已经加载 lsmod | grep -E pl2303|usbseriallsusb的输出里如果没有067b:2303说明 USB 枚举这关就没过先不要急着弄驱动优先换线、换 USB 口、重新插拔。如果能看到设备继续看dmesg。正常加载会有类似pl2303 converter now attached to ttyUSB0的日志如果出现device not supported或者failed to set vendor info那就是驱动认出芯片但拒绝绑定。lsmod这步用来确认模块是否已经驻留在内核里如果输出为空说明模块压根没有被加载需要手动modprobe pl2303或者排查模块加载路径。三条命令跑完后我一般会把结论套到下面这张表里直接定位故障层面lsusb 结果dmesg 关键日志/dev/ttyUSB0故障层面无设备无任何 USB 枚举信息无USB 链路层换线换口有设备枚举正常无 pl2303 日志无驱动未加载或未匹配有设备not supported / rejected无驱动与芯片版本不兼容有设备attached to ttyUSB0有驱动正常查上层配置2.3 x86_64 的驱动包为什么在 ARM64 上不可靠网上能搜到的 PL2303 驱动安装包很大一部分是面向 x86_64 架构的.deb或者.rpm。这类包里的.ko文件是编译好的二进制架构不匹配时modprobe会直接报invalid module format。ARM64 和 x86_64 的指令集完全不同内核模块又没有跨架构运行的说法所以“下载安装包双击安装”这条路在 AGX Orin 上基本走不通。那能不能直接用内核自带的驱动可以但有限制。如果你用的 Ubuntu 22.04 内核版本比较新自带的pl2303驱动对常见型号支持还算完整而 AGX Orin 这类 ARM64 平台出厂内核可能修改过配置可能没有把pl2303编进去也可能编进去了但版本较老。最稳妥的做法是自己拿源码编译一份模块并通过 DKMS 管理让它在内核升级后还能自动重建。这个思路在嵌入式平台上是常规操作也是后面几章要重点展开的内容。3. 编译前置给 AGX Orin 准备好内核头文件和 DKMS 环境3.1 先确认当前内核版本和头文件是否匹配编译内核模块最怕两件事一是没有头文件二是头文件和当前内核版本对不上。前者直接导致编译无法开始后者更隐蔽编译可能成功但安装后modprobe依然报错。所以第一步是确认当前运行内核和头文件路径。# 查看当前内核版本 uname -r # 查看对应的内核头文件目录是否存在 ls -ld /usr/src/linux-headers-$(uname -r) # 查看内核编译选项里是否已经包含 PL2303 相关配置 zcat /proc/config.gz 2/dev/null | grep -i pl2303uname -r输出的是正在运行的内核版本比如5.10.104-tegra带tegra后缀就说明是平台定制内核。/usr/src/linux-headers-xxx目录存在说明头文件已经装好如果不存在需要补装。最后一条命令是为了确认内核配置里CONFIG_USB_SERIAL_PL2303是m还是nm表示作为模块编译n表示完全没有启用。如果zcat没有输出说明/proc/config.gz不存在可以跳过这步用后面的modinfo判断。3.2 安装编译工具链和 dkms接下来安装编译必需的工具。build-essential 提供 gcc 和 makedkms 负责管理内核模块的源码和自动重建linux-headers 则是对应版本的编译依赖。命令如下# 更新软件源索引然后安装编译工具和 dkms sudo apt update sudo apt install -y build-essential dkms # 尝试安装与当前内核版本一致的头文件 sudo apt install -y linux-headers-$(uname -r) # 如果 apt 提示没有可用软件包就必须手动确认内核源码包的获取方式需要注意平台定制内核的头文件不一定能从 Ubuntu 软件源里装到。遇到Unable to locate package linux-headers-xxx的情况说明这个内核不在 APT 仓库里你需要去平台厂商提供的 Linux 内核源码包中找对应版本解压后手动放到/usr/src下。判断头文件是否工作可以检查目录里有没有Makefile# 检查内核头文件目录结构是否完整 ls /usr/src/linux-headers-$(uname -r)/Makefile如果这个Makefile不存在说明头文件不完整直接做模块编译大概率会在Kbuild not found报错处停下来。这里有个细节有些平台把源码放到/usr/src之后还需要执行make modules_prepare但这一步需要完整的内核源码树而不是压缩过的 headers-only 包。大多数情况下模块编译用带Makefile的 headers 包就够了。3.3 检查平台上是否已有出厂预置的 pl2303 模块在动手编译前先确认系统里到底有没有现成的pl2303.ko。很多 AGX Orin 的板级镜像其实默认就带了驱动你遇到的只是权限或者设备兼容问题不需要重复编译。# 用 modinfo 查看模块信息能查到就说明模块存在且可用 modinfo pl2303 2/dev/null | head -n 10 # 直接按路径查找模块文件 find /lib/modules/$(uname -r) -name pl2303* -type f 2/dev/null如果modinfo pl2303能打印出 filename、license、depends 等信息说明模块已经在模块目录里了直接跳到第 5 章排查为什么没有 ttyUSB 节点。如果find命令没有输出那才需要走第 4 章的 DKMS 编译流程。还有一个细节值得注意即使模块文件存在modprobe pl2303时也可能因为固件、依赖模块缺失而失败所以后续加载时先看dmesg再下结论不要凭感觉反复插拔设备。4. 用 DKMS 在 ARM64 上编译安装 PL2303 驱动完整命令与参数4.1 准备驱动源码和 dkms.conf拿到 PL2303 驱动源码压缩包后先解压再把目录放到/usr/src/下并以“驱动名-版本号”命名。这一步是 dkms add 能找到源码的前提。同时需要在该目录里准备一份dkms.conf告诉 dkms 模块名、版本、编译方式和安装位置。# 假设源码包已经下载到当前目录文件名为 pl2303-x.x.x.tar.gz # 版本号 x.x.x 按你实际拿到的源码版本替换 tar -xzf pl2303-x.x.x.tar.gz sudo mv pl2303-x.x.x /usr/src/ # 进入驱动源码目录编写 dkms.conf cd /usr/src/pl2303-x.x.x sudo tee dkms.conf EOF PACKAGE_NAMEpl2303 PACKAGE_VERSIONx.x.x BUILT_MODULE_NAME[0]pl2303 DEST_MODULE_LOCATION[0]/kernel/drivers/usb/serial/ MAKE[0]make -C ${kernel_source_dir} M${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build modules CLEANmake -C ${kernel_source_dir} M${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build clean AUTOINSTALLyes EOFPACKAGE_NAME和PACKAGE_VERSION是 dkms 管理模块的唯一标识dkms build和dkms install用这两个字段定位源码目录。BUILT_MODULE_NAME指定编译产物名称DEST_MODULE_LOCATION是模块安装到内核模块树里的相对路径因为 usb serial 驱动约定放在kernel/drivers/usb/serial/下。MAKE这一行是编译命令模板${kernel_source_dir}会被 dkms 替换成当前内核源码目录${dkms_tree}则指向 dkms 的工作目录。AUTOINSTALLyes表示允许 dkms 在内核更新时自动重建模块建议开启避免日后升级内核后驱动失效。4.2 执行 dkms add、build、install源码和配置准备好后按顺序执行三步。add 只是把源码注册进 dkms 的数据库build 才真正调用编译install 则把编好的.ko复制到当前内核的模块目录。# 把 /usr/src/pl2303-x.x.x 注册进 dkms sudo dkms add /usr/src/pl2303-x.x.x # 编译模块-m 指定模块名-v 指定版本号 sudo dkms build -m pl2303 -v x.x.x # 安装模块到当前内核模块目录 sudo dkms install -m pl2303 -v x.x.x # 查看 dkms 管理的模块状态出现 installed 才说明安装成功 dkms status执行dkms build时如果看到类似Kernel preparation unnecessary的提示是正常的如果出现make: Entering directory后半途报错通常是头文件不完整。重点看报错信息里有没有linux/compiler.h、linux/module.h这类找不到头文件的提示如果有回到第 3 章把头文件重新装一遍。dkms install失败率很低但偶尔会因为模块目录权限或签名校验报错前者用sudo即可后者意味着你的平台启用了一些模块签名机制需要跳过签名检查或重新签名这是另一个话题常见于定制内核。dkms status是最后的验证关口。我习惯在install之前先跑一次sudo dkms build -m pl2303 -v x.x.x --no-depmod快速确认编译能通过再执行 install。这样可以减少无效的模块安装次数。编译过程中如果你改了源码必须重新跑 build只改dkms.conf的话执行sudo dkms update -m pl2303 -v x.x.x更稳妥它会刷新配置并重建状态。4.3 加载模块并确认 ttyUSB0 出现安装完成后先卸载可能存在的旧模块再加载新版模块。千万不要直接插设备先看模块能否正常挂载。# 卸载旧模块避免版本冲突 sudo modprobe -r pl2303 2/dev/null # 加载新模块 sudo modprobe pl2303 # 检查模块加载日志 dmesg | tail -n 20 # 查看是否生成串口节点 ls -l /dev/ttyUSB*modprobe pl2303会自动处理usbserial依赖前提是依赖模块在模块目录里。如果报Module pl2303 not found先执行sudo depmod -a更新模块依赖关系。加载成功后插入 PL2303 设备dmesg末尾应该能看到pl2303 converter now attached to ttyUSB0。如果依然没有 ttyUSB0不要重复加载模块直接看第 5 章的兼容性排查。为了开机自动加载建议在/etc/modules-load.d/下新建一个配置内容只有一行pl2303。另外串口设备通常归dialout组管理当前用户需要加入这个组才能免 sudo 访问这一步容易忘放在这里提醒# 把当前用户加入 dialout 组重新登录后生效 sudo usermod -aG dialout $USER # 写入模块开机加载配置 echo pl2303 | sudo tee /etc/modules-load.d/pl2303.conf权限问题上还可以用 udev 规则把设备节点软链成固定名字比如/dev/pl2303这在多串口设备混插时非常实用后面避坑章节会专门讲端口漂移。5. 驱动装完还是没有 ttyUSB0常见问题与避坑清单5.1 设备枚举正常但 dmesg 出现 not supported现象lsusb能看到067b:2303但dmesg里出现类似device not supported的提示/dev/ttyUSB0始终不出现。原因你手上的线用了兼容版或者克隆版 PL2303 芯片内核驱动在 probe 阶段发现芯片回复的寄存器特征与正规型号不符主动拒绝。这个问题在 ARM64 和 x86_64 上都会出现但在嵌入式平台更容易被误判成“驱动版本不对”。解决先确认芯片来源有条件就换一根用原装芯片的线这是最省事的方法。如果暂时换不了可以尝试加载usbserial通用驱动让它不经过pl2303的校验机制强制绑定# 卸载原驱动改用通用 usbserial 绑定指定 VID/PID sudo modprobe -r pl2303 sudo modprobe usbserial vendor0x067b product0x2303注意通用绑定方式失去了 PL2303 驱动对芯片的特殊初始化部分参数可能不稳定但至少能创建ttyUSB0用来临时调通业务问题不大。还有一种情况是dmesg里没有not supported而是failed to set baudrate之类那通常是芯片供电不足换独立供电的 USB HUB 试试。5.2 编译时报 Kbuild 相关错误现象执行sudo dkms build后输出含有Kbuild not found、linux/compiler.h not found或No rule to make target。原因内核头文件目录虽然存在但没有完整的内核构建目录结构通常是因为头文件不是从对应镜像源安装的或者版本与uname -r不一致。解决重新确认/usr/src/linux-headers-$(uname -r)里有没有Makefile和include/generated目录。缺失的话从平台内核源码包手动安装头文件然后用sudo dkms remove -m pl2303 -v x.x.x --all清掉旧记录重新 add 和 build。编译环境的问题不要靠反复改代码解决先保证make -C /lib/modules/$(uname -r)/build能进入目录再说。5.3 模块安装成功但 modprobe 找不到 .ko现象dkms status显示installed但sudo modprobe pl2303报Module not found。原因dkms install把.ko放到了模块目录但内核模块依赖索引还是旧的或者.ko权限不对。还有一种情况是安装到了错误内核版本的目录下尤其当你更新过内核后重启进新内核旧模块自然不在当前内核里。解决先执行sudo depmod -a重新生成依赖索引再试一次modprobe。仍然失败就找模块文件实际位置# 查找 pl2303.ko 实际放置位置 find /lib/modules/$(uname -r) -name pl2303.ko确认文件存在后再查权限.ko需要可读即可不需要执行权限。如果文件确实不在当前内核目录dkms status里又显示 installed说明版本号或者内核版本匹配出了问题移除后重新 install。5.4 能打开 ttyUSB0 但提示权限不足现象ls /dev/ttyUSB0能看到设备但运行串口工具时报Permission denied或者用echo测试时无输出。原因当前用户不在dialout组没有对串口设备的访问权限。这个问题在桌面版 Ubuntu 上常见在 AGX Orin 这类嵌入式系统上也经常被忽略。解决执行sudo usermod -aG dialout $USER然后重新登录或重启确认组生效后再试。如果你不想影响现有用户组也可以临时用sudo运行串口工具先验证硬件链路是否正常。另外某些系统里串口设备所属组是tty可以用ls -l /dev/ttyUSB0看实际的组名再决定加入哪个组。5.5 多个 USB 转串口插上后端口漂移现象这次插上 PL2303 是ttyUSB0重启后变成了ttyUSB2程序里写死的设备路径失效。原因Linux 按 USB 枚举顺序分配 ttyUSB 编号跟物理接入顺序强相关换口、重启、插入其他 USB 设备都会改变编号。解决用 udev 规则固定设备节点。先拿到设备的序列号或者稳定的系统路径再写规则# 查看设备路径和序列号 udevadm info -a -n /dev/ttyUSB0 | grep -E ATTR{serial}|ATTRS{serial}拿到唯一的序列号后创建/etc/udev/rules.d/99-pl2303.rules内容按实际 serial 替换比如SUBSYSTEMtty, ATTRS{serial}A104O3X2, SYMLINKttyPL2303。重载 udev 规则后插上设备就会出现固定软链/dev/ttyPL2303程序里用它来替代 ttyUSB 编号。要注意克隆芯片的序列号字段可能为空或者完全相同这种情况只能按 USB 口的拓扑路径写规则稳定性稍差。6. 装完驱动之后用回环测试验证串口是否真的能收发驱动装上、/dev/ttyUSB0也出现了但先别急着接外部设备我强烈建议做一次回环测试把串口模块的 TX 和 RX 短接然后从系统里写数据看能不能自己读回来。这一步能把“驱动问题”和“接线问题”快速隔离也是我做串口调试的第一条习惯。# loopback_test.py # 回环测试TX 与 RX 短接后写入一个字节应读到同样的字节 import serial ser serial.Serial( port/dev/ttyUSB0, baudrate115200, timeout2, write_timeout2 ) # 写入 5 个已知字节 ser.write(bpl2303) # 从同一串口读回 data ser.read(5) print(received:, data) # 校验读写一致则测试通过 if data bpl2303: print(loopback test PASS) else: print(loopback test FAIL) ser.close()运行方式python3 loopback_test.py。能完整打印pl2303就说明驱动、设备节点、串口硬件全链路正常。如果读回来的数据是空先确认短接是否可靠别用杜邦线虚接如果读到数据但内容对不上检查波特率和校验位设置。回环测试通过之后我一般还会顺手验证一下两个参数一是不同波特率下重跑一次二是用stty -F /dev/ttyUSB0 9600切换速率后再试这样可以暴露驱动对波特率配置的支持差异。部分兼容芯片在 921600 以上高速率下表现很不稳定做高速通信前一定先测过别等现场才踩坑。我的建议是在 AGX Orin 这类 ARM64 平台上报串口问题不要直接把“没有 /dev/ttyUSB0”等价于“没有驱动”。我第一次调这类问题时就犯了同样的错反复编译了五六遍驱动最后才发现是克隆芯片被内核拒认换了一根原装线立刻就好了。从那以后我每拿到一块新板子都会先花十分钟把枚举、模块、权限、回环测一遍再去看业务代码。这套流程看起来简单但能省下后面大半天的排查时间希望能帮到你。本文还有配套的精品资源点击获取