diff options
author | Johan Hovold <johan@kernel.org> | 2018-05-18 09:25:50 -0400 |
---|---|---|
committer | Johan Hovold <johan@kernel.org> | 2018-05-21 04:04:30 -0400 |
commit | df1cd63d6d112e4a1402166dacc411ccca9b09ac (patch) | |
tree | a659329785392b6bfa1279f360effad665bf8edb /drivers/usb/serial/ftdi_sio.c | |
parent | 1641011549784699e013c7ccfebbd0d5a3dc41e7 (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.c | 81 |
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 */ | ||
2330 | no_c_cflag_changes: | 2324 | no_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 | /* |