All of lore.kernel.org
 help / color / mirror / Atom feed
From: "embedded (VIVAVIS AG)" <embedded@vivavis.com>
To: "linux-usb@vger.kernel.org" <linux-usb@vger.kernel.org>
Subject: AW: ftdi_sio: Problem when changing the baud rate after a transfer
Date: Fri, 28 Jan 2022 10:09:26 +0000	[thread overview]
Message-ID: <1ec54d4f592c46b7a14109df559072e4@vivavis.com> (raw)
In-Reply-To: <5aae37a8029549d8a9ef28f2e39fe58f@vivavis.com>

> Gesendet: Montag, 10. Januar 2022 14:27
> An: linux-usb@vger.kernel.org
> 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


  reply	other threads:[~2022-01-28 10:15 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-10 13:27 ftdi_sio: Problem when changing the baud rate after a transfer embedded (VIVAVIS AG)
2022-01-28 10:09 ` embedded (VIVAVIS AG) [this message]
2022-01-31  7:55   ` Johan Hovold
2022-02-21 15:08     ` AW: " embedded (VIVAVIS AG)
2022-04-11  8:46       ` Johan Hovold

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1ec54d4f592c46b7a14109df559072e4@vivavis.com \
    --to=embedded@vivavis.com \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.