Blame view

drivers/tty/tty_ioctl.c 23.7 KB
e3b3d0f54   Greg Kroah-Hartman   tty: add SPDX ide...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
   *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   *
   * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
   * which can be dynamically activated and de-activated by the line
   * discipline handling modules (like SLIP).
   */
  
  #include <linux/types.h>
  #include <linux/termios.h>
  #include <linux/errno.h>
174cd4b1e   Ingo Molnar   sched/headers: Pr...
13
  #include <linux/sched/signal.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
  #include <linux/kernel.h>
  #include <linux/major.h>
  #include <linux/tty.h>
  #include <linux/fcntl.h>
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/module.h>
  #include <linux/bitops.h>
5785c95ba   Arjan van de Ven   [PATCH] tty: make...
22
  #include <linux/mutex.h>
8193c4290   Thomas Meyer   tty: Support comp...
23
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  
  #include <asm/io.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
26
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  
  #undef TTY_DEBUG_WAIT_UNTIL_SENT
ff8339dc1   Peter Hurley   tty: Replace inli...
29
30
31
32
33
  #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
  # define tty_debug_wait_until_sent(tty, f, args...)    tty_debug(tty, f, ##args)
  #else
  # define tty_debug_wait_until_sent(tty, f, args...)    do {} while (0)
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
  #undef	DEBUG
  
  /*
   * Internal flag options for termios setting behavior
   */
  #define TERMIOS_FLUSH	1
  #define TERMIOS_WAIT	2
  #define TERMIOS_TERMIO	4
edc6afc54   Alan Cox   [PATCH] tty: swit...
42
  #define TERMIOS_OLD	8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

af9b897ee   Alan Cox   [PATCH] tty layer...
44

d81ed1030   Alan Cox   tty: Remove more ...
45
46
47
48
49
50
51
52
  /**
   *	tty_chars_in_buffer	-	characters pending
   *	@tty: terminal
   *
   *	Return the number of bytes of data in the device private
   *	output queue. If no private method is supplied there is assumed
   *	to be no queue on the device.
   */
f34d7a5b7   Alan Cox   tty: The big oper...
53
54
55
56
57
58
59
  int tty_chars_in_buffer(struct tty_struct *tty)
  {
  	if (tty->ops->chars_in_buffer)
  		return tty->ops->chars_in_buffer(tty);
  	else
  		return 0;
  }
f34d7a5b7   Alan Cox   tty: The big oper...
60
  EXPORT_SYMBOL(tty_chars_in_buffer);
d81ed1030   Alan Cox   tty: Remove more ...
61
62
63
64
65
66
67
68
69
70
71
  /**
   *	tty_write_room		-	write queue space
   *	@tty: terminal
   *
   *	Return the number of bytes that can be queued to this device
   *	at the present time. The result should be treated as a guarantee
   *	and the driver cannot offer a value it later shrinks by more than
   *	the number of bytes written. If no method is provided 2K is always
   *	returned and data may be lost as there will be no flow control.
   */
   
f34d7a5b7   Alan Cox   tty: The big oper...
72
73
74
75
76
77
  int tty_write_room(struct tty_struct *tty)
  {
  	if (tty->ops->write_room)
  		return tty->ops->write_room(tty);
  	return 2048;
  }
f34d7a5b7   Alan Cox   tty: The big oper...
78
  EXPORT_SYMBOL(tty_write_room);
d81ed1030   Alan Cox   tty: Remove more ...
79
80
81
82
83
84
85
86
  /**
   *	tty_driver_flush_buffer	-	discard internal buffer
   *	@tty: terminal
   *
   *	Discard the internal output buffer for this device. If no method
   *	is provided then either the buffer cannot be hardware flushed or
   *	there is no buffer driver side.
   */
f34d7a5b7   Alan Cox   tty: The big oper...
87
88
89
90
91
  void tty_driver_flush_buffer(struct tty_struct *tty)
  {
  	if (tty->ops->flush_buffer)
  		tty->ops->flush_buffer(tty);
  }
f34d7a5b7   Alan Cox   tty: The big oper...
92
  EXPORT_SYMBOL(tty_driver_flush_buffer);
d81ed1030   Alan Cox   tty: Remove more ...
93
94
95
96
97
  /**
   *	tty_throttle		-	flow control
   *	@tty: terminal
   *
   *	Indicate that a tty should stop transmitting data down the stack.
6a1c0680c   Peter Hurley   tty: Convert term...
98
   *	Takes the termios rwsem to protect against parallel throttle/unthrottle
38db89799   Alan Cox   tty: throttling r...
99
100
   *	and also to ensure the driver can consistently reference its own
   *	termios data at this point when implementing software flow control.
d81ed1030   Alan Cox   tty: Remove more ...
101
   */
39c2e60f8   Alan Cox   tty: add throttle...
102
103
  void tty_throttle(struct tty_struct *tty)
  {
6a1c0680c   Peter Hurley   tty: Convert term...
104
  	down_write(&tty->termios_rwsem);
39c2e60f8   Alan Cox   tty: add throttle...
105
106
107
108
  	/* check TTY_THROTTLED first so it indicates our state */
  	if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
  	    tty->ops->throttle)
  		tty->ops->throttle(tty);
70bc12647   Peter Hurley   tty: Add safe tty...
109
  	tty->flow_change = 0;
6a1c0680c   Peter Hurley   tty: Convert term...
110
  	up_write(&tty->termios_rwsem);
39c2e60f8   Alan Cox   tty: add throttle...
111
112
  }
  EXPORT_SYMBOL(tty_throttle);
d81ed1030   Alan Cox   tty: Remove more ...
113
114
115
116
117
  /**
   *	tty_unthrottle		-	flow control
   *	@tty: terminal
   *
   *	Indicate that a tty may continue transmitting data down the stack.
6a1c0680c   Peter Hurley   tty: Convert term...
118
   *	Takes the termios rwsem to protect against parallel throttle/unthrottle
38db89799   Alan Cox   tty: throttling r...
119
120
121
122
123
   *	and also to ensure the driver can consistently reference its own
   *	termios data at this point when implementing software flow control.
   *
   *	Drivers should however remember that the stack can issue a throttle,
   *	then change flow control method, then unthrottle.
d81ed1030   Alan Cox   tty: Remove more ...
124
   */
