1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
296fd7ce5SGreg Kroah-Hartman /*
396fd7ce5SGreg Kroah-Hartman * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
496fd7ce5SGreg Kroah-Hartman *
596fd7ce5SGreg Kroah-Hartman * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
696fd7ce5SGreg Kroah-Hartman * which can be dynamically activated and de-activated by the line
796fd7ce5SGreg Kroah-Hartman * discipline handling modules (like SLIP).
896fd7ce5SGreg Kroah-Hartman */
996fd7ce5SGreg Kroah-Hartman
100b05223bSIlpo Järvinen #include <linux/bits.h>
1196fd7ce5SGreg Kroah-Hartman #include <linux/types.h>
1296fd7ce5SGreg Kroah-Hartman #include <linux/termios.h>
1396fd7ce5SGreg Kroah-Hartman #include <linux/errno.h>
14174cd4b1SIngo Molnar #include <linux/sched/signal.h>
1596fd7ce5SGreg Kroah-Hartman #include <linux/kernel.h>
1696fd7ce5SGreg Kroah-Hartman #include <linux/major.h>
1796fd7ce5SGreg Kroah-Hartman #include <linux/tty.h>
1896fd7ce5SGreg Kroah-Hartman #include <linux/fcntl.h>
1996fd7ce5SGreg Kroah-Hartman #include <linux/string.h>
2096fd7ce5SGreg Kroah-Hartman #include <linux/mm.h>
2196fd7ce5SGreg Kroah-Hartman #include <linux/module.h>
2296fd7ce5SGreg Kroah-Hartman #include <linux/bitops.h>
2396fd7ce5SGreg Kroah-Hartman #include <linux/mutex.h>
248193c429SThomas Meyer #include <linux/compat.h>
25c9874d3fSAl Viro #include <linux/termios_internal.h>
269f72cab1SGreg Kroah-Hartman #include "tty.h"
2796fd7ce5SGreg Kroah-Hartman
2896fd7ce5SGreg Kroah-Hartman #include <asm/io.h>
297c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
3096fd7ce5SGreg Kroah-Hartman
3196fd7ce5SGreg Kroah-Hartman #undef DEBUG
3296fd7ce5SGreg Kroah-Hartman
3396fd7ce5SGreg Kroah-Hartman /*
3496fd7ce5SGreg Kroah-Hartman * Internal flag options for termios setting behavior
3596fd7ce5SGreg Kroah-Hartman */
360b05223bSIlpo Järvinen #define TERMIOS_FLUSH BIT(0)
370b05223bSIlpo Järvinen #define TERMIOS_WAIT BIT(1)
380b05223bSIlpo Järvinen #define TERMIOS_TERMIO BIT(2)
390b05223bSIlpo Järvinen #define TERMIOS_OLD BIT(3)
4096fd7ce5SGreg Kroah-Hartman
4196fd7ce5SGreg Kroah-Hartman /**
4296fd7ce5SGreg Kroah-Hartman * tty_chars_in_buffer - characters pending
4396fd7ce5SGreg Kroah-Hartman * @tty: terminal
4496fd7ce5SGreg Kroah-Hartman *
453b1a696bSJiri Slaby (SUSE) * Returns: the number of bytes of data in the device private output queue. If
463b1a696bSJiri Slaby (SUSE) * no private method is supplied there is assumed to be no queue on the device.
4796fd7ce5SGreg Kroah-Hartman */
tty_chars_in_buffer(struct tty_struct * tty)48fff4ef17SJiri Slaby unsigned int tty_chars_in_buffer(struct tty_struct *tty)
4996fd7ce5SGreg Kroah-Hartman {
5096fd7ce5SGreg Kroah-Hartman if (tty->ops->chars_in_buffer)
5196fd7ce5SGreg Kroah-Hartman return tty->ops->chars_in_buffer(tty);
5296fd7ce5SGreg Kroah-Hartman return 0;
5396fd7ce5SGreg Kroah-Hartman }
5496fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(tty_chars_in_buffer);
5596fd7ce5SGreg Kroah-Hartman
5696fd7ce5SGreg Kroah-Hartman /**
5796fd7ce5SGreg Kroah-Hartman * tty_write_room - write queue space
5896fd7ce5SGreg Kroah-Hartman * @tty: terminal
5996fd7ce5SGreg Kroah-Hartman *
603b1a696bSJiri Slaby (SUSE) * Returns: the number of bytes that can be queued to this device at the present
613b1a696bSJiri Slaby (SUSE) * time. The result should be treated as a guarantee and the driver cannot
623b1a696bSJiri Slaby (SUSE) * offer a value it later shrinks by more than the number of bytes written. If
633b1a696bSJiri Slaby (SUSE) * no method is provided, 2K is always returned and data may be lost as there
643b1a696bSJiri Slaby (SUSE) * will be no flow control.
6596fd7ce5SGreg Kroah-Hartman */
tty_write_room(struct tty_struct * tty)6603b3b1a2SJiri Slaby unsigned int tty_write_room(struct tty_struct *tty)
6796fd7ce5SGreg Kroah-Hartman {
6896fd7ce5SGreg Kroah-Hartman if (tty->ops->write_room)
6996fd7ce5SGreg Kroah-Hartman return tty->ops->write_room(tty);
7096fd7ce5SGreg Kroah-Hartman return 2048;
7196fd7ce5SGreg Kroah-Hartman }
7296fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(tty_write_room);
7396fd7ce5SGreg Kroah-Hartman
7496fd7ce5SGreg Kroah-Hartman /**
7596fd7ce5SGreg Kroah-Hartman * tty_driver_flush_buffer - discard internal buffer
7696fd7ce5SGreg Kroah-Hartman * @tty: terminal
7796fd7ce5SGreg Kroah-Hartman *
783b1a696bSJiri Slaby (SUSE) * Discard the internal output buffer for this device. If no method is provided,
793b1a696bSJiri Slaby (SUSE) * then either the buffer cannot be hardware flushed or there is no buffer
803b1a696bSJiri Slaby (SUSE) * driver side.
8196fd7ce5SGreg Kroah-Hartman */
tty_driver_flush_buffer(struct tty_struct * tty)8296fd7ce5SGreg Kroah-Hartman void tty_driver_flush_buffer(struct tty_struct *tty)
8396fd7ce5SGreg Kroah-Hartman {
8496fd7ce5SGreg Kroah-Hartman if (tty->ops->flush_buffer)
8596fd7ce5SGreg Kroah-Hartman tty->ops->flush_buffer(tty);
8696fd7ce5SGreg Kroah-Hartman }
8796fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(tty_driver_flush_buffer);
8896fd7ce5SGreg Kroah-Hartman
8996fd7ce5SGreg Kroah-Hartman /**
9096fd7ce5SGreg Kroah-Hartman * tty_unthrottle - flow control
9196fd7ce5SGreg Kroah-Hartman * @tty: terminal
9296fd7ce5SGreg Kroah-Hartman *
933b1a696bSJiri Slaby (SUSE) * Indicate that a @tty may continue transmitting data down the stack. Takes
943b1a696bSJiri Slaby (SUSE) * the &tty_struct->termios_rwsem to protect against parallel
953b1a696bSJiri Slaby (SUSE) * throttle/unthrottle and also to ensure the driver can consistently reference
963b1a696bSJiri Slaby (SUSE) * its own termios data at this point when implementing software flow control.
9796fd7ce5SGreg Kroah-Hartman *
983b1a696bSJiri Slaby (SUSE) * Drivers should however remember that the stack can issue a throttle, then
993b1a696bSJiri Slaby (SUSE) * change flow control method, then unthrottle.
10096fd7ce5SGreg Kroah-Hartman */
tty_unthrottle(struct tty_struct * tty)10196fd7ce5SGreg Kroah-Hartman void tty_unthrottle(struct tty_struct *tty)
10296fd7ce5SGreg Kroah-Hartman {
1036a1c0680SPeter Hurley down_write(&tty->termios_rwsem);
10496fd7ce5SGreg Kroah-Hartman if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
10596fd7ce5SGreg Kroah-Hartman tty->ops->unthrottle)
10696fd7ce5SGreg Kroah-Hartman tty->ops->unthrottle(tty);
107e5d0424aSJiri Slaby (SUSE) tty->flow_change = TTY_FLOW_NO_CHANGE;
1086a1c0680SPeter Hurley up_write(&tty->termios_rwsem);
10996fd7ce5SGreg Kroah-Hartman }
11096fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(tty_unthrottle);
11196fd7ce5SGreg Kroah-Hartman
11296fd7ce5SGreg Kroah-Hartman /**
11370bc1264SPeter Hurley * tty_throttle_safe - flow control
11470bc1264SPeter Hurley * @tty: terminal
11570bc1264SPeter Hurley *
1163b1a696bSJiri Slaby (SUSE) * Indicate that a @tty should stop transmitting data down the stack.
1173b1a696bSJiri Slaby (SUSE) * tty_throttle_safe() will only attempt throttle if @tty->flow_change is
1183b1a696bSJiri Slaby (SUSE) * %TTY_THROTTLE_SAFE. Prevents an accidental throttle due to race conditions
1193b1a696bSJiri Slaby (SUSE) * when throttling is conditional on factors evaluated prior to throttling.
12070bc1264SPeter Hurley *
1213b1a696bSJiri Slaby (SUSE) * Returns: %true if @tty is throttled (or was already throttled)
12270bc1264SPeter Hurley */
tty_throttle_safe(struct tty_struct * tty)123c2a36609SJiri Slaby (SUSE) bool tty_throttle_safe(struct tty_struct *tty)
12470bc1264SPeter Hurley {
1255b4f9cf3SJiri Slaby (SUSE) bool ret = true;
12670bc1264SPeter Hurley
127d8c1f929SPeter Hurley mutex_lock(&tty->throttle_mutex);
12897ef38b8SPeter Hurley if (!tty_throttled(tty)) {
12970bc1264SPeter Hurley if (tty->flow_change != TTY_THROTTLE_SAFE)
1305b4f9cf3SJiri Slaby (SUSE) ret = false;
13170bc1264SPeter Hurley else {
132579a00a5SPeter Hurley set_bit(TTY_THROTTLED, &tty->flags);
13370bc1264SPeter Hurley if (tty->ops->throttle)
13470bc1264SPeter Hurley tty->ops->throttle(tty);
13570bc1264SPeter Hurley }
13670bc1264SPeter Hurley }
137d8c1f929SPeter Hurley mutex_unlock(&tty->throttle_mutex);
13870bc1264SPeter Hurley
13970bc1264SPeter Hurley return ret;
14070bc1264SPeter Hurley }
14170bc1264SPeter Hurley
14270bc1264SPeter Hurley /**
14370bc1264SPeter Hurley * tty_unthrottle_safe - flow control
14470bc1264SPeter Hurley * @tty: terminal
14570bc1264SPeter Hurley *
1463b1a696bSJiri Slaby (SUSE) * Similar to tty_unthrottle() but will only attempt unthrottle if
1473b1a696bSJiri Slaby (SUSE) * @tty->flow_change is %TTY_UNTHROTTLE_SAFE. Prevents an accidental unthrottle
1483b1a696bSJiri Slaby (SUSE) * due to race conditions when unthrottling is conditional on factors evaluated
1493b1a696bSJiri Slaby (SUSE) * prior to unthrottling.
15070bc1264SPeter Hurley *
1513b1a696bSJiri Slaby (SUSE) * Returns: %true if @tty is unthrottled (or was already unthrottled)
15270bc1264SPeter Hurley */
tty_unthrottle_safe(struct tty_struct * tty)153c2a36609SJiri Slaby (SUSE) bool tty_unthrottle_safe(struct tty_struct *tty)
15470bc1264SPeter Hurley {
1555b4f9cf3SJiri Slaby (SUSE) bool ret = true;
15670bc1264SPeter Hurley
157d8c1f929SPeter Hurley mutex_lock(&tty->throttle_mutex);
15897ef38b8SPeter Hurley if (tty_throttled(tty)) {
15970bc1264SPeter Hurley if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
1605b4f9cf3SJiri Slaby (SUSE) ret = false;
16170bc1264SPeter Hurley else {
162579a00a5SPeter Hurley clear_bit(TTY_THROTTLED, &tty->flags);
16370bc1264SPeter Hurley if (tty->ops->unthrottle)
16470bc1264SPeter Hurley tty->ops->unthrottle(tty);
16570bc1264SPeter Hurley }
16670bc1264SPeter Hurley }
167d8c1f929SPeter Hurley mutex_unlock(&tty->throttle_mutex);
16870bc1264SPeter Hurley
16970bc1264SPeter Hurley return ret;
17070bc1264SPeter Hurley }
17170bc1264SPeter Hurley
17270bc1264SPeter Hurley /**
17396fd7ce5SGreg Kroah-Hartman * tty_wait_until_sent - wait for I/O to finish
17496fd7ce5SGreg Kroah-Hartman * @tty: tty we are waiting for
17596fd7ce5SGreg Kroah-Hartman * @timeout: how long we will wait
17696fd7ce5SGreg Kroah-Hartman *
1773b1a696bSJiri Slaby (SUSE) * Wait for characters pending in a tty driver to hit the wire, or for a
1783b1a696bSJiri Slaby (SUSE) * timeout to occur (eg due to flow control).
17996fd7ce5SGreg Kroah-Hartman *
18096fd7ce5SGreg Kroah-Hartman * Locking: none
18196fd7ce5SGreg Kroah-Hartman */
18296fd7ce5SGreg Kroah-Hartman
tty_wait_until_sent(struct tty_struct * tty,long timeout)18396fd7ce5SGreg Kroah-Hartman void tty_wait_until_sent(struct tty_struct *tty, long timeout)
18496fd7ce5SGreg Kroah-Hartman {
18596fd7ce5SGreg Kroah-Hartman if (!timeout)
18696fd7ce5SGreg Kroah-Hartman timeout = MAX_SCHEDULE_TIMEOUT;
18779fbf4a5SJohan Hovold
188c37bc682SJohan Hovold timeout = wait_event_interruptible_timeout(tty->write_wait,
189c37bc682SJohan Hovold !tty_chars_in_buffer(tty), timeout);
190c37bc682SJohan Hovold if (timeout <= 0)
19179fbf4a5SJohan Hovold return;
19279fbf4a5SJohan Hovold
19379fbf4a5SJohan Hovold if (timeout == MAX_SCHEDULE_TIMEOUT)
19479fbf4a5SJohan Hovold timeout = 0;
19579fbf4a5SJohan Hovold
19696fd7ce5SGreg Kroah-Hartman if (tty->ops->wait_until_sent)
19796fd7ce5SGreg Kroah-Hartman tty->ops->wait_until_sent(tty, timeout);
19896fd7ce5SGreg Kroah-Hartman }
19996fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(tty_wait_until_sent);
20096fd7ce5SGreg Kroah-Hartman
20196fd7ce5SGreg Kroah-Hartman
20296fd7ce5SGreg Kroah-Hartman /*
20396fd7ce5SGreg Kroah-Hartman * Termios Helper Methods
20496fd7ce5SGreg Kroah-Hartman */
20596fd7ce5SGreg Kroah-Hartman
unset_locked_termios(struct tty_struct * tty,const struct ktermios * old)206bec5b814SIlpo Järvinen static void unset_locked_termios(struct tty_struct *tty, const struct ktermios *old)
20796fd7ce5SGreg Kroah-Hartman {
208d97ba9cdSPeter Hurley struct ktermios *termios = &tty->termios;
209d97ba9cdSPeter Hurley struct ktermios *locked = &tty->termios_locked;
21096fd7ce5SGreg Kroah-Hartman int i;
21196fd7ce5SGreg Kroah-Hartman
21296fd7ce5SGreg Kroah-Hartman #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
21396fd7ce5SGreg Kroah-Hartman
21496fd7ce5SGreg Kroah-Hartman NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
21596fd7ce5SGreg Kroah-Hartman NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
21696fd7ce5SGreg Kroah-Hartman NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
21796fd7ce5SGreg Kroah-Hartman NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
21896fd7ce5SGreg Kroah-Hartman termios->c_line = locked->c_line ? old->c_line : termios->c_line;
21996fd7ce5SGreg Kroah-Hartman for (i = 0; i < NCCS; i++)
22096fd7ce5SGreg Kroah-Hartman termios->c_cc[i] = locked->c_cc[i] ?
22196fd7ce5SGreg Kroah-Hartman old->c_cc[i] : termios->c_cc[i];
22296fd7ce5SGreg Kroah-Hartman /* FIXME: What should we do for i/ospeed */
22396fd7ce5SGreg Kroah-Hartman }
22496fd7ce5SGreg Kroah-Hartman
22596fd7ce5SGreg Kroah-Hartman /**
22696fd7ce5SGreg Kroah-Hartman * tty_termios_copy_hw - copy hardware settings
2273b1a696bSJiri Slaby (SUSE) * @new: new termios
2283b1a696bSJiri Slaby (SUSE) * @old: old termios
22996fd7ce5SGreg Kroah-Hartman *
2303b1a696bSJiri Slaby (SUSE) * Propagate the hardware specific terminal setting bits from the @old termios
2313b1a696bSJiri Slaby (SUSE) * structure to the @new one. This is used in cases where the hardware does not
2323b1a696bSJiri Slaby (SUSE) * support reconfiguration or as a helper in some cases where only minimal
2333b1a696bSJiri Slaby (SUSE) * reconfiguration is supported.
23496fd7ce5SGreg Kroah-Hartman */
tty_termios_copy_hw(struct ktermios * new,const struct ktermios * old)235d15f89d9SIlpo Järvinen void tty_termios_copy_hw(struct ktermios *new, const struct ktermios *old)
23696fd7ce5SGreg Kroah-Hartman {
23796fd7ce5SGreg Kroah-Hartman /* The bits a dumb device handles in software. Smart devices need
23896fd7ce5SGreg Kroah-Hartman to always provide a set_termios method */
23996fd7ce5SGreg Kroah-Hartman new->c_cflag &= HUPCL | CREAD | CLOCAL;
24096fd7ce5SGreg Kroah-Hartman new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
24196fd7ce5SGreg Kroah-Hartman new->c_ispeed = old->c_ispeed;
24296fd7ce5SGreg Kroah-Hartman new->c_ospeed = old->c_ospeed;
24396fd7ce5SGreg Kroah-Hartman }
24496fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(tty_termios_copy_hw);
24596fd7ce5SGreg Kroah-Hartman
24696fd7ce5SGreg Kroah-Hartman /**
24796fd7ce5SGreg Kroah-Hartman * tty_termios_hw_change - check for setting change
24896fd7ce5SGreg Kroah-Hartman * @a: termios
24996fd7ce5SGreg Kroah-Hartman * @b: termios to compare
25096fd7ce5SGreg Kroah-Hartman *
2513b1a696bSJiri Slaby (SUSE) * Check if any of the bits that affect a dumb device have changed between the
2523b1a696bSJiri Slaby (SUSE) * two termios structures, or a speed change is needed.
2533b1a696bSJiri Slaby (SUSE) *
2543b1a696bSJiri Slaby (SUSE) * Returns: %true if change is needed
25596fd7ce5SGreg Kroah-Hartman */
tty_termios_hw_change(const struct ktermios * a,const struct ktermios * b)25687f22db4SIlpo Järvinen bool tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
25796fd7ce5SGreg Kroah-Hartman {
25896fd7ce5SGreg Kroah-Hartman if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
25987f22db4SIlpo Järvinen return true;
26096fd7ce5SGreg Kroah-Hartman if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
26187f22db4SIlpo Järvinen return true;
26287f22db4SIlpo Järvinen return false;
26396fd7ce5SGreg Kroah-Hartman }
26496fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(tty_termios_hw_change);
26596fd7ce5SGreg Kroah-Hartman
26696fd7ce5SGreg Kroah-Hartman /**
267654ee49bSJiri Slaby * tty_get_char_size - get size of a character
268654ee49bSJiri Slaby * @cflag: termios cflag value
269654ee49bSJiri Slaby *
2703b1a696bSJiri Slaby (SUSE) * Returns: size (in bits) of a character depending on @cflag's %CSIZE setting
271654ee49bSJiri Slaby */
tty_get_char_size(unsigned int cflag)272654ee49bSJiri Slaby unsigned char tty_get_char_size(unsigned int cflag)
273654ee49bSJiri Slaby {
274654ee49bSJiri Slaby switch (cflag & CSIZE) {
275654ee49bSJiri Slaby case CS5:
276654ee49bSJiri Slaby return 5;
277654ee49bSJiri Slaby case CS6:
278654ee49bSJiri Slaby return 6;
279654ee49bSJiri Slaby case CS7:
280654ee49bSJiri Slaby return 7;
281654ee49bSJiri Slaby case CS8:
282654ee49bSJiri Slaby default:
283654ee49bSJiri Slaby return 8;
284654ee49bSJiri Slaby }
285654ee49bSJiri Slaby }
286654ee49bSJiri Slaby EXPORT_SYMBOL_GPL(tty_get_char_size);
287654ee49bSJiri Slaby
288654ee49bSJiri Slaby /**
289654ee49bSJiri Slaby * tty_get_frame_size - get size of a frame
290654ee49bSJiri Slaby * @cflag: termios cflag value
291654ee49bSJiri Slaby *
2923b1a696bSJiri Slaby (SUSE) * Get the size (in bits) of a frame depending on @cflag's %CSIZE, %CSTOPB, and
2933b1a696bSJiri Slaby (SUSE) * %PARENB setting. The result is a sum of character size, start and stop bits
2943b1a696bSJiri Slaby (SUSE) * -- one bit each -- second stop bit (if set), and parity bit (if set).
2953b1a696bSJiri Slaby (SUSE) *
2963b1a696bSJiri Slaby (SUSE) * Returns: size (in bits) of a frame depending on @cflag's setting.
297654ee49bSJiri Slaby */
tty_get_frame_size(unsigned int cflag)298654ee49bSJiri Slaby unsigned char tty_get_frame_size(unsigned int cflag)
299654ee49bSJiri Slaby {
300654ee49bSJiri Slaby unsigned char bits = 2 + tty_get_char_size(cflag);
301654ee49bSJiri Slaby
302654ee49bSJiri Slaby if (cflag & CSTOPB)
303654ee49bSJiri Slaby bits++;
304654ee49bSJiri Slaby if (cflag & PARENB)
305654ee49bSJiri Slaby bits++;
3064f768e94SIlpo Järvinen if (cflag & ADDRB)
3074f768e94SIlpo Järvinen bits++;
308654ee49bSJiri Slaby
309654ee49bSJiri Slaby return bits;
310654ee49bSJiri Slaby }
311654ee49bSJiri Slaby EXPORT_SYMBOL_GPL(tty_get_frame_size);
312654ee49bSJiri Slaby
313654ee49bSJiri Slaby /**
3148d075b19SAlan Cox * tty_set_termios - update termios values
31596fd7ce5SGreg Kroah-Hartman * @tty: tty to update
31696fd7ce5SGreg Kroah-Hartman * @new_termios: desired new value
31796fd7ce5SGreg Kroah-Hartman *
3183b1a696bSJiri Slaby (SUSE) * Perform updates to the termios values set on this @tty. A master pty's
3193b1a696bSJiri Slaby (SUSE) * termios should never be set.
3206460fbbfSPeter Hurley *
3213b1a696bSJiri Slaby (SUSE) * Locking: &tty_struct->termios_rwsem
32296fd7ce5SGreg Kroah-Hartman */
tty_set_termios(struct tty_struct * tty,struct ktermios * new_termios)323b00f5c2dSFrederic Danis int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
32496fd7ce5SGreg Kroah-Hartman {
32596fd7ce5SGreg Kroah-Hartman struct ktermios old_termios;
32696fd7ce5SGreg Kroah-Hartman struct tty_ldisc *ld;
32796fd7ce5SGreg Kroah-Hartman
3286460fbbfSPeter Hurley WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
3296460fbbfSPeter Hurley tty->driver->subtype == PTY_TYPE_MASTER);
33096fd7ce5SGreg Kroah-Hartman /*
33196fd7ce5SGreg Kroah-Hartman * Perform the actual termios internal changes under lock.
33296fd7ce5SGreg Kroah-Hartman */
33396fd7ce5SGreg Kroah-Hartman
33496fd7ce5SGreg Kroah-Hartman
33596fd7ce5SGreg Kroah-Hartman /* FIXME: we need to decide on some locking/ordering semantics
33696fd7ce5SGreg Kroah-Hartman for the set_termios notification eventually */
3376a1c0680SPeter Hurley down_write(&tty->termios_rwsem);
338adc8d746SAlan Cox old_termios = tty->termios;
339adc8d746SAlan Cox tty->termios = *new_termios;
340d97ba9cdSPeter Hurley unset_locked_termios(tty, &old_termios);
3414f768e94SIlpo Järvinen /* Reset any ADDRB changes, ADDRB is changed through ->rs485_config() */
3424f768e94SIlpo Järvinen tty->termios.c_cflag ^= (tty->termios.c_cflag ^ old_termios.c_cflag) & ADDRB;
34396fd7ce5SGreg Kroah-Hartman
34496fd7ce5SGreg Kroah-Hartman if (tty->ops->set_termios)
345c961bfb1SPeter Hurley tty->ops->set_termios(tty, &old_termios);
34696fd7ce5SGreg Kroah-Hartman else
347adc8d746SAlan Cox tty_termios_copy_hw(&tty->termios, &old_termios);
34896fd7ce5SGreg Kroah-Hartman
34996fd7ce5SGreg Kroah-Hartman ld = tty_ldisc_ref(tty);
35096fd7ce5SGreg Kroah-Hartman if (ld != NULL) {
35196fd7ce5SGreg Kroah-Hartman if (ld->ops->set_termios)
352c961bfb1SPeter Hurley ld->ops->set_termios(tty, &old_termios);
35396fd7ce5SGreg Kroah-Hartman tty_ldisc_deref(ld);
35496fd7ce5SGreg Kroah-Hartman }
3556a1c0680SPeter Hurley up_write(&tty->termios_rwsem);
3568d075b19SAlan Cox return 0;
35796fd7ce5SGreg Kroah-Hartman }
358b00f5c2dSFrederic Danis EXPORT_SYMBOL_GPL(tty_set_termios);
35996fd7ce5SGreg Kroah-Hartman
3601d5d6682SAl Viro
3611d5d6682SAl Viro /*
3621d5d6682SAl Viro * Translate a "termio" structure into a "termios". Ugh.
3631d5d6682SAl Viro */
user_termio_to_kernel_termios(struct ktermios * termios,struct termio __user * termio)3641d5d6682SAl Viro __weak int user_termio_to_kernel_termios(struct ktermios *termios,
3651d5d6682SAl Viro struct termio __user *termio)
3661d5d6682SAl Viro {
3671d5d6682SAl Viro struct termio v;
3681d5d6682SAl Viro
3691d5d6682SAl Viro if (copy_from_user(&v, termio, sizeof(struct termio)))
3701d5d6682SAl Viro return -EFAULT;
3711d5d6682SAl Viro
3721d5d6682SAl Viro termios->c_iflag = (0xffff0000 & termios->c_iflag) | v.c_iflag;
3731d5d6682SAl Viro termios->c_oflag = (0xffff0000 & termios->c_oflag) | v.c_oflag;
3741d5d6682SAl Viro termios->c_cflag = (0xffff0000 & termios->c_cflag) | v.c_cflag;
3751d5d6682SAl Viro termios->c_lflag = (0xffff0000 & termios->c_lflag) | v.c_lflag;
3761d5d6682SAl Viro termios->c_line = (0xffff0000 & termios->c_lflag) | v.c_line;
3771d5d6682SAl Viro memcpy(termios->c_cc, v.c_cc, NCC);
3781d5d6682SAl Viro return 0;
3791d5d6682SAl Viro }
3801d5d6682SAl Viro
3811d5d6682SAl Viro /*
3821d5d6682SAl Viro * Translate a "termios" structure into a "termio". Ugh.
3831d5d6682SAl Viro */
kernel_termios_to_user_termio(struct termio __user * termio,struct ktermios * termios)3841d5d6682SAl Viro __weak int kernel_termios_to_user_termio(struct termio __user *termio,
3851d5d6682SAl Viro struct ktermios *termios)
3861d5d6682SAl Viro {
3871d5d6682SAl Viro struct termio v;
3881d5d6682SAl Viro memset(&v, 0, sizeof(struct termio));
3891d5d6682SAl Viro v.c_iflag = termios->c_iflag;
3901d5d6682SAl Viro v.c_oflag = termios->c_oflag;
3911d5d6682SAl Viro v.c_cflag = termios->c_cflag;
3921d5d6682SAl Viro v.c_lflag = termios->c_lflag;
3931d5d6682SAl Viro v.c_line = termios->c_line;
3941d5d6682SAl Viro memcpy(v.c_cc, termios->c_cc, NCC);
3951d5d6682SAl Viro return copy_to_user(termio, &v, sizeof(struct termio));
3961d5d6682SAl Viro }
3971d5d6682SAl Viro
3981d5d6682SAl Viro #ifdef TCGETS2
user_termios_to_kernel_termios(struct ktermios * k,struct termios2 __user * u)3991d5d6682SAl Viro __weak int user_termios_to_kernel_termios(struct ktermios *k,
4001d5d6682SAl Viro struct termios2 __user *u)
4011d5d6682SAl Viro {
4021d5d6682SAl Viro return copy_from_user(k, u, sizeof(struct termios2));
4031d5d6682SAl Viro }
kernel_termios_to_user_termios(struct termios2 __user * u,struct ktermios * k)4041d5d6682SAl Viro __weak int kernel_termios_to_user_termios(struct termios2 __user *u,
4051d5d6682SAl Viro struct ktermios *k)
4061d5d6682SAl Viro {
4071d5d6682SAl Viro return copy_to_user(u, k, sizeof(struct termios2));
4081d5d6682SAl Viro }
user_termios_to_kernel_termios_1(struct ktermios * k,struct termios __user * u)4091d5d6682SAl Viro __weak int user_termios_to_kernel_termios_1(struct ktermios *k,
4101d5d6682SAl Viro struct termios __user *u)
4111d5d6682SAl Viro {
4121d5d6682SAl Viro return copy_from_user(k, u, sizeof(struct termios));
4131d5d6682SAl Viro }
kernel_termios_to_user_termios_1(struct termios __user * u,struct ktermios * k)4141d5d6682SAl Viro __weak int kernel_termios_to_user_termios_1(struct termios __user *u,
4151d5d6682SAl Viro struct ktermios *k)
4161d5d6682SAl Viro {
4171d5d6682SAl Viro return copy_to_user(u, k, sizeof(struct termios));
4181d5d6682SAl Viro }
4191d5d6682SAl Viro
4201d5d6682SAl Viro #else
4211d5d6682SAl Viro
user_termios_to_kernel_termios(struct ktermios * k,struct termios __user * u)4221d5d6682SAl Viro __weak int user_termios_to_kernel_termios(struct ktermios *k,
4231d5d6682SAl Viro struct termios __user *u)
4241d5d6682SAl Viro {
4251d5d6682SAl Viro return copy_from_user(k, u, sizeof(struct termios));
4261d5d6682SAl Viro }
kernel_termios_to_user_termios(struct termios __user * u,struct ktermios * k)4271d5d6682SAl Viro __weak int kernel_termios_to_user_termios(struct termios __user *u,
4281d5d6682SAl Viro struct ktermios *k)
4291d5d6682SAl Viro {
4301d5d6682SAl Viro return copy_to_user(u, k, sizeof(struct termios));
4311d5d6682SAl Viro }
4321d5d6682SAl Viro #endif /* TCGETS2 */
4331d5d6682SAl Viro
43496fd7ce5SGreg Kroah-Hartman /**
43596fd7ce5SGreg Kroah-Hartman * set_termios - set termios values for a tty
43696fd7ce5SGreg Kroah-Hartman * @tty: terminal device
43796fd7ce5SGreg Kroah-Hartman * @arg: user data
43896fd7ce5SGreg Kroah-Hartman * @opt: option information
43996fd7ce5SGreg Kroah-Hartman *
4403b1a696bSJiri Slaby (SUSE) * Helper function to prepare termios data and run necessary other functions
4413b1a696bSJiri Slaby (SUSE) * before using tty_set_termios() to do the actual changes.
44296fd7ce5SGreg Kroah-Hartman *
4433b1a696bSJiri Slaby (SUSE) * Locking: called functions take &tty_struct->ldisc_sem and
4443b1a696bSJiri Slaby (SUSE) * &tty_struct->termios_rwsem locks
4453b1a696bSJiri Slaby (SUSE) *
4463b1a696bSJiri Slaby (SUSE) * Returns: 0 on success, an error otherwise
44796fd7ce5SGreg Kroah-Hartman */
set_termios(struct tty_struct * tty,void __user * arg,int opt)44896fd7ce5SGreg Kroah-Hartman static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
44996fd7ce5SGreg Kroah-Hartman {
45096fd7ce5SGreg Kroah-Hartman struct ktermios tmp_termios;
45196fd7ce5SGreg Kroah-Hartman struct tty_ldisc *ld;
45296fd7ce5SGreg Kroah-Hartman int retval = tty_check_change(tty);
45396fd7ce5SGreg Kroah-Hartman
45496fd7ce5SGreg Kroah-Hartman if (retval)
45596fd7ce5SGreg Kroah-Hartman return retval;
45696fd7ce5SGreg Kroah-Hartman
4576a1c0680SPeter Hurley down_read(&tty->termios_rwsem);
458adc8d746SAlan Cox tmp_termios = tty->termios;
4596a1c0680SPeter Hurley up_read(&tty->termios_rwsem);
46096fd7ce5SGreg Kroah-Hartman
46196fd7ce5SGreg Kroah-Hartman if (opt & TERMIOS_TERMIO) {
46296fd7ce5SGreg Kroah-Hartman if (user_termio_to_kernel_termios(&tmp_termios,
46396fd7ce5SGreg Kroah-Hartman (struct termio __user *)arg))
46496fd7ce5SGreg Kroah-Hartman return -EFAULT;
46596fd7ce5SGreg Kroah-Hartman #ifdef TCGETS2
46696fd7ce5SGreg Kroah-Hartman } else if (opt & TERMIOS_OLD) {
46796fd7ce5SGreg Kroah-Hartman if (user_termios_to_kernel_termios_1(&tmp_termios,
46896fd7ce5SGreg Kroah-Hartman (struct termios __user *)arg))
46996fd7ce5SGreg Kroah-Hartman return -EFAULT;
47096fd7ce5SGreg Kroah-Hartman } else {
47196fd7ce5SGreg Kroah-Hartman if (user_termios_to_kernel_termios(&tmp_termios,
47296fd7ce5SGreg Kroah-Hartman (struct termios2 __user *)arg))
47396fd7ce5SGreg Kroah-Hartman return -EFAULT;
47496fd7ce5SGreg Kroah-Hartman }
47596fd7ce5SGreg Kroah-Hartman #else
47696fd7ce5SGreg Kroah-Hartman } else if (user_termios_to_kernel_termios(&tmp_termios,
47796fd7ce5SGreg Kroah-Hartman (struct termios __user *)arg))
47896fd7ce5SGreg Kroah-Hartman return -EFAULT;
47996fd7ce5SGreg Kroah-Hartman #endif
48096fd7ce5SGreg Kroah-Hartman
48196fd7ce5SGreg Kroah-Hartman /* If old style Bfoo values are used then load c_ispeed/c_ospeed
48296fd7ce5SGreg Kroah-Hartman * with the real speed so its unconditionally usable */
48396fd7ce5SGreg Kroah-Hartman tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
48496fd7ce5SGreg Kroah-Hartman tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
48596fd7ce5SGreg Kroah-Hartman
486094fb49aSIlpo Järvinen if (opt & (TERMIOS_FLUSH|TERMIOS_WAIT)) {
487094fb49aSIlpo Järvinen retry_write_wait:
488094fb49aSIlpo Järvinen retval = wait_event_interruptible(tty->write_wait, !tty_chars_in_buffer(tty));
489094fb49aSIlpo Järvinen if (retval < 0)
490094fb49aSIlpo Järvinen return retval;
49196fd7ce5SGreg Kroah-Hartman
492af815336SJiri Slaby (SUSE) if (tty_write_lock(tty, false) < 0)
493094fb49aSIlpo Järvinen goto retry_write_wait;
494094fb49aSIlpo Järvinen
495094fb49aSIlpo Järvinen /* Racing writer? */
496094fb49aSIlpo Järvinen if (tty_chars_in_buffer(tty)) {
497094fb49aSIlpo Järvinen tty_write_unlock(tty);
498094fb49aSIlpo Järvinen goto retry_write_wait;
499094fb49aSIlpo Järvinen }
500094fb49aSIlpo Järvinen
501094fb49aSIlpo Järvinen ld = tty_ldisc_ref(tty);
50296fd7ce5SGreg Kroah-Hartman if (ld != NULL) {
50396fd7ce5SGreg Kroah-Hartman if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
50496fd7ce5SGreg Kroah-Hartman ld->ops->flush_buffer(tty);
50596fd7ce5SGreg Kroah-Hartman tty_ldisc_deref(ld);
50696fd7ce5SGreg Kroah-Hartman }
50796fd7ce5SGreg Kroah-Hartman
508094fb49aSIlpo Järvinen if ((opt & TERMIOS_WAIT) && tty->ops->wait_until_sent) {
509094fb49aSIlpo Järvinen tty->ops->wait_until_sent(tty, 0);
510094fb49aSIlpo Järvinen if (signal_pending(current)) {
511094fb49aSIlpo Järvinen tty_write_unlock(tty);
512183d95cdSOleg Nesterov return -ERESTARTSYS;
51396fd7ce5SGreg Kroah-Hartman }
514094fb49aSIlpo Järvinen }
51596fd7ce5SGreg Kroah-Hartman
5168d075b19SAlan Cox tty_set_termios(tty, &tmp_termios);
51796fd7ce5SGreg Kroah-Hartman
518094fb49aSIlpo Järvinen tty_write_unlock(tty);
519094fb49aSIlpo Järvinen } else {
520094fb49aSIlpo Järvinen tty_set_termios(tty, &tmp_termios);
521094fb49aSIlpo Järvinen }
522094fb49aSIlpo Järvinen
52396fd7ce5SGreg Kroah-Hartman /* FIXME: Arguably if tmp_termios == tty->termios AND the
52496fd7ce5SGreg Kroah-Hartman actual requested termios was not tmp_termios then we may
52596fd7ce5SGreg Kroah-Hartman want to return an error as no user requested change has
52696fd7ce5SGreg Kroah-Hartman succeeded */
52796fd7ce5SGreg Kroah-Hartman return 0;
52896fd7ce5SGreg Kroah-Hartman }
52996fd7ce5SGreg Kroah-Hartman
copy_termios(struct tty_struct * tty,struct ktermios * kterm)53096fd7ce5SGreg Kroah-Hartman static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
53196fd7ce5SGreg Kroah-Hartman {
5326a1c0680SPeter Hurley down_read(&tty->termios_rwsem);
533adc8d746SAlan Cox *kterm = tty->termios;
5346a1c0680SPeter Hurley up_read(&tty->termios_rwsem);
53596fd7ce5SGreg Kroah-Hartman }
53696fd7ce5SGreg Kroah-Hartman
copy_termios_locked(struct tty_struct * tty,struct ktermios * kterm)53796fd7ce5SGreg Kroah-Hartman static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
53896fd7ce5SGreg Kroah-Hartman {
5396a1c0680SPeter Hurley down_read(&tty->termios_rwsem);
540adc8d746SAlan Cox *kterm = tty->termios_locked;
5416a1c0680SPeter Hurley up_read(&tty->termios_rwsem);
54296fd7ce5SGreg Kroah-Hartman }
54396fd7ce5SGreg Kroah-Hartman
get_termio(struct tty_struct * tty,struct termio __user * termio)54496fd7ce5SGreg Kroah-Hartman static int get_termio(struct tty_struct *tty, struct termio __user *termio)
54596fd7ce5SGreg Kroah-Hartman {
54696fd7ce5SGreg Kroah-Hartman struct ktermios kterm;
54796fd7ce5SGreg Kroah-Hartman copy_termios(tty, &kterm);
54896fd7ce5SGreg Kroah-Hartman if (kernel_termios_to_user_termio(termio, &kterm))
54996fd7ce5SGreg Kroah-Hartman return -EFAULT;
55096fd7ce5SGreg Kroah-Hartman return 0;
55196fd7ce5SGreg Kroah-Hartman }
55296fd7ce5SGreg Kroah-Hartman
55396fd7ce5SGreg Kroah-Hartman #ifdef TIOCGETP
55496fd7ce5SGreg Kroah-Hartman /*
55596fd7ce5SGreg Kroah-Hartman * These are deprecated, but there is limited support..
55696fd7ce5SGreg Kroah-Hartman *
55796fd7ce5SGreg Kroah-Hartman * The "sg_flags" translation is a joke..
55896fd7ce5SGreg Kroah-Hartman */
get_sgflags(struct tty_struct * tty)55996fd7ce5SGreg Kroah-Hartman static int get_sgflags(struct tty_struct *tty)
56096fd7ce5SGreg Kroah-Hartman {
56196fd7ce5SGreg Kroah-Hartman int flags = 0;
56296fd7ce5SGreg Kroah-Hartman
5639db276f8SPeter Hurley if (!L_ICANON(tty)) {
5649db276f8SPeter Hurley if (L_ISIG(tty))
56596fd7ce5SGreg Kroah-Hartman flags |= 0x02; /* cbreak */
56696fd7ce5SGreg Kroah-Hartman else
56796fd7ce5SGreg Kroah-Hartman flags |= 0x20; /* raw */
56896fd7ce5SGreg Kroah-Hartman }
5699db276f8SPeter Hurley if (L_ECHO(tty))
57096fd7ce5SGreg Kroah-Hartman flags |= 0x08; /* echo */
5719db276f8SPeter Hurley if (O_OPOST(tty))
5729db276f8SPeter Hurley if (O_ONLCR(tty))
57396fd7ce5SGreg Kroah-Hartman flags |= 0x10; /* crmod */
57496fd7ce5SGreg Kroah-Hartman return flags;
57596fd7ce5SGreg Kroah-Hartman }
57696fd7ce5SGreg Kroah-Hartman
get_sgttyb(struct tty_struct * tty,struct sgttyb __user * sgttyb)57796fd7ce5SGreg Kroah-Hartman static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
57896fd7ce5SGreg Kroah-Hartman {
57996fd7ce5SGreg Kroah-Hartman struct sgttyb tmp;
58096fd7ce5SGreg Kroah-Hartman
5816a1c0680SPeter Hurley down_read(&tty->termios_rwsem);
582adc8d746SAlan Cox tmp.sg_ispeed = tty->termios.c_ispeed;
583adc8d746SAlan Cox tmp.sg_ospeed = tty->termios.c_ospeed;
584adc8d746SAlan Cox tmp.sg_erase = tty->termios.c_cc[VERASE];
585adc8d746SAlan Cox tmp.sg_kill = tty->termios.c_cc[VKILL];
58696fd7ce5SGreg Kroah-Hartman tmp.sg_flags = get_sgflags(tty);
5876a1c0680SPeter Hurley up_read(&tty->termios_rwsem);
58896fd7ce5SGreg Kroah-Hartman
58996fd7ce5SGreg Kroah-Hartman return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
59096fd7ce5SGreg Kroah-Hartman }
59196fd7ce5SGreg Kroah-Hartman
set_sgflags(struct ktermios * termios,int flags)59296fd7ce5SGreg Kroah-Hartman static void set_sgflags(struct ktermios *termios, int flags)
59396fd7ce5SGreg Kroah-Hartman {
5949833facfSAlan Cox termios->c_iflag = ICRNL | IXON;
5959833facfSAlan Cox termios->c_oflag = 0;
5969833facfSAlan Cox termios->c_lflag = ISIG | ICANON;
59796fd7ce5SGreg Kroah-Hartman if (flags & 0x02) { /* cbreak */
5989833facfSAlan Cox termios->c_iflag = 0;
5999833facfSAlan Cox termios->c_lflag &= ~ICANON;
60096fd7ce5SGreg Kroah-Hartman }
60196fd7ce5SGreg Kroah-Hartman if (flags & 0x08) { /* echo */
6029833facfSAlan Cox termios->c_lflag |= ECHO | ECHOE | ECHOK |
60396fd7ce5SGreg Kroah-Hartman ECHOCTL | ECHOKE | IEXTEN;
60496fd7ce5SGreg Kroah-Hartman }
60596fd7ce5SGreg Kroah-Hartman if (flags & 0x10) { /* crmod */
6069833facfSAlan Cox termios->c_oflag |= OPOST | ONLCR;
60796fd7ce5SGreg Kroah-Hartman }
60896fd7ce5SGreg Kroah-Hartman if (flags & 0x20) { /* raw */
6099833facfSAlan Cox termios->c_iflag = 0;
6109833facfSAlan Cox termios->c_lflag &= ~(ISIG | ICANON);
61196fd7ce5SGreg Kroah-Hartman }
6129833facfSAlan Cox if (!(termios->c_lflag & ICANON)) {
6139833facfSAlan Cox termios->c_cc[VMIN] = 1;
6149833facfSAlan Cox termios->c_cc[VTIME] = 0;
61596fd7ce5SGreg Kroah-Hartman }
61696fd7ce5SGreg Kroah-Hartman }
61796fd7ce5SGreg Kroah-Hartman
61896fd7ce5SGreg Kroah-Hartman /**
61996fd7ce5SGreg Kroah-Hartman * set_sgttyb - set legacy terminal values
62096fd7ce5SGreg Kroah-Hartman * @tty: tty structure
62196fd7ce5SGreg Kroah-Hartman * @sgttyb: pointer to old style terminal structure
62296fd7ce5SGreg Kroah-Hartman *
6233b1a696bSJiri Slaby (SUSE) * Updates a terminal from the legacy BSD style terminal information structure.
62496fd7ce5SGreg Kroah-Hartman *
6253b1a696bSJiri Slaby (SUSE) * Locking: &tty_struct->termios_rwsem
6263b1a696bSJiri Slaby (SUSE) *
6273b1a696bSJiri Slaby (SUSE) * Returns: 0 on success, an error otherwise
62896fd7ce5SGreg Kroah-Hartman */
set_sgttyb(struct tty_struct * tty,struct sgttyb __user * sgttyb)62996fd7ce5SGreg Kroah-Hartman static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
63096fd7ce5SGreg Kroah-Hartman {
63196fd7ce5SGreg Kroah-Hartman int retval;
63296fd7ce5SGreg Kroah-Hartman struct sgttyb tmp;
63396fd7ce5SGreg Kroah-Hartman struct ktermios termios;
63496fd7ce5SGreg Kroah-Hartman
63596fd7ce5SGreg Kroah-Hartman retval = tty_check_change(tty);
63696fd7ce5SGreg Kroah-Hartman if (retval)
63796fd7ce5SGreg Kroah-Hartman return retval;
63896fd7ce5SGreg Kroah-Hartman
63996fd7ce5SGreg Kroah-Hartman if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
64096fd7ce5SGreg Kroah-Hartman return -EFAULT;
64196fd7ce5SGreg Kroah-Hartman
6426a1c0680SPeter Hurley down_write(&tty->termios_rwsem);
643adc8d746SAlan Cox termios = tty->termios;
64496fd7ce5SGreg Kroah-Hartman termios.c_cc[VERASE] = tmp.sg_erase;
64596fd7ce5SGreg Kroah-Hartman termios.c_cc[VKILL] = tmp.sg_kill;
64696fd7ce5SGreg Kroah-Hartman set_sgflags(&termios, tmp.sg_flags);
64796fd7ce5SGreg Kroah-Hartman /* Try and encode into Bfoo format */
64896fd7ce5SGreg Kroah-Hartman tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
64996fd7ce5SGreg Kroah-Hartman termios.c_ospeed);
6506a1c0680SPeter Hurley up_write(&tty->termios_rwsem);
6518d075b19SAlan Cox tty_set_termios(tty, &termios);
65296fd7ce5SGreg Kroah-Hartman return 0;
65396fd7ce5SGreg Kroah-Hartman }
65496fd7ce5SGreg Kroah-Hartman #endif
65596fd7ce5SGreg Kroah-Hartman
65696fd7ce5SGreg Kroah-Hartman #ifdef TIOCGETC
get_tchars(struct tty_struct * tty,struct tchars __user * tchars)65796fd7ce5SGreg Kroah-Hartman static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
65896fd7ce5SGreg Kroah-Hartman {
65996fd7ce5SGreg Kroah-Hartman struct tchars tmp;
66096fd7ce5SGreg Kroah-Hartman
6616a1c0680SPeter Hurley down_read(&tty->termios_rwsem);
662adc8d746SAlan Cox tmp.t_intrc = tty->termios.c_cc[VINTR];
663adc8d746SAlan Cox tmp.t_quitc = tty->termios.c_cc[VQUIT];
664adc8d746SAlan Cox tmp.t_startc = tty->termios.c_cc[VSTART];
665adc8d746SAlan Cox tmp.t_stopc = tty->termios.c_cc[VSTOP];
666adc8d746SAlan Cox tmp.t_eofc = tty->termios.c_cc[VEOF];
667adc8d746SAlan Cox tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */
6686a1c0680SPeter Hurley up_read(&tty->termios_rwsem);
66996fd7ce5SGreg Kroah-Hartman return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
67096fd7ce5SGreg Kroah-Hartman }
67196fd7ce5SGreg Kroah-Hartman
set_tchars(struct tty_struct * tty,struct tchars __user * tchars)67296fd7ce5SGreg Kroah-Hartman static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
67396fd7ce5SGreg Kroah-Hartman {
67496fd7ce5SGreg Kroah-Hartman struct tchars tmp;
67596fd7ce5SGreg Kroah-Hartman
67696fd7ce5SGreg Kroah-Hartman if (copy_from_user(&tmp, tchars, sizeof(tmp)))
67796fd7ce5SGreg Kroah-Hartman return -EFAULT;
6786a1c0680SPeter Hurley down_write(&tty->termios_rwsem);
679adc8d746SAlan Cox tty->termios.c_cc[VINTR] = tmp.t_intrc;
680adc8d746SAlan Cox tty->termios.c_cc[VQUIT] = tmp.t_quitc;
681adc8d746SAlan Cox tty->termios.c_cc[VSTART] = tmp.t_startc;
682adc8d746SAlan Cox tty->termios.c_cc[VSTOP] = tmp.t_stopc;
683adc8d746SAlan Cox tty->termios.c_cc[VEOF] = tmp.t_eofc;
684adc8d746SAlan Cox tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
6856a1c0680SPeter Hurley up_write(&tty->termios_rwsem);
68696fd7ce5SGreg Kroah-Hartman return 0;
68796fd7ce5SGreg Kroah-Hartman }
68896fd7ce5SGreg Kroah-Hartman #endif
68996fd7ce5SGreg Kroah-Hartman
69096fd7ce5SGreg Kroah-Hartman #ifdef TIOCGLTC
get_ltchars(struct tty_struct * tty,struct ltchars __user * ltchars)69196fd7ce5SGreg Kroah-Hartman static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
69296fd7ce5SGreg Kroah-Hartman {
69396fd7ce5SGreg Kroah-Hartman struct ltchars tmp;
69496fd7ce5SGreg Kroah-Hartman
6956a1c0680SPeter Hurley down_read(&tty->termios_rwsem);
696adc8d746SAlan Cox tmp.t_suspc = tty->termios.c_cc[VSUSP];
69796fd7ce5SGreg Kroah-Hartman /* what is dsuspc anyway? */
698adc8d746SAlan Cox tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
699adc8d746SAlan Cox tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
70096fd7ce5SGreg Kroah-Hartman /* what is flushc anyway? */
701adc8d746SAlan Cox tmp.t_flushc = tty->termios.c_cc[VEOL2];
702adc8d746SAlan Cox tmp.t_werasc = tty->termios.c_cc[VWERASE];
703adc8d746SAlan Cox tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
7046a1c0680SPeter Hurley up_read(&tty->termios_rwsem);
70596fd7ce5SGreg Kroah-Hartman return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
70696fd7ce5SGreg Kroah-Hartman }
70796fd7ce5SGreg Kroah-Hartman
set_ltchars(struct tty_struct * tty,struct ltchars __user * ltchars)70896fd7ce5SGreg Kroah-Hartman static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
70996fd7ce5SGreg Kroah-Hartman {
71096fd7ce5SGreg Kroah-Hartman struct ltchars tmp;
71196fd7ce5SGreg Kroah-Hartman
71296fd7ce5SGreg Kroah-Hartman if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
71396fd7ce5SGreg Kroah-Hartman return -EFAULT;
71496fd7ce5SGreg Kroah-Hartman
7156a1c0680SPeter Hurley down_write(&tty->termios_rwsem);
716adc8d746SAlan Cox tty->termios.c_cc[VSUSP] = tmp.t_suspc;
71796fd7ce5SGreg Kroah-Hartman /* what is dsuspc anyway? */
718adc8d746SAlan Cox tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
719adc8d746SAlan Cox tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
72096fd7ce5SGreg Kroah-Hartman /* what is flushc anyway? */
721adc8d746SAlan Cox tty->termios.c_cc[VEOL2] = tmp.t_flushc;
722adc8d746SAlan Cox tty->termios.c_cc[VWERASE] = tmp.t_werasc;
723adc8d746SAlan Cox tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
7246a1c0680SPeter Hurley up_write(&tty->termios_rwsem);
72596fd7ce5SGreg Kroah-Hartman return 0;
72696fd7ce5SGreg Kroah-Hartman }
72796fd7ce5SGreg Kroah-Hartman #endif
72896fd7ce5SGreg Kroah-Hartman
72996fd7ce5SGreg Kroah-Hartman /**
73096fd7ce5SGreg Kroah-Hartman * tty_change_softcar - carrier change ioctl helper
73196fd7ce5SGreg Kroah-Hartman * @tty: tty to update
7323b1a696bSJiri Slaby (SUSE) * @enable: enable/disable %CLOCAL
73396fd7ce5SGreg Kroah-Hartman *
7343b1a696bSJiri Slaby (SUSE) * Perform a change to the %CLOCAL state and call into the driver layer to make
7353b1a696bSJiri Slaby (SUSE) * it visible.
7363b1a696bSJiri Slaby (SUSE) *
7373b1a696bSJiri Slaby (SUSE) * Locking: &tty_struct->termios_rwsem.
7383b1a696bSJiri Slaby (SUSE) *
7393b1a696bSJiri Slaby (SUSE) * Returns: 0 on success, an error otherwise
74096fd7ce5SGreg Kroah-Hartman */
tty_change_softcar(struct tty_struct * tty,bool enable)74177b425e4SJiri Slaby (SUSE) static int tty_change_softcar(struct tty_struct *tty, bool enable)
74296fd7ce5SGreg Kroah-Hartman {
74396fd7ce5SGreg Kroah-Hartman int ret = 0;
74496fd7ce5SGreg Kroah-Hartman struct ktermios old;
74577b425e4SJiri Slaby (SUSE) tcflag_t bit = enable ? CLOCAL : 0;
74696fd7ce5SGreg Kroah-Hartman
7476a1c0680SPeter Hurley down_write(&tty->termios_rwsem);
748adc8d746SAlan Cox old = tty->termios;
749adc8d746SAlan Cox tty->termios.c_cflag &= ~CLOCAL;
750adc8d746SAlan Cox tty->termios.c_cflag |= bit;
75196fd7ce5SGreg Kroah-Hartman if (tty->ops->set_termios)
75296fd7ce5SGreg Kroah-Hartman tty->ops->set_termios(tty, &old);
7539db276f8SPeter Hurley if (C_CLOCAL(tty) != bit)
75496fd7ce5SGreg Kroah-Hartman ret = -EINVAL;
7556a1c0680SPeter Hurley up_write(&tty->termios_rwsem);
75696fd7ce5SGreg Kroah-Hartman return ret;
75796fd7ce5SGreg Kroah-Hartman }
75896fd7ce5SGreg Kroah-Hartman
75996fd7ce5SGreg Kroah-Hartman /**
76096fd7ce5SGreg Kroah-Hartman * tty_mode_ioctl - mode related ioctls
76196fd7ce5SGreg Kroah-Hartman * @tty: tty for the ioctl
76296fd7ce5SGreg Kroah-Hartman * @cmd: command
76396fd7ce5SGreg Kroah-Hartman * @arg: ioctl argument
76496fd7ce5SGreg Kroah-Hartman *
7653b1a696bSJiri Slaby (SUSE) * Perform non-line discipline specific mode control ioctls. This is designed
7663b1a696bSJiri Slaby (SUSE) * to be called by line disciplines to ensure they provide consistent mode
7673b1a696bSJiri Slaby (SUSE) * setting.
76896fd7ce5SGreg Kroah-Hartman */
tty_mode_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)769dcc223e8SJiri Slaby int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
77096fd7ce5SGreg Kroah-Hartman {
77196fd7ce5SGreg Kroah-Hartman struct tty_struct *real_tty;
77296fd7ce5SGreg Kroah-Hartman void __user *p = (void __user *)arg;
77396fd7ce5SGreg Kroah-Hartman int ret = 0;
77496fd7ce5SGreg Kroah-Hartman struct ktermios kterm;
77596fd7ce5SGreg Kroah-Hartman
77696fd7ce5SGreg Kroah-Hartman if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
77796fd7ce5SGreg Kroah-Hartman tty->driver->subtype == PTY_TYPE_MASTER)
77896fd7ce5SGreg Kroah-Hartman real_tty = tty->link;
77996fd7ce5SGreg Kroah-Hartman else
78096fd7ce5SGreg Kroah-Hartman real_tty = tty;
78196fd7ce5SGreg Kroah-Hartman
78296fd7ce5SGreg Kroah-Hartman switch (cmd) {
78396fd7ce5SGreg Kroah-Hartman #ifdef TIOCGETP
78496fd7ce5SGreg Kroah-Hartman case TIOCGETP:
78596fd7ce5SGreg Kroah-Hartman return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
78696fd7ce5SGreg Kroah-Hartman case TIOCSETP:
78796fd7ce5SGreg Kroah-Hartman case TIOCSETN:
78896fd7ce5SGreg Kroah-Hartman return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
78996fd7ce5SGreg Kroah-Hartman #endif
79096fd7ce5SGreg Kroah-Hartman #ifdef TIOCGETC
79196fd7ce5SGreg Kroah-Hartman case TIOCGETC:
79296fd7ce5SGreg Kroah-Hartman return get_tchars(real_tty, p);
79396fd7ce5SGreg Kroah-Hartman case TIOCSETC:
79496fd7ce5SGreg Kroah-Hartman return set_tchars(real_tty, p);
79596fd7ce5SGreg Kroah-Hartman #endif
79696fd7ce5SGreg Kroah-Hartman #ifdef TIOCGLTC
79796fd7ce5SGreg Kroah-Hartman case TIOCGLTC:
79896fd7ce5SGreg Kroah-Hartman return get_ltchars(real_tty, p);
79996fd7ce5SGreg Kroah-Hartman case TIOCSLTC:
80096fd7ce5SGreg Kroah-Hartman return set_ltchars(real_tty, p);
80196fd7ce5SGreg Kroah-Hartman #endif
80296fd7ce5SGreg Kroah-Hartman case TCSETSF:
80396fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
80496fd7ce5SGreg Kroah-Hartman case TCSETSW:
80596fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
80696fd7ce5SGreg Kroah-Hartman case TCSETS:
80796fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, TERMIOS_OLD);
80896fd7ce5SGreg Kroah-Hartman #ifndef TCGETS2
80996fd7ce5SGreg Kroah-Hartman case TCGETS:
81096fd7ce5SGreg Kroah-Hartman copy_termios(real_tty, &kterm);
81196fd7ce5SGreg Kroah-Hartman if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
81296fd7ce5SGreg Kroah-Hartman ret = -EFAULT;
81396fd7ce5SGreg Kroah-Hartman return ret;
81496fd7ce5SGreg Kroah-Hartman #else
81596fd7ce5SGreg Kroah-Hartman case TCGETS:
81696fd7ce5SGreg Kroah-Hartman copy_termios(real_tty, &kterm);
81796fd7ce5SGreg Kroah-Hartman if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
81896fd7ce5SGreg Kroah-Hartman ret = -EFAULT;
81996fd7ce5SGreg Kroah-Hartman return ret;
82096fd7ce5SGreg Kroah-Hartman case TCGETS2:
82196fd7ce5SGreg Kroah-Hartman copy_termios(real_tty, &kterm);
82296fd7ce5SGreg Kroah-Hartman if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
82396fd7ce5SGreg Kroah-Hartman ret = -EFAULT;
82496fd7ce5SGreg Kroah-Hartman return ret;
82596fd7ce5SGreg Kroah-Hartman case TCSETSF2:
82696fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
82796fd7ce5SGreg Kroah-Hartman case TCSETSW2:
82896fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, TERMIOS_WAIT);
82996fd7ce5SGreg Kroah-Hartman case TCSETS2:
83096fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, 0);
83196fd7ce5SGreg Kroah-Hartman #endif
83296fd7ce5SGreg Kroah-Hartman case TCGETA:
83396fd7ce5SGreg Kroah-Hartman return get_termio(real_tty, p);
83496fd7ce5SGreg Kroah-Hartman case TCSETAF:
83596fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
83696fd7ce5SGreg Kroah-Hartman case TCSETAW:
83796fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
83896fd7ce5SGreg Kroah-Hartman case TCSETA:
83996fd7ce5SGreg Kroah-Hartman return set_termios(real_tty, p, TERMIOS_TERMIO);
84096fd7ce5SGreg Kroah-Hartman #ifndef TCGETS2
84196fd7ce5SGreg Kroah-Hartman case TIOCGLCKTRMIOS:
84296fd7ce5SGreg Kroah-Hartman copy_termios_locked(real_tty, &kterm);
84396fd7ce5SGreg Kroah-Hartman if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
84496fd7ce5SGreg Kroah-Hartman ret = -EFAULT;
84596fd7ce5SGreg Kroah-Hartman return ret;
84696fd7ce5SGreg Kroah-Hartman case TIOCSLCKTRMIOS:
847*e0f25b89SAdrian Reber if (!checkpoint_restore_ns_capable(&init_user_ns))
84896fd7ce5SGreg Kroah-Hartman return -EPERM;
84996fd7ce5SGreg Kroah-Hartman copy_termios_locked(real_tty, &kterm);
85096fd7ce5SGreg Kroah-Hartman if (user_termios_to_kernel_termios(&kterm,
85196fd7ce5SGreg Kroah-Hartman (struct termios __user *) arg))
85296fd7ce5SGreg Kroah-Hartman return -EFAULT;
8536a1c0680SPeter Hurley down_write(&real_tty->termios_rwsem);
854adc8d746SAlan Cox real_tty->termios_locked = kterm;
8556a1c0680SPeter Hurley up_write(&real_tty->termios_rwsem);
85696fd7ce5SGreg Kroah-Hartman return 0;
85796fd7ce5SGreg Kroah-Hartman #else
85896fd7ce5SGreg Kroah-Hartman case TIOCGLCKTRMIOS:
85996fd7ce5SGreg Kroah-Hartman copy_termios_locked(real_tty, &kterm);
86096fd7ce5SGreg Kroah-Hartman if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
86196fd7ce5SGreg Kroah-Hartman ret = -EFAULT;
86296fd7ce5SGreg Kroah-Hartman return ret;
86396fd7ce5SGreg Kroah-Hartman case TIOCSLCKTRMIOS:
864*e0f25b89SAdrian Reber if (!checkpoint_restore_ns_capable(&init_user_ns))
86596fd7ce5SGreg Kroah-Hartman return -EPERM;
86696fd7ce5SGreg Kroah-Hartman copy_termios_locked(real_tty, &kterm);
86796fd7ce5SGreg Kroah-Hartman if (user_termios_to_kernel_termios_1(&kterm,
86896fd7ce5SGreg Kroah-Hartman (struct termios __user *) arg))
86996fd7ce5SGreg Kroah-Hartman return -EFAULT;
8706a1c0680SPeter Hurley down_write(&real_tty->termios_rwsem);
871adc8d746SAlan Cox real_tty->termios_locked = kterm;
8726a1c0680SPeter Hurley up_write(&real_tty->termios_rwsem);
87396fd7ce5SGreg Kroah-Hartman return ret;
87496fd7ce5SGreg Kroah-Hartman #endif
87596fd7ce5SGreg Kroah-Hartman #ifdef TCGETX
876e0efb316SJann Horn case TCGETX:
87796fd7ce5SGreg Kroah-Hartman case TCSETX:
87896fd7ce5SGreg Kroah-Hartman case TCSETXW:
87996fd7ce5SGreg Kroah-Hartman case TCSETXF:
8808871de06SJohan Hovold return -ENOTTY;
88196fd7ce5SGreg Kroah-Hartman #endif
88296fd7ce5SGreg Kroah-Hartman case TIOCGSOFTCAR:
88396fd7ce5SGreg Kroah-Hartman copy_termios(real_tty, &kterm);
88496fd7ce5SGreg Kroah-Hartman ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
88596fd7ce5SGreg Kroah-Hartman (int __user *)arg);
88696fd7ce5SGreg Kroah-Hartman return ret;
88796fd7ce5SGreg Kroah-Hartman case TIOCSSOFTCAR:
88896fd7ce5SGreg Kroah-Hartman if (get_user(arg, (unsigned int __user *) arg))
88996fd7ce5SGreg Kroah-Hartman return -EFAULT;
89096fd7ce5SGreg Kroah-Hartman return tty_change_softcar(real_tty, arg);
89196fd7ce5SGreg Kroah-Hartman default:
89296fd7ce5SGreg Kroah-Hartman return -ENOIOCTLCMD;
89396fd7ce5SGreg Kroah-Hartman }
89496fd7ce5SGreg Kroah-Hartman }
89596fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(tty_mode_ioctl);
89696fd7ce5SGreg Kroah-Hartman
89796fd7ce5SGreg Kroah-Hartman
898e7f3880cSPeter Hurley /* Caller guarantees ldisc reference is held */
__tty_perform_flush(struct tty_struct * tty,unsigned long arg)899e7f3880cSPeter Hurley static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
900e7f3880cSPeter Hurley {
901e7f3880cSPeter Hurley struct tty_ldisc *ld = tty->ldisc;
902e7f3880cSPeter Hurley
90396fd7ce5SGreg Kroah-Hartman switch (arg) {
90496fd7ce5SGreg Kroah-Hartman case TCIFLUSH:
905a1bf9584SIlya Zykov if (ld && ld->ops->flush_buffer) {
90696fd7ce5SGreg Kroah-Hartman ld->ops->flush_buffer(tty);
907a1bf9584SIlya Zykov tty_unthrottle(tty);
908a1bf9584SIlya Zykov }
90996fd7ce5SGreg Kroah-Hartman break;
91096fd7ce5SGreg Kroah-Hartman case TCIOFLUSH:
911a1bf9584SIlya Zykov if (ld && ld->ops->flush_buffer) {
91296fd7ce5SGreg Kroah-Hartman ld->ops->flush_buffer(tty);
913a1bf9584SIlya Zykov tty_unthrottle(tty);
914a1bf9584SIlya Zykov }
915df561f66SGustavo A. R. Silva fallthrough;
91696fd7ce5SGreg Kroah-Hartman case TCOFLUSH:
91796fd7ce5SGreg Kroah-Hartman tty_driver_flush_buffer(tty);
91896fd7ce5SGreg Kroah-Hartman break;
91996fd7ce5SGreg Kroah-Hartman default:
92096fd7ce5SGreg Kroah-Hartman return -EINVAL;
92196fd7ce5SGreg Kroah-Hartman }
92296fd7ce5SGreg Kroah-Hartman return 0;
92396fd7ce5SGreg Kroah-Hartman }
924e7f3880cSPeter Hurley
tty_perform_flush(struct tty_struct * tty,unsigned long arg)925e7f3880cSPeter Hurley int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
926e7f3880cSPeter Hurley {
927e7f3880cSPeter Hurley struct tty_ldisc *ld;
928e7f3880cSPeter Hurley int retval = tty_check_change(tty);
929e7f3880cSPeter Hurley if (retval)
930e7f3880cSPeter Hurley return retval;
931e7f3880cSPeter Hurley
932e7f3880cSPeter Hurley ld = tty_ldisc_ref_wait(tty);
933e7f3880cSPeter Hurley retval = __tty_perform_flush(tty, arg);
934e7f3880cSPeter Hurley if (ld)
935e7f3880cSPeter Hurley tty_ldisc_deref(ld);
936e7f3880cSPeter Hurley return retval;
937e7f3880cSPeter Hurley }
93896fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(tty_perform_flush);
93996fd7ce5SGreg Kroah-Hartman
n_tty_ioctl_helper(struct tty_struct * tty,unsigned int cmd,unsigned long arg)9407c783601SJiri Slaby int n_tty_ioctl_helper(struct tty_struct *tty, unsigned int cmd,
9417c783601SJiri Slaby unsigned long arg)
94296fd7ce5SGreg Kroah-Hartman {
94396fd7ce5SGreg Kroah-Hartman int retval;
94496fd7ce5SGreg Kroah-Hartman
94596fd7ce5SGreg Kroah-Hartman switch (cmd) {
94696fd7ce5SGreg Kroah-Hartman case TCXONC:
94796fd7ce5SGreg Kroah-Hartman retval = tty_check_change(tty);
94896fd7ce5SGreg Kroah-Hartman if (retval)
94996fd7ce5SGreg Kroah-Hartman return retval;
95096fd7ce5SGreg Kroah-Hartman switch (arg) {
95196fd7ce5SGreg Kroah-Hartman case TCOOFF:
9526e94dbc7SJiri Slaby spin_lock_irq(&tty->flow.lock);
9536e94dbc7SJiri Slaby if (!tty->flow.tco_stopped) {
9546e94dbc7SJiri Slaby tty->flow.tco_stopped = true;
955c545b66cSPeter Hurley __stop_tty(tty);
95696fd7ce5SGreg Kroah-Hartman }
9576e94dbc7SJiri Slaby spin_unlock_irq(&tty->flow.lock);
95896fd7ce5SGreg Kroah-Hartman break;
95996fd7ce5SGreg Kroah-Hartman case TCOON:
9606e94dbc7SJiri Slaby spin_lock_irq(&tty->flow.lock);
9616e94dbc7SJiri Slaby if (tty->flow.tco_stopped) {
9626e94dbc7SJiri Slaby tty->flow.tco_stopped = false;
963c545b66cSPeter Hurley __start_tty(tty);
96496fd7ce5SGreg Kroah-Hartman }
9656e94dbc7SJiri Slaby spin_unlock_irq(&tty->flow.lock);
96696fd7ce5SGreg Kroah-Hartman break;
96796fd7ce5SGreg Kroah-Hartman case TCIOFF:
96896fd7ce5SGreg Kroah-Hartman if (STOP_CHAR(tty) != __DISABLED_CHAR)
969c274f6efSPeter Hurley retval = tty_send_xchar(tty, STOP_CHAR(tty));
97096fd7ce5SGreg Kroah-Hartman break;
97196fd7ce5SGreg Kroah-Hartman case TCION:
97296fd7ce5SGreg Kroah-Hartman if (START_CHAR(tty) != __DISABLED_CHAR)
973c274f6efSPeter Hurley retval = tty_send_xchar(tty, START_CHAR(tty));
97496fd7ce5SGreg Kroah-Hartman break;
97596fd7ce5SGreg Kroah-Hartman default:
97696fd7ce5SGreg Kroah-Hartman return -EINVAL;
97796fd7ce5SGreg Kroah-Hartman }
978c274f6efSPeter Hurley return retval;
97996fd7ce5SGreg Kroah-Hartman case TCFLSH:
9805cec7bf6SPeter Hurley retval = tty_check_change(tty);
9815cec7bf6SPeter Hurley if (retval)
9825cec7bf6SPeter Hurley return retval;
983e7f3880cSPeter Hurley return __tty_perform_flush(tty, arg);
98496fd7ce5SGreg Kroah-Hartman default:
98596fd7ce5SGreg Kroah-Hartman /* Try the mode commands */
986dcc223e8SJiri Slaby return tty_mode_ioctl(tty, cmd, arg);
98796fd7ce5SGreg Kroah-Hartman }
98896fd7ce5SGreg Kroah-Hartman }
98996fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(n_tty_ioctl_helper);
990