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