aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/ftdi_sio.c
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2018-05-18 09:25:50 -0400
committerJohan Hovold <johan@kernel.org>2018-05-21 04:04:30 -0400
commitdf1cd63d6d112e4a1402166dacc411ccca9b09ac (patch)
treea659329785392b6bfa1279f360effad665bf8edb /drivers/usb/serial/ftdi_sio.c
parent1641011549784699e013c7ccfebbd0d5a3dc41e7 (diff)
USB: serial: ftdi_sio: clean up flow control management
Clean up the somewhat convoluted hardware-assisted flow control handling. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johan Hovold <johan@kernel.org>
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r--drivers/usb/serial/ftdi_sio.c81
1 files changed, 23 insertions, 58 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 3d7f181e7e2a..b5cef322826f 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,
2191 struct ftdi_private *priv = usb_get_serial_port_data(port); 2191 struct ftdi_private *priv = usb_get_serial_port_data(port);
2192 struct ktermios *termios = &tty->termios; 2192 struct ktermios *termios = &tty->termios;
2193 unsigned int cflag = termios->c_cflag; 2193 unsigned int cflag = termios->c_cflag;
2194 u16 value; 2194 u16 value, index;
2195 2195 int ret;
2196 /* Added for xon/xoff support */
2197 unsigned int iflag = termios->c_iflag;
2198 unsigned char vstop;
2199 unsigned char vstart;
2200 2196
2201 /* Force baud rate if this device requires it, unless it is set to 2197 /* Force baud rate if this device requires it, unless it is set to
2202 B0. */ 2198 B0. */
@@ -2325,61 +2321,30 @@ no_data_parity_stop_changes:
2325 set_mctrl(port, TIOCM_DTR | TIOCM_RTS); 2321 set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
2326 } 2322 }
2327 2323
2328 /* Set flow control */
2329 /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
2330no_c_cflag_changes: 2324no_c_cflag_changes:
2331 if (cflag & CRTSCTS) { 2325 /* Set hardware-assisted flow control */
2332 dev_dbg(ddev, "%s Setting to CRTSCTS flow control\n", __func__); 2326 value = 0;
2333 if (usb_control_msg(dev, 2327
2334 usb_sndctrlpipe(dev, 0), 2328 if (C_CRTSCTS(tty)) {
2335 FTDI_SIO_SET_FLOW_CTRL_REQUEST, 2329 dev_dbg(&port->dev, "enabling rts/cts flow control\n");
2336 FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 2330 index = FTDI_SIO_RTS_CTS_HS;
2337 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), 2331 } else if (I_IXON(tty)) {
2338 NULL, 0, WDR_TIMEOUT) < 0) { 2332 dev_dbg(&port->dev, "enabling xon/xoff flow control\n");
2339 dev_err(ddev, "urb failed to set to rts/cts flow control\n"); 2333 index = FTDI_SIO_XON_XOFF_HS;
2340 } 2334 value = STOP_CHAR(tty) << 8 | START_CHAR(tty);
2341 } else { 2335 } else {
2342 /* 2336 dev_dbg(&port->dev, "disabling flow control\n");
2343 * Xon/Xoff code 2337 index = FTDI_SIO_DISABLE_FLOW_CTRL;
2344 */
2345 if (iflag & IXON) {
2346 dev_dbg(ddev, "%s request to enable xonxoff iflag=%04x\n",
2347 __func__, iflag);
2348 /* Try to enable the XON/XOFF on the ftdi_sio
2349 * Set the vstart and vstop -- could have been done up
2350 * above where a lot of other dereferencing is done but
2351 * that would be very inefficient as vstart and vstop
2352 * are not always needed.
2353 */
2354 vstart = termios->c_cc[VSTART];
2355 vstop = termios->c_cc[VSTOP];
2356 value = (vstop << 8) | (vstart);
2357
2358 if (usb_control_msg(dev,
2359 usb_sndctrlpipe(dev, 0),
2360 FTDI_SIO_SET_FLOW_CTRL_REQUEST,
2361 FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
2362 value , (FTDI_SIO_XON_XOFF_HS
2363 | priv->interface),
2364 NULL, 0, WDR_TIMEOUT) < 0) {
2365 dev_err(&port->dev, "urb failed to set to "
2366 "xon/xoff flow control\n");
2367 }
2368 } else {
2369 /* else clause to only run if cflag ! CRTSCTS and iflag
2370 * ! XON. CHECKME Assuming XON/XOFF handled by tty
2371 * stack - not by device */
2372 dev_dbg(ddev, "%s Turning off hardware flow control\n", __func__);
2373 if (usb_control_msg(dev,
2374 usb_sndctrlpipe(dev, 0),
2375 FTDI_SIO_SET_FLOW_CTRL_REQUEST,
2376 FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
2377 0, priv->interface,
2378 NULL, 0, WDR_TIMEOUT) < 0) {
2379 dev_err(ddev, "urb failed to clear flow control\n");
2380 }
2381 }
2382 } 2338 }
2339
2340 index |= priv->interface;
2341
2342 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
2343 FTDI_SIO_SET_FLOW_CTRL_REQUEST,
2344 FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
2345 value, index, NULL, 0, WDR_TIMEOUT);
2346 if (ret < 0)
2347 dev_err(&port->dev, "failed to set flow control: %d\n", ret);
2383} 2348}
2384 2349
2385/* 2350/*