那是电流涌动,造成识别错误。我拿手摸TTL线也会在终端上显示出字符。
那是电流涌动,造成识别错误。我拿手摸TTL线也会在终端上显示出字符。
不是硬件干扰
插拔 USB 后串口冒出 nn*n 乱码?根因找到了:设备管理器的 hwinfo 探测
一句话:deepin-devicemanager-server 每次 USB 插拔都会执行 hwinfo --usb --keyboard --mouse,而 hwinfo 的串口鼠标探测会把你正在用的串口强行改成 1200/7N1,并往里写 4 遍字符串 "*n"(正好 8 字节)。这就是乱码的来源。
这不是新问题,GitHub issue #6921(2024-01)报过同一件事,当年给了补丁但没修好(原因见下),至今仍是 open。
【现象】
picocom 连着开发板(115200 8N1),每次插上/拔掉任意 USB 设备(U 盘、鼠标、另一个串口线都算),窗口里就闪出一串重复字符:
*n*n*n*n
删掉/改名 hwinfo 就正常。
【根因:三段代码】
谁在调用(deepin-devicemanager 源码)
/* src/hotplug/detectthread.cpp:107 */
process.start("hwinfo", QStringList() << "--usb" << "--keyboard" << "--mouse");
由 monitorusb.cpp 的 libudev 监听触发,add/remove 事件即执行。关键是带了 --mouse。
hwinfo 拿着 --mouse 干了什么(hwinfo 源码)
/* src/hd/mouse.c:389-397 */
if( hd->sub_class.id == sc_com_ser && // 是串口(每个 ttyUSB* 都被这么标)
!hd->tag.skip_mouse ) {
fd = open(hd->unix_dev_name, O_RDWR | O_NONBLOCK); // 抢你的口,不看锁文件
setspeed(fd, 1200, 1, CS7); // :410 强制 1200 / 7 位数据位
写进去的就是 "*n" 这两个字符
/* src/hd/mouse.c:558 / :562 */
case 1200: default: c = "*n"; tty.c_cflag = flags | B1200; break;
if(needtowrite) { write(fd, c, 2); } // 把 "*n" 写进你的串口
/* src/hd/mouse.c:573 */
for(i = 9600; i >= 1200; i >>= 1) // 4 轮循环
_setspeed(fd, i, new, needtowrite, flags);
循环 4 轮、每轮 2 字节 —— 所以屏幕上是同一个图案重复,而不是随机乱码。
注:这段代码的注释写着 "Baud setting magic taken from gpm.",是控制台鼠标守护 gpm 的老逻辑,*n 本来是 MouseSystems 协议问鼠标型号的指令。对着不是鼠标的串口发,就是纯破坏。
【实锤:8 = 4 × 2】
issue #6921 里报告人量到的是「拔插 USB 后 /proc/tty/driver/serial 的 tx 值加 8」。
4 轮循环 × 每轮 write(fd, "*n", 2) = 8 字节
两个不同的人、两台机器、相隔一年多,测出来的数字和源码逐字节吻合。
顺带解释当年那个补丁为什么"没屏蔽全":补丁只注释掉了 _setspeed() 里的 tcsetattr(不改波特率了),但没动紧跟其后的那个 write,8 字节照发、tx 照 +8。
【为什么有的串口没事(别高兴太早)】
hwinfo 的 usb.c:957-963 里写死了一条豁免:
// bnc #408715 (T-Balancer BigNG)
if(vendor == 0x0403 && device == 0x6001) // = FT232R 芯片
skip_mouse = skip_modem = 1;
这是 2008 年为保护一个 FTDI 芯片的水冷控制器打的补丁(openSUSE changelog: "Mon Jul 21 2008 skip T-Balancer BigNG")。它按芯片 ID 匹配,于是误保护了所有 FT232R 设备,而 CP2102 / CH340 等一律不豁免。
注意:这条豁免不覆盖 braille,也没法用 udev / 环境变量改(编译进二进制的逻辑)。
【修复:给 hwinfo 加 hwprobe(推荐)】
hwinfo 有官方开关 hwprobe,官方文档写明它 "cannot be overridden by command line switches" —— 也就是说设备管理器传 --mouse 也压不过它。
sudo dpkg-divert --rename --divert /usr/sbin/hwinfo.real --add /usr/sbin/hwinfo
sudo tee /usr/sbin/hwinfo >/dev/null <<'EOF'
#!/bin/sh
: "${hwprobe:=-mouse,-modem,-braille}"
export hwprobe
exec /usr/sbin/hwinfo.real "$@"
EOF
sudo chmod 755 /usr/sbin/hwinfo
用 dpkg-divert 是故意的:以后 hwinfo 升级,新二进制会装到 hwinfo.real,wrapper 不会被冲掉。
撤销:sudo dpkg-divert --remove --rename /usr/sbin/hwinfo
想全局覆盖(需重启)也可以改内核命令行加 hwprobe=-mouse,-modem,-braille。
副作用:设备管理器的"鼠标"页信息可能变少(有 lshw/sysfs 兜底)。对开发机来说这个代价很划算。
不建议:直接删 hwinfo(会连带废掉设备管理器的 USB/鼠标/键盘信息,且 apt 一升级就装回来)。
【验证(30 秒)】
# 改之前:能看到往非 FT232R 的口写 "*n"
sudo strace -f -e trace=openat,write -s 16 /usr/sbin/hwinfo --mouse 2>&1 | grep -E 'ttyUSB|"\*n"'
# 改之后:应该完全无输出
sudo strace -f -e trace=openat,write -s 16 /usr/sbin/hwinfo --usb --keyboard --mouse 2>&1 | grep -E 'ttyUSB|"\*n"'
【给官方】
- detectthread.cpp:107 那行的 --mouse 建议去掉(识别 USB 设备用 --usb 就够,且 --usb 不碰串口),或者给 hwinfo 调用统一加 hwprobe=-mouse,-modem,-braille。
- 用一个会 open(O_RDWR) 并改写串口 termios 的工具做设备信息采集,本身就不安全。
参考:
· issue #6921 https://github.com/linuxdeepin/developer-center/issues/6921
· 论坛旧帖 2025-01 https://bbs.deepin.org/post/283222
· hwinfo 源码 https://github.com/openSUSE/hwinfo
· deepin-devicemanager 源码 https://github.com/linuxdeepin/deepin-devicemanager
Popular Ranking
ChangePopular Events
More

中文 


插拔usb设备会导致串口异常输出
设备
Bus 001 Device 011: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
暂时应对
删除 /sbin/hwinfo就正常
sudo mv /sbin/hwinfo /sbin/hwinfo.bak