You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UDEV+USB设备检测异常问题求助

问题描述

在Yocto嵌入式Linux平台上,通过udev规则触发USB声卡插拔的音频采集脚本:

ACTION=="add", SUBSYSTEMS=="usb", DRIVERS=="snd-usb-audio", RUN+="/usr/bin/audio.sh start"
ACTION=="remove", ENV{ID_MODEL}=="xxxxxx", RUN+="/usr/bin/audio.sh stop"

首次插拔设备完全正常,但再次连接设备后1分钟会出现udev worker超时警告:

udevd[128]: worker [559] /devices/platform/soc/2100000.bus/2184000.usb/ci_hdrc.0/usb1/1-1/1-1:1.0 is taking a long time

2分钟后出现脚本超时和USB设备控制读取失败日志:

[981.155879] udevd[559]: timeout '/usr/bin/audio.sh start'
[984.571667] usb 1-1: cannot get ctl value: req = 0x81, wValue = 0x202, wIndex = 0x200, type = 4

此时断开设备,remove规则能正常触发;若提前断开,需等待worker超时才会执行remove逻辑。即使简化脚本为单命令,仍会出现worker被kill的错误,修改udev.conf的event_timeout为5秒也无效,更换设备问题依旧。

解决思路与方案

1. 绝对不要让udev直接运行阻塞/长时间进程

udev worker是同步执行的,会持有设备节点锁直到脚本结束。如果你的audio.sh start启动了持续运行的音频采集进程,udev worker会一直等待,最终触发超时。

解决方法:

  • 在脚本末尾加&让进程后台运行,同时重定向输出避免阻塞:
    # audio.sh start里的执行逻辑改成
    /path/to/your/audio_capture >/dev/null 2>&1 &
    
  • 更可靠的方式是用systemd service替代直接RUN脚本:
    1. 创建usb-audio-capture.service:
      [Unit]
      Description=USB Audio Capture Service
      BindsTo=sys-devices-platform-soc-2100000.bus-2184000.usb-ci_hdrc.0-usb1-1-1.device  # 替换为你的设备路径
      
      [Service]
      Type=simple
      ExecStart=/usr/bin/audio.sh start
      ExecStop=/usr/bin/audio.sh stop
      RemainAfterExit=no
      
    2. 修改udev规则为启动/停止service:
      ACTION=="add", SUBSYSTEMS=="usb", DRIVERS=="snd-usb-audio", RUN+="/usr/bin/systemctl start usb-audio-capture.service"
      ACTION=="remove", ENV{ID_MODEL}=="xxxxxx", RUN+="/usr/bin/systemctl stop usb-audio-capture.service"
      

2. 检查脚本是否残留设备占用

日志里的cannot get ctl value是关键——这说明udev尝试读取USB设备控制信息时,设备被其他进程占用了。

  • 确保audio.sh stop能彻底杀死所有相关进程:
    # 不要只用pkill,精准匹配进程名或PID文件
    PID=$(pgrep audio_capture)
    if [ -n "$PID" ]; then
        kill -9 "$PID"
        wait "$PID" 2>/dev/null
    fi
    
  • 首次插拔后,用lsof /dev/snd/*检查设备节点是否被正确释放,再次插拔前确保无残留进程。

3. 优化udev规则的匹配精准度

当前add规则匹配SUBSYSTEMS=="usb",可能会触发多次(USB设备枚举时多个节点触发),导致重复执行脚本,进而占用设备。

  • 改为匹配音频子系统,减少误触发:
    ACTION=="add", SUBSYSTEM=="sound", DEVPATH=="*usb*", DRIVERS=="snd-usb-audio", RUN+="/usr/bin/audio.sh start &"
    
  • Remove规则用ID_SERIAL替代ID_MODEL,避免同型号设备冲突,或者直接匹配设备路径:
    ACTION=="remove", DEVPATH=="/devices/platform/soc/2100000.bus/2184000.usb/ci_hdrc.0/usb1/1-1", RUN+="/usr/bin/audio.sh stop"
    

4. 正确设置udev超时(而非全局event_timeout)

修改udev.conf的event_timeout无效,是因为这个参数是全局事件队列超时,而worker的超时需要在规则里单独设置:

ACTION=="add", SUBSYSTEMS=="usb", DRIVERS=="snd-usb-audio", TIMEOUT="5", RUN+="/usr/bin/audio.sh start &"

或者修改udevd的启动参数,在systemd/system/udevd.service里添加--timeout=5:

ExecStart=/usr/lib/systemd/systemd-udevd --timeout=5

5. 排查USB内核驱动问题

如果更换多个设备都出现cannot get ctl value,可能是Yocto内核的USB驱动(比如ci_hdrc)存在bug:

  • 升级Yocto的内核版本,或者检查是否有相关补丁(比如USB设备重新枚举时的资源泄漏补丁);
  • 在内核配置里开启CONFIG_USB_DEBUG,查看更详细的USB驱动日志,定位设备控制请求失败的原因。

内容的提问来源于stack exchange,提问作者tmakr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 05:08:23