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

嵌入式Linux下无需重启切换g_printer与g_serial USB驱动的技术问询

嵌入式Linux USB Gadget模式切换问题

背景

我正在基于嵌入式Linux设备开发C语言项目,通过同一USB线缆使用两款USB Gadget驱动:

  • g_printer(Linux USB Printer Gadget Driver)
  • g_serial(Linux Gadget Serial Driver)

模式切换流程

USB虚拟串口模式切换步骤

  1. 检查设备文件/dev/g_printer0是否已打开,若是则关闭对应文件描述符。
  2. 执行system("lsmod | grep g_printer > /dev/null");检查g_printer是否加载,若是则执行system("rmmod g_printer");卸载。
  3. 执行system("lsmod | grep usb_f_printer > /dev/null");检查usb_f_printer是否加载,若是则执行system("rmmod usb_f_printer");卸载。
  4. 执行system("modprobe g_serial");加载g_serial。
  5. 打开设备文件/dev/ttyGS0。

USB打印机模式切换步骤

流程类似,先卸载g_serial相关模块,再加载g_printer,对应关闭/打开的设备文件为/dev/ttyGS0和/dev/g_printer0。

问题现象

从USB打印机模式切换到USB虚拟串口模式时,步骤3崩溃,日志报错:

rmmod: can't unload module 'usb_f_printer': Resource temporarily unavailable

系统启动后会自动加载g_printer,此时/dev/g_printer0未被打开,按上述步骤切换到串口模式可正常执行,无报错。目前临时方案是将模式选择保存到配置文件,重启系统后加载对应模式,但体验不佳。

限制条件:

  • 这是设备上运行的唯一进程,无法杀死该进程
  • 不能通过exec启动其他进程处理USB通信,避免资源浪费

提问

  1. 是否存在无需重启Linux系统即可让用户切换这两种模式的方法?
  2. 是否意味着一旦进程打开/dev/g_printer0设备文件,即便已关闭文件描述符,该驱动也无法卸载,只能重启系统或杀死进程?

解答

问题1:无需重启的切换方法

有几种可行的方案:

  1. 检查并释放驱动所有引用

    • 除了关闭自身进程打开的/dev/g_printer0文件描述符,可通过cat /sys/module/usb_f_printer/refcnt查看模块当前引用计数,若计数大于0,说明存在未释放的资源。
    • 先关闭UDC设备:执行echo 0 > /sys/class/udc/<udc-device>/state(替换<udc-device>为实际设备名,比如dwc2.0.auto),再卸载模块,之后重新启用UDC并加载新驱动。
    • 替换system调用为更可靠的内核接口操作:比如直接调用unload_module系统调用(需root权限),或使用libudev管理设备和模块,比解析lsmod输出更准确。
  2. 使用USB复合Gadget框架
    无需单独加载单一功能驱动,而是配置一个包含串口和打印机功能的复合Gadget,通过动态启用/禁用功能节点切换模式:

    • 初始化时创建USB Gadget配置,同时添加acm(串口)和printer功能。
    • 切换到串口模式:执行echo 0 > /sys/kernel/config/usb_gadget/<gadget-name>/functions/printer.0/enable禁用打印机功能,再启用串口功能。
    • 切换到打印机模式则反向操作。这种方式无需卸载模块,从根源避免引用计数问题。
  3. 修复驱动引用计数bug
    若定制内核的usb_f_printer模块存在bug(比如关闭设备文件后未正确递减引用计数),可修改驱动代码,确保release函数中正确清理所有内核态资源并更新引用计数,重新编译模块后替换原文件。

问题2:关闭文件描述符后仍无法卸载的原因

不是必须重启或杀死进程,常见原因有:

  • 驱动未正确释放内核资源:用户态文件描述符关闭后,驱动的release函数可能未清理内核态资源(如USB端点、设备上下文、申请的内存等),导致模块引用计数仍大于0。
  • UDC设备未解绑:USB设备控制器(UDC)仍绑定到打印机Gadget,会占用usb_f_printer模块,需先解绑UDC再尝试卸载。
  • 存在其他模块依赖或内核引用:比如其他内核模块依赖usb_f_printer,或内核线程持有未关闭的文件句柄。可通过lsmod查看模块依赖关系,排查是否有其他模块在使用它。

若确认所有用户态和内核态资源都已释放,但引用计数仍不为0,大概率是驱动bug,此时才需要考虑重启或杀死进程,但优先尝试问题1中的方案规避。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 05:15:34