39c2e60f8   Alan Cox   tty: add throttle...
125
126
  void tty_unthrottle(struct tty_struct *tty)
  {
6a1c0680c   Peter Hurley   tty: Convert term...
127
  	down_write(&tty->termios_rwsem);
39c2e60f8   Alan Cox   tty: add throttle...
128
129
130
  	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
  	    tty->ops->unthrottle)
  		tty->ops->unthrottle(tty);
70bc12647   Peter Hurley   tty: Add safe tty...
131
  	tty->flow_change = 0;
6a1c0680c   Peter Hurley   tty: Convert term...
132
  	up_write(&tty->termios_rwsem);
39c2e60f8   Alan Cox   tty: add throttle...
133
134
  }
  EXPORT_SYMBOL(tty_unthrottle);
f34d7a5b7   Alan Cox   tty: The big oper...
135

af9b897ee   Alan Cox   [PATCH] tty layer...
136
  /**
70bc12647   Peter Hurley   tty: Add safe tty...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
   *	tty_throttle_safe	-	flow control
   *	@tty: terminal
   *
   *	Similar to tty_throttle() but will only attempt throttle
   *	if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
   *	throttle due to race conditions when throttling is conditional
   *	on factors evaluated prior to throttling.
   *
   *	Returns 0 if tty is throttled (or was already throttled)
   */
  
  int tty_throttle_safe(struct tty_struct *tty)
  {
  	int ret = 0;
d8c1f929a   Peter Hurley   tty: Only guarant...
151
  	mutex_lock(&tty->throttle_mutex);
97ef38b82   Peter Hurley   tty: Replace TTY_...
152
  	if (!tty_throttled(tty)) {
70bc12647   Peter Hurley   tty: Add safe tty...
153
154
155
  		if (tty->flow_change != TTY_THROTTLE_SAFE)
  			ret = 1;
  		else {
579a00a5c   Peter Hurley   tty: Fix unsafe b...
156
  			set_bit(TTY_THROTTLED, &tty->flags);
70bc12647   Peter Hurley   tty: Add safe tty...
157
158
159
160
  			if (tty->ops->throttle)
  				tty->ops->throttle(tty);
  		}
  	}
d8c1f929a   Peter Hurley   tty: Only guarant...
161
  	mutex_unlock(&tty->throttle_mutex);
70bc12647   Peter Hurley   tty: Add safe tty...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  
  	return ret;
  }
  
  /**
   *	tty_unthrottle_safe	-	flow control
   *	@tty: terminal
   *
   *	Similar to tty_unthrottle() but will only attempt unthrottle
   *	if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
   *	unthrottle due to race conditions when unthrottling is conditional
   *	on factors evaluated prior to unthrottling.
   *
   *	Returns 0 if tty is unthrottled (or was already unthrottled)
   */
  
  int tty_unthrottle_safe(struct tty_struct *tty)
  {
  	int ret = 0;
d8c1f929a   Peter Hurley   tty: Only guarant...
181
  	mutex_lock(&tty->throttle_mutex);
97ef38b82   Peter Hurley   tty: Replace TTY_...
182
  	if (tty_throttled(tty)) {
70bc12647   Peter Hurley   tty: Add safe tty...
183
184
185
  		if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
  			ret = 1;
  		else {
579a00a5c   Peter Hurley   tty: Fix unsafe b...
186
  			clear_bit(TTY_THROTTLED, &tty->flags);
70bc12647   Peter Hurley   tty: Add safe tty...
187
188
189
190
  			if (tty->ops->unthrottle)
  				tty->ops->unthrottle(tty);
  		}
  	}
d8c1f929a   Peter Hurley   tty: Only guarant...
191
  	mutex_unlock(&tty->throttle_mutex);
70bc12647   Peter Hurley   tty: Add safe tty...
192
193
194
195
196
  
  	return ret;
  }
  
  /**
af9b897ee   Alan Cox   [PATCH] tty layer...
197
198
199
200
201
202
203
204
205
   *	tty_wait_until_sent	-	wait for I/O to finish
   *	@tty: tty we are waiting for
   *	@timeout: how long we will wait
   *
   *	Wait for characters pending in a tty driver to hit the wire, or
   *	for a timeout to occur (eg due to flow control)
   *
   *	Locking: none
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
206
  void tty_wait_until_sent(struct tty_struct *tty, long timeout)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  {
d435cefe9   Peter Hurley   tty: Remove __fun...
208
209
  	tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld
  ", timeout);
ff8339dc1   Peter Hurley   tty: Replace inli...
210

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
  	if (!timeout)
  		timeout = MAX_SCHEDULE_TIMEOUT;
79fbf4a55   Johan Hovold   TTY: fix tty_wait...
213

c37bc682e   Johan Hovold   TTY: fix tty_wait...
214
215
216
  	timeout = wait_event_interruptible_timeout(tty->write_wait,
  			!tty_chars_in_buffer(tty), timeout);
  	if (timeout <= 0)
79fbf4a55   Johan Hovold   TTY: fix tty_wait...
217
  		return;
79fbf4a55   Johan Hovold   TTY: fix tty_wait...
218
219
220
221
222
223
  
  	if (timeout == MAX_SCHEDULE_TIMEOUT)
  		timeout = 0;
  
  	if (tty->ops->wait_until_sent)
  		tty->ops->wait_until_sent(tty, timeout);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  EXPORT_SYMBOL(tty_wait_until_sent);
d81ed1030   Alan Cox   tty: Remove more ...
226
227
228
229
  
  /*
   *		Termios Helper Methods
   */
