xref: /OK3568_Linux_fs/kernel/drivers/tty/tty_ioctl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
6*4882a593Smuzhiyun  * which can be dynamically activated and de-activated by the line
7*4882a593Smuzhiyun  * discipline handling modules (like SLIP).
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/types.h>
11*4882a593Smuzhiyun #include <linux/termios.h>
12*4882a593Smuzhiyun #include <linux/errno.h>
13*4882a593Smuzhiyun #include <linux/sched/signal.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/major.h>
16*4882a593Smuzhiyun #include <linux/tty.h>
17*4882a593Smuzhiyun #include <linux/fcntl.h>
18*4882a593Smuzhiyun #include <linux/string.h>
19*4882a593Smuzhiyun #include <linux/mm.h>
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/bitops.h>
22*4882a593Smuzhiyun #include <linux/mutex.h>
23*4882a593Smuzhiyun #include <linux/compat.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <asm/io.h>
26*4882a593Smuzhiyun #include <linux/uaccess.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #undef TTY_DEBUG_WAIT_UNTIL_SENT
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
31*4882a593Smuzhiyun # define tty_debug_wait_until_sent(tty, f, args...)    tty_debug(tty, f, ##args)
32*4882a593Smuzhiyun #else
33*4882a593Smuzhiyun # define tty_debug_wait_until_sent(tty, f, args...)    do {} while (0)
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #undef	DEBUG
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /*
39*4882a593Smuzhiyun  * Internal flag options for termios setting behavior
40*4882a593Smuzhiyun  */
41*4882a593Smuzhiyun #define TERMIOS_FLUSH	1
42*4882a593Smuzhiyun #define TERMIOS_WAIT	2
43*4882a593Smuzhiyun #define TERMIOS_TERMIO	4
44*4882a593Smuzhiyun #define TERMIOS_OLD	8
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /**
48*4882a593Smuzhiyun  *	tty_chars_in_buffer	-	characters pending
49*4882a593Smuzhiyun  *	@tty: terminal
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  *	Return the number of bytes of data in the device private
52*4882a593Smuzhiyun  *	output queue. If no private method is supplied there is assumed
53*4882a593Smuzhiyun  *	to be no queue on the device.
54*4882a593Smuzhiyun  */
55*4882a593Smuzhiyun 
tty_chars_in_buffer(struct tty_struct * tty)56*4882a593Smuzhiyun int tty_chars_in_buffer(struct tty_struct *tty)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	if (tty->ops->chars_in_buffer)
59*4882a593Smuzhiyun 		return tty->ops->chars_in_buffer(tty);
60*4882a593Smuzhiyun 	else
61*4882a593Smuzhiyun 		return 0;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun EXPORT_SYMBOL(tty_chars_in_buffer);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /**
66*4882a593Smuzhiyun  *	tty_write_room		-	write queue space
67*4882a593Smuzhiyun  *	@tty: terminal
68*4882a593Smuzhiyun  *
69*4882a593Smuzhiyun  *	Return the number of bytes that can be queued to this device
70*4882a593Smuzhiyun  *	at the present time. The result should be treated as a guarantee
71*4882a593Smuzhiyun  *	and the driver cannot offer a value it later shrinks by more than
72*4882a593Smuzhiyun  *	the number of bytes written. If no method is provided 2K is always
73*4882a593Smuzhiyun  *	returned and data may be lost as there will be no flow control.
74*4882a593Smuzhiyun  */
75*4882a593Smuzhiyun 
tty_write_room(struct tty_struct * tty)76*4882a593Smuzhiyun int tty_write_room(struct tty_struct *tty)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	if (tty->ops->write_room)
79*4882a593Smuzhiyun 		return tty->ops->write_room(tty);
80*4882a593Smuzhiyun 	return 2048;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun EXPORT_SYMBOL(tty_write_room);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /**
85*4882a593Smuzhiyun  *	tty_driver_flush_buffer	-	discard internal buffer
86*4882a593Smuzhiyun  *	@tty: terminal
87*4882a593Smuzhiyun  *
88*4882a593Smuzhiyun  *	Discard the internal output buffer for this device. If no method
89*4882a593Smuzhiyun  *	is provided then either the buffer cannot be hardware flushed or
90*4882a593Smuzhiyun  *	there is no buffer driver side.
91*4882a593Smuzhiyun  */
tty_driver_flush_buffer(struct tty_struct * tty)92*4882a593Smuzhiyun void tty_driver_flush_buffer(struct tty_struct *tty)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	if (tty->ops->flush_buffer)
95*4882a593Smuzhiyun 		tty->ops->flush_buffer(tty);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun EXPORT_SYMBOL(tty_driver_flush_buffer);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /**
100*4882a593Smuzhiyun  *	tty_throttle		-	flow control
101*4882a593Smuzhiyun  *	@tty: terminal
102*4882a593Smuzhiyun  *
103*4882a593Smuzhiyun  *	Indicate that a tty should stop transmitting data down the stack.
104*4882a593Smuzhiyun  *	Takes the termios rwsem to protect against parallel throttle/unthrottle
105*4882a593Smuzhiyun  *	and also to ensure the driver can consistently reference its own
106*4882a593Smuzhiyun  *	termios data at this point when implementing software flow control.
107*4882a593Smuzhiyun  */
108*4882a593Smuzhiyun 
tty_throttle(struct tty_struct * tty)109*4882a593Smuzhiyun void tty_throttle(struct tty_struct *tty)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	down_write(&tty->termios_rwsem);
112*4882a593Smuzhiyun 	/* check TTY_THROTTLED first so it indicates our state */
113*4882a593Smuzhiyun 	if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
114*4882a593Smuzhiyun 	    tty->ops->throttle)
115*4882a593Smuzhiyun 		tty->ops->throttle(tty);
116*4882a593Smuzhiyun 	tty->flow_change = 0;
117*4882a593Smuzhiyun 	up_write(&tty->termios_rwsem);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun EXPORT_SYMBOL(tty_throttle);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun /**
122*4882a593Smuzhiyun  *	tty_unthrottle		-	flow control
123*4882a593Smuzhiyun  *	@tty: terminal
124*4882a593Smuzhiyun  *
125*4882a593Smuzhiyun  *	Indicate that a tty may continue transmitting data down the stack.
126*4882a593Smuzhiyun  *	Takes the termios rwsem to protect against parallel throttle/unthrottle
127*4882a593Smuzhiyun  *	and also to ensure the driver can consistently reference its own
128*4882a593Smuzhiyun  *	termios data at this point when implementing software flow control.
129*4882a593Smuzhiyun  *
130*4882a593Smuzhiyun  *	Drivers should however remember that the stack can issue a throttle,
131*4882a593Smuzhiyun  *	then change flow control method, then unthrottle.
132*4882a593Smuzhiyun  */
133*4882a593Smuzhiyun 
tty_unthrottle(struct tty_struct * tty)134*4882a593Smuzhiyun void tty_unthrottle(struct tty_struct *tty)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	down_write(&tty->termios_rwsem);
137*4882a593Smuzhiyun 	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
138*4882a593Smuzhiyun 	    tty->ops->unthrottle)
139*4882a593Smuzhiyun 		tty->ops->unthrottle(tty);
140*4882a593Smuzhiyun 	tty->flow_change = 0;
141*4882a593Smuzhiyun 	up_write(&tty->termios_rwsem);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun EXPORT_SYMBOL(tty_unthrottle);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /**
146*4882a593Smuzhiyun  *	tty_throttle_safe	-	flow control
147*4882a593Smuzhiyun  *	@tty: terminal
148*4882a593Smuzhiyun  *
149*4882a593Smuzhiyun  *	Similar to tty_throttle() but will only attempt throttle
150*4882a593Smuzhiyun  *	if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
151*4882a593Smuzhiyun  *	throttle due to race conditions when throttling is conditional
152*4882a593Smuzhiyun  *	on factors evaluated prior to throttling.
153*4882a593Smuzhiyun  *
154*4882a593Smuzhiyun  *	Returns 0 if tty is throttled (or was already throttled)
155*4882a593Smuzhiyun  */
156*4882a593Smuzhiyun 
tty_throttle_safe(struct tty_struct * tty)157*4882a593Smuzhiyun int tty_throttle_safe(struct tty_struct *tty)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	int ret = 0;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	mutex_lock(&tty->throttle_mutex);
162*4882a593Smuzhiyun 	if (!tty_throttled(tty)) {
163*4882a593Smuzhiyun 		if (tty->flow_change != TTY_THROTTLE_SAFE)
164*4882a593Smuzhiyun 			ret = 1;
165*4882a593Smuzhiyun 		else {
166*4882a593Smuzhiyun 			set_bit(TTY_THROTTLED, &tty->flags);
167*4882a593Smuzhiyun 			if (tty->ops->throttle)
168*4882a593Smuzhiyun 				tty->ops->throttle(tty);
169*4882a593Smuzhiyun 		}
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 	mutex_unlock(&tty->throttle_mutex);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	return ret;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun /**
177*4882a593Smuzhiyun  *	tty_unthrottle_safe	-	flow control
178*4882a593Smuzhiyun  *	@tty: terminal
179*4882a593Smuzhiyun  *
180*4882a593Smuzhiyun  *	Similar to tty_unthrottle() but will only attempt unthrottle
181*4882a593Smuzhiyun  *	if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
182*4882a593Smuzhiyun  *	unthrottle due to race conditions when unthrottling is conditional
183*4882a593Smuzhiyun  *	on factors evaluated prior to unthrottling.
184*4882a593Smuzhiyun  *
185*4882a593Smuzhiyun  *	Returns 0 if tty is unthrottled (or was already unthrottled)
186*4882a593Smuzhiyun  */
187*4882a593Smuzhiyun 
tty_unthrottle_safe(struct tty_struct * tty)188*4882a593Smuzhiyun int tty_unthrottle_safe(struct tty_struct *tty)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	int ret = 0;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	mutex_lock(&tty->throttle_mutex);
193*4882a593Smuzhiyun 	if (tty_throttled(tty)) {
194*4882a593Smuzhiyun 		if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
195*4882a593Smuzhiyun 			ret = 1;
196*4882a593Smuzhiyun 		else {
197*4882a593Smuzhiyun 			clear_bit(TTY_THROTTLED, &tty->flags);
198*4882a593Smuzhiyun 			if (tty->ops->unthrottle)
199*4882a593Smuzhiyun 				tty->ops->unthrottle(tty);
200*4882a593Smuzhiyun 		}
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 	mutex_unlock(&tty->throttle_mutex);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	return ret;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun /**
208*4882a593Smuzhiyun  *	tty_wait_until_sent	-	wait for I/O to finish
209*4882a593Smuzhiyun  *	@tty: tty we are waiting for
210*4882a593Smuzhiyun  *	@timeout: how long we will wait
211*4882a593Smuzhiyun  *
212*4882a593Smuzhiyun  *	Wait for characters pending in a tty driver to hit the wire, or
213*4882a593Smuzhiyun  *	for a timeout to occur (eg due to flow control)
214*4882a593Smuzhiyun  *
215*4882a593Smuzhiyun  *	Locking: none
216*4882a593Smuzhiyun  */
217*4882a593Smuzhiyun 
tty_wait_until_sent(struct tty_struct * tty,long timeout)218*4882a593Smuzhiyun void tty_wait_until_sent(struct tty_struct *tty, long timeout)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (!timeout)
223*4882a593Smuzhiyun 		timeout = MAX_SCHEDULE_TIMEOUT;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	timeout = wait_event_interruptible_timeout(tty->write_wait,
226*4882a593Smuzhiyun 			!tty_chars_in_buffer(tty), timeout);
227*4882a593Smuzhiyun 	if (timeout <= 0)
228*4882a593Smuzhiyun 		return;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	if (timeout == MAX_SCHEDULE_TIMEOUT)
231*4882a593Smuzhiyun 		timeout = 0;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	if (tty->ops->wait_until_sent)
234*4882a593Smuzhiyun 		tty->ops->wait_until_sent(tty, timeout);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun EXPORT_SYMBOL(tty_wait_until_sent);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun /*
240*4882a593Smuzhiyun  *		Termios Helper Methods
241*4882a593Smuzhiyun  */
242*4882a593Smuzhiyun 
unset_locked_termios(struct tty_struct * tty,struct ktermios * old)243*4882a593Smuzhiyun static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	struct ktermios *termios = &tty->termios;
246*4882a593Smuzhiyun 	struct ktermios *locked  = &tty->termios_locked;
247*4882a593Smuzhiyun 	int	i;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
252*4882a593Smuzhiyun 	NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
253*4882a593Smuzhiyun 	NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
254*4882a593Smuzhiyun 	NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
255*4882a593Smuzhiyun 	termios->c_line = locked->c_line ? old->c_line : termios->c_line;
256*4882a593Smuzhiyun 	for (i = 0; i < NCCS; i++)
257*4882a593Smuzhiyun 		termios->c_cc[i] = locked->c_cc[i] ?
258*4882a593Smuzhiyun 			old->c_cc[i] : termios->c_cc[i];
259*4882a593Smuzhiyun 	/* FIXME: What should we do for i/ospeed */
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun /**
263*4882a593Smuzhiyun  *	tty_termios_copy_hw	-	copy hardware settings
264*4882a593Smuzhiyun  *	@new: New termios
265*4882a593Smuzhiyun  *	@old: Old termios
266*4882a593Smuzhiyun  *
267*4882a593Smuzhiyun  *	Propagate the hardware specific terminal setting bits from
268*4882a593Smuzhiyun  *	the old termios structure to the new one. This is used in cases
269*4882a593Smuzhiyun  *	where the hardware does not support reconfiguration or as a helper
270*4882a593Smuzhiyun  *	in some cases where only minimal reconfiguration is supported
271*4882a593Smuzhiyun  */
272*4882a593Smuzhiyun 
tty_termios_copy_hw(struct ktermios * new,struct ktermios * old)273*4882a593Smuzhiyun void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	/* The bits a dumb device handles in software. Smart devices need
276*4882a593Smuzhiyun 	   to always provide a set_termios method */
277*4882a593Smuzhiyun 	new->c_cflag &= HUPCL | CREAD | CLOCAL;
278*4882a593Smuzhiyun 	new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
279*4882a593Smuzhiyun 	new->c_ispeed = old->c_ispeed;
280*4882a593Smuzhiyun 	new->c_ospeed = old->c_ospeed;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun EXPORT_SYMBOL(tty_termios_copy_hw);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun /**
285*4882a593Smuzhiyun  *	tty_termios_hw_change	-	check for setting change
286*4882a593Smuzhiyun  *	@a: termios
287*4882a593Smuzhiyun  *	@b: termios to compare
288*4882a593Smuzhiyun  *
289*4882a593Smuzhiyun  *	Check if any of the bits that affect a dumb device have changed
290*4882a593Smuzhiyun  *	between the two termios structures, or a speed change is needed.
291*4882a593Smuzhiyun  */
292*4882a593Smuzhiyun 
tty_termios_hw_change(const struct ktermios * a,const struct ktermios * b)293*4882a593Smuzhiyun int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
296*4882a593Smuzhiyun 		return 1;
297*4882a593Smuzhiyun 	if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
298*4882a593Smuzhiyun 		return 1;
299*4882a593Smuzhiyun 	return 0;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun EXPORT_SYMBOL(tty_termios_hw_change);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun /**
304*4882a593Smuzhiyun  *	tty_set_termios		-	update termios values
305*4882a593Smuzhiyun  *	@tty: tty to update
306*4882a593Smuzhiyun  *	@new_termios: desired new value
307*4882a593Smuzhiyun  *
308*4882a593Smuzhiyun  *	Perform updates to the termios values set on this terminal.
309*4882a593Smuzhiyun  *	A master pty's termios should never be set.
310*4882a593Smuzhiyun  *
311*4882a593Smuzhiyun  *	Locking: termios_rwsem
312*4882a593Smuzhiyun  */
313*4882a593Smuzhiyun 
tty_set_termios(struct tty_struct * tty,struct ktermios * new_termios)314*4882a593Smuzhiyun int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun 	struct ktermios old_termios;
317*4882a593Smuzhiyun 	struct tty_ldisc *ld;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
320*4882a593Smuzhiyun 		tty->driver->subtype == PTY_TYPE_MASTER);
321*4882a593Smuzhiyun 	/*
322*4882a593Smuzhiyun 	 *	Perform the actual termios internal changes under lock.
323*4882a593Smuzhiyun 	 */
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	/* FIXME: we need to decide on some locking/ordering semantics
327*4882a593Smuzhiyun 	   for the set_termios notification eventually */
328*4882a593Smuzhiyun 	down_write(&tty->termios_rwsem);
329*4882a593Smuzhiyun 	old_termios = tty->termios;
330*4882a593Smuzhiyun 	tty->termios = *new_termios;
331*4882a593Smuzhiyun 	unset_locked_termios(tty, &old_termios);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	if (tty->ops->set_termios)
334*4882a593Smuzhiyun 		tty->ops->set_termios(tty, &old_termios);
335*4882a593Smuzhiyun 	else
336*4882a593Smuzhiyun 		tty_termios_copy_hw(&tty->termios, &old_termios);
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	ld = tty_ldisc_ref(tty);
339*4882a593Smuzhiyun 	if (ld != NULL) {
340*4882a593Smuzhiyun 		if (ld->ops->set_termios)
341*4882a593Smuzhiyun 			ld->ops->set_termios(tty, &old_termios);
342*4882a593Smuzhiyun 		tty_ldisc_deref(ld);
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 	up_write(&tty->termios_rwsem);
345*4882a593Smuzhiyun 	return 0;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_set_termios);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun /**
350*4882a593Smuzhiyun  *	set_termios		-	set termios values for a tty
351*4882a593Smuzhiyun  *	@tty: terminal device
352*4882a593Smuzhiyun  *	@arg: user data
353*4882a593Smuzhiyun  *	@opt: option information
354*4882a593Smuzhiyun  *
355*4882a593Smuzhiyun  *	Helper function to prepare termios data and run necessary other
356*4882a593Smuzhiyun  *	functions before using tty_set_termios to do the actual changes.
357*4882a593Smuzhiyun  *
358*4882a593Smuzhiyun  *	Locking:
359*4882a593Smuzhiyun  *		Called functions take ldisc and termios_rwsem locks
360*4882a593Smuzhiyun  */
361*4882a593Smuzhiyun 
set_termios(struct tty_struct * tty,void __user * arg,int opt)362*4882a593Smuzhiyun static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	struct ktermios tmp_termios;
365*4882a593Smuzhiyun 	struct tty_ldisc *ld;
366*4882a593Smuzhiyun 	int retval = tty_check_change(tty);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	if (retval)
369*4882a593Smuzhiyun 		return retval;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	down_read(&tty->termios_rwsem);
372*4882a593Smuzhiyun 	tmp_termios = tty->termios;
373*4882a593Smuzhiyun 	up_read(&tty->termios_rwsem);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (opt & TERMIOS_TERMIO) {
376*4882a593Smuzhiyun 		if (user_termio_to_kernel_termios(&tmp_termios,
377*4882a593Smuzhiyun 						(struct termio __user *)arg))
378*4882a593Smuzhiyun 			return -EFAULT;
379*4882a593Smuzhiyun #ifdef TCGETS2
380*4882a593Smuzhiyun 	} else if (opt & TERMIOS_OLD) {
381*4882a593Smuzhiyun 		if (user_termios_to_kernel_termios_1(&tmp_termios,
382*4882a593Smuzhiyun 						(struct termios __user *)arg))
383*4882a593Smuzhiyun 			return -EFAULT;
384*4882a593Smuzhiyun 	} else {
385*4882a593Smuzhiyun 		if (user_termios_to_kernel_termios(&tmp_termios,
386*4882a593Smuzhiyun 						(struct termios2 __user *)arg))
387*4882a593Smuzhiyun 			return -EFAULT;
388*4882a593Smuzhiyun 	}
389*4882a593Smuzhiyun #else
390*4882a593Smuzhiyun 	} else if (user_termios_to_kernel_termios(&tmp_termios,
391*4882a593Smuzhiyun 					(struct termios __user *)arg))
392*4882a593Smuzhiyun 		return -EFAULT;
393*4882a593Smuzhiyun #endif
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	/* If old style Bfoo values are used then load c_ispeed/c_ospeed
396*4882a593Smuzhiyun 	 * with the real speed so its unconditionally usable */
397*4882a593Smuzhiyun 	tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
398*4882a593Smuzhiyun 	tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	ld = tty_ldisc_ref(tty);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	if (ld != NULL) {
403*4882a593Smuzhiyun 		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
404*4882a593Smuzhiyun 			ld->ops->flush_buffer(tty);
405*4882a593Smuzhiyun 		tty_ldisc_deref(ld);
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (opt & TERMIOS_WAIT) {
409*4882a593Smuzhiyun 		tty_wait_until_sent(tty, 0);
410*4882a593Smuzhiyun 		if (signal_pending(current))
411*4882a593Smuzhiyun 			return -ERESTARTSYS;
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	tty_set_termios(tty, &tmp_termios);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	/* FIXME: Arguably if tmp_termios == tty->termios AND the
417*4882a593Smuzhiyun 	   actual requested termios was not tmp_termios then we may
418*4882a593Smuzhiyun 	   want to return an error as no user requested change has
419*4882a593Smuzhiyun 	   succeeded */
420*4882a593Smuzhiyun 	return 0;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
copy_termios(struct tty_struct * tty,struct ktermios * kterm)423*4882a593Smuzhiyun static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	down_read(&tty->termios_rwsem);
426*4882a593Smuzhiyun 	*kterm = tty->termios;
427*4882a593Smuzhiyun 	up_read(&tty->termios_rwsem);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
copy_termios_locked(struct tty_struct * tty,struct ktermios * kterm)430*4882a593Smuzhiyun static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun 	down_read(&tty->termios_rwsem);
433*4882a593Smuzhiyun 	*kterm = tty->termios_locked;
434*4882a593Smuzhiyun 	up_read(&tty->termios_rwsem);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
get_termio(struct tty_struct * tty,struct termio __user * termio)437*4882a593Smuzhiyun static int get_termio(struct tty_struct *tty, struct termio __user *termio)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	struct ktermios kterm;
440*4882a593Smuzhiyun 	copy_termios(tty, &kterm);
441*4882a593Smuzhiyun 	if (kernel_termios_to_user_termio(termio, &kterm))
442*4882a593Smuzhiyun 		return -EFAULT;
443*4882a593Smuzhiyun 	return 0;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun #ifdef TIOCGETP
447*4882a593Smuzhiyun /*
448*4882a593Smuzhiyun  * These are deprecated, but there is limited support..
449*4882a593Smuzhiyun  *
450*4882a593Smuzhiyun  * The "sg_flags" translation is a joke..
451*4882a593Smuzhiyun  */
get_sgflags(struct tty_struct * tty)452*4882a593Smuzhiyun static int get_sgflags(struct tty_struct *tty)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun 	int flags = 0;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	if (!L_ICANON(tty)) {
457*4882a593Smuzhiyun 		if (L_ISIG(tty))
458*4882a593Smuzhiyun 			flags |= 0x02;		/* cbreak */
459*4882a593Smuzhiyun 		else
460*4882a593Smuzhiyun 			flags |= 0x20;		/* raw */
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun 	if (L_ECHO(tty))
463*4882a593Smuzhiyun 		flags |= 0x08;			/* echo */
464*4882a593Smuzhiyun 	if (O_OPOST(tty))
465*4882a593Smuzhiyun 		if (O_ONLCR(tty))
466*4882a593Smuzhiyun 			flags |= 0x10;		/* crmod */
467*4882a593Smuzhiyun 	return flags;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
get_sgttyb(struct tty_struct * tty,struct sgttyb __user * sgttyb)470*4882a593Smuzhiyun static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	struct sgttyb tmp;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	down_read(&tty->termios_rwsem);
475*4882a593Smuzhiyun 	tmp.sg_ispeed = tty->termios.c_ispeed;
476*4882a593Smuzhiyun 	tmp.sg_ospeed = tty->termios.c_ospeed;
477*4882a593Smuzhiyun 	tmp.sg_erase = tty->termios.c_cc[VERASE];
478*4882a593Smuzhiyun 	tmp.sg_kill = tty->termios.c_cc[VKILL];
479*4882a593Smuzhiyun 	tmp.sg_flags = get_sgflags(tty);
480*4882a593Smuzhiyun 	up_read(&tty->termios_rwsem);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
set_sgflags(struct ktermios * termios,int flags)485*4882a593Smuzhiyun static void set_sgflags(struct ktermios *termios, int flags)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun 	termios->c_iflag = ICRNL | IXON;
488*4882a593Smuzhiyun 	termios->c_oflag = 0;
489*4882a593Smuzhiyun 	termios->c_lflag = ISIG | ICANON;
490*4882a593Smuzhiyun 	if (flags & 0x02) {	/* cbreak */
491*4882a593Smuzhiyun 		termios->c_iflag = 0;
492*4882a593Smuzhiyun 		termios->c_lflag &= ~ICANON;
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 	if (flags & 0x08) {		/* echo */
495*4882a593Smuzhiyun 		termios->c_lflag |= ECHO | ECHOE | ECHOK |
496*4882a593Smuzhiyun 				    ECHOCTL | ECHOKE | IEXTEN;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 	if (flags & 0x10) {		/* crmod */
499*4882a593Smuzhiyun 		termios->c_oflag |= OPOST | ONLCR;
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 	if (flags & 0x20) {	/* raw */
502*4882a593Smuzhiyun 		termios->c_iflag = 0;
503*4882a593Smuzhiyun 		termios->c_lflag &= ~(ISIG | ICANON);
504*4882a593Smuzhiyun 	}
505*4882a593Smuzhiyun 	if (!(termios->c_lflag & ICANON)) {
506*4882a593Smuzhiyun 		termios->c_cc[VMIN] = 1;
507*4882a593Smuzhiyun 		termios->c_cc[VTIME] = 0;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun /**
512*4882a593Smuzhiyun  *	set_sgttyb		-	set legacy terminal values
513*4882a593Smuzhiyun  *	@tty: tty structure
514*4882a593Smuzhiyun  *	@sgttyb: pointer to old style terminal structure
515*4882a593Smuzhiyun  *
516*4882a593Smuzhiyun  *	Updates a terminal from the legacy BSD style terminal information
517*4882a593Smuzhiyun  *	structure.
518*4882a593Smuzhiyun  *
519*4882a593Smuzhiyun  *	Locking: termios_rwsem
520*4882a593Smuzhiyun  */
521*4882a593Smuzhiyun 
set_sgttyb(struct tty_struct * tty,struct sgttyb __user * sgttyb)522*4882a593Smuzhiyun static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun 	int retval;
525*4882a593Smuzhiyun 	struct sgttyb tmp;
526*4882a593Smuzhiyun 	struct ktermios termios;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	retval = tty_check_change(tty);
529*4882a593Smuzhiyun 	if (retval)
530*4882a593Smuzhiyun 		return retval;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
533*4882a593Smuzhiyun 		return -EFAULT;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	down_write(&tty->termios_rwsem);
536*4882a593Smuzhiyun 	termios = tty->termios;
537*4882a593Smuzhiyun 	termios.c_cc[VERASE] = tmp.sg_erase;
538*4882a593Smuzhiyun 	termios.c_cc[VKILL] = tmp.sg_kill;
539*4882a593Smuzhiyun 	set_sgflags(&termios, tmp.sg_flags);
540*4882a593Smuzhiyun 	/* Try and encode into Bfoo format */
541*4882a593Smuzhiyun #ifdef BOTHER
542*4882a593Smuzhiyun 	tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
543*4882a593Smuzhiyun 						termios.c_ospeed);
544*4882a593Smuzhiyun #endif
545*4882a593Smuzhiyun 	up_write(&tty->termios_rwsem);
546*4882a593Smuzhiyun 	tty_set_termios(tty, &termios);
547*4882a593Smuzhiyun 	return 0;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun #endif
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun #ifdef TIOCGETC
get_tchars(struct tty_struct * tty,struct tchars __user * tchars)552*4882a593Smuzhiyun static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	struct tchars tmp;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	down_read(&tty->termios_rwsem);
557*4882a593Smuzhiyun 	tmp.t_intrc = tty->termios.c_cc[VINTR];
558*4882a593Smuzhiyun 	tmp.t_quitc = tty->termios.c_cc[VQUIT];
559*4882a593Smuzhiyun 	tmp.t_startc = tty->termios.c_cc[VSTART];
560*4882a593Smuzhiyun 	tmp.t_stopc = tty->termios.c_cc[VSTOP];
561*4882a593Smuzhiyun 	tmp.t_eofc = tty->termios.c_cc[VEOF];
562*4882a593Smuzhiyun 	tmp.t_brkc = tty->termios.c_cc[VEOL2];	/* what is brkc anyway? */
563*4882a593Smuzhiyun 	up_read(&tty->termios_rwsem);
564*4882a593Smuzhiyun 	return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun 
set_tchars(struct tty_struct * tty,struct tchars __user * tchars)567*4882a593Smuzhiyun static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun 	struct tchars tmp;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	if (copy_from_user(&tmp, tchars, sizeof(tmp)))
572*4882a593Smuzhiyun 		return -EFAULT;
573*4882a593Smuzhiyun 	down_write(&tty->termios_rwsem);
574*4882a593Smuzhiyun 	tty->termios.c_cc[VINTR] = tmp.t_intrc;
575*4882a593Smuzhiyun 	tty->termios.c_cc[VQUIT] = tmp.t_quitc;
576*4882a593Smuzhiyun 	tty->termios.c_cc[VSTART] = tmp.t_startc;
577*4882a593Smuzhiyun 	tty->termios.c_cc[VSTOP] = tmp.t_stopc;
578*4882a593Smuzhiyun 	tty->termios.c_cc[VEOF] = tmp.t_eofc;
579*4882a593Smuzhiyun 	tty->termios.c_cc[VEOL2] = tmp.t_brkc;	/* what is brkc anyway? */
580*4882a593Smuzhiyun 	up_write(&tty->termios_rwsem);
581*4882a593Smuzhiyun 	return 0;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun #endif
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun #ifdef TIOCGLTC
get_ltchars(struct tty_struct * tty,struct ltchars __user * ltchars)586*4882a593Smuzhiyun static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun 	struct ltchars tmp;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	down_read(&tty->termios_rwsem);
591*4882a593Smuzhiyun 	tmp.t_suspc = tty->termios.c_cc[VSUSP];
592*4882a593Smuzhiyun 	/* what is dsuspc anyway? */
593*4882a593Smuzhiyun 	tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
594*4882a593Smuzhiyun 	tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
595*4882a593Smuzhiyun 	/* what is flushc anyway? */
596*4882a593Smuzhiyun 	tmp.t_flushc = tty->termios.c_cc[VEOL2];
597*4882a593Smuzhiyun 	tmp.t_werasc = tty->termios.c_cc[VWERASE];
598*4882a593Smuzhiyun 	tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
599*4882a593Smuzhiyun 	up_read(&tty->termios_rwsem);
600*4882a593Smuzhiyun 	return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun 
set_ltchars(struct tty_struct * tty,struct ltchars __user * ltchars)603*4882a593Smuzhiyun static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	struct ltchars tmp;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
608*4882a593Smuzhiyun 		return -EFAULT;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	down_write(&tty->termios_rwsem);
611*4882a593Smuzhiyun 	tty->termios.c_cc[VSUSP] = tmp.t_suspc;
612*4882a593Smuzhiyun 	/* what is dsuspc anyway? */
613*4882a593Smuzhiyun 	tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
614*4882a593Smuzhiyun 	tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
615*4882a593Smuzhiyun 	/* what is flushc anyway? */
616*4882a593Smuzhiyun 	tty->termios.c_cc[VEOL2] = tmp.t_flushc;
617*4882a593Smuzhiyun 	tty->termios.c_cc[VWERASE] = tmp.t_werasc;
618*4882a593Smuzhiyun 	tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
619*4882a593Smuzhiyun 	up_write(&tty->termios_rwsem);
620*4882a593Smuzhiyun 	return 0;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun #endif
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun /**
625*4882a593Smuzhiyun  *	tty_change_softcar	-	carrier change ioctl helper
626*4882a593Smuzhiyun  *	@tty: tty to update
627*4882a593Smuzhiyun  *	@arg: enable/disable CLOCAL
628*4882a593Smuzhiyun  *
629*4882a593Smuzhiyun  *	Perform a change to the CLOCAL state and call into the driver
630*4882a593Smuzhiyun  *	layer to make it visible. All done with the termios rwsem
631*4882a593Smuzhiyun  */
632*4882a593Smuzhiyun 
tty_change_softcar(struct tty_struct * tty,int arg)633*4882a593Smuzhiyun static int tty_change_softcar(struct tty_struct *tty, int arg)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	int ret = 0;
636*4882a593Smuzhiyun 	int bit = arg ? CLOCAL : 0;
637*4882a593Smuzhiyun 	struct ktermios old;
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	down_write(&tty->termios_rwsem);
640*4882a593Smuzhiyun 	old = tty->termios;
641*4882a593Smuzhiyun 	tty->termios.c_cflag &= ~CLOCAL;
642*4882a593Smuzhiyun 	tty->termios.c_cflag |= bit;
643*4882a593Smuzhiyun 	if (tty->ops->set_termios)
644*4882a593Smuzhiyun 		tty->ops->set_termios(tty, &old);
645*4882a593Smuzhiyun 	if (C_CLOCAL(tty) != bit)
646*4882a593Smuzhiyun 		ret = -EINVAL;
647*4882a593Smuzhiyun 	up_write(&tty->termios_rwsem);
648*4882a593Smuzhiyun 	return ret;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun /**
652*4882a593Smuzhiyun  *	tty_mode_ioctl		-	mode related ioctls
653*4882a593Smuzhiyun  *	@tty: tty for the ioctl
654*4882a593Smuzhiyun  *	@file: file pointer for the tty
655*4882a593Smuzhiyun  *	@cmd: command
656*4882a593Smuzhiyun  *	@arg: ioctl argument
657*4882a593Smuzhiyun  *
658*4882a593Smuzhiyun  *	Perform non line discipline specific mode control ioctls. This
659*4882a593Smuzhiyun  *	is designed to be called by line disciplines to ensure they provide
660*4882a593Smuzhiyun  *	consistent mode setting.
661*4882a593Smuzhiyun  */
662*4882a593Smuzhiyun 
tty_mode_ioctl(struct tty_struct * tty,struct file * file,unsigned int cmd,unsigned long arg)663*4882a593Smuzhiyun int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
664*4882a593Smuzhiyun 			unsigned int cmd, unsigned long arg)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun 	struct tty_struct *real_tty;
667*4882a593Smuzhiyun 	void __user *p = (void __user *)arg;
668*4882a593Smuzhiyun 	int ret = 0;
669*4882a593Smuzhiyun 	struct ktermios kterm;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	BUG_ON(file == NULL);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
674*4882a593Smuzhiyun 	    tty->driver->subtype == PTY_TYPE_MASTER)
675*4882a593Smuzhiyun 		real_tty = tty->link;
676*4882a593Smuzhiyun 	else
677*4882a593Smuzhiyun 		real_tty = tty;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	switch (cmd) {
680*4882a593Smuzhiyun #ifdef TIOCGETP
681*4882a593Smuzhiyun 	case TIOCGETP:
682*4882a593Smuzhiyun 		return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
683*4882a593Smuzhiyun 	case TIOCSETP:
684*4882a593Smuzhiyun 	case TIOCSETN:
685*4882a593Smuzhiyun 		return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
686*4882a593Smuzhiyun #endif
687*4882a593Smuzhiyun #ifdef TIOCGETC
688*4882a593Smuzhiyun 	case TIOCGETC:
689*4882a593Smuzhiyun 		return get_tchars(real_tty, p);
690*4882a593Smuzhiyun 	case TIOCSETC:
691*4882a593Smuzhiyun 		return set_tchars(real_tty, p);
692*4882a593Smuzhiyun #endif
693*4882a593Smuzhiyun #ifdef TIOCGLTC
694*4882a593Smuzhiyun 	case TIOCGLTC:
695*4882a593Smuzhiyun 		return get_ltchars(real_tty, p);
696*4882a593Smuzhiyun 	case TIOCSLTC:
697*4882a593Smuzhiyun 		return set_ltchars(real_tty, p);
698*4882a593Smuzhiyun #endif
699*4882a593Smuzhiyun 	case TCSETSF:
700*4882a593Smuzhiyun 		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
701*4882a593Smuzhiyun 	case TCSETSW:
702*4882a593Smuzhiyun 		return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
703*4882a593Smuzhiyun 	case TCSETS:
704*4882a593Smuzhiyun 		return set_termios(real_tty, p, TERMIOS_OLD);
705*4882a593Smuzhiyun #ifndef TCGETS2
706*4882a593Smuzhiyun 	case TCGETS:
707*4882a593Smuzhiyun 		copy_termios(real_tty, &kterm);
708*4882a593Smuzhiyun 		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
709*4882a593Smuzhiyun 			ret = -EFAULT;
710*4882a593Smuzhiyun 		return ret;
711*4882a593Smuzhiyun #else
712*4882a593Smuzhiyun 	case TCGETS:
713*4882a593Smuzhiyun 		copy_termios(real_tty, &kterm);
714*4882a593Smuzhiyun 		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
715*4882a593Smuzhiyun 			ret = -EFAULT;
716*4882a593Smuzhiyun 		return ret;
717*4882a593Smuzhiyun 	case TCGETS2:
718*4882a593Smuzhiyun 		copy_termios(real_tty, &kterm);
719*4882a593Smuzhiyun 		if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
720*4882a593Smuzhiyun 			ret = -EFAULT;
721*4882a593Smuzhiyun 		return ret;
722*4882a593Smuzhiyun 	case TCSETSF2:
723*4882a593Smuzhiyun 		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
724*4882a593Smuzhiyun 	case TCSETSW2:
725*4882a593Smuzhiyun 		return set_termios(real_tty, p, TERMIOS_WAIT);
726*4882a593Smuzhiyun 	case TCSETS2:
727*4882a593Smuzhiyun 		return set_termios(real_tty, p, 0);
728*4882a593Smuzhiyun #endif
729*4882a593Smuzhiyun 	case TCGETA:
730*4882a593Smuzhiyun 		return get_termio(real_tty, p);
731*4882a593Smuzhiyun 	case TCSETAF:
732*4882a593Smuzhiyun 		return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
733*4882a593Smuzhiyun 	case TCSETAW:
734*4882a593Smuzhiyun 		return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
735*4882a593Smuzhiyun 	case TCSETA:
736*4882a593Smuzhiyun 		return set_termios(real_tty, p, TERMIOS_TERMIO);
737*4882a593Smuzhiyun #ifndef TCGETS2
738*4882a593Smuzhiyun 	case TIOCGLCKTRMIOS:
739*4882a593Smuzhiyun 		copy_termios_locked(real_tty, &kterm);
740*4882a593Smuzhiyun 		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
741*4882a593Smuzhiyun 			ret = -EFAULT;
742*4882a593Smuzhiyun 		return ret;
743*4882a593Smuzhiyun 	case TIOCSLCKTRMIOS:
744*4882a593Smuzhiyun 		if (!capable(CAP_SYS_ADMIN))
745*4882a593Smuzhiyun 			return -EPERM;
746*4882a593Smuzhiyun 		copy_termios_locked(real_tty, &kterm);
747*4882a593Smuzhiyun 		if (user_termios_to_kernel_termios(&kterm,
748*4882a593Smuzhiyun 					       (struct termios __user *) arg))
749*4882a593Smuzhiyun 			return -EFAULT;
750*4882a593Smuzhiyun 		down_write(&real_tty->termios_rwsem);
751*4882a593Smuzhiyun 		real_tty->termios_locked = kterm;
752*4882a593Smuzhiyun 		up_write(&real_tty->termios_rwsem);
753*4882a593Smuzhiyun 		return 0;
754*4882a593Smuzhiyun #else
755*4882a593Smuzhiyun 	case TIOCGLCKTRMIOS:
756*4882a593Smuzhiyun 		copy_termios_locked(real_tty, &kterm);
757*4882a593Smuzhiyun 		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
758*4882a593Smuzhiyun 			ret = -EFAULT;
759*4882a593Smuzhiyun 		return ret;
760*4882a593Smuzhiyun 	case TIOCSLCKTRMIOS:
761*4882a593Smuzhiyun 		if (!capable(CAP_SYS_ADMIN))
762*4882a593Smuzhiyun 			return -EPERM;
763*4882a593Smuzhiyun 		copy_termios_locked(real_tty, &kterm);
764*4882a593Smuzhiyun 		if (user_termios_to_kernel_termios_1(&kterm,
765*4882a593Smuzhiyun 					       (struct termios __user *) arg))
766*4882a593Smuzhiyun 			return -EFAULT;
767*4882a593Smuzhiyun 		down_write(&real_tty->termios_rwsem);
768*4882a593Smuzhiyun 		real_tty->termios_locked = kterm;
769*4882a593Smuzhiyun 		up_write(&real_tty->termios_rwsem);
770*4882a593Smuzhiyun 		return ret;
771*4882a593Smuzhiyun #endif
772*4882a593Smuzhiyun #ifdef TCGETX
773*4882a593Smuzhiyun 	case TCGETX:
774*4882a593Smuzhiyun 	case TCSETX:
775*4882a593Smuzhiyun 	case TCSETXW:
776*4882a593Smuzhiyun 	case TCSETXF:
777*4882a593Smuzhiyun 		return -ENOTTY;
778*4882a593Smuzhiyun #endif
779*4882a593Smuzhiyun 	case TIOCGSOFTCAR:
780*4882a593Smuzhiyun 		copy_termios(real_tty, &kterm);
781*4882a593Smuzhiyun 		ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
782*4882a593Smuzhiyun 						(int __user *)arg);
783*4882a593Smuzhiyun 		return ret;
784*4882a593Smuzhiyun 	case TIOCSSOFTCAR:
785*4882a593Smuzhiyun 		if (get_user(arg, (unsigned int __user *) arg))
786*4882a593Smuzhiyun 			return -EFAULT;
787*4882a593Smuzhiyun 		return tty_change_softcar(real_tty, arg);
788*4882a593Smuzhiyun 	default:
789*4882a593Smuzhiyun 		return -ENOIOCTLCMD;
790*4882a593Smuzhiyun 	}
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_mode_ioctl);
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun /* Caller guarantees ldisc reference is held */
__tty_perform_flush(struct tty_struct * tty,unsigned long arg)796*4882a593Smuzhiyun static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
797*4882a593Smuzhiyun {
798*4882a593Smuzhiyun 	struct tty_ldisc *ld = tty->ldisc;
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	switch (arg) {
801*4882a593Smuzhiyun 	case TCIFLUSH:
802*4882a593Smuzhiyun 		if (ld && ld->ops->flush_buffer) {
803*4882a593Smuzhiyun 			ld->ops->flush_buffer(tty);
804*4882a593Smuzhiyun 			tty_unthrottle(tty);
805*4882a593Smuzhiyun 		}
806*4882a593Smuzhiyun 		break;
807*4882a593Smuzhiyun 	case TCIOFLUSH:
808*4882a593Smuzhiyun 		if (ld && ld->ops->flush_buffer) {
809*4882a593Smuzhiyun 			ld->ops->flush_buffer(tty);
810*4882a593Smuzhiyun 			tty_unthrottle(tty);
811*4882a593Smuzhiyun 		}
812*4882a593Smuzhiyun 		fallthrough;
813*4882a593Smuzhiyun 	case TCOFLUSH:
814*4882a593Smuzhiyun 		tty_driver_flush_buffer(tty);
815*4882a593Smuzhiyun 		break;
816*4882a593Smuzhiyun 	default:
817*4882a593Smuzhiyun 		return -EINVAL;
818*4882a593Smuzhiyun 	}
819*4882a593Smuzhiyun 	return 0;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun 
tty_perform_flush(struct tty_struct * tty,unsigned long arg)822*4882a593Smuzhiyun int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun 	struct tty_ldisc *ld;
825*4882a593Smuzhiyun 	int retval = tty_check_change(tty);
826*4882a593Smuzhiyun 	if (retval)
827*4882a593Smuzhiyun 		return retval;
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	ld = tty_ldisc_ref_wait(tty);
830*4882a593Smuzhiyun 	retval = __tty_perform_flush(tty, arg);
831*4882a593Smuzhiyun 	if (ld)
832*4882a593Smuzhiyun 		tty_ldisc_deref(ld);
833*4882a593Smuzhiyun 	return retval;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_perform_flush);
836*4882a593Smuzhiyun 
n_tty_ioctl_helper(struct tty_struct * tty,struct file * file,unsigned int cmd,unsigned long arg)837*4882a593Smuzhiyun int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
838*4882a593Smuzhiyun 		       unsigned int cmd, unsigned long arg)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun 	int retval;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	switch (cmd) {
843*4882a593Smuzhiyun 	case TCXONC:
844*4882a593Smuzhiyun 		retval = tty_check_change(tty);
845*4882a593Smuzhiyun 		if (retval)
846*4882a593Smuzhiyun 			return retval;
847*4882a593Smuzhiyun 		switch (arg) {
848*4882a593Smuzhiyun 		case TCOOFF:
849*4882a593Smuzhiyun 			spin_lock_irq(&tty->flow_lock);
850*4882a593Smuzhiyun 			if (!tty->flow_stopped) {
851*4882a593Smuzhiyun 				tty->flow_stopped = 1;
852*4882a593Smuzhiyun 				__stop_tty(tty);
853*4882a593Smuzhiyun 			}
854*4882a593Smuzhiyun 			spin_unlock_irq(&tty->flow_lock);
855*4882a593Smuzhiyun 			break;
856*4882a593Smuzhiyun 		case TCOON:
857*4882a593Smuzhiyun 			spin_lock_irq(&tty->flow_lock);
858*4882a593Smuzhiyun 			if (tty->flow_stopped) {
859*4882a593Smuzhiyun 				tty->flow_stopped = 0;
860*4882a593Smuzhiyun 				__start_tty(tty);
861*4882a593Smuzhiyun 			}
862*4882a593Smuzhiyun 			spin_unlock_irq(&tty->flow_lock);
863*4882a593Smuzhiyun 			break;
864*4882a593Smuzhiyun 		case TCIOFF:
865*4882a593Smuzhiyun 			if (STOP_CHAR(tty) != __DISABLED_CHAR)
866*4882a593Smuzhiyun 				retval = tty_send_xchar(tty, STOP_CHAR(tty));
867*4882a593Smuzhiyun 			break;
868*4882a593Smuzhiyun 		case TCION:
869*4882a593Smuzhiyun 			if (START_CHAR(tty) != __DISABLED_CHAR)
870*4882a593Smuzhiyun 				retval = tty_send_xchar(tty, START_CHAR(tty));
871*4882a593Smuzhiyun 			break;
872*4882a593Smuzhiyun 		default:
873*4882a593Smuzhiyun 			return -EINVAL;
874*4882a593Smuzhiyun 		}
875*4882a593Smuzhiyun 		return retval;
876*4882a593Smuzhiyun 	case TCFLSH:
877*4882a593Smuzhiyun 		retval = tty_check_change(tty);
878*4882a593Smuzhiyun 		if (retval)
879*4882a593Smuzhiyun 			return retval;
880*4882a593Smuzhiyun 		return __tty_perform_flush(tty, arg);
881*4882a593Smuzhiyun 	default:
882*4882a593Smuzhiyun 		/* Try the mode commands */
883*4882a593Smuzhiyun 		return tty_mode_ioctl(tty, file, cmd, arg);
884*4882a593Smuzhiyun 	}
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun EXPORT_SYMBOL(n_tty_ioctl_helper);
887