On Tue, Jul 12, 2022 at 01:53:05PM +0200, Marek Behún wrote: > From: Pali Rohár <pali@xxxxxxxxxx> > > When ASYNC_SPD_CUST is used, update custom_divisor and c_*speed fields > so that they correspond to the newly set baud rate value, so that > userspace GET ioctls will see the true baud rate that is being used. No, this is wrong. In fact, there's a long-standing bug in this driver which started reporting back the actual baud rate when using SPD_CUST. The rate should be left unchanged at 38400 in that case. > Signed-off-by: Pali Rohár <pali@xxxxxxxxxx> > Tested-by: Marek Behún <kabel@xxxxxxxxxx> > Signed-off-by: Marek Behún <kabel@xxxxxxxxxx> > --- > drivers/usb/serial/ftdi_sio.c | 16 ++++++++++++++++ > 1 file changed, 16 insertions(+) > > diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c > index 5db1293bb7a2..39e8c5d06157 100644 > --- a/drivers/usb/serial/ftdi_sio.c > +++ b/drivers/usb/serial/ftdi_sio.c > @@ -1303,6 +1303,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, > { > struct ftdi_private *priv = usb_get_serial_port_data(port); > struct device *dev = &port->dev; > + int fix_custom_divisor = 0; > int div_value = 0; > int div_okay = 1; > int baud; > @@ -1317,6 +1318,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, > if (baud == 38400 && > ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && > (priv->custom_divisor)) { > + fix_custom_divisor = 1; > baud = DIV_ROUND_CLOSEST(priv->baud_base, priv->custom_divisor); > dev_dbg(dev, "%s - custom divisor %d sets baud rate to %d\n", > __func__, priv->custom_divisor, baud); > @@ -1401,7 +1403,19 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, > ftdi_chip_name[priv->chip_type]); > } > > + /* Fix deprecated async-compatible custom_divisor hack and update tty baud rate */ > + if (fix_custom_divisor) { > + priv->custom_divisor = DIV_ROUND_CLOSEST(priv->baud_base, baud); > + old_baud = baud; > + baud = 38400; > + } > + > tty_encode_baud_rate(tty, baud, baud); > + > + /* For async-compatible custom_divisor store into TCGETS2 c_*speed fields real baud rate */ > + if (fix_custom_divisor) > + tty->termios.c_ispeed = tty->termios.c_ospeed = old_baud; > + > return div_value; > } > > @@ -2674,6 +2688,8 @@ static void ftdi_set_termios(struct tty_struct *tty, > dev_dbg(ddev, "%s: forcing baud rate for this device\n", __func__); > tty_encode_baud_rate(tty, priv->force_baud, > priv->force_baud); > + termios->c_ispeed = termios->c_ospeed = > + DIV_ROUND_CLOSEST(priv->baud_base, priv->custom_divisor); > } > > /* Force RTS-CTS if this device requires it. */ Johan