d97ba9cda   Peter Hurley   tty: core: Refact...
230
  static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  {
d97ba9cda   Peter Hurley   tty: core: Refact...
232
233
  	struct ktermios *termios = &tty->termios;
  	struct ktermios *locked  = &tty->termios_locked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  	int	i;
355d95a1c   Alan Cox   tty_ioctl: drag s...
235
236
  
  #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
  	NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
  	NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
  	NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
  	NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
  	termios->c_line = locked->c_line ? old->c_line : termios->c_line;
355d95a1c   Alan Cox   tty_ioctl: drag s...
243
  	for (i = 0; i < NCCS; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
  		termios->c_cc[i] = locked->c_cc[i] ?
  			old->c_cc[i] : termios->c_cc[i];
edc6afc54   Alan Cox   [PATCH] tty: swit...
246
  	/* FIXME: What should we do for i/ospeed */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  }
edc6afc54   Alan Cox   [PATCH] tty: swit...
248
  /**
5f519d728   Alan Cox   tty: expose new m...
249
250
251
252
   *	tty_termios_copy_hw	-	copy hardware settings
   *	@new: New termios
   *	@old: Old termios
   *
25985edce   Lucas De Marchi   Fix common misspe...
253
   *	Propagate the hardware specific terminal setting bits from
5f519d728   Alan Cox   tty: expose new m...
254
255
256
257
258
259
260
261
262
263
264
265
266
267
   *	the old termios structure to the new one. This is used in cases
   *	where the hardware does not support reconfiguration or as a helper
   *	in some cases where only minimal reconfiguration is supported
   */
  
  void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
  {
  	/* The bits a dumb device handles in software. Smart devices need
  	   to always provide a set_termios method */
  	new->c_cflag &= HUPCL | CREAD | CLOCAL;
  	new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
  	new->c_ispeed = old->c_ispeed;
  	new->c_ospeed = old->c_ospeed;
  }
5f519d728   Alan Cox   tty: expose new m...
268
269
270
  EXPORT_SYMBOL(tty_termios_copy_hw);
  
  /**
bf5e5834b   Alan Cox   pl2303: Fix mode ...
271
272
273
274
275
276
277
   *	tty_termios_hw_change	-	check for setting change
   *	@a: termios
   *	@b: termios to compare
   *
   *	Check if any of the bits that affect a dumb device have changed
   *	between the two termios structures, or a speed change is needed.
   */
7b0c6b38c   Johan Hovold   tty: add missing ...
278
  int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
bf5e5834b   Alan Cox   pl2303: Fix mode ...
279
280
281
282
283
284
285
286
287
288
  {
  	if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
  		return 1;
  	if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
  		return 1;
  	return 0;
  }
  EXPORT_SYMBOL(tty_termios_hw_change);
  
  /**
8d075b199   Alan Cox   tty: add a helper...
289
   *	tty_set_termios		-	update termios values
af9b897ee   Alan Cox   [PATCH] tty layer...
290
291
292
   *	@tty: tty to update
   *	@new_termios: desired new value
   *
dbfcd851a   Peter Hurley   tty: Move pty-spe...
293
   *	Perform updates to the termios values set on this terminal.
6460fbbf4   Peter Hurley   tty: WARN for att...
294
295
   *	A master pty's termios should never be set.
   *
6a1c0680c   Peter Hurley   tty: Convert term...
296
   *	Locking: termios_rwsem
af9b897ee   Alan Cox   [PATCH] tty layer...
297
   */
b00f5c2dc   Frederic Danis   tty: Re-add exter...
298
  int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  {
978e595f8   Alan Cox   tty/serial: lay t...
300
  	struct ktermios old_termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  	struct tty_ldisc *ld;
355d95a1c   Alan Cox   tty_ioctl: drag s...
302

6460fbbf4   Peter Hurley   tty: WARN for att...
303
304
  	WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
  		tty->driver->subtype == PTY_TYPE_MASTER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
  	/*
  	 *	Perform the actual termios internal changes under lock.
  	 */
355d95a1c   Alan Cox   tty_ioctl: drag s...
308

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  
  	/* FIXME: we need to decide on some locking/ordering semantics
  	   for the set_termios notification eventually */
6a1c0680c   Peter Hurley   tty: Convert term...
312
  	down_write(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
313
314
  	old_termios = tty->termios;
  	tty->termios = *new_termios;
d97ba9cda   Peter Hurley   tty: core: Refact...
315
  	unset_locked_termios(tty, &old_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316

f34d7a5b7   Alan Cox   tty: The big oper...
317
  	if (tty->ops->set_termios)
c961bfb17   Peter Hurley   tty: Call methods...
318
  		tty->ops->set_termios(tty, &old_termios);
5f519d728   Alan Cox   tty: expose new m...
319
  	else
adc8d746c   Alan Cox   tty: move the ter...
320
  		tty_termios_copy_hw(&tty->termios, &old_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
  
  	ld = tty_ldisc_ref(tty);
  	if (ld != NULL) {
a352def21   Alan Cox   tty: Ldisc revamp
324
  		if (ld->ops->set_termios)
c961bfb17   Peter Hurley   tty: Call methods...
325
  			ld->ops->set_termios(tty, &old_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
  		tty_ldisc_deref(ld);
  	}
6a1c0680c   Peter Hurley   tty: Convert term...
328
  	up_write(&tty->termios_rwsem);
8d075b199   Alan Cox   tty: add a helper...
329
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  }
b00f5c2dc   Frederic Danis   tty: Re-add exter...
331
  EXPORT_SYMBOL_GPL(tty_set_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332

af9b897ee   Alan Cox   [PATCH] tty layer...
333
334
335
336
337
338
  /**
   *	set_termios		-	set termios values for a tty
   *	@tty: terminal device
   *	@arg: user data
   *	@opt: option information
   *
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
339
   *	Helper function to prepare termios data and run necessary other
8d075b199   Alan Cox   tty: add a helper...
340
   *	functions before using tty_set_termios to do the actual changes.
af9b897ee   Alan Cox   [PATCH] tty layer...
341
342
   *
   *	Locking:
6a1c0680c   Peter Hurley   tty: Convert term...
343
   *		Called functions take ldisc and termios_rwsem locks
af9b897ee   Alan Cox   [PATCH] tty layer...
344
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
345
  static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  {
edc6afc54   Alan Cox   [PATCH] tty: swit...
347
  	struct ktermios tmp_termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
  	struct tty_ldisc *ld;
  	int retval = tty_check_change(tty);
  
  	if (retval)
  		return retval;
6a1c0680c   Peter Hurley   tty: Convert term...
353
  	down_read(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
354
  	tmp_termios = tty->termios;
6a1c0680c   Peter Hurley   tty: Convert term...
355
  	up_read(&tty->termios_rwsem);
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
356

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  	if (opt & TERMIOS_TERMIO) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
  		if (user_termio_to_kernel_termios(&tmp_termios,
  						(struct termio __user *)arg))
  			return -EFAULT;
edc6afc54   Alan Cox   [PATCH] tty: swit...
361
362
  #ifdef TCGETS2
  	} else if (opt & TERMIOS_OLD) {
edc6afc54   Alan Cox   [PATCH] tty: swit...
363
  		if (user_termios_to_kernel_termios_1(&tmp_termios,
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
364
  						(struct termios __user *)arg))
edc6afc54   Alan Cox   [PATCH] tty: swit...
365
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
  	} else {
  		if (user_termios_to_kernel_termios(&tmp_termios,
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
368
  						(struct termios2 __user *)arg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
  			return -EFAULT;
  	}
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
371
372
373
374
375
  #else
  	} else if (user_termios_to_kernel_termios(&tmp_termios,
  					(struct termios __user *)arg))
  		return -EFAULT;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376

355d95a1c   Alan Cox   tty_ioctl: drag s...
377
378
  	/* If old style Bfoo values are used then load c_ispeed/c_ospeed
  	 * with the real speed so its unconditionally usable */
edc6afc54   Alan Cox   [PATCH] tty: swit...
379
380
  	tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
  	tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
  	ld = tty_ldisc_ref(tty);
355d95a1c   Alan Cox   tty_ioctl: drag s...
382

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  	if (ld != NULL) {
a352def21   Alan Cox   tty: Ldisc revamp
384
385
  		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
  			ld->ops->flush_buffer(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
  		tty_ldisc_deref(ld);
  	}
355d95a1c   Alan Cox   tty_ioctl: drag s...
388

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
  	if (opt & TERMIOS_WAIT) {
  		tty_wait_until_sent(tty, 0);
  		if (signal_pending(current))
183d95cdd   Oleg Nesterov   tty: set_termios/...
392
  			return -ERESTARTSYS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  	}
8d075b199   Alan Cox   tty: add a helper...
394
  	tty_set_termios(tty, &tmp_termios);
5f519d728   Alan Cox   tty: expose new m...
395
396
397
398
399
  
  	/* FIXME: Arguably if tmp_termios == tty->termios AND the
  	   actual requested termios was not tmp_termios then we may
  	   want to return an error as no user requested change has
  	   succeeded */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  	return 0;
  }
26a2e20f4   Alan Cox   tty: Untangle ter...
402
403
  static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
  {
6a1c0680c   Peter Hurley   tty: Convert term...
404
  	down_read(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
405
  	*kterm = tty->termios;
6a1c0680c   Peter Hurley   tty: Convert term...
406
  	up_read(&tty->termios_rwsem);
26a2e20f4   Alan Cox   tty: Untangle ter...
407
408
409
410
  }
  
  static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
  {
6a1c0680c   Peter Hurley   tty: Convert term...
411
  	down_read(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
412
  	*kterm = tty->termios_locked;
6a1c0680c   Peter Hurley   tty: Convert term...
413
  	up_read(&tty->termios_rwsem);
26a2e20f4   Alan Cox   tty: Untangle ter...
414
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
415
  static int get_termio(struct tty_struct *tty, struct termio __user *termio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  {
26a2e20f4   Alan Cox   tty: Untangle ter...
417
418
419
  	struct ktermios kterm;
  	copy_termios(tty, &kterm);
  	if (kernel_termios_to_user_termio(termio, &kterm))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
  		return -EFAULT;
  	return 0;
  }
1d65b4a08   Alan Cox   tty: Add termiox
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
  
  #ifdef TCGETX
  
  /**
   *	set_termiox	-	set termiox fields if possible
   *	@tty: terminal
   *	@arg: termiox structure from user
   *	@opt: option flags for ioctl type
   *
   *	Implement the device calling points for the SYS5 termiox ioctl
   *	interface in Linux
   */
  
  static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
  {
  	struct termiox tnew;
  	struct tty_ldisc *ld;
  
  	if (tty->termiox == NULL)
  		return -EINVAL;
  	if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
  		return -EFAULT;
  
  	ld = tty_ldisc_ref(tty);
  	if (ld != NULL) {
  		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
  			ld->ops->flush_buffer(tty);
  		tty_ldisc_deref(ld);
  	}
  	if (opt & TERMIOS_WAIT) {
  		tty_wait_until_sent(tty, 0);
  		if (signal_pending(current))
183d95cdd   Oleg Nesterov   tty: set_termios/...
455
  			return -ERESTARTSYS;
1d65b4a08   Alan Cox   tty: Add termiox
456
  	}
6a1c0680c   Peter Hurley   tty: Convert term...
457
  	down_write(&tty->termios_rwsem);
1d65b4a08   Alan Cox   tty: Add termiox
458
459
  	if (tty->ops->set_termiox)
  		tty->ops->set_termiox(tty, &tnew);
6a1c0680c   Peter Hurley   tty: Convert term...
460
  	up_write(&tty->termios_rwsem);
1d65b4a08   Alan Cox   tty: Add termiox
461
462
463
464
  	return 0;
  }
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
469
470
471
  
  #ifdef TIOCGETP
  /*
   * These are deprecated, but there is limited support..
   *
   * The "sg_flags" translation is a joke..
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
472
  static int get_sgflags(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
  {
  	int flags = 0;
9db276f8f   Peter Hurley   tty: Use termios ...
475
476
  	if (!L_ICANON(tty)) {
  		if (L_ISIG(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
  			flags |= 0x02;		/* cbreak */
  		else
  			flags |= 0x20;		/* raw */
  	}
9db276f8f   Peter Hurley   tty: Use termios ...
481
  	if (L_ECHO(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  		flags |= 0x08;			/* echo */
9db276f8f   Peter Hurley   tty: Use termios ...
483
484
  	if (O_OPOST(tty))
  		if (O_ONLCR(tty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
  			flags |= 0x10;		/* crmod */
  	return flags;
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
488
  static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
  {
  	struct sgttyb tmp;
6a1c0680c   Peter Hurley   tty: Convert term...
491
  	down_read(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
492
493
494
495
  	tmp.sg_ispeed = tty->termios.c_ispeed;
  	tmp.sg_ospeed = tty->termios.c_ospeed;
  	tmp.sg_erase = tty->termios.c_cc[VERASE];
  	tmp.sg_kill = tty->termios.c_cc[VKILL];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  	tmp.sg_flags = get_sgflags(tty);
6a1c0680c   Peter Hurley   tty: Convert term...
497
  	up_read(&tty->termios_rwsem);
355d95a1c   Alan Cox   tty_ioctl: drag s...
498

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
  	return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
501
  static void set_sgflags(struct ktermios *termios, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
  {
9833facf9   Alan Cox   tty: Fix up PPC f...
503
504
505
  	termios->c_iflag = ICRNL | IXON;
  	termios->c_oflag = 0;
  	termios->c_lflag = ISIG | ICANON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  	if (flags & 0x02) {	/* cbreak */
9833facf9   Alan Cox   tty: Fix up PPC f...
507
508
  		termios->c_iflag = 0;
  		termios->c_lflag &= ~ICANON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  	}
  	if (flags & 0x08) {		/* echo */
9833facf9   Alan Cox   tty: Fix up PPC f...
511
  		termios->c_lflag |= ECHO | ECHOE | ECHOK |
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
  				    ECHOCTL | ECHOKE | IEXTEN;
  	}
  	if (flags & 0x10) {		/* crmod */
9833facf9   Alan Cox   tty: Fix up PPC f...
515
  		termios->c_oflag |= OPOST | ONLCR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  	}
  	if (flags & 0x20) {	/* raw */
9833facf9   Alan Cox   tty: Fix up PPC f...
518
519
  		termios->c_iflag = 0;
  		termios->c_lflag &= ~(ISIG | ICANON);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  	}
9833facf9   Alan Cox   tty: Fix up PPC f...
521
522
523
  	if (!(termios->c_lflag & ICANON)) {
  		termios->c_cc[VMIN] = 1;
  		termios->c_cc[VTIME] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
  	}
  }
af9b897ee   Alan Cox   [PATCH] tty layer...
526
527
528
529
530
531
532
533
  /**
   *	set_sgttyb		-	set legacy terminal values
   *	@tty: tty structure
   *	@sgttyb: pointer to old style terminal structure
   *
   *	Updates a terminal from the legacy BSD style terminal information
   *	structure.
   *
6a1c0680c   Peter Hurley   tty: Convert term...
534
   *	Locking: termios_rwsem
af9b897ee   Alan Cox   [PATCH] tty layer...
535
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
536
  static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
  {
  	int retval;
  	struct sgttyb tmp;
edc6afc54   Alan Cox   [PATCH] tty: swit...
540
  	struct ktermios termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
544
  
  	retval = tty_check_change(tty);
  	if (retval)
  		return retval;
355d95a1c   Alan Cox   tty_ioctl: drag s...
545

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
  	if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
  		return -EFAULT;
6a1c0680c   Peter Hurley   tty: Convert term...
548
  	down_write(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
549
  	termios = tty->termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
  	termios.c_cc[VERASE] = tmp.sg_erase;
  	termios.c_cc[VKILL] = tmp.sg_kill;
  	set_sgflags(&termios, tmp.sg_flags);
edc6afc54   Alan Cox   [PATCH] tty: swit...
553
554
  	/* Try and encode into Bfoo format */
  #ifdef BOTHER
355d95a1c   Alan Cox   tty_ioctl: drag s...
555
556
  	tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
  						termios.c_ospeed);
edc6afc54   Alan Cox   [PATCH] tty: swit...
557
  #endif
6a1c0680c   Peter Hurley   tty: Convert term...
558
  	up_write(&tty->termios_rwsem);
8d075b199   Alan Cox   tty: add a helper...
559
  	tty_set_termios(tty, &termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
564
  	return 0;
  }
  #endif
  
  #ifdef TIOCGETC
355d95a1c   Alan Cox   tty_ioctl: drag s...
565
  static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
  {
  	struct tchars tmp;
6a1c0680c   Peter Hurley   tty: Convert term...
568
  	down_read(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
569
570
571
572
573
574
  	tmp.t_intrc = tty->termios.c_cc[VINTR];
  	tmp.t_quitc = tty->termios.c_cc[VQUIT];
  	tmp.t_startc = tty->termios.c_cc[VSTART];
  	tmp.t_stopc = tty->termios.c_cc[VSTOP];
  	tmp.t_eofc = tty->termios.c_cc[VEOF];
  	tmp.t_brkc = tty->termios.c_cc[VEOL2];	/* what is brkc anyway? */
6a1c0680c   Peter Hurley   tty: Convert term...
575
  	up_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
  	return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
578
  static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
582
583
  {
  	struct tchars tmp;
  
  	if (copy_from_user(&tmp, tchars, sizeof(tmp)))
  		return -EFAULT;
6a1c0680c   Peter Hurley   tty: Convert term...
584
  	down_write(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
585
586
587
588
589
590
  	tty->termios.c_cc[VINTR] = tmp.t_intrc;
  	tty->termios.c_cc[VQUIT] = tmp.t_quitc;
  	tty->termios.c_cc[VSTART] = tmp.t_startc;
  	tty->termios.c_cc[VSTOP] = tmp.t_stopc;
  	tty->termios.c_cc[VEOF] = tmp.t_eofc;
  	tty->termios.c_cc[VEOL2] = tmp.t_brkc;	/* what is brkc anyway? */
6a1c0680c   Peter Hurley   tty: Convert term...
591
  	up_write(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
  	return 0;
  }
  #endif
  
  #ifdef TIOCGLTC
355d95a1c   Alan Cox   tty_ioctl: drag s...
597
  static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
  {
  	struct ltchars tmp;
6a1c0680c   Peter Hurley   tty: Convert term...
600
  	down_read(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
601
  	tmp.t_suspc = tty->termios.c_cc[VSUSP];
355d95a1c   Alan Cox   tty_ioctl: drag s...
602
  	/* what is dsuspc anyway? */
adc8d746c   Alan Cox   tty: move the ter...
603
604
  	tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
  	tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
355d95a1c   Alan Cox   tty_ioctl: drag s...
605
  	/* what is flushc anyway? */
adc8d746c   Alan Cox   tty: move the ter...
606
607
608
  	tmp.t_flushc = tty->termios.c_cc[VEOL2];
  	tmp.t_werasc = tty->termios.c_cc[VWERASE];
  	tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
6a1c0680c   Peter Hurley   tty: Convert term...
609
  	up_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
  	return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
612
  static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
  {
  	struct ltchars tmp;
  
  	if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
  		return -EFAULT;
6a1c0680c   Peter Hurley   tty: Convert term...
618
  	down_write(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
619
  	tty->termios.c_cc[VSUSP] = tmp.t_suspc;
355d95a1c   Alan Cox   tty_ioctl: drag s...
620
  	/* what is dsuspc anyway? */
adc8d746c   Alan Cox   tty: move the ter...
621
622
  	tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
  	tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
355d95a1c   Alan Cox   tty_ioctl: drag s...
623
  	/* what is flushc anyway? */
adc8d746c   Alan Cox   tty: move the ter...
624
625
626
  	tty->termios.c_cc[VEOL2] = tmp.t_flushc;
  	tty->termios.c_cc[VWERASE] = tmp.t_werasc;
  	tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
6a1c0680c   Peter Hurley   tty: Convert term...
627
  	up_write(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
  	return 0;
  }
  #endif
af9b897ee   Alan Cox   [PATCH] tty layer...
631
  /**
1c2630ccf   Alan Cox   tty_ioctl: soft c...
632
633
634
635
636
   *	tty_change_softcar	-	carrier change ioctl helper
   *	@tty: tty to update
   *	@arg: enable/disable CLOCAL
   *
   *	Perform a change to the CLOCAL state and call into the driver
6a1c0680c   Peter Hurley   tty: Convert term...
637
   *	layer to make it visible. All done with the termios rwsem
1c2630ccf   Alan Cox   tty_ioctl: soft c...
638
639
640
641
642
643
   */
  
  static int tty_change_softcar(struct tty_struct *tty, int arg)
  {
  	int ret = 0;
  	int bit = arg ? CLOCAL : 0;
f34d7a5b7   Alan Cox   tty: The big oper...
644
  	struct ktermios old;
1c2630ccf   Alan Cox   tty_ioctl: soft c...
645

6a1c0680c   Peter Hurley   tty: Convert term...
646
  	down_write(&tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
647
648
649
  	old = tty->termios;
  	tty->termios.c_cflag &= ~CLOCAL;
  	tty->termios.c_cflag |= bit;
f34d7a5b7   Alan Cox   tty: The big oper...
650
651
  	if (tty->ops->set_termios)
  		tty->ops->set_termios(tty, &old);
9db276f8f   Peter Hurley   tty: Use termios ...
652
  	if (C_CLOCAL(tty) != bit)
1c2630ccf   Alan Cox   tty_ioctl: soft c...
653
  		ret = -EINVAL;
6a1c0680c   Peter Hurley   tty: Convert term...
654
  	up_write(&tty->termios_rwsem);
1c2630ccf   Alan Cox   tty_ioctl: soft c...
655
656
657
658
  	return ret;
  }
  
  /**
0fc00e244   Alan Cox   [TTY]: Fix networ...
659
660
661
662
663
664
665
666
667
668
   *	tty_mode_ioctl		-	mode related ioctls
   *	@tty: tty for the ioctl
   *	@file: file pointer for the tty
   *	@cmd: command
   *	@arg: ioctl argument
   *
   *	Perform non line discipline specific mode control ioctls. This
   *	is designed to be called by line disciplines to ensure they provide
   *	consistent mode setting.
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
669
  int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
0fc00e244   Alan Cox   [TTY]: Fix networ...
670
  			unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  {
355d95a1c   Alan Cox   tty_ioctl: drag s...
672
  	struct tty_struct *real_tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  	void __user *p = (void __user *)arg;
8f5200218   Alan Cox   tty: Termios lock...
674
  	int ret = 0;
26a2e20f4   Alan Cox   tty: Untangle ter...
675
  	struct ktermios kterm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676

8d075b199   Alan Cox   tty: add a helper...
677
  	BUG_ON(file == NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
683
684
685
  	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
  	    tty->driver->subtype == PTY_TYPE_MASTER)
  		real_tty = tty->link;
  	else
  		real_tty = tty;
  
  	switch (cmd) {
  #ifdef TIOCGETP
355d95a1c   Alan Cox   tty_ioctl: drag s...
686
687
688
689
690
  	case TIOCGETP:
  		return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
  	case TIOCSETP:
  	case TIOCSETN:
  		return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
  #endif
  #ifdef TIOCGETC
355d95a1c   Alan Cox   tty_ioctl: drag s...
693
694
695
696
  	case TIOCGETC:
  		return get_tchars(real_tty, p);
  	case TIOCSETC:
  		return set_tchars(real_tty, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
  #endif
  #ifdef TIOCGLTC
355d95a1c   Alan Cox   tty_ioctl: drag s...
699
700
701
702
  	case TIOCGLTC:
  		return get_ltchars(real_tty, p);
  	case TIOCSLTC:
  		return set_ltchars(real_tty, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
  #endif
355d95a1c   Alan Cox   tty_ioctl: drag s...
704
705
706
707
708
709
  	case TCSETSF:
  		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
  	case TCSETSW:
  		return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
  	case TCSETS:
  		return set_termios(real_tty, p, TERMIOS_OLD);
edc6afc54   Alan Cox   [PATCH] tty: swit...
710
  #ifndef TCGETS2
355d95a1c   Alan Cox   tty_ioctl: drag s...
711
  	case TCGETS:
26a2e20f4   Alan Cox   tty: Untangle ter...
712
713
  		copy_termios(real_tty, &kterm);
  		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
714
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
715
  		return ret;
edc6afc54   Alan Cox   [PATCH] tty: swit...
716
  #else
355d95a1c   Alan Cox   tty_ioctl: drag s...
717
  	case TCGETS:
26a2e20f4   Alan Cox   tty: Untangle ter...
718
719
  		copy_termios(real_tty, &kterm);
  		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
720
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
721
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
722
  	case TCGETS2:
26a2e20f4   Alan Cox   tty: Untangle ter...
723
724
  		copy_termios(real_tty, &kterm);
  		if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
725
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
726
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
727
728
729
730
731
732
  	case TCSETSF2:
  		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
  	case TCSETSW2:
  		return set_termios(real_tty, p, TERMIOS_WAIT);
  	case TCSETS2:
  		return set_termios(real_tty, p, 0);
edc6afc54   Alan Cox   [PATCH] tty: swit...
733
  #endif
355d95a1c   Alan Cox   tty_ioctl: drag s...
734
735
736
737
738
739
740
741
  	case TCGETA:
  		return get_termio(real_tty, p);
  	case TCSETAF:
  		return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
  	case TCSETAW:
  		return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
  	case TCSETA:
  		return set_termios(real_tty, p, TERMIOS_TERMIO);
0fc00e244   Alan Cox   [TTY]: Fix networ...
742
  #ifndef TCGETS2
355d95a1c   Alan Cox   tty_ioctl: drag s...
743
  	case TIOCGLCKTRMIOS:
26a2e20f4   Alan Cox   tty: Untangle ter...
744
745
  		copy_termios_locked(real_tty, &kterm);
  		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
746
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
747
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
748
749
750
  	case TIOCSLCKTRMIOS:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EPERM;
26a2e20f4   Alan Cox   tty: Untangle ter...
751
752
  		copy_termios_locked(real_tty, &kterm);
  		if (user_termios_to_kernel_termios(&kterm,
355d95a1c   Alan Cox   tty_ioctl: drag s...
753
  					       (struct termios __user *) arg))
26a2e20f4   Alan Cox   tty: Untangle ter...
754
  			return -EFAULT;
6a1c0680c   Peter Hurley   tty: Convert term...
755
  		down_write(&real_tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
756
  		real_tty->termios_locked = kterm;
6a1c0680c   Peter Hurley   tty: Convert term...
757
  		up_write(&real_tty->termios_rwsem);
26a2e20f4   Alan Cox   tty: Untangle ter...
758
  		return 0;
0fc00e244   Alan Cox   [TTY]: Fix networ...
759
  #else
355d95a1c   Alan Cox   tty_ioctl: drag s...
760
  	case TIOCGLCKTRMIOS:
26a2e20f4   Alan Cox   tty: Untangle ter...
761
762
  		copy_termios_locked(real_tty, &kterm);
  		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
763
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
764
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
765
766
  	case TIOCSLCKTRMIOS:
  		if (!capable(CAP_SYS_ADMIN))
26a2e20f4   Alan Cox   tty: Untangle ter...
767
768
769
  			return -EPERM;
  		copy_termios_locked(real_tty, &kterm);
  		if (user_termios_to_kernel_termios_1(&kterm,
355d95a1c   Alan Cox   tty_ioctl: drag s...
770
  					       (struct termios __user *) arg))
26a2e20f4   Alan Cox   tty: Untangle ter...
771
  			return -EFAULT;
6a1c0680c   Peter Hurley   tty: Convert term...
772
  		down_write(&real_tty->termios_rwsem);
adc8d746c   Alan Cox   tty: move the ter...
773
  		real_tty->termios_locked = kterm;
6a1c0680c   Peter Hurley   tty: Convert term...
774
  		up_write(&real_tty->termios_rwsem);
8f5200218   Alan Cox   tty: Termios lock...
775
  		return ret;
0fc00e244   Alan Cox   [TTY]: Fix networ...
776
  #endif
1d65b4a08   Alan Cox   tty: Add termiox
777
  #ifdef TCGETX
5dca607bc   Mike Frysinger   tty: fix unused w...
778
779
  	case TCGETX: {
  		struct termiox ktermx;
1d65b4a08   Alan Cox   tty: Add termiox
780
781
  		if (real_tty->termiox == NULL)
  			return -EINVAL;
6a1c0680c   Peter Hurley   tty: Convert term...
782
  		down_read(&real_tty->termios_rwsem);
26a2e20f4   Alan Cox   tty: Untangle ter...
783
  		memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
6a1c0680c   Peter Hurley   tty: Convert term...
784
  		up_read(&real_tty->termios_rwsem);
26a2e20f4   Alan Cox   tty: Untangle ter...
785
786
  		if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
787
  		return ret;
5dca607bc   Mike Frysinger   tty: fix unused w...
788
  	}
1d65b4a08   Alan Cox   tty: Add termiox
789
790
791
792
793
794
795
  	case TCSETX:
  		return set_termiox(real_tty, p, 0);
  	case TCSETXW:
  		return set_termiox(real_tty, p, TERMIOS_WAIT);
  	case TCSETXF:
  		return set_termiox(real_tty, p, TERMIOS_FLUSH);
  #endif		
355d95a1c   Alan Cox   tty_ioctl: drag s...
796
  	case TIOCGSOFTCAR:
26a2e20f4   Alan Cox   tty: Untangle ter...
797
798
  		copy_termios(real_tty, &kterm);
  		ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
355d95a1c   Alan Cox   tty_ioctl: drag s...
799
  						(int __user *)arg);
8f5200218   Alan Cox   tty: Termios lock...
800
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
801
802
803
  	case TIOCSSOFTCAR:
  		if (get_user(arg, (unsigned int __user *) arg))
  			return -EFAULT;
f753f3272   Alan Cox   tty: TIOCGSOFTCAR...
804
  		return tty_change_softcar(real_tty, arg);
355d95a1c   Alan Cox   tty_ioctl: drag s...
805
806
  	default:
  		return -ENOIOCTLCMD;
0fc00e244   Alan Cox   [TTY]: Fix networ...
807
808
  	}
  }
0fc00e244   Alan Cox   [TTY]: Fix networ...
809
  EXPORT_SYMBOL_GPL(tty_mode_ioctl);
e7f3880cd   Peter Hurley   tty: Fix recursiv...
810
811
812
  
  /* Caller guarantees ldisc reference is held */
  static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
0fc00e244   Alan Cox   [TTY]: Fix networ...
813
  {
e7f3880cd   Peter Hurley   tty: Fix recursiv...
814
  	struct tty_ldisc *ld = tty->ldisc;
0fc00e244   Alan Cox   [TTY]: Fix networ...
815

0fc00e244   Alan Cox   [TTY]: Fix networ...
816
817
  	switch (arg) {
  	case TCIFLUSH:
a1bf95844   Ilya Zykov   tty: Add driver u...
818
  		if (ld && ld->ops->flush_buffer) {
a352def21   Alan Cox   tty: Ldisc revamp
819
  			ld->ops->flush_buffer(tty);
a1bf95844   Ilya Zykov   tty: Add driver u...
820
821
  			tty_unthrottle(tty);
  		}
0fc00e244   Alan Cox   [TTY]: Fix networ...
822
823
  		break;
  	case TCIOFLUSH:
a1bf95844   Ilya Zykov   tty: Add driver u...
824
  		if (ld && ld->ops->flush_buffer) {
a352def21   Alan Cox   tty: Ldisc revamp
825
  			ld->ops->flush_buffer(tty);
a1bf95844   Ilya Zykov   tty: Add driver u...
826
827
  			tty_unthrottle(tty);
  		}
df561f668   Gustavo A. R. Silva   treewide: Use fal...
828
  		fallthrough;
0fc00e244   Alan Cox   [TTY]: Fix networ...
829
  	case TCOFLUSH:
f34d7a5b7   Alan Cox   tty: The big oper...
830
  		tty_driver_flush_buffer(tty);
0fc00e244   Alan Cox   [TTY]: Fix networ...
831
832
  		break;
  	default:
0fc00e244   Alan Cox   [TTY]: Fix networ...
833
834
  		return -EINVAL;
  	}
0fc00e244   Alan Cox   [TTY]: Fix networ...
835
836
  	return 0;
  }
e7f3880cd   Peter Hurley   tty: Fix recursiv...
837
838
839
840
841
842
843
844
845
846
847
848
849
850
  
  int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
  {
  	struct tty_ldisc *ld;
  	int retval = tty_check_change(tty);
  	if (retval)
  		return retval;
  
  	ld = tty_ldisc_ref_wait(tty);
  	retval = __tty_perform_flush(tty, arg);
  	if (ld)
  		tty_ldisc_deref(ld);
  	return retval;
  }
0fc00e244   Alan Cox   [TTY]: Fix networ...
851
  EXPORT_SYMBOL_GPL(tty_perform_flush);
47afa7a5a   Alan Cox   tty: some ICANON ...
852
  int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
0fc00e244   Alan Cox   [TTY]: Fix networ...
853
854
  		       unsigned int cmd, unsigned long arg)
  {
0fc00e244   Alan Cox   [TTY]: Fix networ...
855
  	int retval;
0fc00e244   Alan Cox   [TTY]: Fix networ...
856
  	switch (cmd) {
355d95a1c   Alan Cox   tty_ioctl: drag s...
857
858
859
860
861
862
  	case TCXONC:
  		retval = tty_check_change(tty);
  		if (retval)
  			return retval;
  		switch (arg) {
  		case TCOOFF:
c545b66c6   Peter Hurley   tty: Serialize tc...
863
  			spin_lock_irq(&tty->flow_lock);
355d95a1c   Alan Cox   tty_ioctl: drag s...
864
865
  			if (!tty->flow_stopped) {
  				tty->flow_stopped = 1;
c545b66c6   Peter Hurley   tty: Serialize tc...
866
  				__stop_tty(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  			}
c545b66c6   Peter Hurley   tty: Serialize tc...
868
  			spin_unlock_irq(&tty->flow_lock);
355d95a1c   Alan Cox   tty_ioctl: drag s...
869
870
  			break;
  		case TCOON:
c545b66c6   Peter Hurley   tty: Serialize tc...
871
  			spin_lock_irq(&tty->flow_lock);
355d95a1c   Alan Cox   tty_ioctl: drag s...
872
873
  			if (tty->flow_stopped) {
  				tty->flow_stopped = 0;
c545b66c6   Peter Hurley   tty: Serialize tc...
874
  				__start_tty(tty);
355d95a1c   Alan Cox   tty_ioctl: drag s...
875
  			}
c545b66c6   Peter Hurley   tty: Serialize tc...
876
  			spin_unlock_irq(&tty->flow_lock);
355d95a1c   Alan Cox   tty_ioctl: drag s...
877
878
879
  			break;
  		case TCIOFF:
  			if (STOP_CHAR(tty) != __DISABLED_CHAR)
c274f6ef1   Peter Hurley   tty: Hold termios...
880
  				retval = tty_send_xchar(tty, STOP_CHAR(tty));
355d95a1c   Alan Cox   tty_ioctl: drag s...
881
882
883
  			break;
  		case TCION:
  			if (START_CHAR(tty) != __DISABLED_CHAR)
c274f6ef1   Peter Hurley   tty: Hold termios...
884
  				retval = tty_send_xchar(tty, START_CHAR(tty));
355d95a1c   Alan Cox   tty_ioctl: drag s...
885
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  		default:
355d95a1c   Alan Cox   tty_ioctl: drag s...
887
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  		}
c274f6ef1   Peter Hurley   tty: Hold termios...
889
  		return retval;
355d95a1c   Alan Cox   tty_ioctl: drag s...
890
  	case TCFLSH:
5cec7bf69   Peter Hurley   tty: Fix SIGTTOU ...
891
892
893
  		retval = tty_check_change(tty);
  		if (retval)
  			return retval;
e7f3880cd   Peter Hurley   tty: Fix recursiv...
894
  		return __tty_perform_flush(tty, arg);
355d95a1c   Alan Cox   tty_ioctl: drag s...
895
896
897
898
  	default:
  		/* Try the mode commands */
  		return tty_mode_ioctl(tty, file, cmd, arg);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
  }
47afa7a5a   Alan Cox   tty: some ICANON ...
900
  EXPORT_SYMBOL(n_tty_ioctl_helper);