> Gesendet: Montag, 10. Januar 2022 14:27 > An: linux-usb@xxxxxxxxxxxxxxx > Betreff: ftdi_sio: Problem when changing the baud rate after a transfer > > Hi, > there seems to be a problem with the ftdi_sio driver in conjunction with an FT2232C and changing the baud rate. > This behavior is observable at least on linux 4.19.190. > The following was done in order to observe this problem: > A transfer is started over one of the serial interfaces of the FT2232C at a lower baud rate, eg. 300 baud. > The code waits for the driver to empty the tx buffer by calling tcdrain(). After the call returns the code changes > the baud rate of the serial interface to a higher rate, eg. 4800 baud, and writes another stream of bytes. > Now the problem occurs: Looking at the TX pin of the used interface with an oscilloscope, one can see that > the last byte of the previous transfer, which is supposed to be transferred at 300 baud, is transferred at the > higher rate of 4800 baud. Even worse, it is not even the complete byte, but rather some of the last bits of > that last byte which are transferred at the new baud rate configured. This problem occurs independent of > whether the interface is opened in blocking or non-blocking mode. > I verified that the driver does in fact ask the hardware if it's tx buffer is empty when the hardware status is > reported. However, it seems that the reported status by the FT2232C does not check the status of it's shift > register (if that is even possible at all), which is clearly influenced by the changed baud rate. > > Can someone confirm this behavior and is there a proper way to fix it? > > Regards, > Yasin Morsli > > > PS: Here is an MWE to test this behavior: > > #include <stdio.h> > #include <fcntl.h> > #include <string.h> > #include <termios.h> > > const char* help_msg = > "Usage: %s [tty] [data]\n" > " tty: filepath to the tty\n" > " data: data to transfer\n"; > > int error(const char* msg) { > printf("Error: %s\n", msg); > return -1; >} > >int setspeed(int fd_tty, int speed) { > struct termios tty; > if (tcgetattr(fd_tty, &tty) != 0) return error("tcgetattr failed"); > > cfsetospeed(&tty, speed); > cfsetispeed(&tty, speed); > > if (tcsetattr(fd_tty, TCSANOW, &tty) != 0) return error("tcsetattr failed"); > > return 0; >} > >int main(int argc, const char** argv) { > if (argc < 3) { > printf(help_msg, argv[0]); > return 0; > } > > const char* path_tty = argv[1]; > const char* data_tty = argv[2]; > > int fd_tty = open(path_tty, O_RDWR | O_NOCTTY); > if (fd_tty < 0) return error("open failed"); > > struct termios tty; > if (tcgetattr(fd_tty, &tty) != 0) return error("tcgetattr failed"); > > tty.c_cflag &= ~(CSIZE | PARENB | CRTSCTS); > tty.c_cflag |= (CS7 | CSTOPB); > tty.c_iflag &= ~(IXON | IXOFF | IXANY | IGNBRK); > tty.c_lflag = 0; > tty.c_oflag = 0; > tty.c_cc[VMIN] = 0; > > if (tcsetattr(fd_tty, TCSANOW, &tty) != 0) return error("tcsetattr failed"); > > if (setspeed(fd_tty, B300) != 0) return error("setspeed failed"); > write(fd_tty, data_tty, strlen(data_tty)); > tcdrain(fd_tty); > > if (setspeed(fd_tty, B4800) != 0) return error("setspeed failed"); > write(fd_tty, data_tty, strlen(data_tty)); > tcdrain(fd_tty); > > close(fd_tty); > > return 0; >} I've found this older thread https://www.spinics.net/lists/linux-usb/msg71689.html. The proposed solution or patch with chars_in_buffer() function doesn't exist in more recent kernels (4.19 or newer), but the same functionality is achieved by ftdi_tx_empty(), which is indeed called, when tcdrain() is called from userspace. ftdi_tx_empty() calls ftdi_get_modem_status() and checks whether FTDI_RS_TEMPT flag is set. If set (i.e. shift register empty) ftdi_tx_empty() returns true. But I wonder why FTDI_RS_THRE (transmit holding register empty) is not taken into account. Furthermore, I can not find any checks for tx-fifos. But possibly the FTDI chip has a guarantee that if FTDI_RS_TEMPT is set, the holding register and internal tx-fifos are empty, too. As Yasin stated above, it can be observed that the chip transmits data, even if the driver reports ftdi_tx_empty() == true. Possibly due to a bug in the driver or by poor chip design. Any thoughts on this? Carsten