
1. 从一次设备消失说起为什么lsusb是排查USB问题的第一站上周帮同事处理一个嵌入式调试板的问题板子插上Ubuntu工作站之后/dev/ttyUSB0死活不出现dmesg里也看不到任何新设备接入的痕迹。同事第一反应是驱动没装折腾了半天FT232R的驱动重装了两遍还是没反应。我过去看了一眼让他先跑一条命令lsusb结果输出里压根没有FTDI相关的条目。这就说明问题根本不在驱动层——内核连设备枚举这一步都没走完驱动装一百遍也没用。后来换了一根数据线设备立刻出现。这个场景在Linux日常运维和嵌入式开发里太常见了。USB设备识别不了可能是线的问题、供电的问题、内核模块的问题、udev规则的问题、权限的问题甚至可能是USB控制器本身的问题。如果一上来就盲目装驱动、改配置很容易在错误的方向上浪费大量时间。而lsusb这条命令的价值就在于它能在几秒钟内告诉你内核到底有没有看见这个设备。看见了问题在驱动或应用层没看见问题在物理层或控制器层。这一个判断就能把排查范围砍掉一半。这篇文章面向的是经常和Linux打交道的开发者、运维和嵌入式工程师尤其是那些需要接USB转串口、USB转CAN、USB Blaster、调试探针等外设的人。我会把lsusb这条命令的用法讲透然后给出一套从物理层到应用层的完整排查流程最后分享几个我在实际项目中踩过的坑。整套流程走下来大部分USB识别问题都能在5到10分钟内定位到根因。2. lsusb到底读的是什么理解它的数据来源和输出结构2.1 它读的不是设备列表而是内核的USB设备树很多人以为lsusb是去扫描物理接口其实不是。它读取的是/sys/bus/usb/devices/和/dev/bus/usb/下的信息这些信息由内核的USB子系统在枚举设备时创建。换句话说lsusb能看到的东西都是内核已经成功枚举并注册的设备。如果设备在物理层就没被识别lsusb里不会有任何记录这也是它能作为第一道分界线的原因。理解这一点很关键。它意味着lsusb的输出反映的是内核视角的USB拓扑而不是硬件的真实连接状态。一个设备插着但没出现在lsusb里说明内核根本没收到枚举请求或者枚举失败了。2.2 默认输出怎么读直接跑lsusb输出大概长这样Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 004: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC Bus 001 Device 003: ID 046d:c52b Logitech, Inc. Unifying Receiver Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub每一行的结构是固定的Bus 002设备挂在哪条USB总线上。总线编号对应的是控制器不是物理接口。Device 001这条总线上的设备地址是动态分配的插拔后会变。ID 1d6b:0003冒号前是厂商IDVID冒号后是产品IDPID。这两个值是排查的核心。最后是厂商和产品的描述字符串来自设备自己上报的描述符。VID和PID是设备的身份证。比如0403是FTDI10c4是Silicon LabsCP210x系列0483是STMicroelectronics。记住几个常用的VID排查时一眼就能认出来。2.3 树形视图才是排查利器默认输出是平铺的看不出层级关系。用-t参数能看到完整的USB拓扑树lsusb -t输出类似/: Bus 02.Port 1: Dev 1, Classroot_hub, Driverxhci_hcd/6p, 5000M /: Bus 01.Port 1: Dev 1, Classroot_hub, Driverxhci_hcd/12p, 480M |__ Port 3: Dev 4, If 0, ClassVendor Specific Class, Driverftdi_sio, 12M |__ Port 5: Dev 3, If 0, ClassHuman Interface Device, Driverusbhid, 12M这个视图信息量极大。你能看到设备挂在哪个根集线器的哪个端口上、协商的速率是多少12M是全速480M是高速5000M是超高速、以及内核给它绑定了哪个驱动。如果某个设备显示Driver(none)说明设备被枚举了但没匹配到驱动问题就定位到驱动层了。2.4 详细模式拿到设备的完整描述符需要看某个设备的详细信息时用-d指定VID:PID配合-vlsusb -d 0403:6001 -v这会输出设备的全部描述符包括设备描述符、配置描述符、接口描述符、端点描述符以及字符串描述符。排查一些设备能识别但功能不正常的问题时这个输出非常有用。比如串口设备如果没有正确上报接口类或者端点配置异常都能从这里看出来。提示-v的输出很长建议配合grep过滤比如lsusb -d 0403:6001 -v | grep -i bInterfaceClass。3. 五步排查流程从物理层一路查到应用层3.1 第一步确认内核是否看见设备插上设备立刻跑lsusb对比插拔前后的输出差异。如果设备出现了说明内核枚举成功跳到第三步。如果没出现继续第二步。这一步有个小技巧可以先用watch持续监控watch -n 1 lsusb然后插拔设备观察输出变化。这样不会漏掉那些插上又立刻掉线的设备。3.2 第二步内核没看见先查物理层和控制器lsusb里没有设备问题一定在枚举之前。按这个顺序排查换线。这是最高频的原因没有之一。很多USB线是充电线只有电源线没有数据线插上只能供电不能通信。尤其是那些来路不明的短线、赠品线。我遇到过至少三次问题最终定位到线材上。换口。换一个USB接口最好换到主板直出的口避开前面板扩展口和USB Hub。有些Hub供电不足大功率设备比如USB转CAN、USB Blaster根本起不来。查内核日志。插拔的瞬间看dmesgdmesg -w如果插上设备后dmesg里连一行新日志都没有基本可以确定是物理层问题——线、口、或者设备本身。如果出现了device descriptor read/64, error -71这类错误说明枚举过程中通信失败通常是线材质量或供电问题。error -110是超时error -32是管道错误这些错误码都指向物理层。查USB控制器。用lspci确认控制器是否正常lspci | grep -i usb如果控制器本身有问题所有USB口都会失效这时候要查的是主板或内核驱动而不是单个设备。3.3 第三步内核看见了但驱动没绑上lsusb里有设备但lsusb -t里显示Driver(none)或者设备节点没出现。这时候问题在驱动层。先确认设备需要的驱动模块是否加载lsmod | grep -i ftdi以FT232R为例驱动模块是ftdi_sio。如果没加载手动加载sudo modprobe ftdi_sio如果加载了但没绑定可能是VID:PID不在驱动支持列表里。可以手动把设备ID喂给驱动echo 0403 6001 | sudo tee /sys/bus/usb-serial/drivers/ftdi_sio/new_id这条命令的意思是告诉ftdi_sio驱动去绑定VID为0403、PID为6001的设备。很多国产USB转串口芯片用的是FTDI或CP210x的兼容方案VID:PID可能不在默认列表里用这招能救回来。对于CP210x系列Silicon Labs驱动是cp210x操作类似sudo modprobe cp210x echo 10c4 ea60 | sudo tee /sys/bus/usb-serial/drivers/cp210x/new_id3.4 第四步驱动绑上了但设备节点不对驱动正常绑定后串口设备应该出现在/dev/ttyUSB*或/dev/ttyACM*下。用这个命令确认ls -l /dev/ttyUSB* /dev/ttyACM*如果没有检查dmesg里驱动绑定后的日志通常会打印出创建了哪个设备节点。有时候节点创建了但名字不是预期的比如多路串口设备会创建ttyUSB0到ttyUSB3。如果节点存在但权限不对普通用户访问不了需要加udev规则。创建一个规则文件sudo vim /etc/udev/rules.d/99-usb-serial.rules内容SUBSYSTEMtty, ATTRS{idVendor}0403, ATTRS{idProduct}6001, MODE0666, GROUPdialout然后重载规则sudo udevadm control --reload-rules sudo udevadm trigger重新插拔设备权限就对了。把用户加入dialout组也能解决权限问题sudo usermod -aG dialout $USER注意这条命令需要重新登录才生效。3.5 第五步设备节点正常但应用层用不了到了这一步硬件、内核、驱动、权限都没问题了问题在应用层。常见的情况有波特率不匹配。用stty确认当前配置stty -F /dev/ttyUSB0 -a设备被其他进程占用。用lsof查sudo lsof /dev/ttyUSB0如果有进程占着先杀掉再试。ModemManager是常见的抢设备元凶它会自动去探测新插入的串口设备导致你的程序打不开。可以临时停掉sudo systemctl stop ModemManager协议层问题。比如USB转CAN设备设备节点出来了但CAN接口没起来。这时候要查的是ip link和CAN相关的配置而不是USB本身了。4. 几个高频场景的针对性排查4.1 USB转串口设备识别不了这是最常见的一类。FTDIFT232R、FT231X、Silicon LabsCP2102、CP2104、CH340/CH341、PL2303这几家芯片占了绝大多数。排查时先看lsusb里的VID:PID芯片VIDPID驱动模块FTDI FT232R04036001ftdi_sioFTDI FT231X04036015ftdi_sioCP210210c4ea60cp210xCH3401a867523ch341PL2303067b2303pl2303如果lsusb里能看到设备但驱动没绑按3.3节的方法手动喂ID。CH340比较特殊它的驱动是ch341有些老内核里没有需要自己编译。PL2303有个著名的坑新版芯片PL2303HXD之后和老驱动不兼容会出现乱码或无法通信需要打补丁或者换芯片。4.2 USB Blaster和调试探针识别不了Altera USB Blaster的VID:PID是09fb:6001原厂或09fb:6810兼容版。这类设备对USB线材和供电比较敏感尤其是兼容版经常因为供电不足导致枚举失败。排查时优先换短线、换主板直出口。如果lsusb能看到但Quartus识别不了通常是udev权限问题。创建规则SUBSYSTEMusb, ATTR{idVendor}09fb, MODE06664.3 STM32等MCU的USB设备识别不了STM32自带的USB外设比如USB DFU、USB CDC识别不了先确认MCU端的USB时钟配置是否正确。48MHz的USB时钟如果配错设备根本不会发起枚举lsusb里自然看不到。这种情况下Linux端怎么排查都没用得回去查MCU的时钟树。如果MCU端配置没问题lsusb能看到设备但功能异常检查描述符是否正确。用lsusb -v看bMaxPower字段如果设备申请的电流超过端口能提供的会被拒绝枚举。4.4 虚拟机里的USB设备识别不了虚拟机场景很特殊。宿主机能看到设备但虚拟机里看不到问题在虚拟机的USB透传配置。以VirtualBox为例需要安装Extension Pack然后在虚拟机设置里添加USB设备过滤器。VMware Workstation则是要在虚拟机设置里勾选显示所有USB输入设备然后手动连接。一个常见的坑虚拟机抢占了USB设备后宿主机反而看不到了。排查时先在宿主机确认lsusb能看到设备再去虚拟机里查。5. 那些文档里不会写的实操心得5.1 用udevadm info反查设备属性lsusb给的是VID:PID但写udev规则时经常需要更多属性比如序列号、物理端口路径。用udevadm能拿到完整属性udevadm info -a -n /dev/ttyUSB0这个输出里包含了从设备节点一路回溯到根集线器的所有属性写规则时按需取用。比如要区分两个同型号的串口设备可以用ATTRS{serial}来区分。5.2 dmesg的过滤技巧dmesg输出太多用-w实时监控配合grep过滤USB相关dmesg -w | grep -i usb插拔设备时相关的日志会实时打印出来。如果看到usb 1-3: new full-speed USB device number 5 using xhci_hcd说明枚举开始了后面跟着usb 1-3: New USB device found, idVendor0403, idProduct6001说明枚举成功再后面是驱动绑定的日志。如果枚举中途卡住或者报错错误码就是排查方向。5.3 复位USB控制器有时候USB控制器会进入异常状态所有设备都识别不了。这时候可以尝试复位控制器。先找到控制器的PCI地址lspci | grep -i usb然后解绑再重新绑定echo 0000:00:14.0 | sudo tee /sys/bus/pci/drivers/xhci_hcd/unbind echo 0000:00:14.0 | sudo tee /sys/bus/pci/drivers/xhci_hcd/bind这个操作会重置整个控制器的状态对某些控制器假死的情况有效。注意地址要换成你自己的。5.4 供电不足的隐蔽表现供电不足不一定表现为完全识别不了有时候是能识别但工作不稳定。比如USB转CAN设备在大量收发数据时突然掉线或者USB Blaster在烧录大文件时失败。这种问题最难查因为lsusb里设备一直在。判断方法用带供电的USB Hub或者换到能提供更大电流的USB 3.0口USB 3.0标准提供900mAUSB 2.0只有500mA。如果换了之后问题消失就是供电问题。5.5 记录设备的指纹对于需要长期稳定运行的设备建议记录它的物理端口路径。用这个命令lsusb -t找到设备对应的Bus和Port比如Bus 01.Port 3。这个路径在硬件不变的情况下是固定的而/dev/ttyUSB0这种节点名会随插拔顺序变化。写程序时用/dev/serial/by-path/下的符号链接更可靠ls -l /dev/serial/by-path/这个目录下的链接名包含了物理端口路径插拔顺序变化时不会乱。6. 把排查流程固化成习惯整套流程走下来核心逻辑其实就一句话先用lsusb判断内核有没有看见设备再根据结果决定往物理层还是驱动层查。这个判断花不了5秒钟但能省下大量盲目试错的时间。我自己的习惯是遇到USB问题先跑三条命令lsusb lsusb -t dmesg -w | grep -i usb第一条看设备在不在第二条看驱动绑没绑第三条看枚举过程有没有报错。三条命令的输出基本就能定位到问题在哪一层。剩下的就是针对性地处理物理层换线换口驱动层喂ID或装模块权限层写udev规则应用层查占用和配置。最后分享一个我踩过的坑有一次调试一块USB转CANFD接口卡lsusb能看到设备lsusb -t显示驱动也绑了但CAN接口死活起不来。查了半天USB最后发现是CAN相关的内核模块can和can_raw没加载。所以排查时别忘了USB只是通道通道通了之后上层协议栈的配置也得跟上。