tty: Fix tty_send_xchar() lock order inversion
[linux-2.6-block.git] / drivers / tty / tty_ioctl.c
CommitLineData
1da177e4 1/*
1da177e4
LT
2 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
3 *
4 * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
5 * which can be dynamically activated and de-activated by the line
6 * discipline handling modules (like SLIP).
7 */
8
9#include <linux/types.h>
10#include <linux/termios.h>
11#include <linux/errno.h>
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/major.h>
15#include <linux/tty.h>
16#include <linux/fcntl.h>
17#include <linux/string.h>
18#include <linux/mm.h>
19#include <linux/module.h>
20#include <linux/bitops.h>
5785c95b 21#include <linux/mutex.h>
8193c429 22#include <linux/compat.h>
1da177e4
LT
23
24#include <asm/io.h>
25#include <asm/uaccess.h>
1da177e4
LT
26
27#undef TTY_DEBUG_WAIT_UNTIL_SENT
28
ff8339dc
PH
29#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
30# define tty_debug_wait_until_sent(tty, f, args...) tty_debug(tty, f, ##args)
31#else
32# define tty_debug_wait_until_sent(tty, f, args...) do {} while (0)
33#endif
34
1da177e4
LT
35#undef DEBUG
36
37/*
38 * Internal flag options for termios setting behavior
39 */
40#define TERMIOS_FLUSH 1
41#define TERMIOS_WAIT 2
42#define TERMIOS_TERMIO 4
edc6afc5 43#define TERMIOS_OLD 8
1da177e4 44
af9b897e 45
d81ed103
AC
46/**
47 * tty_chars_in_buffer - characters pending
48 * @tty: terminal
49 *
50 * Return the number of bytes of data in the device private
51 * output queue. If no private method is supplied there is assumed
52 * to be no queue on the device.
53 */
54
f34d7a5b
AC
55int tty_chars_in_buffer(struct tty_struct *tty)
56{
57 if (tty->ops->chars_in_buffer)
58 return tty->ops->chars_in_buffer(tty);
59 else
60 return 0;
61}
f34d7a5b
AC
62EXPORT_SYMBOL(tty_chars_in_buffer);
63
d81ed103
AC
64/**
65 * tty_write_room - write queue space
66 * @tty: terminal
67 *
68 * Return the number of bytes that can be queued to this device
69 * at the present time. The result should be treated as a guarantee
70 * and the driver cannot offer a value it later shrinks by more than
71 * the number of bytes written. If no method is provided 2K is always
72 * returned and data may be lost as there will be no flow control.
73 */
74
f34d7a5b
AC
75int tty_write_room(struct tty_struct *tty)
76{
77 if (tty->ops->write_room)
78 return tty->ops->write_room(tty);
79 return 2048;
80}
f34d7a5b
AC
81EXPORT_SYMBOL(tty_write_room);
82
d81ed103
AC
83/**
84 * tty_driver_flush_buffer - discard internal buffer
85 * @tty: terminal
86 *
87 * Discard the internal output buffer for this device. If no method
88 * is provided then either the buffer cannot be hardware flushed or
89 * there is no buffer driver side.
90 */
f34d7a5b
AC
91void tty_driver_flush_buffer(struct tty_struct *tty)
92{
93 if (tty->ops->flush_buffer)
94 tty->ops->flush_buffer(tty);
95}
f34d7a5b
AC
96EXPORT_SYMBOL(tty_driver_flush_buffer);
97
d81ed103
AC
98/**
99 * tty_throttle - flow control
100 * @tty: terminal
101 *
102 * Indicate that a tty should stop transmitting data down the stack.
6a1c0680 103 * Takes the termios rwsem to protect against parallel throttle/unthrottle
38db8979
AC
104 * and also to ensure the driver can consistently reference its own
105 * termios data at this point when implementing software flow control.
d81ed103
AC
106 */
107
39c2e60f
AC
108void tty_throttle(struct tty_struct *tty)
109{
6a1c0680 110 down_write(&tty->termios_rwsem);
39c2e60f
AC
111 /* check TTY_THROTTLED first so it indicates our state */
112 if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
113 tty->ops->throttle)
114 tty->ops->throttle(tty);
70bc1264 115 tty->flow_change = 0;
6a1c0680 116 up_write(&tty->termios_rwsem);
39c2e60f
AC
117}
118EXPORT_SYMBOL(tty_throttle);
119
d81ed103
AC
120/**
121 * tty_unthrottle - flow control
122 * @tty: terminal
123 *
124 * Indicate that a tty may continue transmitting data down the stack.
6a1c0680 125 * Takes the termios rwsem to protect against parallel throttle/unthrottle
38db8979
AC
126 * and also to ensure the driver can consistently reference its own
127 * termios data at this point when implementing software flow control.
128 *
129 * Drivers should however remember that the stack can issue a throttle,
130 * then change flow control method, then unthrottle.
d81ed103
AC
131 */
132
39c2e60f
AC
133void tty_unthrottle(struct tty_struct *tty)
134{
6a1c0680 135 down_write(&tty->termios_rwsem);
39c2e60f
AC
136 if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
137 tty->ops->unthrottle)
138 tty->ops->unthrottle(tty);
70bc1264 139 tty->flow_change = 0;
6a1c0680 140 up_write(&tty->termios_rwsem);
39c2e60f
AC
141}
142EXPORT_SYMBOL(tty_unthrottle);
f34d7a5b 143
70bc1264
PH
144/**
145 * tty_throttle_safe - flow control
146 * @tty: terminal
147 *
148 * Similar to tty_throttle() but will only attempt throttle
149 * if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
150 * throttle due to race conditions when throttling is conditional
151 * on factors evaluated prior to throttling.
152 *
153 * Returns 0 if tty is throttled (or was already throttled)
154 */
155
156int tty_throttle_safe(struct tty_struct *tty)
157{
158 int ret = 0;
159
d8c1f929 160 mutex_lock(&tty->throttle_mutex);
70bc1264
PH
161 if (!test_bit(TTY_THROTTLED, &tty->flags)) {
162 if (tty->flow_change != TTY_THROTTLE_SAFE)
163 ret = 1;
164 else {
579a00a5 165 set_bit(TTY_THROTTLED, &tty->flags);
70bc1264
PH
166 if (tty->ops->throttle)
167 tty->ops->throttle(tty);
168 }
169 }
d8c1f929 170 mutex_unlock(&tty->throttle_mutex);
70bc1264
PH
171
172 return ret;
173}
174
175/**
176 * tty_unthrottle_safe - flow control
177 * @tty: terminal
178 *
179 * Similar to tty_unthrottle() but will only attempt unthrottle
180 * if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
181 * unthrottle due to race conditions when unthrottling is conditional
182 * on factors evaluated prior to unthrottling.
183 *
184 * Returns 0 if tty is unthrottled (or was already unthrottled)
185 */
186
187int tty_unthrottle_safe(struct tty_struct *tty)
188{
189 int ret = 0;
190
d8c1f929 191 mutex_lock(&tty->throttle_mutex);
70bc1264
PH
192 if (test_bit(TTY_THROTTLED, &tty->flags)) {
193 if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
194 ret = 1;
195 else {
579a00a5 196 clear_bit(TTY_THROTTLED, &tty->flags);
70bc1264
PH
197 if (tty->ops->unthrottle)
198 tty->ops->unthrottle(tty);
199 }
200 }
d8c1f929 201 mutex_unlock(&tty->throttle_mutex);
70bc1264
PH
202
203 return ret;
204}
205
af9b897e
AC
206/**
207 * tty_wait_until_sent - wait for I/O to finish
208 * @tty: tty we are waiting for
209 * @timeout: how long we will wait
210 *
211 * Wait for characters pending in a tty driver to hit the wire, or
212 * for a timeout to occur (eg due to flow control)
213 *
214 * Locking: none
215 */
216
355d95a1 217void tty_wait_until_sent(struct tty_struct *tty, long timeout)
1da177e4 218{
ff8339dc
PH
219 tty_debug_wait_until_sent(tty, "\n");
220
1da177e4
LT
221 if (!timeout)
222 timeout = MAX_SCHEDULE_TIMEOUT;
79fbf4a5 223
c37bc682
JH
224 timeout = wait_event_interruptible_timeout(tty->write_wait,
225 !tty_chars_in_buffer(tty), timeout);
226 if (timeout <= 0)
79fbf4a5 227 return;
79fbf4a5
JH
228
229 if (timeout == MAX_SCHEDULE_TIMEOUT)
230 timeout = 0;
231
232 if (tty->ops->wait_until_sent)
233 tty->ops->wait_until_sent(tty, timeout);
1da177e4 234}
1da177e4
LT
235EXPORT_SYMBOL(tty_wait_until_sent);
236
d81ed103
AC
237
238/*
239 * Termios Helper Methods
240 */
241
edc6afc5
AC
242static void unset_locked_termios(struct ktermios *termios,
243 struct ktermios *old,
244 struct ktermios *locked)
1da177e4
LT
245{
246 int i;
355d95a1
AC
247
248#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
1da177e4
LT
249
250 if (!locked) {
251 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
252 return;
253 }
254
255 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
256 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
257 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
258 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
259 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
355d95a1 260 for (i = 0; i < NCCS; i++)
1da177e4
LT
261 termios->c_cc[i] = locked->c_cc[i] ?
262 old->c_cc[i] : termios->c_cc[i];
edc6afc5 263 /* FIXME: What should we do for i/ospeed */
1da177e4
LT
264}
265
edc6afc5
AC
266/*
267 * Routine which returns the baud rate of the tty
268 *
269 * Note that the baud_table needs to be kept in sync with the
270 * include/asm/termbits.h file.
271 */
272static const speed_t baud_table[] = {
273 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
274 9600, 19200, 38400, 57600, 115200, 230400, 460800,
275#ifdef __sparc__
276 76800, 153600, 307200, 614400, 921600
277#else
278 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
279 2500000, 3000000, 3500000, 4000000
280#endif
281};
282
283#ifndef __sparc__
284static const tcflag_t baud_bits[] = {
285 B0, B50, B75, B110, B134, B150, B200, B300, B600,
286 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
287 B57600, B115200, B230400, B460800, B500000, B576000,
288 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
289 B3000000, B3500000, B4000000
290};
291#else
292static const tcflag_t baud_bits[] = {
293 B0, B50, B75, B110, B134, B150, B200, B300, B600,
294 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
295 B57600, B115200, B230400, B460800, B76800, B153600,
296 B307200, B614400, B921600
297};
298#endif
299
300static int n_baud_table = ARRAY_SIZE(baud_table);
301
302/**
303 * tty_termios_baud_rate
304 * @termios: termios structure
305 *
306 * Convert termios baud rate data into a speed. This should be called
307 * with the termios lock held if this termios is a terminal termios
308 * structure. May change the termios data. Device drivers can call this
309 * function but should use ->c_[io]speed directly as they are updated.
310 *
311 * Locking: none
312 */
313
314speed_t tty_termios_baud_rate(struct ktermios *termios)
315{
316 unsigned int cbaud;
317
318 cbaud = termios->c_cflag & CBAUD;
319
320#ifdef BOTHER
25985edc 321 /* Magic token for arbitrary speed via c_ispeed/c_ospeed */
edc6afc5
AC
322 if (cbaud == BOTHER)
323 return termios->c_ospeed;
324#endif
325 if (cbaud & CBAUDEX) {
326 cbaud &= ~CBAUDEX;
327
328 if (cbaud < 1 || cbaud + 15 > n_baud_table)
329 termios->c_cflag &= ~CBAUDEX;
330 else
331 cbaud += 15;
332 }
333 return baud_table[cbaud];
334}
edc6afc5
AC
335EXPORT_SYMBOL(tty_termios_baud_rate);
336
337/**
338 * tty_termios_input_baud_rate
339 * @termios: termios structure
340 *
341 * Convert termios baud rate data into a speed. This should be called
342 * with the termios lock held if this termios is a terminal termios
343 * structure. May change the termios data. Device drivers can call this
344 * function but should use ->c_[io]speed directly as they are updated.
345 *
346 * Locking: none
347 */
348
349speed_t tty_termios_input_baud_rate(struct ktermios *termios)
350{
351#ifdef IBSHIFT
352 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
353
354 if (cbaud == B0)
355 return tty_termios_baud_rate(termios);
356
25985edc 357 /* Magic token for arbitrary speed via c_ispeed*/
edc6afc5
AC
358 if (cbaud == BOTHER)
359 return termios->c_ispeed;
360
361 if (cbaud & CBAUDEX) {
362 cbaud &= ~CBAUDEX;
363
364 if (cbaud < 1 || cbaud + 15 > n_baud_table)
365 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
366 else
367 cbaud += 15;
368 }
369 return baud_table[cbaud];
370#else
371 return tty_termios_baud_rate(termios);
372#endif
373}
edc6afc5
AC
374EXPORT_SYMBOL(tty_termios_input_baud_rate);
375
edc6afc5
AC
376/**
377 * tty_termios_encode_baud_rate
78137e3b 378 * @termios: ktermios structure holding user requested state
edc6afc5
AC
379 * @ispeed: input speed
380 * @ospeed: output speed
381 *
382 * Encode the speeds set into the passed termios structure. This is
f98e5b80 383 * used as a library helper for drivers so that they can report back
edc6afc5
AC
384 * the actual speed selected when it differs from the speed requested
385 *
78137e3b
AC
386 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
387 * we need to carefully set the bits when the user does not get the
388 * desired speed. We allow small margins and preserve as much of possible
06fe9fb4 389 * of the input intent to keep compatibility.
edc6afc5
AC
390 *
391 * Locking: Caller should hold termios lock. This is already held
392 * when calling this function from the driver termios handler.
5f519d72
AC
393 *
394 * The ifdefs deal with platforms whose owners have yet to update them
395 * and will all go away once this is done.
edc6afc5
AC
396 */
397
75e8b71d
MR
398void tty_termios_encode_baud_rate(struct ktermios *termios,
399 speed_t ibaud, speed_t obaud)
edc6afc5
AC
400{
401 int i = 0;
78137e3b
AC
402 int ifound = -1, ofound = -1;
403 int iclose = ibaud/50, oclose = obaud/50;
404 int ibinput = 0;
edc6afc5 405
5f519d72
AC
406 if (obaud == 0) /* CD dropped */
407 ibaud = 0; /* Clear ibaud to be sure */
408
edc6afc5
AC
409 termios->c_ispeed = ibaud;
410 termios->c_ospeed = obaud;
411
5f519d72 412#ifdef BOTHER
78137e3b 413 /* If the user asked for a precise weird speed give a precise weird
a1d51aa2 414 answer. If they asked for a Bfoo speed they may have problems
78137e3b
AC
415 digesting non-exact replies so fuzz a bit */
416
417 if ((termios->c_cflag & CBAUD) == BOTHER)
418 oclose = 0;
419 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
420 iclose = 0;
421 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
422 ibinput = 1; /* An input speed was specified */
5f519d72 423#endif
edc6afc5 424 termios->c_cflag &= ~CBAUD;
edc6afc5 425
5f519d72
AC
426 /*
427 * Our goal is to find a close match to the standard baud rate
428 * returned. Walk the baud rate table and if we get a very close
429 * match then report back the speed as a POSIX Bxxxx value by
430 * preference
431 */
432
edc6afc5 433 do {
75e8b71d
MR
434 if (obaud - oclose <= baud_table[i] &&
435 obaud + oclose >= baud_table[i]) {
edc6afc5 436 termios->c_cflag |= baud_bits[i];
78137e3b 437 ofound = i;
edc6afc5 438 }
75e8b71d
MR
439 if (ibaud - iclose <= baud_table[i] &&
440 ibaud + iclose >= baud_table[i]) {
441 /* For the case input == output don't set IBAUD bits
442 if the user didn't do so */
5f519d72
AC
443 if (ofound == i && !ibinput)
444 ifound = i;
445#ifdef IBSHIFT
446 else {
447 ifound = i;
78137e3b 448 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
5f519d72
AC
449 }
450#endif
edc6afc5 451 }
6804396f 452 } while (++i < n_baud_table);
5f519d72
AC
453
454 /*
455 * If we found no match then use BOTHER if provided or warn
456 * the user their platform maintainer needs to wake up if not.
457 */
458#ifdef BOTHER
78137e3b 459 if (ofound == -1)
edc6afc5 460 termios->c_cflag |= BOTHER;
78137e3b
AC
461 /* Set exact input bits only if the input and output differ or the
462 user already did */
6804396f 463 if (ifound == -1 && (ibaud != obaud || ibinput))
edc6afc5 464 termios->c_cflag |= (BOTHER << IBSHIFT);
5f519d72
AC
465#else
466 if (ifound == -1 || ofound == -1) {
9074d963 467 printk_once(KERN_WARNING "tty: Unable to return correct "
5f519d72
AC
468 "speed data as your architecture needs updating.\n");
469 }
470#endif
edc6afc5 471}
edc6afc5
AC
472EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
473
d81ed103
AC
474/**
475 * tty_encode_baud_rate - set baud rate of the tty
476 * @ibaud: input baud rate
477 * @obad: output baud rate
478 *
479 * Update the current termios data for the tty with the new speed
6a1c0680 480 * settings. The caller must hold the termios_rwsem for the tty in
d81ed103
AC
481 * question.
482 */
483
5f519d72
AC
484void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
485{
adc8d746 486 tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
5f519d72
AC
487}
488EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
edc6afc5 489
5f519d72
AC
490/**
491 * tty_termios_copy_hw - copy hardware settings
492 * @new: New termios
493 * @old: Old termios
494 *
25985edc 495 * Propagate the hardware specific terminal setting bits from
5f519d72
AC
496 * the old termios structure to the new one. This is used in cases
497 * where the hardware does not support reconfiguration or as a helper
498 * in some cases where only minimal reconfiguration is supported
499 */
500
501void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
502{
503 /* The bits a dumb device handles in software. Smart devices need
504 to always provide a set_termios method */
505 new->c_cflag &= HUPCL | CREAD | CLOCAL;
506 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
507 new->c_ispeed = old->c_ispeed;
508 new->c_ospeed = old->c_ospeed;
509}
5f519d72
AC
510EXPORT_SYMBOL(tty_termios_copy_hw);
511
bf5e5834
AC
512/**
513 * tty_termios_hw_change - check for setting change
514 * @a: termios
515 * @b: termios to compare
516 *
517 * Check if any of the bits that affect a dumb device have changed
518 * between the two termios structures, or a speed change is needed.
519 */
520
521int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
522{
523 if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
524 return 1;
525 if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
526 return 1;
527 return 0;
528}
529EXPORT_SYMBOL(tty_termios_hw_change);
530
af9b897e 531/**
8d075b19 532 * tty_set_termios - update termios values
af9b897e
AC
533 * @tty: tty to update
534 * @new_termios: desired new value
535 *
dbfcd851 536 * Perform updates to the termios values set on this terminal.
6460fbbf
PH
537 * A master pty's termios should never be set.
538 *
6a1c0680 539 * Locking: termios_rwsem
af9b897e
AC
540 */
541
b00f5c2d 542int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
1da177e4 543{
978e595f 544 struct ktermios old_termios;
1da177e4 545 struct tty_ldisc *ld;
355d95a1 546
6460fbbf
PH
547 WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
548 tty->driver->subtype == PTY_TYPE_MASTER);
1da177e4
LT
549 /*
550 * Perform the actual termios internal changes under lock.
551 */
355d95a1 552
1da177e4
LT
553
554 /* FIXME: we need to decide on some locking/ordering semantics
555 for the set_termios notification eventually */
6a1c0680 556 down_write(&tty->termios_rwsem);
adc8d746
AC
557 old_termios = tty->termios;
558 tty->termios = *new_termios;
559 unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
1da177e4 560
f34d7a5b 561 if (tty->ops->set_termios)
c961bfb1 562 tty->ops->set_termios(tty, &old_termios);
5f519d72 563 else
adc8d746 564 tty_termios_copy_hw(&tty->termios, &old_termios);
1da177e4
LT
565
566 ld = tty_ldisc_ref(tty);
567 if (ld != NULL) {
a352def2 568 if (ld->ops->set_termios)
c961bfb1 569 ld->ops->set_termios(tty, &old_termios);
1da177e4
LT
570 tty_ldisc_deref(ld);
571 }
6a1c0680 572 up_write(&tty->termios_rwsem);
8d075b19 573 return 0;
1da177e4 574}
b00f5c2d 575EXPORT_SYMBOL_GPL(tty_set_termios);
1da177e4 576
af9b897e
AC
577/**
578 * set_termios - set termios values for a tty
579 * @tty: terminal device
580 * @arg: user data
581 * @opt: option information
582 *
3a4fa0a2 583 * Helper function to prepare termios data and run necessary other
8d075b19 584 * functions before using tty_set_termios to do the actual changes.
af9b897e
AC
585 *
586 * Locking:
6a1c0680 587 * Called functions take ldisc and termios_rwsem locks
af9b897e
AC
588 */
589
355d95a1 590static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
1da177e4 591{
edc6afc5 592 struct ktermios tmp_termios;
1da177e4
LT
593 struct tty_ldisc *ld;
594 int retval = tty_check_change(tty);
595
596 if (retval)
597 return retval;
598
6a1c0680 599 down_read(&tty->termios_rwsem);
adc8d746 600 tmp_termios = tty->termios;
6a1c0680 601 up_read(&tty->termios_rwsem);
64bb6c5e 602
1da177e4 603 if (opt & TERMIOS_TERMIO) {
1da177e4
LT
604 if (user_termio_to_kernel_termios(&tmp_termios,
605 (struct termio __user *)arg))
606 return -EFAULT;
edc6afc5
AC
607#ifdef TCGETS2
608 } else if (opt & TERMIOS_OLD) {
edc6afc5 609 if (user_termios_to_kernel_termios_1(&tmp_termios,
64bb6c5e 610 (struct termios __user *)arg))
edc6afc5 611 return -EFAULT;
1da177e4
LT
612 } else {
613 if (user_termios_to_kernel_termios(&tmp_termios,
64bb6c5e 614 (struct termios2 __user *)arg))
1da177e4
LT
615 return -EFAULT;
616 }
64bb6c5e
AC
617#else
618 } else if (user_termios_to_kernel_termios(&tmp_termios,
619 (struct termios __user *)arg))
620 return -EFAULT;
621#endif
1da177e4 622
355d95a1
AC
623 /* If old style Bfoo values are used then load c_ispeed/c_ospeed
624 * with the real speed so its unconditionally usable */
edc6afc5
AC
625 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
626 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
627
1da177e4 628 ld = tty_ldisc_ref(tty);
355d95a1 629
1da177e4 630 if (ld != NULL) {
a352def2
AC
631 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
632 ld->ops->flush_buffer(tty);
1da177e4
LT
633 tty_ldisc_deref(ld);
634 }
355d95a1 635
1da177e4
LT
636 if (opt & TERMIOS_WAIT) {
637 tty_wait_until_sent(tty, 0);
638 if (signal_pending(current))
183d95cd 639 return -ERESTARTSYS;
1da177e4
LT
640 }
641
8d075b19 642 tty_set_termios(tty, &tmp_termios);
5f519d72
AC
643
644 /* FIXME: Arguably if tmp_termios == tty->termios AND the
645 actual requested termios was not tmp_termios then we may
646 want to return an error as no user requested change has
647 succeeded */
1da177e4
LT
648 return 0;
649}
650
26a2e20f
AC
651static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
652{
6a1c0680 653 down_read(&tty->termios_rwsem);
adc8d746 654 *kterm = tty->termios;
6a1c0680 655 up_read(&tty->termios_rwsem);
26a2e20f
AC
656}
657
658static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
659{
6a1c0680 660 down_read(&tty->termios_rwsem);
adc8d746 661 *kterm = tty->termios_locked;
6a1c0680 662 up_read(&tty->termios_rwsem);
26a2e20f
AC
663}
664
355d95a1 665static int get_termio(struct tty_struct *tty, struct termio __user *termio)
1da177e4 666{
26a2e20f
AC
667 struct ktermios kterm;
668 copy_termios(tty, &kterm);
669 if (kernel_termios_to_user_termio(termio, &kterm))
1da177e4
LT
670 return -EFAULT;
671 return 0;
672}
673
1d65b4a0
AC
674
675#ifdef TCGETX
676
677/**
678 * set_termiox - set termiox fields if possible
679 * @tty: terminal
680 * @arg: termiox structure from user
681 * @opt: option flags for ioctl type
682 *
683 * Implement the device calling points for the SYS5 termiox ioctl
684 * interface in Linux
685 */
686
687static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
688{
689 struct termiox tnew;
690 struct tty_ldisc *ld;
691
692 if (tty->termiox == NULL)
693 return -EINVAL;
694 if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
695 return -EFAULT;
696
697 ld = tty_ldisc_ref(tty);
698 if (ld != NULL) {
699 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
700 ld->ops->flush_buffer(tty);
701 tty_ldisc_deref(ld);
702 }
703 if (opt & TERMIOS_WAIT) {
704 tty_wait_until_sent(tty, 0);
705 if (signal_pending(current))
183d95cd 706 return -ERESTARTSYS;
1d65b4a0
AC
707 }
708
6a1c0680 709 down_write(&tty->termios_rwsem);
1d65b4a0
AC
710 if (tty->ops->set_termiox)
711 tty->ops->set_termiox(tty, &tnew);
6a1c0680 712 up_write(&tty->termios_rwsem);
1d65b4a0
AC
713 return 0;
714}
715
716#endif
717
1da177e4
LT
718
719#ifdef TIOCGETP
720/*
721 * These are deprecated, but there is limited support..
722 *
723 * The "sg_flags" translation is a joke..
724 */
355d95a1 725static int get_sgflags(struct tty_struct *tty)
1da177e4
LT
726{
727 int flags = 0;
728
adc8d746
AC
729 if (!(tty->termios.c_lflag & ICANON)) {
730 if (tty->termios.c_lflag & ISIG)
1da177e4
LT
731 flags |= 0x02; /* cbreak */
732 else
733 flags |= 0x20; /* raw */
734 }
adc8d746 735 if (tty->termios.c_lflag & ECHO)
1da177e4 736 flags |= 0x08; /* echo */
adc8d746
AC
737 if (tty->termios.c_oflag & OPOST)
738 if (tty->termios.c_oflag & ONLCR)
1da177e4
LT
739 flags |= 0x10; /* crmod */
740 return flags;
741}
742
355d95a1 743static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
1da177e4
LT
744{
745 struct sgttyb tmp;
746
6a1c0680 747 down_read(&tty->termios_rwsem);
adc8d746
AC
748 tmp.sg_ispeed = tty->termios.c_ispeed;
749 tmp.sg_ospeed = tty->termios.c_ospeed;
750 tmp.sg_erase = tty->termios.c_cc[VERASE];
751 tmp.sg_kill = tty->termios.c_cc[VKILL];
1da177e4 752 tmp.sg_flags = get_sgflags(tty);
6a1c0680 753 up_read(&tty->termios_rwsem);
355d95a1 754
1da177e4
LT
755 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
756}
757
355d95a1 758static void set_sgflags(struct ktermios *termios, int flags)
1da177e4 759{
9833facf
AC
760 termios->c_iflag = ICRNL | IXON;
761 termios->c_oflag = 0;
762 termios->c_lflag = ISIG | ICANON;
1da177e4 763 if (flags & 0x02) { /* cbreak */
9833facf
AC
764 termios->c_iflag = 0;
765 termios->c_lflag &= ~ICANON;
1da177e4
LT
766 }
767 if (flags & 0x08) { /* echo */
9833facf 768 termios->c_lflag |= ECHO | ECHOE | ECHOK |
1da177e4
LT
769 ECHOCTL | ECHOKE | IEXTEN;
770 }
771 if (flags & 0x10) { /* crmod */
9833facf 772 termios->c_oflag |= OPOST | ONLCR;
1da177e4
LT
773 }
774 if (flags & 0x20) { /* raw */
9833facf
AC
775 termios->c_iflag = 0;
776 termios->c_lflag &= ~(ISIG | ICANON);
1da177e4 777 }
9833facf
AC
778 if (!(termios->c_lflag & ICANON)) {
779 termios->c_cc[VMIN] = 1;
780 termios->c_cc[VTIME] = 0;
1da177e4
LT
781 }
782}
783
af9b897e
AC
784/**
785 * set_sgttyb - set legacy terminal values
786 * @tty: tty structure
787 * @sgttyb: pointer to old style terminal structure
788 *
789 * Updates a terminal from the legacy BSD style terminal information
790 * structure.
791 *
6a1c0680 792 * Locking: termios_rwsem
af9b897e
AC
793 */
794
355d95a1 795static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
1da177e4
LT
796{
797 int retval;
798 struct sgttyb tmp;
edc6afc5 799 struct ktermios termios;
1da177e4
LT
800
801 retval = tty_check_change(tty);
802 if (retval)
803 return retval;
355d95a1 804
1da177e4
LT
805 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
806 return -EFAULT;
807
6a1c0680 808 down_write(&tty->termios_rwsem);
adc8d746 809 termios = tty->termios;
1da177e4
LT
810 termios.c_cc[VERASE] = tmp.sg_erase;
811 termios.c_cc[VKILL] = tmp.sg_kill;
812 set_sgflags(&termios, tmp.sg_flags);
edc6afc5
AC
813 /* Try and encode into Bfoo format */
814#ifdef BOTHER
355d95a1
AC
815 tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
816 termios.c_ospeed);
edc6afc5 817#endif
6a1c0680 818 up_write(&tty->termios_rwsem);
8d075b19 819 tty_set_termios(tty, &termios);
1da177e4
LT
820 return 0;
821}
822#endif
823
824#ifdef TIOCGETC
355d95a1 825static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
1da177e4
LT
826{
827 struct tchars tmp;
828
6a1c0680 829 down_read(&tty->termios_rwsem);
adc8d746
AC
830 tmp.t_intrc = tty->termios.c_cc[VINTR];
831 tmp.t_quitc = tty->termios.c_cc[VQUIT];
832 tmp.t_startc = tty->termios.c_cc[VSTART];
833 tmp.t_stopc = tty->termios.c_cc[VSTOP];
834 tmp.t_eofc = tty->termios.c_cc[VEOF];
835 tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */
6a1c0680 836 up_read(&tty->termios_rwsem);
1da177e4
LT
837 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
838}
839
355d95a1 840static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
1da177e4
LT
841{
842 struct tchars tmp;
843
844 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
845 return -EFAULT;
6a1c0680 846 down_write(&tty->termios_rwsem);
adc8d746
AC
847 tty->termios.c_cc[VINTR] = tmp.t_intrc;
848 tty->termios.c_cc[VQUIT] = tmp.t_quitc;
849 tty->termios.c_cc[VSTART] = tmp.t_startc;
850 tty->termios.c_cc[VSTOP] = tmp.t_stopc;
851 tty->termios.c_cc[VEOF] = tmp.t_eofc;
852 tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
6a1c0680 853 up_write(&tty->termios_rwsem);
1da177e4
LT
854 return 0;
855}
856#endif
857
858#ifdef TIOCGLTC
355d95a1 859static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
1da177e4
LT
860{
861 struct ltchars tmp;
862
6a1c0680 863 down_read(&tty->termios_rwsem);
adc8d746 864 tmp.t_suspc = tty->termios.c_cc[VSUSP];
355d95a1 865 /* what is dsuspc anyway? */
adc8d746
AC
866 tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
867 tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
355d95a1 868 /* what is flushc anyway? */
adc8d746
AC
869 tmp.t_flushc = tty->termios.c_cc[VEOL2];
870 tmp.t_werasc = tty->termios.c_cc[VWERASE];
871 tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
6a1c0680 872 up_read(&tty->termios_rwsem);
1da177e4
LT
873 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
874}
875
355d95a1 876static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
1da177e4
LT
877{
878 struct ltchars tmp;
879
880 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
881 return -EFAULT;
882
6a1c0680 883 down_write(&tty->termios_rwsem);
adc8d746 884 tty->termios.c_cc[VSUSP] = tmp.t_suspc;
355d95a1 885 /* what is dsuspc anyway? */
adc8d746
AC
886 tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
887 tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
355d95a1 888 /* what is flushc anyway? */
adc8d746
AC
889 tty->termios.c_cc[VEOL2] = tmp.t_flushc;
890 tty->termios.c_cc[VWERASE] = tmp.t_werasc;
891 tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
6a1c0680 892 up_write(&tty->termios_rwsem);
1da177e4
LT
893 return 0;
894}
895#endif
896
1c2630cc
AC
897/**
898 * tty_change_softcar - carrier change ioctl helper
899 * @tty: tty to update
900 * @arg: enable/disable CLOCAL
901 *
902 * Perform a change to the CLOCAL state and call into the driver
6a1c0680 903 * layer to make it visible. All done with the termios rwsem
1c2630cc
AC
904 */
905
906static int tty_change_softcar(struct tty_struct *tty, int arg)
907{
908 int ret = 0;
909 int bit = arg ? CLOCAL : 0;
f34d7a5b 910 struct ktermios old;
1c2630cc 911
6a1c0680 912 down_write(&tty->termios_rwsem);
adc8d746
AC
913 old = tty->termios;
914 tty->termios.c_cflag &= ~CLOCAL;
915 tty->termios.c_cflag |= bit;
f34d7a5b
AC
916 if (tty->ops->set_termios)
917 tty->ops->set_termios(tty, &old);
adc8d746 918 if ((tty->termios.c_cflag & CLOCAL) != bit)
1c2630cc 919 ret = -EINVAL;
6a1c0680 920 up_write(&tty->termios_rwsem);
1c2630cc
AC
921 return ret;
922}
923
0fc00e24
AC
924/**
925 * tty_mode_ioctl - mode related ioctls
926 * @tty: tty for the ioctl
927 * @file: file pointer for the tty
928 * @cmd: command
929 * @arg: ioctl argument
930 *
931 * Perform non line discipline specific mode control ioctls. This
932 * is designed to be called by line disciplines to ensure they provide
933 * consistent mode setting.
934 */
935
355d95a1 936int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
0fc00e24 937 unsigned int cmd, unsigned long arg)
1da177e4 938{
355d95a1 939 struct tty_struct *real_tty;
1da177e4 940 void __user *p = (void __user *)arg;
8f520021 941 int ret = 0;
26a2e20f 942 struct ktermios kterm;
1da177e4 943
8d075b19
AC
944 BUG_ON(file == NULL);
945
1da177e4
LT
946 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
947 tty->driver->subtype == PTY_TYPE_MASTER)
948 real_tty = tty->link;
949 else
950 real_tty = tty;
951
952 switch (cmd) {
953#ifdef TIOCGETP
355d95a1
AC
954 case TIOCGETP:
955 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
956 case TIOCSETP:
957 case TIOCSETN:
958 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
1da177e4
LT
959#endif
960#ifdef TIOCGETC
355d95a1
AC
961 case TIOCGETC:
962 return get_tchars(real_tty, p);
963 case TIOCSETC:
964 return set_tchars(real_tty, p);
1da177e4
LT
965#endif
966#ifdef TIOCGLTC
355d95a1
AC
967 case TIOCGLTC:
968 return get_ltchars(real_tty, p);
969 case TIOCSLTC:
970 return set_ltchars(real_tty, p);
1da177e4 971#endif
355d95a1
AC
972 case TCSETSF:
973 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
974 case TCSETSW:
975 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
976 case TCSETS:
977 return set_termios(real_tty, p, TERMIOS_OLD);
edc6afc5 978#ifndef TCGETS2
355d95a1 979 case TCGETS:
26a2e20f
AC
980 copy_termios(real_tty, &kterm);
981 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
8f520021 982 ret = -EFAULT;
8f520021 983 return ret;
edc6afc5 984#else
355d95a1 985 case TCGETS:
26a2e20f
AC
986 copy_termios(real_tty, &kterm);
987 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
8f520021 988 ret = -EFAULT;
8f520021 989 return ret;
355d95a1 990 case TCGETS2:
26a2e20f
AC
991 copy_termios(real_tty, &kterm);
992 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
8f520021 993 ret = -EFAULT;
8f520021 994 return ret;
355d95a1
AC
995 case TCSETSF2:
996 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
997 case TCSETSW2:
998 return set_termios(real_tty, p, TERMIOS_WAIT);
999 case TCSETS2:
1000 return set_termios(real_tty, p, 0);
edc6afc5 1001#endif
355d95a1
AC
1002 case TCGETA:
1003 return get_termio(real_tty, p);
1004 case TCSETAF:
1005 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
1006 case TCSETAW:
1007 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
1008 case TCSETA:
1009 return set_termios(real_tty, p, TERMIOS_TERMIO);
0fc00e24 1010#ifndef TCGETS2
355d95a1 1011 case TIOCGLCKTRMIOS:
26a2e20f
AC
1012 copy_termios_locked(real_tty, &kterm);
1013 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
8f520021 1014 ret = -EFAULT;
8f520021 1015 return ret;
355d95a1
AC
1016 case TIOCSLCKTRMIOS:
1017 if (!capable(CAP_SYS_ADMIN))
1018 return -EPERM;
26a2e20f
AC
1019 copy_termios_locked(real_tty, &kterm);
1020 if (user_termios_to_kernel_termios(&kterm,
355d95a1 1021 (struct termios __user *) arg))
26a2e20f 1022 return -EFAULT;
6a1c0680 1023 down_write(&real_tty->termios_rwsem);
adc8d746 1024 real_tty->termios_locked = kterm;
6a1c0680 1025 up_write(&real_tty->termios_rwsem);
26a2e20f 1026 return 0;
0fc00e24 1027#else
355d95a1 1028 case TIOCGLCKTRMIOS:
26a2e20f
AC
1029 copy_termios_locked(real_tty, &kterm);
1030 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
8f520021 1031 ret = -EFAULT;
8f520021 1032 return ret;
355d95a1
AC
1033 case TIOCSLCKTRMIOS:
1034 if (!capable(CAP_SYS_ADMIN))
26a2e20f
AC
1035 return -EPERM;
1036 copy_termios_locked(real_tty, &kterm);
1037 if (user_termios_to_kernel_termios_1(&kterm,
355d95a1 1038 (struct termios __user *) arg))
26a2e20f 1039 return -EFAULT;
6a1c0680 1040 down_write(&real_tty->termios_rwsem);
adc8d746 1041 real_tty->termios_locked = kterm;
6a1c0680 1042 up_write(&real_tty->termios_rwsem);
8f520021 1043 return ret;
0fc00e24 1044#endif
1d65b4a0 1045#ifdef TCGETX
5dca607b
MF
1046 case TCGETX: {
1047 struct termiox ktermx;
1d65b4a0
AC
1048 if (real_tty->termiox == NULL)
1049 return -EINVAL;
6a1c0680 1050 down_read(&real_tty->termios_rwsem);
26a2e20f 1051 memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
6a1c0680 1052 up_read(&real_tty->termios_rwsem);
26a2e20f
AC
1053 if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
1054 ret = -EFAULT;
8f520021 1055 return ret;
5dca607b 1056 }
1d65b4a0
AC
1057 case TCSETX:
1058 return set_termiox(real_tty, p, 0);
1059 case TCSETXW:
1060 return set_termiox(real_tty, p, TERMIOS_WAIT);
1061 case TCSETXF:
1062 return set_termiox(real_tty, p, TERMIOS_FLUSH);
1063#endif
355d95a1 1064 case TIOCGSOFTCAR:
26a2e20f
AC
1065 copy_termios(real_tty, &kterm);
1066 ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
355d95a1 1067 (int __user *)arg);
8f520021 1068 return ret;
355d95a1
AC
1069 case TIOCSSOFTCAR:
1070 if (get_user(arg, (unsigned int __user *) arg))
1071 return -EFAULT;
f753f327 1072 return tty_change_softcar(real_tty, arg);
355d95a1
AC
1073 default:
1074 return -ENOIOCTLCMD;
0fc00e24
AC
1075 }
1076}
0fc00e24
AC
1077EXPORT_SYMBOL_GPL(tty_mode_ioctl);
1078
e7f3880c
PH
1079
1080/* Caller guarantees ldisc reference is held */
1081static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
0fc00e24 1082{
e7f3880c 1083 struct tty_ldisc *ld = tty->ldisc;
0fc00e24 1084
0fc00e24
AC
1085 switch (arg) {
1086 case TCIFLUSH:
a1bf9584 1087 if (ld && ld->ops->flush_buffer) {
a352def2 1088 ld->ops->flush_buffer(tty);
a1bf9584
IZ
1089 tty_unthrottle(tty);
1090 }
0fc00e24
AC
1091 break;
1092 case TCIOFLUSH:
a1bf9584 1093 if (ld && ld->ops->flush_buffer) {
a352def2 1094 ld->ops->flush_buffer(tty);
a1bf9584
IZ
1095 tty_unthrottle(tty);
1096 }
0fc00e24
AC
1097 /* fall through */
1098 case TCOFLUSH:
f34d7a5b 1099 tty_driver_flush_buffer(tty);
0fc00e24
AC
1100 break;
1101 default:
0fc00e24
AC
1102 return -EINVAL;
1103 }
0fc00e24
AC
1104 return 0;
1105}
e7f3880c
PH
1106
1107int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
1108{
1109 struct tty_ldisc *ld;
1110 int retval = tty_check_change(tty);
1111 if (retval)
1112 return retval;
1113
1114 ld = tty_ldisc_ref_wait(tty);
1115 retval = __tty_perform_flush(tty, arg);
1116 if (ld)
1117 tty_ldisc_deref(ld);
1118 return retval;
1119}
0fc00e24
AC
1120EXPORT_SYMBOL_GPL(tty_perform_flush);
1121
47afa7a5 1122int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
0fc00e24
AC
1123 unsigned int cmd, unsigned long arg)
1124{
0fc00e24
AC
1125 int retval;
1126
0fc00e24 1127 switch (cmd) {
355d95a1
AC
1128 case TCXONC:
1129 retval = tty_check_change(tty);
1130 if (retval)
1131 return retval;
1132 switch (arg) {
1133 case TCOOFF:
c545b66c 1134 spin_lock_irq(&tty->flow_lock);
355d95a1
AC
1135 if (!tty->flow_stopped) {
1136 tty->flow_stopped = 1;
c545b66c 1137 __stop_tty(tty);
1da177e4 1138 }
c545b66c 1139 spin_unlock_irq(&tty->flow_lock);
355d95a1
AC
1140 break;
1141 case TCOON:
c545b66c 1142 spin_lock_irq(&tty->flow_lock);
355d95a1
AC
1143 if (tty->flow_stopped) {
1144 tty->flow_stopped = 0;
c545b66c 1145 __start_tty(tty);
355d95a1 1146 }
c545b66c 1147 spin_unlock_irq(&tty->flow_lock);
355d95a1
AC
1148 break;
1149 case TCIOFF:
1150 if (STOP_CHAR(tty) != __DISABLED_CHAR)
c274f6ef 1151 retval = tty_send_xchar(tty, STOP_CHAR(tty));
355d95a1
AC
1152 break;
1153 case TCION:
1154 if (START_CHAR(tty) != __DISABLED_CHAR)
c274f6ef 1155 retval = tty_send_xchar(tty, START_CHAR(tty));
355d95a1 1156 break;
1da177e4 1157 default:
355d95a1 1158 return -EINVAL;
1da177e4 1159 }
c274f6ef 1160 return retval;
355d95a1 1161 case TCFLSH:
5cec7bf6
PH
1162 retval = tty_check_change(tty);
1163 if (retval)
1164 return retval;
e7f3880c 1165 return __tty_perform_flush(tty, arg);
355d95a1
AC
1166 default:
1167 /* Try the mode commands */
1168 return tty_mode_ioctl(tty, file, cmd, arg);
1169 }
1da177e4 1170}
47afa7a5 1171EXPORT_SYMBOL(n_tty_ioctl_helper);
8193c429
TM
1172
1173#ifdef CONFIG_COMPAT
1174long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
1175 unsigned int cmd, unsigned long arg)
1176{
1177 switch (cmd) {
1178 case TIOCGLCKTRMIOS:
1179 case TIOCSLCKTRMIOS:
1180 return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg));
1181 default:
1182 return -ENOIOCTLCMD;
1183 }
1184}
1185EXPORT_SYMBOL(n_tty_compat_ioctl_helper);
1186#endif
1187