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