Linux tty port在打开时自发发送数据

问题描述 投票:2回答:2

当打开插入基于ARM9的嵌入式板的USB主机的基于FDTI USB UART的串行端口时,它会自动传输数据。即使在设置了比特率之前,它在打开时也是如此,或者对fd做了其他任何事情。

发送的数据总是或多或少相同:

^@^@^@^@^@

以十六进制表示法:0x5e 0x40 0x5e 0x40 0x5e 0x40 0x5e 0x40 0x5e 0x40。重复次数从一对不等,最多256对。

我已追溯到这些数据,它起源于tty Kernel workqueue。所以它不是由一个错误的驱动程序引起的,它有一个未正确初始化的传输队列或沿着那条线的任何东西。很明显,内核在打开的系统调用时故意传输这些数据。

只有在重新启动后或插入FTDI USB UART后第一次打开tty端口时才会出现此问题。 (重启会重启USB设备,因此这两者基本相同。)

是的,我确实意识到^ @意味着'\ 0'。并且还可以使用NULL来实现延迟。从手册:

延迟位指定当某些字符被发送到终端时传输停止以允许机械或其他移动的时间。在所有情况下,值0表示没有延迟。如果设置了OFILL,则应传输填充字符以延迟而不是定时延迟。这对于仅需要最小延迟的高波特率终端非常有用。如果设置了OFDEL,则填充字符应为DEL;否则,NUL。

但是,我的TTY设置并未指示此设置处于活动状态:

root@IVW78103 ~$ stty -F /dev/ttyUSB0 -a
speed 9600 baud;stty: /dev/ttyUSB0
 line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke

现在,最后 - 也是最重要的 - 线索是,FTDI串口端的设备在上电时会输出大量数据(= USB插件)。当我隔离FTDI RxD线时,问题不会发生。很明显,这个数据中的内核,termios或tty都是冒犯的。

现在的问题是:如何阻止发送^ @数据?因为FTDI串口端的设备对它没有很好的响应。

编辑:输出似乎是termios回显输入。如果我通过在... / drivers / tty / n_tty.c中注释掉这段代码来对内核进行分类,那么症状就会消失:process_echoes:639

tty_put_char(tty, '^');
tty_put_char(tty, op ^ 0100);

它仍然让我感到困惑,为什么它在打开tty端口之前很久就回应了收到的数据。我可能是USB UART无法真正清除所有数据的副作用。

linux serial-port tty termios
2个回答
1
投票

此问题是由默认启用的termios echo和不支持刷新的FTDI tty设备驱动程序组合引起的。

Greg在他的评论here中解释了后者。他的评论主要是关于TCOFLUSH,但显然TCIFLUSH也不支持。评论是关于FDTI tty驱动程序的,但我确信许多(如果不是全部)其他USB UART驱动程序也是如此。

错误模式如下:当USB串行设备插入并接通电源时,它会执行POST并将结果输出转储到串行端口上,作为该端口的默认比特率。稍后,当应用程序打开该tty端口时,它在打开时不会刷新。从那一刻起,仍在移位寄存器,FIFO和USB缓冲区中的累积POST数据被读取,并且由于默认情况下启用了回声,因此将回显。由于比特率不匹配,回显的数据看起来像NULL字符或垃圾。

由于真正的解决方案是正确实现刷新,并且因为这可能很难实现,所以我已经通过这个简单的补丁禁用了内核中所有USB UART的默认的termios回声:

    Index: drivers/usb/serial/usb-serial.c
===================================================================
--- drivers/usb/serial/usb-serial.c (revision 1166)
+++ drivers/usb/serial/usb-serial.c (working copy)
@@ -1270,6 +1270,8 @@
                            | HUPCL | CLOCAL;
    usb_serial_tty_driver->init_termios.c_ispeed = 9600;
    usb_serial_tty_driver->init_termios.c_ospeed = 9600;
+   usb_serial_tty_driver->init_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+   usb_serial_tty_driver->init_termios.c_oflag &= ~OPOST;
    tty_set_operations(usb_serial_tty_driver, &serial_ops);
    result = tty_register_driver(usb_serial_tty_driver);
    if (result) {

这个补丁做了一点点;它将tty端口置于原始模式,因为我不再冒任何机会了。禁用ICANON和ECHO就足够了。

有了这个补丁,打开时自发传输的数据就消失了。

打开后,我仍然在表单中打开NULL字符之前收到POST数据。并且在打开之后不会像我期望的那样立即,但只有在发出第一个字节之后。这可能是由于驱动程序中的接收事件在打开之前被忽略,而在打开之后没有被触发,因为打开后没有收到任何信息。

由于我的应用程序在启动时忽略了无框架数据,因此我决定在此修补程序中解决此问题的解决方案。

我希望它也有助于其他人。


0
投票

您必须修补内核的原因是设备驱动程序默认将RTS(请求发送)设置为“已启用”。在应用tty设置(禁用回声等)后,必须在应用程序中将RTS设置为“启用” - 并且在设备中检查是否在发送任何内容之前启用了RTS。

We loose the ability to do "cat /dev/ttyACM0" from shell (which is not important to us), but we gain
 the
ability to set tty attributes before device starts sending (which is VERY important to us).
@@ -602,10 +602,7 @@ static void acm_port_dtr_rts(struct tty_port *port, int raise)
  int val;
  int res;

- if (raise)
-  val = ACM_CTRL_DTR | ACM_CTRL_RTS;
- else
-  val = 0;
+ val = 0;

  /* FIXME: add missing ctrlout locking throughout driver */
  acm->ctrlout = val;
© www.soinside.com 2019 - 2024. All rights reserved.