尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Linux下识别USB设备的4种实用方法:lsusb、dmesg、sysfs与udevadm

Linux下识别USB设备的4种实用方法:lsusb、dmesg、sysfs与udevadm 我干这行快十年了几乎每天都在跟各种 USB 设备打交道。打印机、U盘、开发板、USB转串口模块、无线网卡、工业读卡器……可以说折腾 Linux 系统时你避不开的一个基础操作就是搞清楚 USB 设备到底被系统识别成什么了。很多人一上来就敲个lsusb看到一行厂商信息就完事了。但实际工作中光知道“有个设备在”远远不够。你要知道它的厂商 ID、产品 ID、挂在哪条总线上、用的什么驱动、有没有被正确枚举、主控是 xHCI 还是 EHCI甚至还要在设备插拔的一瞬间抓到内核日志。这些需求对应着不同的识别方法也就是我这次要整理的Linux 系统下识别 USB 设备的 4 种实用思路。这几种方法没有绝对的优劣之分关键是看场景。插上没反应时该用哪个命令驱动加载失败时该看哪里想写 udev 规则时去哪里拿设备属性我这次会把每种方法的核心原理、常用命令、输出解读、实战中容易踩的坑都讲清楚尽量让不同基础的读者都能照着操作。1. 先搞清楚你说的“识别”到底是哪一层识别很多人觉得识别 USB 设备就是“系统认出这个东西了”其实这句话说得太笼统。Linux 系统里的 USB 识别至少可以分成两个层面理解这一点你才能明白为什么有时候lsusb能看到设备但/dev下就是没有节点。1.1 设备层识别内核看见了什么USB 设备插上后最先反应的是主机控制器。现在绝大多数机器用的是 xHCIUSB 3.0 及以上也有老一点的 EHCIUSB 2.0、OHCI/UHCIUSB 1.1。主控制器检测到端口电平变化就会给设备供电、复位总线、开始枚举过程。枚举是 USB 协议层的核心动作主机依次给设备发送标准请求读取设备描述符Device Descriptor、配置描述符Configuration Descriptor拿到厂商 IDVID、产品 IDPID、设备类别、端点信息等。这些信息构成了一条完整的“设备识别链”。内核里的 USB core 驱动完成枚举之后会把设备挂到 USB 总线上分配一个逻辑编号比如1-2.3这种形式。到这一步设备就算被“内核识别”了。1.2 用户层识别系统展示给你什么内核识别了设备之后系统才会进一步决定怎么把它暴露给用户空间。如果设备是 HID 类键鼠系统会加载 usbhid 驱动产生 input 事件如果是大容量存储类U盘会加载 usb-storage 或 uas 驱动生成/dev/sd*设备如果是 CDC-ACM 类或者使用 FTDI、CP210x、CH340 这类芯片的 USB 转串口系统会加载对应驱动生成/dev/ttyUSB*或/dev/ttyACM*。换句话说你在lsusb里看到的每一条记录内核一定已经识别到设备了但/dev下有没有对应的节点、节点叫什么名字取决于驱动匹配和子系统注册这是更高一层的“识别”。再往细了说应用层还能继续识别比如通过libusb直接和设备通信或者通过gio、udisks2这类抽象层访问设备。我们这里主要讨论前两层也就是“内核层识别”和“系统层识别”因为它们对应了绝大多数排查场景。2. 方法一lsusb —— 最直接的快速识别先说最常用的。lsusb来自 usbutils 工具包几乎所有发行版默认都装了。它读取的是内核维护的 USB 设备列表把每个设备的两级 hub 拓扑关系、厂商信息、产品信息、设备版本这些整理成可读文本。2.1 lsusb 基本用法和输出解读终端里敲lsusb输出大概是这样的$ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 001 Device 003: ID 046d:c52b Logitech, Inc. Unifying Receiver Bus 001 Device 004: ID 0bda:0129 Realtek Semiconductor Corp. RTS5129 Card Reader Controller Bus 001 Device 005: ID 13d3:3495 IMC Networks USB2.0 UVC HD Webcam Bus 002 Device 002: ID 0951:1666 Kingston Technology DataTraveler 100 G3/G4/SE9 9GB/32GB每一行从左到右分别是总线编号、设备编号、VID:PID 以及厂商和产品字符串。这里面有个容易被忽略的重点Bus 001和Bus 002通常对应不同类型的控制器。你可以用lsusb -t查看树状拓扑这样能更清楚地看到设备挂在哪个控制器上。在 Linux 系统识别 USB 设备这个场景里VID:PID是最关键的信息。它相当于 USB 设备的身份证号。比如刚才输出里的0951:16660951是 Kingston 的厂商 ID1666是这款 DataTraveler 的产品 ID。驱动匹配、udev 规则编写、libusb 程序开发全都靠这对组合。2.2 从 lsusb 输出里能读出的深层信息很多人不知道lsusb -v能输出设备的所有标准描述符包括设备描述符里的bcdUSB、idVendor、idProduct、bDeviceClass以及配置描述符里的接口信息、端点地址、传输类型、最大包大小等等。我排查 USB 转串口驱动问题时最常用它来确认设备到底是不是 CDC-ACM 类设备。$ lsusb -v -d 0403:6001这个命令只查看 VID 为 0403FTDI、PID 为 6001FT232R的设备。输出里会有一大段描述了接口类、子类、协议如果看到bInterfaceClass 10 CDC Data说明这个设备走的是 CDC 协议。这个信息能帮你判断为什么某个串口工具连不上驱动匹配对了但内核把接口当成调制解调器处理了应用层配置不对通不上。2.3 lsusb 的进阶参数和脚本化思路-t以树状拓扑显示。-v输出完整描述符。-s [[bus]:][devnum]只看某个总线上的某个设备。-d [vendor]:[product]按 VID:PID 过滤。-D /dev/bus/usb/xxx/yyy直接读取指定设备文件。写脚本轮询时我习惯用lsusb -d 046d:c52b这样的方式来检测某个外设是否在线。结合 shell 脚本就是#!/bin/bash if lsusb -d 046d:c52b /dev/null 21; then echo Logitech receiver is present. else echo Logitech receiver is absent. fi这个方法在嵌入式设备、无人值守工控机上特别实用。系统里挂的每个 USB 外设是否在位用一条命令就能监控到。我做过一个现场运行的小工具每 30 秒检查一次几个关键 USB 设备是否在线不在线就通过串口发送告警信号就是这么用lsusb实现的。提醒lsusb显示的信息来自内核启动或设备插拔时缓存的描述符数据。如果设备在插拔时枚举就失败了lsusb可能看不见它这时候就得用方法二去查。3. 方法二dmesg —— 从内核日志还原设备接入全过程如果说lsusb是拍一张当前的“合影”那dmesg就是把设备从插入到枚举的整个过程录成了“视频”。排查 USB 识别问题时dmesg往往才是真正能定位问题的关键。3.1 为什么 dmesg 是排查 USB 问题的第一选择USB 设备接入时内核 USB core 会打印一系列日志。从检测到端口状态变化、复位、枚举、获取描述符到驱动 probe 成功每一步都有迹可循。如果哪一步失败日志里通常会有明确的原因比如device descriptor read/64, error -71、Device not accepting address、No configuration chosen、cannot enable. Maybe the USB cable is bad?。我曾经遇到过一个 U盘在 Windows 下正常插到 Linux 上lsusb完全看不到。用dmesg一看[ 2502.129401] usb 2-1.2: new high-speed USB device number 8 using ehci-pci [ 2502.231004] usb 2-1.2: device descriptor read/64, error -71 [ 2502.431989] usb 2-1.2: device descriptor read/64, error -71 [ 2502.641943] usb 2-1.2: new full-speed USB device number 9 using ehci-pci [ 2502.746960] usb 2-1.2: device descriptor read/64, error -71 [ 2502.953217] usb 2-1.2: device descriptor read/64, error -71 [ 2503.159779] usb 2-1.2: new full-speed USB device number 10 using ehci-pci内核反复读取设备描述符失败这就是典型的接触不良或者线材质量不行。换了一根线马上就好了。这种问题你光用lsusb是看不出来的。3.2 如何用 dmesg 精准过滤 USB 事件dmesg输出很吵闹直接看会被一堆无关信息淹没。我一般用grep组合关键字dmesg | grep -i usb dmesg | grep -i usb 2-1 dmesg | grep -iE usb|ttyUSB|ttyACM配合tail只看最近的新增日志这样插拔设备时能看到实时过程dmesg -wdmesg -w是持续监听模式插拔 USB 设备时它会实时把新的内核日志打印出来。调试多设备冲突或者看驱动加载过程时开着这个窗口再插设备是最直观的。如果你用的是 Systemd 系发行版journalctl也能看内核日志journalctl -k -f journalctl -k | grep -i usbjournalctl -k走的是 systemd 日志系统比起dmesg有持久化优势重启后也能查历史。有些场景下dmesg显示的内容被kernel.dmesg_restrict限制了普通用户看不了这时候journalctl反而是更通用的选择。3.3 实战案例USB 转串口FT232R/CH340驱动加载过程USB 转串口模块是调试嵌入式设备时最常用的东西正好拿它举例。插入一个 FT232R 模块后dmesg的典型日志是usb 1-3: new full-speed USB device number 5 using xhci_hcd usb 1-3: New USB device found, idVendor0403, idProduct6001 usb 1-3: New USB device strings: Mfr1, Product2, SerialNumber3 usb 1-3: Product: FT232R USB UART usb 1-3: Manufacturer: FTDI usb 1-3: SerialNumber: A10LEDVF usbserial 1-3:1.0: FTDI USB Serial Device converter detected usb 1-3: FTDI USB Serial Device converter now attached to ttyUSB0看到now attached to ttyUSB0说明驱动加载成功设备节点生成。如果只看到FTDI USB Serial Device converter detected但后面没有attached可能是驱动加载被接口占用或者其他冲突。我再给个 CH340 芯片国产的 USB 转串口方案的例子。它的 VID:PID 是1a86:7523驱动是ch341。插上后日志里会出现usb 1-2: ch341-uart converter now attached to ttyUSB0如果设备被识别成ttyACM0而不是ttyUSB0说明芯片可能工作在 CDC-ACM 模式或者用了不同的驱动路径。这时候千万别按惯性去开/dev/ttyUSB0要先用dmesg看清楚实际节点后面所有配置才不会白做。实操心得插上设备前执行dmesg -w插拔一次再把日志复制出来看。这是最完整的 USB 设备接入记录比任何工具都有说服力。4. 方法三/sys 与 /proc —— 用文件系统看底层细节lsusb和dmesg已经能解决 80% 的日常需求了但如果要写 udev 规则、做设备权限管理、或者写代码去枚举设备那就得去/sys或者/proc里挖底层数据。这也是 Linux 设计的一项核心思想一切皆文件。4.1 /sys/bus/usb/devices 目录结构/sys/bus/usb/devices/下面会列出所有 USB 设备命名方式是1-0:1.0这样带有拓扑关系和接口号的格式。读一下每个目录里的文件就能拿到内核视角的最原始属性。我还常常用sysfs里的product、manufacturer、serial、idVendor、idProduct、speed、devnum、busnum等文件。比如想获取某个设备的序列号用于 udev 精确匹配直接cat /sys/bus/usb/devices/1-3/serial注意有些设备没写序列号那个文件可能不存在或者内容是空的。这种设备做 udev 规则匹配时就只能退而求其次用 VID/PID 匹配了。4.2 从 /sys 里获取设备树和驱动信息lsusb -t显示的树状结构在/sys里就是目录的层级关系。比如设备被识别为1-2.3它的父设备是1-2这是接在 USB 2.0 hub 第 2 口下的第 3 端口设备。理解这种层级对排查“为什么这个口能识别、那个口不能识别”的问题特别有帮助。想知道某个设备当前绑定到哪个驱动看driver符号链接ls -l /sys/bus/usb/devices/1-3:1.0/driver输出可能指向ftdi_sio、ch341、usb_storage、usbhid等。这在驱动冲突排查时价值很高。我遇到过同一个 USB 网卡插在不同的口上有时被识别为 CDC Ethernet、有时被识别为 vendor-specific 设备实际上就是内核模块加载顺序不一致的问题。通过link文件能直接确认该接口当前用的是哪个驱动。另外/sys/kernel/debug/usb/devices这个 debugfs 文件也会提供一份完整的 USB 设备树带描述符信息比/proc/bus/usb/devices更新更全。不过需要 root 权限并且部分发行版默认没有挂载 debugfs得先mount -t debugfs none /sys/kernel/debug。/proc/bus/usb/devices是早期的接口。在新内核上只要没有启用CONFIG_USB_DEVICEFS这个文件基本不存在了或者内容为空。看到老教程里说这个路径先用cat试一下如果路径不存在就说明你的内核已经放弃了这种展示方式直接用 sysfs/debugfs 就好。4.3 综合实操用 sysfs 自动生成 U盘设备节点信息我写过一个运维小脚本需求是监控某个 U盘是否被插入并且判断序列号对不对。用 sysfs 做就是遍历/sys/bus/usb/devices/下每个idVendor、idProduct匹配到之后再读serialfor dev in /sys/bus/usb/devices/*/; do vid$(cat $dev/idVendor 2/dev/null) pid$(cat $dev/idProduct 2/dev/null) if [ $vid 0951 ] [ $pid 1666 ]; then echo Found device: $dev echo Serial: $(cat $dev/serial 2/dev/null) fi done这种脚本跑在树莓派、工控机上都很稳不需要装任何额外的依赖。这也是为什么我说/sys路径值得花时间搞懂它是系统给用户空间开的一扇底层窗户比解析命令行输出更稳定、更精准。特别提醒很多临时挂载点是按设备名动态变化的写脚本时优先用/sys而不是解析lsblk这种中间输出。内核接口的稳定性比上层工具好很多这是我在生产环境踩过坑之后养成的习惯。5. 方法四udevadm 与桌面图形工具 —— 管理维度的识别前面几种方法都是被动地“看设备”但有时候你需要在设备插入的瞬间做出反应比如自动加载某个驱动、创建节点别名、调整权限。这时就需要理解 Linux 的 udev 机制而udevadm就是它的核心管理命令。5.1 udevadm monitor实时监控设备事件udevadm monitor可以实时监听内核产生的 uevent 和 udev 处理后的事件。插拔 USB 设备时输出会显示旧设备路径、新设备路径、各种环境变量。这一招在调试“为什么我的 udev 规则没生效”时特别好用。udevadm monitor --property --udev加了--property之后输出里会带上一大堆环境变量比如ID_VENDOR、ID_MODEL、ID_SERIAL、ID_PATH、DEVTYPE、ACTION这些。写 udev 规则时这些变量就是你能拿来匹配的资源。比如你要给某个特定的 USB 串口设备在/dev下创建一个固定的符号链接就得先通过这个命令调查清楚它独有的属性。5.2 用 udevadm info 获取设备的全部属性如果设备已经插入不想等下一次插拔那就用udevadm info -a -n /dev/ttyUSB0这条命令会对/dev/ttyUSB0逐层解析父设备链输出每个层级的设备属性。注意看里面ATTRS{idVendor}、ATTRS{idProduct}、ATTRS{serial}的位置这决定了你在 udev 规则里用哪一层的匹配条件。很多人在这里犯迷糊因为不同属性属于不同层级ATTR和ATTRS不能混着用而udevadm info -a的输出恰恰能帮你定位层级关系。举个例子给 FT232R 串口设备创建稳定别名/dev/my_ftdiSUBSYSTEMtty, ATTRS{idVendor}0403, ATTRS{idProduct}6001, ATTRS{serial}A10LEDVF, SYMLINKmy_ftdi规则里我用的是ATTRS而不是ATTR因为在SUBSYSTEMtty这个匹配条件下idVendor通常不在 tty 设备本身那一层而是向上游父设备找。拿udevadm info -a输出对照一下就能确认自己写的是否能匹配上。5.3 图形化工具给不习惯命令行的用户准备的兜底方案虽然我们是命令行派但也不得不承认图形化工具在快速确认设备状态时效率很高。Linux 下主要有几个选择gnome-disks看磁盘和分区对 U盘、移动硬盘特别直观。usbview图形化显示 USB 总线拓扑能看到每个端口的连接状态。lsusb -t虽然它不是图形工具但树状可视化效果在终端里最接近拓扑图。dmesg --followjournalctl -f如果发行版自带 systemd 日志面板也能实时看到设备事件。对于已经装了桌面环境的发行版插入 U盘时文件管理器自动弹出挂载窗口这本身就是 udev udisks2 工作的结果。如果 U盘不弹窗但lsusb能看到那么问题往往出在挂载环节而不是识别环节。我用usbview的次数不多但它有个独特优势能展示每个设备当前请求了多少电流mA这在调试供电不足问题时很关键。USB 协议规定设备在配置描述符里声明电流需求usbview 直接把这个值显示出来比拿钳表测方便得多。6. 四种方法怎么选对照表与实战场景识别 USB 设备的方法有了但用什么场景选什么方法还是要有个清晰的判断框架。我不想让读者看完文章之后不知道该用哪个这里直接给一个我在实操中总结的选型逻辑。6.1 方法对比从使用场景看选型方法典型命令/路径最适合的场景局限lsusblsusb、lsusb -v快速确认设备是否在线、获取 VID/PID设备枚举失败时可能看不到dmesgdmesg -w、journalctl -k排查插拔异常、驱动加载失败输出量大需过滤阅读sysfs/sys/bus/usb/devices/写脚本、制作 udev 规则、程序化访问需要理解目录层级udevadmudevadm monitor、udevadm info -a管理设备权限、创建符号链接需要理解 udev 规则语法如果你只想知道“设备在不在”用lsusb如果你想知道“设备为什么不在”用dmesg如果你想给某个设备做定点规则用udevadm info -a如果你想在代码里稳定读取信息用/sys。6.2 实战案例新设备无法识别时按什么顺序排查假设你插上了一个新的 USB 转串口设备lsusb看不到串口工具也打开不了。别慌按下面的顺序来先跑lsusb看看有没有。如果看到设备了跳去第 3 步如果没看到立刻开dmesg -w重新插拔一次。dmesg里如果出现大量的error -71或device descriptor read失败优先怀疑线材和供电换线、直接插主板后置 USB 口再试。如果dmesg里显示New USB device found但后面没有驱动绑定日志用lsusb -v -d VID:PID查看设备描述符确认接口类型。再去内核模块列表里检查对应驱动是否加载modprobe ftdi_sio modprobe ch341最后如果设备节点已经出现但权限不足用udevadm info -a -n /dev/ttyUSB0拿到设备属性写一条 udev 规则把当前用户加入dialout组或者给节点设置0666权限。这一步是 Linux 下 USB 串口最常见的权限问题网上问“无法打开 ttyUSB0”的人十有八九是这里没处理好。7. 常见问题与排查技巧实录最后这一节我把这些年实际工作中遇到的高频问题集中整理一下。每一个都是真实踩过的坑照着排查基本能解决九成以上的 USB 设备识别疑难杂症。7.1 问题一lsusb 看不到设备但设备电源灯亮着电源灯亮不代表数据线通了。很多 USB 设备用线里的 VBUS 供电就能让 LED 亮起来但 D/D- 数据线可能断了一根或者接触不良。判断方法有两个一是换一根已知完好的线二是看dmesg里有没有new USB device相关记录。如果dmesg完全没有新事件说明设备在物理层就没有被主控制器检测到重点查线材和接口。如果dmesg有事件但报错那就按上文 3.1 里的描述符读取错误来处理。7.2 问题二插上 U盘后 lsusb 能看到但 /dev 下没有 sdb/sdc能枚举成功说明 USB 协议层没问题问题出在存储子系统。先用dmesg | grep sd看看有没有 SCSI 层日志如果内核认为它是一种Unknown或Unsupported设备可能是 U盘的 SCSI 命令集实现有问题或者触发了 UAS 驱动 bug。一个老旧的 U盘插入后只有sd 0:0:0:0: [sda] No Caching mode page found这类提示时可以考虑禁用 UAS 改用 usb-storageecho 0951 1666 /sys/bus/usb/drivers/uas/unbind echo 0951 1666 /sys/bus/usb/drivers/usb/unbind不过这个操作比较复杂一般不建议手动处理先用lsusb -t查看是不是走了uas驱动再说。如果设备不重要直接换一个 U盘试一下成本更低。7.3 问题三USB 3.0 设备只能在 2.0 速度下工作lsusb -t输出每个设备的速度如果显示480M而不是5000M/10000M说明设备降速了。常见原因是线材不支持 SuperSpeed、插在了 USB 2.0 only 的端口上或者设备本身固件有问题。这类问题在笔记本上特别常见很多笔记本的 Type-C 口并非所有口都支持 USB 3.0 xHCI。用lsusb -t看清楚设备挂在哪个控制器上就能区分是不是硬件接口限制。7.4 问题四USB 设备频繁断开重连表现为dmesg里不断出现USB disconnect、new USB device周而复始。这通常有三个原因供电不足尤其是移动硬盘、不带供电的 hub、延长线。绿节能autosuspend把设备挂起设备不支持唤醒导致假死。主控制器或端口开启了省电策略。如果是 Linux 桌面环境下可能是 USB autosuspend 在捣乱。可以临时关闭某个设备的 autosuspendecho 0 /sys/bus/usb/devices/1-3/power/autosuspend_delay_ms或者用udevadm monitor确认是否是电源管理事件导致的。这个坑很多人一辈子都遇不到但一旦遇到近端设备频繁抽风排查起来很折磨人。7.5 问题五udev 规则写了但没生效我见过太多人在这里卡壳。常见原因有四种规则文件权限不是 root、文件名没有以.rules结尾、没有执行udevadm control --reload、匹配条件层级用错ATTR和ATTRS。正确操作流程是写完规则后执行sudo udevadm control --reload sudo udevadm trigger然后重新插拔设备再用udevadm test /sys/bus/usb/devices/1-3验证。如果还是不行用udevadm monitor --property看实际触发的事件变量对照着调整规则条件。匹配条件里属性在哪个父设备上就得用哪一层对应的ATTRS别想当然。避坑提示udev规则里匹配KERNEL时要注意通配符ttyUSB*是合法写法ttyUSB?也是但两者匹配逻辑不同。写规则前先贴出udevadm info -a输出对照。最后聊几句我的实践经验做嵌入式开发和服务器运维这么多年识别 USB 设备这件事看起来基础但恰恰是很多疑难杂症的入口。我个人的习惯是任何关于 USB 的问题第一步永远是dmesg -w配合一次插拔把日志抓完整再谈其他。lsusb和/sys提供的是静态快照dmesg和udevadm提供的是动态过程两两组合才能真正还原设备状态。有一次我在现场调试一台数据采集设备上位机总是报找不到 USB 设备对方工程师一口咬定是嵌入式主板坏了。结果我插上设备后用udevadm monitor --property一抓发现系统把设备识别成了显示器类根本没加载串口驱动。最后在应用层指定了正确的 VID/PID问题秒解。这种案例全靠一开始就把每个层面的识别信息都摸清了才快。顺便分享一个还在用的小技巧在多个 USB 串口设备同时接入的生产环境里我给每个设备都用 udev 规则绑定了固定的/dev/设备名符号链接应用层只认链接名不认ttyUSB0这种动态节点。这样哪怕设备插拔顺序乱了逻辑也永远不会错乱。这个思路大家也可以参考。Linux 和 USB 是两个越深入越有乐趣的话题但日常使用不需要把协议栈背下来把这几种识别方法融会贯通遇到设备不认、驱动不对、权限不足的问题时你就比绝大多数人少走很多弯路。
返回列表