USB Remote Wakeup 与 Suspend/Resume 调试

USB Remote Wakeup、Suspend/Resume 失败、Selective Suspend 断连、漏掉的 Wake 事件、电源管理 Bug、Resume 信号——用抓包定位。

USB Remote Wakeup, Suspend Resume, Selective Suspend, USB 电源管理, Wake 事件丢失, USB 诊断, 总线分析

USB 电源管理的 bug 难排查,因为设备在系统活跃的时候可能完全正常,只在空闲、休眠、Selective Suspend、Dock 休眠、笔记本合盖、显示器断电之后才出问题。搜 "USB Remote Wakeup 不工作"、"USB Selective Suspend 断连"、"USB 设备唤不醒主机"、"USB Resume 失败"、"USB Suspend/Resume Bug"、"HID 键盘无法唤醒主机" 这一类关键词的人,都是这类问题的受害者。

Bus Scope 在这个场景下有用,因为 Suspend 和 Resume 是总线级事件,不是单纯的应用错误。你需要看到:主机是否挂起了设备、Remote Wakeup 是否被允许、设备是否发了 Resume 信号、主机是否恢复了流量、设备是恢复原状态还是重新枚举了。

Remote Wakeup 是什么

Remote Wakeup 允许一台被挂起的 USB 设备请求主机恢复通信。常见场景:

  • 键盘唤醒处于休眠状态的台式机
  • 鼠标唤醒处于空闲状态的笔记本
  • Dock 按钮唤醒工作站
  • 条码枪唤醒 kiosk
  • 工业控制器唤醒 panel PC
  • HID 传感器在外部事件后唤醒主机

Remote Wakeup 不是"设备有电"那么简单。主机得允许、设备得声明支持、Feature 得启用、Resume 信号得在正确的时间发出来。

常见症状

Remote Wakeup 和 Suspend 问题看起来是:

  • 设备一直能用,电脑一休眠就坏
  • 设备唤不醒主机
  • 设备 Suspend 之后立刻把系统叫醒
  • Resume 之后设备消失
  • 设备以新地址重新枚举
  • 空闲之后 HID 输入丢失
  • Selective Suspend 之后串口不发了
  • 音频/摄像头设备睡眠回来没数据
  • 固件只有重新插拔才能恢复

这些症状经常被甩锅给驱动,但抓包可能会告诉你这是固件的电源状态问题。

描述符和 Feature 证据

Configuration Descriptor 可以声明 Remote Wakeup 能力。主机可以启用或禁用 Remote Wakeup 这个 Feature。一份合格的 USB 诊断 trace 应该回答:

  • 设备有没有声明 Remote Wakeup?
  • 主机有没有发 SET_FEATURE(DEVICE_REMOTE_WAKEUP)
  • 主机后来有没有清掉这个 Feature?
  • 空闲之后 Suspend 有没有发生?
  • 设备有没有尝试 Resume 信号?
  • 主机有没有恢复正常的传输?

没有这些事实,诊断就是猜。

Selective Suspend

Selective Suspend 让操作系统把一台空闲的 USB 设备挂起来,整机不必跟着休眠。它能省电,但会把固件 bug 暴露出来。

失败模式:

  • 设备进了低功耗但没恢复端点状态
  • 固件丢了挂起的 Interrupt IN 状态
  • Resume 之后设备一直 NAK
  • 主机超时之后 Reset 设备
  • 应用看到超时或设备移除
  • 组合设备一个接口恢复了另一个没恢复

搜 "USB selective suspend 随机断连" 的人很多,因为设备看起来"断了",但真正的事件是 Suspend/Resume 失败。

Resume vs 重新枚举

休眠之后会有两种完全不同的结果:

  • Resume:同一台设备用现有配置继续工作
  • 重新枚举:主机 Reset 设备,重新走一次枚举

物理断连之后重新枚举可以接受,常规 Suspend 之后重新枚举就值得怀疑了。它会把还握着的应用句柄、串口名、HID 路径、摄像头采集会话全打断。

Bus Scope 应该能帮你看清:trace 里是正常的 Resume 流量,还是全新的 GET_DESCRIPTORSET_ADDRESSSET_CONFIGURATION 序列。

Wake 事件漏掉

有时候设备看到了外部事件,但主机没被唤醒。原因包括:

  • 没声明 Remote Wakeup
  • 主机没启用 Remote Wakeup
  • 设备 Resume 发得太早
  • 设备 Resume 发得太晚
  • Hub 阻塞或错误处理了 Wake 信号
  • BIOS 或操作系统 Wake 策略禁用了端口
  • 设备固件进入比预期更深的睡眠
  • 事件发生在 Suspend 完成之前

包级证据替代不了操作系统的电源策略,但它能把问题收窄:设备到底有没有权限唤醒主机?它到底有没有尝试?

挂起之后立刻唤醒

反过来的问题也很常见:系统 Suspend 之后立刻又被叫醒。USB 设备在以下情况可能这么做:stale input、Interrupt 状态噪声、去抖 bug、固件把 Suspend 当成新事件。

要收集的证据:

  • Suspend 之前的最后一笔 Interrupt 报告
  • 主机有没有启用 Wake
  • Suspend 和 Resume 之间的时间间隔
  • 设备类和接口
  • 同一端点上有没有 pending 数据
  • 每次 Suspend 是否都重复触发

这在键盘、鼠标、触摸屏、游戏手柄、自定义 HID 设备上特别常见。

排查清单

按这个流程:

  1. 从插入开始抓枚举
  2. 在描述符里确认 Remote Wakeup 能力
  3. 看主机有没有启用 Remote Wakeup
  4. 记录 Suspend 之前的空闲时长
  5. 识别 Suspend 的时点
  6. 看有没有 Resume 信号或主机 Resume 流量
  7. 把 Resume 和完整重新枚举分开
  8. 看 Resume 之后端点的行为
  9. 对比同一台设备在直连端口和走 Hub 上的表现
  10. Suspend 前和 Resume 后的包都保留

最终诊断

USB Remote Wakeup 和 Suspend/Resume 的 bug 是电源状态协议问题。有用的证据是:描述符能力、主机 Feature 选择、Suspend 时序、Resume 信号、端点恢复、以及主机到底是恢复了还是重新枚举了。

Bus Scope 把这些证据摊开来——"USB Wake 不工作"就不再是来回甩锅驱动的死循环,而是一个具体的诊断。