From df1cd63d6d112e4a1402166dacc411ccca9b09ac Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 18 May 2018 15:25:50 +0200 Subject: [PATCH] USB: serial: ftdi_sio: clean up flow control management Clean up the somewhat convoluted hardware-assisted flow control handling. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 81 ++++++++++++------------------------------- 1 file changed, 23 insertions(+), 58 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3d7f181..b5cef32 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2191,12 +2191,8 @@ static void ftdi_set_termios(struct tty_struct *tty, struct ftdi_private *priv = usb_get_serial_port_data(port); struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; - u16 value; - - /* Added for xon/xoff support */ - unsigned int iflag = termios->c_iflag; - unsigned char vstop; - unsigned char vstart; + u16 value, index; + int ret; /* Force baud rate if this device requires it, unless it is set to B0. */ @@ -2325,61 +2321,30 @@ no_data_parity_stop_changes: set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } - /* Set flow control */ - /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ no_c_cflag_changes: - if (cflag & CRTSCTS) { - dev_dbg(ddev, "%s Setting to CRTSCTS flow control\n", __func__); - if (usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), - NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(ddev, "urb failed to set to rts/cts flow control\n"); - } + /* Set hardware-assisted flow control */ + value = 0; + + if (C_CRTSCTS(tty)) { + dev_dbg(&port->dev, "enabling rts/cts flow control\n"); + index = FTDI_SIO_RTS_CTS_HS; + } else if (I_IXON(tty)) { + dev_dbg(&port->dev, "enabling xon/xoff flow control\n"); + index = FTDI_SIO_XON_XOFF_HS; + value = STOP_CHAR(tty) << 8 | START_CHAR(tty); } else { - /* - * Xon/Xoff code - */ - if (iflag & IXON) { - dev_dbg(ddev, "%s request to enable xonxoff iflag=%04x\n", - __func__, iflag); - /* Try to enable the XON/XOFF on the ftdi_sio - * Set the vstart and vstop -- could have been done up - * above where a lot of other dereferencing is done but - * that would be very inefficient as vstart and vstop - * are not always needed. - */ - vstart = termios->c_cc[VSTART]; - vstop = termios->c_cc[VSTOP]; - value = (vstop << 8) | (vstart); - - if (usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - value , (FTDI_SIO_XON_XOFF_HS - | priv->interface), - NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "urb failed to set to " - "xon/xoff flow control\n"); - } - } else { - /* else clause to only run if cflag ! CRTSCTS and iflag - * ! XON. CHECKME Assuming XON/XOFF handled by tty - * stack - not by device */ - dev_dbg(ddev, "%s Turning off hardware flow control\n", __func__); - if (usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, - NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(ddev, "urb failed to clear flow control\n"); - } - } + dev_dbg(&port->dev, "disabling flow control\n"); + index = FTDI_SIO_DISABLE_FLOW_CTRL; } + + index |= priv->interface; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + value, index, NULL, 0, WDR_TIMEOUT); + if (ret < 0) + dev_err(&port->dev, "failed to set flow control: %d\n", ret); } /* -- 2.7.4