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

关闭USB CDC-ACM串行接口时清除缓冲区的问题排查

问题背景

我正在为NXP i.MX 8M mini SoC嵌入式设备开发软件,该设备运行Linux 5.15.32内核,通过USB复合gadget利用SoC内置USB接口提供串行I/O功能。

该gadget同时提供RNDIS网络接口和ACM串行接口,两者功能正常,但存在以下问题:当周期性向ACM设备/dev/ttyGS0写入数据的应用终止时,关闭该设备文件描述符有时会耗时16秒。

现象细节

  • 延迟仅在ACM接口另一端无应用读取数据时出现;若主机端有读取操作(如执行cat /dev/ttyACM0 > /dev/null),close()调用会立即完成。
  • 确定延迟是由USB驱动中排队的数据导致,close()调用在等待数据被远端接收,16秒后超时。

已尝试的解决方法

  • 在close()前调用tcflush(fd, TCIOFLUSH),无效果;
  • 将波特率设为B0(调制解调器挂起事件),期望清除数据,同样无效;
  • 显式启用/禁用流控制(c_cflag |= CRTSCTS),无变化。

相关配置代码

USB gadget配置脚本(bash)

modprobe libcomposite
cd /sys/kernel/config/usb_gadget
mkdir g
cd g

echo 0x1d6b > idVendor    # Linux Foundation
echo 0x0104 > idProduct   # Multifunction composite gadget
echo 0x0100 > bcdDevice   # v1.0.0
echo 0x0200 > bcdUSB      # USB 2.0

# Miscellaneous / Wire Adapter Multifunction programming interface
echo 0xEF > bDeviceClass
echo 0x02 > bDeviceSubClass
echo 0x01 > bDeviceProtocol

mkdir -p strings/0x409
echo "my_serial_no"    > strings/0x409/serialnumber
echo "my_manufacturer" > strings/0x409/manufacturer

mkdir -p functions/acm.usb0
mkdir -p configs/c.1
echo 250 > configs/c.1/MaxPower
ln -s functions/acm.usb0  configs/c.1

(creation and configuration of RNDIS function omitted)

ln -s configs/c.1 os_desc

文件描述符打开与配置代码(C++)

fd = open("/dev/ttyGS0", O_RDWR | O_NONBLOCK);

struct termios settings;

tcgetattr(fd, &settings);

cfsetospeed(&settings, B1000000);  // 1Mbps

settings.c_cflag &= ~(CSTOPB |  // 1 stop bit
                      CSIZE  |  // Clear previous bit-size bits
                      PARENB);  // Don't use parity checking
settings.c_cflag |= (CS8 |      // 8 data bits
                     CLOCAL);   // Ignore modem control lines
settings.c_iflag &= ~(IGNBRK |  // Don't ignore break
                      BRKINT |  // Don't generate SIGINT on BRK
                      PARMRK |  // Don't mark framing/parity errors
                      ISTRIP |  // Don't strip the 8th bit
                      INLCR  |  // Don't translate NL to CR
                      IGNCR  |  // Don't ignore CR
                      ICRNL  |  // Don't ignore NL
                      IXON);    // Don't use XON/XOFF flow control
settings.c_oflag &= ~OPOST;     // Don't use implementation-defined output processing
settings.c_lflag &= ~(ECHO   |  // Don't echo input characters
                      ECHONL |  // Don't echo NL
                      ICANON |  // Don't use canonical mode
                      ISIG   |  // Don't generate signals
                      IEXTEN);  // Don't use implementation-defined input processing

settings.c_cc[VTIME] = 0;  // Disable timeout for non canonical read
settings.c_cc[VMIN]  = 0;  // No minimum chars for non canonical read

tcsetattr(fd, TCSANOW, &settings);
tcflush(fd, TCOFLUSH);

问题解答

1. 是否可通过修改ACM设备配置或termios配置解决该问题?

常规的termios配置(包括流控制、波特率、flush操作)无法解决这个问题,因为延迟的根源是USB gadget驱动层的发送队列未被清空,而非tty层的缓冲区。你尝试的tcflush仅操作tty层的用户态/内核态缓冲区,无法触达USB驱动中已提交到硬件队列或等待主机ACK的数据。

ACM设备的gadget配置(如class/subclass/protocol)也不影响关闭时的超时逻辑,这些配置仅定义设备的USB枚举属性,和驱动的关闭行为无关。

2. 若不可行,是否有办法告知Linux关闭文件描述符时无需等待?

可以在close()之前调用ioctl(fd, TIOCSFLUSH, (void*)1),这个操作会强制tty驱动清空所有未发送的缓冲区,包括USB驱动层的队列。Linux 5.15内核已支持该操作,能替代无效的tcflush,让close()无需等待超时。

另外,打开设备时设置O_NDELAY标志仅影响读写操作的阻塞行为,对close()的等待逻辑无直接作用。

3. 若上述均不可行,是否有办法让ACM驱动刷新/丢弃缓冲区以避免close()等待?

除了TIOCSFLUSH ioctl,还可以通过sysfs节点重置ACM功能:

  • 进入ACM功能的sysfs目录(如/sys/kernel/config/usb_gadget/g/functions/acm.usb0)
  • 执行echo 1 > reset,这会重置ACM接口的发送队列,丢弃所有未发送的数据。
    不过该方法需要应用拥有root权限,且可能影响其他使用该ACM接口的进程,需谨慎使用。

如果允许修改内核,可在drivers/usb/gadget/function/f_acm.c的acm_tty_release函数中,强制调用usb_ep_disable或直接清空发送队列,替代默认的超时等待逻辑,之后重新编译内核即可。

4. 若以上都无法实现,设备能否检测到ACM接口另一端是否有应用连接,从而让我的应用在无接收端时停止发送数据?

可以通过检测tty设备的CD(Carrier Detect)状态判断主机端是否有应用打开ACM接口:当主机端打开/dev/ttyACM0时,USB gadget驱动会设置tty的CD标志;主机端关闭设备时,CD标志会被清除。

应用中可通过以下代码检测:

int status;
ioctl(fd, TIOCMGET, &status);
if (!(status & TIOCM_CD)) {
    // 主机端无应用连接,停止发送数据
}

也可以监听tty设备的POLLPRI事件,当CD状态变化时,应用会收到通知,从而动态调整发送逻辑。


内容的提问来源于stack exchange,提问作者David C.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 04:57:12