ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

Linux下CH34x串口设备消失?brltty服务冲突的排查与解决

Linux下CH34x串口设备消失?brltty服务冲突的排查与解决 1. 问题缘起一个看似无解的“设备消失”之谜最近在折腾一个基于CH340G芯片的USB转串口设备用来调试一块嵌入式开发板。环境是Ubuntu 22.04 LTS按理说内核自带驱动插上就能用。但诡异的事情发生了设备插入后ls /dev/ttyUSB*空空如也dmesg里却能看到设备被成功识别并加载了ch341驱动。更奇怪的是几秒钟后系统日志里会闪过一条关于brltty服务的信息然后这个串口设备就像从未出现过一样从系统中“蒸发”了。如果你也遇到了类似情况——无论是CH340、CH341还是其他CH34x系列芯片的设备在Linux系统下无法正常创建/dev/ttyUSB0这样的设备节点那么你很可能也踩进了同一个坑。这个问题与一个名为brltty的系统服务有关它会在后台“劫持”你的串口设备导致正常的串口通信工具如minicom,screen,picocom根本无法访问。网络上相关的求助帖不少但解决方案往往语焉不详或者只给命令不给解释。今天我就结合自己的排查过程和原理分析把这个问题彻底讲透并提供几种不同场景下的解决思路。简单来说brltty是一个盲文显示设备守护进程它会自动检测并尝试接管系统上新出现的串行设备包括USB转串口设备。对于CH34x这类常见的USB转串口芯片brltty的错误接管会导致内核的ch34x驱动无法正常创建设备文件从而使你的串口工具“找不到设备”。2. 深入拆解brltty 是什么以及它为何“多管闲事”要解决问题必须先理解对手。brltty的全称是Braille Display Driver是Linux上一个历史相当悠久的服务主要功能是为视障用户提供盲文显示终端支持。它的设计初衷是好的自动扫描系统上的串行端口如/dev/ttyS*,/dev/ttyUSB*,/dev/ttyACM*一旦发现可能兼容的盲文显示器就主动建立连接并提供服务。2.1 brltty 的工作机制与冲突根源brltty通常以系统守护进程daemon的形式运行由systemd或udev规则触发。其冲突的核心机制在于基于 udev 的自动捕获现代Linux发行版使用udev管理设备节点。当一个新的USB设备插入时内核会通知udevudev根据一系列规则创建设备节点并可能触发相关服务。brltty安装时会向系统添加自己的udev规则通常位于/lib/udev/rules.d/或/etc/udev/rules.d/下如85-brltty.rules。这条规则的内容本质上是“如果检测到一个新的串行设备满足特定条件就通知brltty服务去尝试连接它”。设备节点占用当brltty尝试连接一个设备时它会以独占模式打开该设备的文件描述符。在Linux中一个设备文件被一个进程以读写方式打开后其他进程通常就无法再以同样的方式打开了尽管有些驱动支持共享但串口设备通常不支持。对于CH34x设备brltty的连接尝试虽然不是永久成功因为它无法与CH34x正常通信但这个短暂的独占打开动作足以干扰后续正常的ch34x驱动操作和用户空间程序如minicom的访问。与内核驱动的“竞争”问题更微妙之处在于时序。理想流程是设备插入 → 内核ch341驱动绑定并创建设备节点/dev/ttyUSB0→ 用户程序打开/dev/ttyUSB0使用。但加入了brltty后流程可能变成设备插入 → 内核驱动绑定 →udev创建设备节点 →brltty的udev规则被触发立即尝试打开该设备 → 打开失败或产生冲突 → 导致设备节点状态异常或无法被正常访问。你可以通过以下命令验证brltty是否正在运行并监听设备systemctl status brltty或者查看是否有相关的udev规则grep -r brltty /lib/udev/rules.d/ /etc/udev/rules.d/ 2/dev/null2.2 为什么偏偏是 CH34x 容易中招这并非CH34x芯片的“专利”但CH34x系列作为市面上最廉价、最常见的USB转串口芯片之一用户基数极大因此暴露该问题的概率也最高。任何通过cdc_acmUSB通信设备类抽象控制模型或ftdi_sio、pl2303、ch341等专用驱动实现的USB转串口设备理论上都可能被brltty扫描到。CH34x只是其中之一。关键在于brltty的自动检测规则可能过于“宽泛”。它可能不仅仅针对真正的盲文显示器而是对所有它“不认识”的串行设备都进行尝试连接。而大多数嵌入式开发者使用的USB转串口模块显然不是盲文显示器于是便产生了这场“美丽的误会”。3. 诊断与确认如何判断你的问题确实是 brltty 导致的在动手解决之前需要确凿的证据。以下是系统的诊断步骤你可以跟着一步步确认。3.1 查看内核日志dmesg插入CH34x设备后立即在终端运行sudo dmesg -w或者查看最近的日志sudo dmesg | tail -30你需要关注的关键信息序列应该是这样的[ 1234.567890] usb 1-2: new full-speed USB device number 10 using xhci_hcd [ 1234.721234] usb 1-2: New USB device found, idVendor1a86, idProduct7523 [ 1234.721245] usb 1-2: New USB device strings: Mfr0, Product2, SerialNumber0 [ 1234.721250] usb 1-2: Product: USB Serial [ 1234.721876] ch341 1-2:1.0: ch341-uart converter detected [ 1234.723456] usb 1-2: ch341-uart converter now attached to ttyUSB0这表示ch341驱动识别成功并创建了ttyUSB0。如果紧接着你看到类似下面的信息[ 1234.825678] brltty[12345]: /dev/ttyUSB0: unable to open device: No such device or address或者设备节点/dev/ttyUSB0出现后又很快消失那么brltty就是头号嫌疑犯。3.2 检查设备节点状态在插入设备后快速执行ls -la /dev/ttyUSB*如果没有任何输出或者设备文件存在但你用minicom或cat /dev/ttyUSB0时提示“Permission denied”或“Device or resource busy”可以进一步检查是哪个进程占用了它sudo lsof /dev/ttyUSB0如果ttyUSB0不存在可以尝试查找相关的USB设备lsusb找到你的CH34x设备通常厂商ID是1a86记下总线号和设备号如Bus 001 Device 010然后查看该设备对应的内核驱动信息ls -la /sys/bus/usb/devices/1-2/进入该目录查看driver符号链接指向哪里以及tty子目录下是否有内容。3.3 观察 systemd 单元日志brltty服务如果被触发会在 systemd 日志中留下记录sudo journalctl -u brltty -f插入设备观察是否有新的日志条目出现。如果看到它正在尝试打开你的/dev/ttyUSB*设备那就是铁证。4. 解决方案大全从临时禁用到永久根治根据你的使用场景临时调试、个人开发机、生产环境或需要兼顾无障碍功能可以选择不同层级的解决方案。我按推荐程度和影响范围从低到高排列。4.1 方案一最直接粗暴——停止并禁用 brltty 服务推荐给个人开发者这是最彻底、最一劳永逸的方法前提是你和系统其他用户完全不需要盲文显示功能。步骤立即停止当前运行的服务sudo systemctl stop brltty执行后尝试重新插拔你的CH34x设备看看/dev/ttyUSB0是否出现并能正常使用。禁止 brltty 开机自启sudo systemctl disable brltty这可以防止下次重启后问题复现。可选屏蔽 brltty 的 udev 规则 停止服务后udev规则可能仍然会触发虽然服务没运行不会造成占用但可能会产生错误日志。我们可以通过覆盖规则的方式禁用它# 创建一个本地 udev 规则覆盖系统的规则 echo # 禁用 brltty 对串行设备的自动捕获 | sudo tee /etc/udev/rules.d/85-brltty.rules # 或者更稳妥地直接移除或重命名原规则文件 sudo mv /lib/udev/rules.d/85-brltty.rules /lib/udev/rules.d/85-brltty.rules.disabled注意不同发行版规则文件的位置和名称可能略有不同如可能是69-brltty.rules请根据之前grep命令的结果操作。重新加载 udev 规则并触发设备重载sudo udevadm control --reload-rules sudo udevadm trigger再次插拔设备问题应该得到解决。实操心得对于绝大多数嵌入式开发者和单片机爱好者brltty服务是完全用不到的。直接禁用是最佳选择。在Ubuntu Desktop版本中这个服务默认可能是启用的而Server版本通常不安装。如果你不确定禁用它不会有任何负面影响。4.2 方案二精准打击——修改 udev 规则排除特定设备如果你需要在系统上保留brltty服务例如为其他硬件提供支持或者你不想完全禁用一个系统服务那么可以修改udev规则让它忽略你的CH34x设备。原理udev规则可以通过设备的属性如厂商IDID_VENDOR_ID、产品IDID_MODEL_ID、驱动程序DRIVER等进行精细匹配。我们可以添加一条规则让匹配到CH34x设备时不执行触发brltty的动作。步骤创建自定义 udev 规则sudo nano /etc/udev/rules.d/99-disable-brltty-for-ch34x.rules写入规则内容# 禁止 brltty 接管 CH34x 系列 USB 转串口设备 # 匹配条件驱动程序为 ch341并且子系统为 tty SUBSYSTEMtty, DRIVERch341, ENV{PROGRAM}/bin/true # 或者使用更通用的方法直接移除触发 brltty 的环境变量 SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, ENV{BRLTTY_BRAILLE_DRIVER}, ENV{BRLTTY_DRIVER}规则解释SUBSYSTEMtty匹配设备子系统为 tty串口终端。DRIVERch341匹配内核驱动为ch341。你也可以用ATTRS{idVendor}1a86CH34x的常见厂商ID来匹配。ENV{PROGRAM}/bin/true这是一个“欺骗”brltty相关规则的小技巧。原brltty规则可能会检查PROGRAM执行结果我们将其覆盖为一个总是成功返回0的空命令。第二行规则更直接清空BRLTTY_BRAILLE_DRIVER和BRLTTY_DRIVER这两个环境变量这是brltty的udev规则用来决定是否触发服务的关键变量。清空它们brltty就不会被唤醒了。保存文件并重新加载 udev 规则sudo udevadm control --reload-rules sudo udevadm trigger现在插入CH34x设备brltty服务应该不会被触发而/dev/ttyUSB0可以正常使用。注意事项你需要知道你的CH34x设备的确切idVendor和idProduct。使用lsusb命令查看格式为ID xxxx:xxxx。例如ID 1a86:7523表示idVendor1a86,idProduct7523。不同批次的CH340/CH341芯片ID可能略有不同。4.3 方案三临时应对——在打开串口前手动停止 brltty如果你只是偶尔用一下或者没有管理员权限sudo可以尝试这个临时方法。步骤插入设备前先检查brltty是否活跃并尝试用普通用户权限停止它如果允许systemctl --user stop brltty # 如果它以用户服务运行 # 或者如果知道进程ID用 pkill pkill -f brltty快速插入设备并立即尝试打开串口工具。因为brltty服务可能由udev自动重启所以这个时间窗口可能很短。这个方法很不稳定仅作为权宜之计。4.4 方案四釜底抽薪——卸载 brltty 软件包如果确定永远不需要可以直接卸载# 对于 Debian/Ubuntu 系 sudo apt remove --purge brltty # 对于 RHEL/CentOS/Fedora 系 sudo yum remove brltty # 或 sudo dnf remove brltty卸载后相关的udev规则、系统服务文件都会被清理是最干净的做法。但请注意在某些桌面环境中无障碍功能套件可能依赖brltty卸载前请确认。5. 验证与测试确保问题真正解决采取上述任一方案后必须进行验证。重启 brltty 服务如果未卸载如果你选择的是方案二修改规则可以重启brltty服务来测试规则是否生效。sudo systemctl restart brltty sudo journalctl -u brltty -n 20 --no-pager查看日志不应该再有关于/dev/ttyUSB设备的错误或尝试连接信息。模拟设备热插拔# 先拔掉设备 # 清除内核环缓冲区日志 sudo dmesg -C # 插入设备 # 查看 dmesg sudo dmesg | tail -20你应该看到ch341驱动正常绑定并且没有brltty相关的错误信息。使用串口工具测试# 设置权限可选如果当前用户不在 dialout 组 sudo chmod arw /dev/ttyUSB0 # 使用 screen 简单测试 screen /dev/ttyUSB0 115200如果能正常进入串口会话可能是空白或者看到开发板的启动日志按CtrlA然后K再Y退出。或者用minicom、picocom等工具进行正式通信测试。6. 举一反三其他可能引发类似冲突的服务与场景brltty并非唯一一个会“自动抓取”串口设备的服务。理解这个模式后你可以处理类似问题。ModemManager这是一个管理移动宽带WWAN设备的服务。它也会扫描串行设备尝试将其初始化为调制解调器。如果你用来做普通串口通信的USB转串口设备被ModemManager当成 modem 并尝试进行AT命令对话会导致设备被占用和干扰。解决方法类似通过udev规则排除特定设备或者禁用该服务sudo systemctl stop ModemManagersudo systemctl disable ModemManager。蓝牙串口RFCOMM某些蓝牙配置可能会创建虚拟串口虽然不直接冲突但需要注意设备名分配。多个同类USB转串口设备同时插入多个相同芯片的转换器时设备节点可能依次命名为ttyUSB0,ttyUSB1… 顺序可能因插拔顺序或udev规则而变。为了稳定建议使用udev规则通过设备的唯一序列号如果芯片提供或USB端口位置创建固定的、有意义的符号链接例如/dev/ttyMyBoard。排查通用思路 当任何USB或串口设备出现“时好时坏”、“突然消失”、“资源忙”的问题时可以按以下顺序排查查日志dmesg和journalctl -f是第一时间要看的。查进程使用lsof /dev/设备名或fuser -v /dev/设备名查看哪个进程占用了设备。查服务检查是否有像brltty、ModemManager这样的系统服务在运行systemctl list-units | grep -i serial或modem或brl。查规则查看/etc/udev/rules.d/和/lib/udev/rules.d/下是否有可疑的规则文件。隔离测试尝试在停止相关服务、卸载相关模块后问题是否消失。7. 深度剖析udev 规则编写的核心技巧与避坑指南在方案二中我们通过编写udev规则来解决问题。这里分享一些编写高效、准确udev规则的经验。7.1 如何获取设备的准确属性udev规则依赖于设备属性。获取属性最可靠的方法是# 插入设备后先找到它在 /sys 下的路径例如 /sys/bus/usb/devices/1-2 # 然后使用 udevadm 查看所有属性 udevadm info -a -p /sys/bus/usb/devices/1-2或者更简单通过设备节点反查udevadm info -a -n /dev/ttyUSB0在输出中你会看到层层递进的属性块从设备本身到它的父设备。编写规则时通常从最具体的设备本身属性开始匹配。例如匹配 CH340 设备使用ATTRS{idVendor}1a86和ATTRS{idProduct}7523是非常精准的。7.2 规则的作用域与优先级优先级/etc/udev/rules.d/中的规则优先级高于/lib/udev/rules.d/。规则文件按数字顺序读取数字小的先读。因此我们创建的99-开头的规则会在大部分系统规则之后生效可以覆盖前面的设置。作用域一条规则中的多个匹配条件用逗号分隔是“与”的关系必须全部满足。赋值操作或:和运行程序RUN是规则匹配成功后执行的动作。7.3 一个更健壮的排除规则示例下面这条规则结合了多种匹配条件并使用了更优雅的“跳过后续规则”的方法# 文件/etc/udev/rules.d/99-ignore-ch34x-for-brlty.rules # 匹配 CH34x 设备并设置一个环境变量来指示 brltty 跳过此设备 SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, ENV{BRLTTY_DRIVER}skip, GOTObrltty_end SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}5512, ENV{BRLTTY_DRIVER}skip, GOTObrltty_end LABELbrltty_end这里我们设置BRLTTY_DRIVERskip。原始的brltty规则如85-brltty.rules可能会检查这个变量如果值是 “skip” 或空就不会触发服务。你需要查看原规则的具体逻辑来设计最合适的覆盖值。使用GOTO跳转到规则末尾可以避免执行其他不必要的操作。7.4 常见坑点规则语法错误多余的空格、错误的运算符如写成、字符串引号不匹配都会导致规则失效。写完后可以用udevadm test模拟测试需要root权限sudo udevadm test /sys/bus/usb/devices/1-2/ 21 | grep -A5 -B5 你的规则内容属性匹配错误确保你使用的属性如idVendor确实存在于udevadm info输出的正确层级中。ATTRS是匹配父设备属性ATTR是匹配当前设备属性容易混淆。规则未生效修改规则后必须执行sudo udevadm control --reload-rules sudo udevadm trigger来重新加载并触发规则。或者更直接地重新插拔设备。经过以上从问题现象、原理分析到多种解决方案的详细拆解相信你已经对 CH34x 设备与brltty的冲突问题有了透彻的理解。这个问题的本质是系统服务对硬件资源的自动管理策略与用户特定需求之间的冲突。在Linux桌面生态中类似的情况并不少见解决问题的关键在于学会使用dmesg、journalctl、lsof、udevadm这些强大的工具进行诊断并灵活运用systemctl和udev规则进行精准控制。下次再遇到设备“神秘消失”或“资源被占”你就能有条不紊地抓住那个“幕后黑手”了。
返回列表