系统休眠唤醒时候,GSM模组USB重新枚举问题
问题描述:rk3588平台,每次休眠唤醒,GSM模块会断掉然后重新枚举:

解决方案如下:
--- a/kernel-6.1/drivers/usb/serial/option.c
+++ b/kernel-6.1/drivers/usb/serial/option.c
@@ -2483,6 +2483,9 @@ static struct usb_serial_driver option_1port_device = {
.suspend = usb_wwan_suspend,
.resume = usb_wwan_resume,
#endif
+#if 1
+ .reset_resume = usb_wwan_resume,
+#endif
};
借助AI解决了该问题,分析如下:
完整机制解释
这一行 .reset_resume = usb_wwan_resume 的缺失,触发了三层连锁反应。
第一层:udriver->reset_resume 不会被注册
usb-serial.c 第 1504~1507 行:/* we only set the reset_resume field if the serial_driver has one */
for (sd = serial_drivers; *sd; ++sd) {
if ((*sd)->reset_resume) { /* ← option 的 reset_resume */
udriver->reset_resume = usb_serial_reset_resume; /* ← USB 设备驱动的 reset_resume */
break;
}
}
这里 (*sd) 是 option_1port_device(即 usb_serial_driver 结构体),udriver 是最终注册到 USB core 的 usb_driver 结构体。
A13:option_1port_device.reset_resume = usb_wwan_resume ≠ NULL → udriver->reset_resume = usb_serial_reset_resume
A14:option_1port_device.reset_resume = 不存在(NULL)→ udriver->reset_resume 保持 NULL
第二层:resume 时走的函数不一样
系统唤醒后,USB core 在 usb_resume_interface() 中判断:/* 简化后的逻辑 */
if (reset_resume) {
if (driver->reset_resume) /* 检查 udriver->reset_resume */
ret = driver->reset_resume(intf); /* → usb_serial_reset_resume() */
else if (driver->resume)
ret = driver->resume(intf); /* → usb_serial_resume() */
}
A13:走 reset_resume 分支 → 调用 usb_serial_reset_resume()
A14:走 resume 分支 → 调用 usb_serial_resume()
第三层(致命区别):URB 的 poison 状态没有清除
usb_reset_and_verify_device() 在做 USB 设备原地复位时,会调 usb_disable_interface() 来禁用接口,这个过程中 URB 被标记为 poisoned(中毒状态)。复位完成后,URB 必须先解除中毒才能重新提交。
现在看两个函数的具体区别:
usb_serial_reset_resume()(A13 走的路径):static int usb_serial_reset_resume(struct usb_interface *intf)
{
...
usb_serial_unpoison_port_urbs(serial); /* ← 解除 URB 中毒! */
if (serial->type->reset_resume) /* = usb_wwan_resume */
rv = serial->type->reset_resume(serial);
else
rv = serial->type->resume(serial);
...
}
usb_serial_resume()(A14 走的路径):int usb_serial_resume(struct usb_interface *intf)
{
...
/* ← 这里没有 usb_serial_unpoison_port_urbs()! */
if (serial->type->resume) /* = usb_wwan_resume */
rv = serial->type->resume(serial);
...
}
usb_serial_resume() 缺了 usb_serial_unpoison_port_urbs() 这一行。
最终效果对比
A13: driver->reset_resume → usb_serial_reset_resume()
→ unpoison_port_urbs() ← URB中毒解除
→ usb_wwan_resume() ← URB重新提交成功 ✓
→ ttyUSB正常工作
A14: driver->reset_resume = NULL → 走 driver->resume → usb_serial_resume()
→ (没有unpoison) ← URB仍处于中毒状态
→ usb_wwan_resume() ← usb_submit_urb() 返回 -EPIPE ✗
→ ttyUSB死亡 → 应用层收发失败 → RIL检测到异常
usb_submit_urb() 在 URB 被 poisoned 时返回 -EPIPE 或 -ESHUTDOWN,URB 无法提交,串口端口实际上无法工作。这种情况下,上层 RIL 尝试读写 ttyUSB 失败,最终只能由系统触发断开重连。
所以这几行代码的完整依赖链是:
option.c usb-serial.c USB core
─────────────────────────────────────────────────────────────────────────────
option_1port_device usb_serial_register_driver() usb_resume_interface()
│ │ │
│ .reset_resume = udriver->reset_resume = if (reset_resume &&
│ usb_wwan_resume ────[A13]──→ usb_serial_reset_resume ───→ driver->reset_resume())
│ │ │
│ │ usb_serial_reset_resume() │
│ │ ├ unpoison_port_urbs() ← 关键 │
│ │ └ usb_wwan_resume() │
│ │ └ submit_urb() → OK ✓ │
│ │ │
│ .reset_resume = NULL ────[A14]──→ udriver->reset_resume = NULL else if (driver->resume())
│ │
│ driver->resume()
│ usb_serial_resume()
│ ├ (NO unpoison!) ← 致命
│ └ usb_wwan_resume()
│ └ submit_urb() → -EPIPE ✗
A13: 有 .reset_resume A14: 无 .reset_resume
→ udriver->reset_resume 注册 → udriver->reset_resume = NULL
→ usb_serial_reset_resume() → 走 driver->resume()
→ unpoison_port_urbs() ✓ → usb_serial_resume()
→ usb_wwan_resume() OK → 缺 unpoison,URB 中毒未解除
→ ttyUSB 正常恢复 → usb_submit_urb() 返回 -EPIPE
→ 串口死掉,RIL 异常→触发重枚举
Linux系统还需要多改一个地方:
kernel defconfig 里没配 CONFIG_USB_DEFAULT_PERSIST=y,导致所有 USB 设备在 root hub 掉电后没有 persist 保护,走 disconnect + 完整重枚举路径。
该配置Android系统默认是打开的。
一句话总结:.reset_resume = usb_wwan_resume 缺了,usb_serial_reset_resume() 就不会被注册到 USB core,USB core 改走 usb_serial_resume(),而后者没有调用 unpoison_port_urbs() 清除 URB 中毒状态,导致 usb_wwan_resume() 提交 URB 失败,串口没法用,最终设备只能断开重枚举。

浙公网安备 33010602011771号