USB: serial: fix infinite wait_until_sent timeout
[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
632f32e2 533static int 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 552 if (tty->ops->set_termios)
c961bfb1 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 559 if (ld->ops->set_termios)
c961bfb1 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
LT
565}
566
af9b897e
AC
567/**
568 * set_termios - set termios values for a tty
569 * @tty: terminal device
570 * @arg: user data
571 * @opt: option information
572 *
3a4fa0a2 573 * Helper function to prepare termios data and run necessary other
8d075b19 574 * functions before using tty_set_termios to do the actual changes.
af9b897e
AC
575 *
576 * Locking:
6a1c0680 577 * Called functions take ldisc and termios_rwsem locks
af9b897e
AC
578 */
579
355d95a1 580static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
1da177e4 581{
edc6afc5 582 struct ktermios tmp_termios;
1da177e4
LT
583 struct tty_ldisc *ld;
584 int retval = tty_check_change(tty);
585
586 if (retval)
587 return retval;
588
6a1c0680 589 down_read(&tty->termios_rwsem);
adc8d746 590 tmp_termios = tty->termios;
6a1c0680 591 up_read(&tty->termios_rwsem);
64bb6c5e 592
1da177e4 593 if (opt & TERMIOS_TERMIO) {
1da177e4
LT
594 if (user_termio_to_kernel_termios(&tmp_termios,
595 (struct termio __user *)arg))
596 return -EFAULT;
edc6afc5
AC
597#ifdef TCGETS2
598 } else if (opt & TERMIOS_OLD) {
edc6afc5 599 if (user_termios_to_kernel_termios_1(&tmp_termios,
64bb6c5e 600 (struct termios __user *)arg))
edc6afc5 601 return -EFAULT;
1da177e4
LT
602 } else {
603 if (user_termios_to_kernel_termios(&tmp_termios,
64bb6c5e 604 (struct termios2 __user *)arg))
1da177e4
LT
605 return -EFAULT;
606 }
64bb6c5e
AC
607#else
608 } else if (user_termios_to_kernel_termios(&tmp_termios,
609 (struct termios __user *)arg))
610 return -EFAULT;
611#endif
1da177e4 612
355d95a1
AC
613 /* If old style Bfoo values are used then load c_ispeed/c_ospeed
614 * with the real speed so its unconditionally usable */
edc6afc5
AC
615 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
616 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
617
1da177e4 618 ld = tty_ldisc_ref(tty);
355d95a1 619
1da177e4 620 if (ld != NULL) {
a352def2
AC
621 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
622 ld->ops->flush_buffer(tty);
1da177e4
LT
623 tty_ldisc_deref(ld);
624 }
355d95a1 625
1da177e4
LT
626 if (opt & TERMIOS_WAIT) {
627 tty_wait_until_sent(tty, 0);
628 if (signal_pending(current))
183d95cd 629 return -ERESTARTSYS;
1da177e4
LT
630 }
631
8d075b19 632 tty_set_termios(tty, &tmp_termios);
5f519d72
AC
633
634 /* FIXME: Arguably if tmp_termios == tty->termios AND the
635 actual requested termios was not tmp_termios then we may
636 want to return an error as no user requested change has
637 succeeded */
1da177e4
LT
638 return 0;
639}
640
26a2e20f
AC
641static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
642{
6a1c0680 643 down_read(&tty->termios_rwsem);
adc8d746 644 *kterm = tty->termios;
6a1c0680 645 up_read(&tty->termios_rwsem);
26a2e20f
AC
646}
647
648static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
649{
6a1c0680 650 down_read(&tty->termios_rwsem);
adc8d746 651 *kterm = tty->termios_locked;
6a1c0680 652 up_read(&tty->termios_rwsem);
26a2e20f
AC
653}
654
355d95a1 655static int get_termio(struct tty_struct *tty, struct termio __user *termio)
1da177e4 656{
26a2e20f
AC
657 struct ktermios kterm;
658 copy_termios(tty, &kterm);
659 if (kernel_termios_to_user_termio(termio, &kterm))
1da177e4
LT
660 return -EFAULT;
661 return 0;
662}
663
1d65b4a0
AC
664
665#ifdef TCGETX
666
667/**
668 * set_termiox - set termiox fields if possible
669 * @tty: terminal
670 * @arg: termiox structure from user
671 * @opt: option flags for ioctl type
672 *
673 * Implement the device calling points for the SYS5 termiox ioctl
674 * interface in Linux
675 */
676
677static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
678{
679 struct termiox tnew;
680 struct tty_ldisc *ld;
681
682 if (tty->termiox == NULL)
683 return -EINVAL;
684 if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
685 return -EFAULT;
686
687 ld = tty_ldisc_ref(tty);
688 if (ld != NULL) {
689 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
690 ld->ops->flush_buffer(tty);
691 tty_ldisc_deref(ld);
692 }
693 if (opt & TERMIOS_WAIT) {
694 tty_wait_until_sent(tty, 0);
695 if (signal_pending(current))
183d95cd 696 return -ERESTARTSYS;
1d65b4a0
AC
697 }
698
6a1c0680 699 down_write(&tty->termios_rwsem);
1d65b4a0
AC
700 if (tty->ops->set_termiox)
701 tty->ops->set_termiox(tty, &tnew);
6a1c0680 702 up_write(&tty->termios_rwsem);
1d65b4a0
AC
703 return 0;
704}
705
706#endif
707
1da177e4
LT
708
709#ifdef TIOCGETP
710/*
711 * These are deprecated, but there is limited support..
712 *
713 * The "sg_flags" translation is a joke..
714 */
355d95a1 715static int get_sgflags(struct tty_struct *tty)
1da177e4
LT
716{
717 int flags = 0;
718
adc8d746
AC
719 if (!(tty->termios.c_lflag & ICANON)) {
720 if (tty->termios.c_lflag & ISIG)
1da177e4
LT
721 flags |= 0x02; /* cbreak */
722 else
723 flags |= 0x20; /* raw */
724 }
adc8d746 725 if (tty->termios.c_lflag & ECHO)
1da177e4 726 flags |= 0x08; /* echo */
adc8d746
AC
727 if (tty->termios.c_oflag & OPOST)
728 if (tty->termios.c_oflag & ONLCR)
1da177e4
LT
729 flags |= 0x10; /* crmod */
730 return flags;
731}
732
355d95a1 733static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
1da177e4
LT
734{
735 struct sgttyb tmp;
736
6a1c0680 737 down_read(&tty->termios_rwsem);
adc8d746
AC
738 tmp.sg_ispeed = tty->termios.c_ispeed;
739 tmp.sg_ospeed = tty->termios.c_ospeed;
740 tmp.sg_erase = tty->termios.c_cc[VERASE];
741 tmp.sg_kill = tty->termios.c_cc[VKILL];
1da177e4 742 tmp.sg_flags = get_sgflags(tty);
6a1c0680 743 up_read(&tty->termios_rwsem);
355d95a1 744
1da177e4
LT
745 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
746}
747
355d95a1 748static void set_sgflags(struct ktermios *termios, int flags)
1da177e4 749{
9833facf
AC
750 termios->c_iflag = ICRNL | IXON;
751 termios->c_oflag = 0;
752 termios->c_lflag = ISIG | ICANON;
1da177e4 753 if (flags & 0x02) { /* cbreak */
9833facf
AC
754 termios->c_iflag = 0;
755 termios->c_lflag &= ~ICANON;
1da177e4
LT
756 }
757 if (flags & 0x08) { /* echo */
9833facf 758 termios->c_lflag |= ECHO | ECHOE | ECHOK |
1da177e4
LT
759 ECHOCTL | ECHOKE | IEXTEN;
760 }
761 if (flags & 0x10) { /* crmod */
9833facf 762 termios->c_oflag |= OPOST | ONLCR;
1da177e4
LT
763 }
764 if (flags & 0x20) { /* raw */
9833facf
AC
765 termios->c_iflag = 0;
766 termios->c_lflag &= ~(ISIG | ICANON);
1da177e4 767 }
9833facf
AC
768 if (!(termios->c_lflag & ICANON)) {
769 termios->c_cc[VMIN] = 1;
770 termios->c_cc[VTIME] = 0;
1da177e4
LT
771 }
772}
773
af9b897e
AC
774/**
775 * set_sgttyb - set legacy terminal values
776 * @tty: tty structure
777 * @sgttyb: pointer to old style terminal structure
778 *
779 * Updates a terminal from the legacy BSD style terminal information
780 * structure.
781 *
6a1c0680 782 * Locking: termios_rwsem
af9b897e
AC
783 */
784
355d95a1 785static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
1da177e4
LT
786{
787 int retval;
788 struct sgttyb tmp;
edc6afc5 789 struct ktermios termios;
1da177e4
LT
790
791 retval = tty_check_change(tty);
792 if (retval)
793 return retval;
355d95a1 794
1da177e4
LT
795 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
796 return -EFAULT;
797
6a1c0680 798 down_write(&tty->termios_rwsem);
adc8d746 799 termios = tty->termios;
1da177e4
LT
800 termios.c_cc[VERASE] = tmp.sg_erase;
801 termios.c_cc[VKILL] = tmp.sg_kill;
802 set_sgflags(&termios, tmp.sg_flags);
edc6afc5
AC
803 /* Try and encode into Bfoo format */
804#ifdef BOTHER
355d95a1
AC
805 tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
806 termios.c_ospeed);
edc6afc5 807#endif
6a1c0680 808 up_write(&tty->termios_rwsem);
8d075b19 809 tty_set_termios(tty, &termios);
1da177e4
LT
810 return 0;
811}
812#endif
813
814#ifdef TIOCGETC
355d95a1 815static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
1da177e4
LT
816{
817 struct tchars tmp;
818
6a1c0680 819 down_read(&tty->termios_rwsem);
adc8d746
AC
820 tmp.t_intrc = tty->termios.c_cc[VINTR];
821 tmp.t_quitc = tty->termios.c_cc[VQUIT];
822 tmp.t_startc = tty->termios.c_cc[VSTART];
823 tmp.t_stopc = tty->termios.c_cc[VSTOP];
824 tmp.t_eofc = tty->termios.c_cc[VEOF];
825 tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */
6a1c0680 826 up_read(&tty->termios_rwsem);
1da177e4
LT
827 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
828}
829
355d95a1 830static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
1da177e4
LT
831{
832 struct tchars tmp;
833
834 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
835 return -EFAULT;
6a1c0680 836 down_write(&tty->termios_rwsem);
adc8d746
AC
837 tty->termios.c_cc[VINTR] = tmp.t_intrc;
838 tty->termios.c_cc[VQUIT] = tmp.t_quitc;
839 tty->termios.c_cc[VSTART] = tmp.t_startc;
840 tty->termios.c_cc[VSTOP] = tmp.t_stopc;
841 tty->termios.c_cc[VEOF] = tmp.t_eofc;
842 tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
6a1c0680 843 up_write(&tty->termios_rwsem);
1da177e4
LT
844 return 0;
845}
846#endif
847
848#ifdef TIOCGLTC
355d95a1 849static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
1da177e4
LT
850{
851 struct ltchars tmp;
852
6a1c0680 853 down_read(&tty->termios_rwsem);
adc8d746 854 tmp.t_suspc = tty->termios.c_cc[VSUSP];
355d95a1 855 /* what is dsuspc anyway? */
adc8d746
AC
856 tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
857 tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
355d95a1 858 /* what is flushc anyway? */
adc8d746
AC
859 tmp.t_flushc = tty->termios.c_cc[VEOL2];
860 tmp.t_werasc = tty->termios.c_cc[VWERASE];
861 tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
6a1c0680 862 up_read(&tty->termios_rwsem);
1da177e4
LT
863 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
864}
865
355d95a1 866static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
1da177e4
LT
867{
868 struct ltchars tmp;
869
870 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
871 return -EFAULT;
872
6a1c0680 873 down_write(&tty->termios_rwsem);
adc8d746 874 tty->termios.c_cc[VSUSP] = tmp.t_suspc;
355d95a1 875 /* what is dsuspc anyway? */
adc8d746
AC
876 tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
877 tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
355d95a1 878 /* what is flushc anyway? */
adc8d746
AC
879 tty->termios.c_cc[VEOL2] = tmp.t_flushc;
880 tty->termios.c_cc[VWERASE] = tmp.t_werasc;
881 tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
6a1c0680 882 up_write(&tty->termios_rwsem);
1da177e4
LT
883 return 0;
884}
885#endif
886
1c2630cc
AC
887/**
888 * tty_change_softcar - carrier change ioctl helper
889 * @tty: tty to update
890 * @arg: enable/disable CLOCAL
891 *
892 * Perform a change to the CLOCAL state and call into the driver
6a1c0680 893 * layer to make it visible. All done with the termios rwsem
1c2630cc
AC
894 */
895
896static int tty_change_softcar(struct tty_struct *tty, int arg)
897{
898 int ret = 0;
899 int bit = arg ? CLOCAL : 0;
f34d7a5b 900 struct ktermios old;
1c2630cc 901
6a1c0680 902 down_write(&tty->termios_rwsem);
adc8d746
AC
903 old = tty->termios;
904 tty->termios.c_cflag &= ~CLOCAL;
905 tty->termios.c_cflag |= bit;
f34d7a5b
AC
906 if (tty->ops->set_termios)
907 tty->ops->set_termios(tty, &old);
adc8d746 908 if ((tty->termios.c_cflag & CLOCAL) != bit)
1c2630cc 909 ret = -EINVAL;
6a1c0680 910 up_write(&tty->termios_rwsem);
1c2630cc
AC
911 return ret;
912}
913
0fc00e24
AC
914/**
915 * tty_mode_ioctl - mode related ioctls
916 * @tty: tty for the ioctl
917 * @file: file pointer for the tty
918 * @cmd: command
919 * @arg: ioctl argument
920 *
921 * Perform non line discipline specific mode control ioctls. This
922 * is designed to be called by line disciplines to ensure they provide
923 * consistent mode setting.
924 */
925
355d95a1 926int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
0fc00e24 927 unsigned int cmd, unsigned long arg)
1da177e4 928{
355d95a1 929 struct tty_struct *real_tty;
1da177e4 930 void __user *p = (void __user *)arg;
8f520021 931 int ret = 0;
26a2e20f 932 struct ktermios kterm;
1da177e4 933
8d075b19
AC
934 BUG_ON(file == NULL);
935
1da177e4
LT
936 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
937 tty->driver->subtype == PTY_TYPE_MASTER)
938 real_tty = tty->link;
939 else
940 real_tty = tty;
941
942 switch (cmd) {
943#ifdef TIOCGETP
355d95a1
AC
944 case TIOCGETP:
945 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
946 case TIOCSETP:
947 case TIOCSETN:
948 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
1da177e4
LT
949#endif
950#ifdef TIOCGETC
355d95a1
AC
951 case TIOCGETC:
952 return get_tchars(real_tty, p);
953 case TIOCSETC:
954 return set_tchars(real_tty, p);
1da177e4
LT
955#endif
956#ifdef TIOCGLTC
355d95a1
AC
957 case TIOCGLTC:
958 return get_ltchars(real_tty, p);
959 case TIOCSLTC:
960 return set_ltchars(real_tty, p);
1da177e4 961#endif
355d95a1
AC
962 case TCSETSF:
963 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
964 case TCSETSW:
965 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
966 case TCSETS:
967 return set_termios(real_tty, p, TERMIOS_OLD);
edc6afc5 968#ifndef TCGETS2
355d95a1 969 case TCGETS:
26a2e20f
AC
970 copy_termios(real_tty, &kterm);
971 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
8f520021 972 ret = -EFAULT;
8f520021 973 return ret;
edc6afc5 974#else
355d95a1 975 case TCGETS:
26a2e20f
AC
976 copy_termios(real_tty, &kterm);
977 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
8f520021 978 ret = -EFAULT;
8f520021 979 return ret;
355d95a1 980 case TCGETS2:
26a2e20f
AC
981 copy_termios(real_tty, &kterm);
982 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
8f520021 983 ret = -EFAULT;
8f520021 984 return ret;
355d95a1
AC
985 case TCSETSF2:
986 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
987 case TCSETSW2:
988 return set_termios(real_tty, p, TERMIOS_WAIT);
989 case TCSETS2:
990 return set_termios(real_tty, p, 0);
edc6afc5 991#endif
355d95a1
AC
992 case TCGETA:
993 return get_termio(real_tty, p);
994 case TCSETAF:
995 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
996 case TCSETAW:
997 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
998 case TCSETA:
999 return set_termios(real_tty, p, TERMIOS_TERMIO);
0fc00e24 1000#ifndef TCGETS2
355d95a1 1001 case TIOCGLCKTRMIOS:
26a2e20f
AC
1002 copy_termios_locked(real_tty, &kterm);
1003 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
8f520021 1004 ret = -EFAULT;
8f520021 1005 return ret;
355d95a1
AC
1006 case TIOCSLCKTRMIOS:
1007 if (!capable(CAP_SYS_ADMIN))
1008 return -EPERM;
26a2e20f
AC
1009 copy_termios_locked(real_tty, &kterm);
1010 if (user_termios_to_kernel_termios(&kterm,
355d95a1 1011 (struct termios __user *) arg))
26a2e20f 1012 return -EFAULT;
6a1c0680 1013 down_write(&real_tty->termios_rwsem);
adc8d746 1014 real_tty->termios_locked = kterm;
6a1c0680 1015 up_write(&real_tty->termios_rwsem);
26a2e20f 1016 return 0;
0fc00e24 1017#else
355d95a1 1018 case TIOCGLCKTRMIOS:
26a2e20f
AC
1019 copy_termios_locked(real_tty, &kterm);
1020 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
8f520021 1021 ret = -EFAULT;
8f520021 1022 return ret;
355d95a1
AC
1023 case TIOCSLCKTRMIOS:
1024 if (!capable(CAP_SYS_ADMIN))
26a2e20f
AC
1025 return -EPERM;
1026 copy_termios_locked(real_tty, &kterm);
1027 if (user_termios_to_kernel_termios_1(&kterm,
355d95a1 1028 (struct termios __user *) arg))
26a2e20f 1029 return -EFAULT;
6a1c0680 1030 down_write(&real_tty->termios_rwsem);
adc8d746 1031 real_tty->termios_locked = kterm;
6a1c0680 1032 up_write(&real_tty->termios_rwsem);
8f520021 1033 return ret;
0fc00e24 1034#endif
1d65b4a0 1035#ifdef TCGETX
5dca607b
MF
1036 case TCGETX: {
1037 struct termiox ktermx;
1d65b4a0
AC
1038 if (real_tty->termiox == NULL)
1039 return -EINVAL;
6a1c0680 1040 down_read(&real_tty->termios_rwsem);
26a2e20f 1041 memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
6a1c0680 1042 up_read(&real_tty->termios_rwsem);
26a2e20f
AC
1043 if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
1044 ret = -EFAULT;
8f520021 1045 return ret;
5dca607b 1046 }
1d65b4a0
AC
1047 case TCSETX:
1048 return set_termiox(real_tty, p, 0);
1049 case TCSETXW:
1050 return set_termiox(real_tty, p, TERMIOS_WAIT);
1051 case TCSETXF:
1052 return set_termiox(real_tty, p, TERMIOS_FLUSH);
1053#endif
355d95a1 1054 case TIOCGSOFTCAR:
26a2e20f
AC
1055 copy_termios(real_tty, &kterm);
1056 ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
355d95a1 1057 (int __user *)arg);
8f520021 1058 return ret;
355d95a1
AC
1059 case TIOCSSOFTCAR:
1060 if (get_user(arg, (unsigned int __user *) arg))
1061 return -EFAULT;
f753f327 1062 return tty_change_softcar(real_tty, arg);
355d95a1
AC
1063 default:
1064 return -ENOIOCTLCMD;
0fc00e24
AC
1065 }
1066}
0fc00e24
AC
1067EXPORT_SYMBOL_GPL(tty_mode_ioctl);
1068
e7f3880c
PH
1069
1070/* Caller guarantees ldisc reference is held */
1071static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
0fc00e24 1072{
e7f3880c 1073 struct tty_ldisc *ld = tty->ldisc;
0fc00e24 1074
0fc00e24
AC
1075 switch (arg) {
1076 case TCIFLUSH:
a1bf9584 1077 if (ld && ld->ops->flush_buffer) {
a352def2 1078 ld->ops->flush_buffer(tty);
a1bf9584
IZ
1079 tty_unthrottle(tty);
1080 }
0fc00e24
AC
1081 break;
1082 case TCIOFLUSH:
a1bf9584 1083 if (ld && ld->ops->flush_buffer) {
a352def2 1084 ld->ops->flush_buffer(tty);
a1bf9584
IZ
1085 tty_unthrottle(tty);
1086 }
0fc00e24
AC
1087 /* fall through */
1088 case TCOFLUSH:
f34d7a5b 1089 tty_driver_flush_buffer(tty);
0fc00e24
AC
1090 break;
1091 default:
0fc00e24
AC
1092 return -EINVAL;
1093 }
0fc00e24
AC
1094 return 0;
1095}
e7f3880c
PH
1096
1097int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
1098{
1099 struct tty_ldisc *ld;
1100 int retval = tty_check_change(tty);
1101 if (retval)
1102 return retval;
1103
1104 ld = tty_ldisc_ref_wait(tty);
1105 retval = __tty_perform_flush(tty, arg);
1106 if (ld)
1107 tty_ldisc_deref(ld);
1108 return retval;
1109}
0fc00e24
AC
1110EXPORT_SYMBOL_GPL(tty_perform_flush);
1111
47afa7a5 1112int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
0fc00e24
AC
1113 unsigned int cmd, unsigned long arg)
1114{
0fc00e24
AC
1115 int retval;
1116
0fc00e24 1117 switch (cmd) {
355d95a1
AC
1118 case TCXONC:
1119 retval = tty_check_change(tty);
1120 if (retval)
1121 return retval;
1122 switch (arg) {
1123 case TCOOFF:
c545b66c 1124 spin_lock_irq(&tty->flow_lock);
355d95a1
AC
1125 if (!tty->flow_stopped) {
1126 tty->flow_stopped = 1;
c545b66c 1127 __stop_tty(tty);
1da177e4 1128 }
c545b66c 1129 spin_unlock_irq(&tty->flow_lock);
355d95a1
AC
1130 break;
1131 case TCOON:
c545b66c 1132 spin_lock_irq(&tty->flow_lock);
355d95a1
AC
1133 if (tty->flow_stopped) {
1134 tty->flow_stopped = 0;
c545b66c 1135 __start_tty(tty);
355d95a1 1136 }
c545b66c 1137 spin_unlock_irq(&tty->flow_lock);
355d95a1
AC
1138 break;
1139 case TCIOFF:
c274f6ef 1140 down_read(&tty->termios_rwsem);
355d95a1 1141 if (STOP_CHAR(tty) != __DISABLED_CHAR)
c274f6ef
PH
1142 retval = tty_send_xchar(tty, STOP_CHAR(tty));
1143 up_read(&tty->termios_rwsem);
355d95a1
AC
1144 break;
1145 case TCION:
c274f6ef 1146 down_read(&tty->termios_rwsem);
355d95a1 1147 if (START_CHAR(tty) != __DISABLED_CHAR)
c274f6ef
PH
1148 retval = tty_send_xchar(tty, START_CHAR(tty));
1149 up_read(&tty->termios_rwsem);
355d95a1 1150 break;
1da177e4 1151 default:
355d95a1 1152 return -EINVAL;
1da177e4 1153 }
c274f6ef 1154 return retval;
355d95a1 1155 case TCFLSH:
5cec7bf6
PH
1156 retval = tty_check_change(tty);
1157 if (retval)
1158 return retval;
e7f3880c 1159 return __tty_perform_flush(tty, arg);
355d95a1
AC
1160 default:
1161 /* Try the mode commands */
1162 return tty_mode_ioctl(tty, file, cmd, arg);
1163 }
1da177e4 1164}
47afa7a5 1165EXPORT_SYMBOL(n_tty_ioctl_helper);
8193c429
TM
1166
1167#ifdef CONFIG_COMPAT
1168long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
1169 unsigned int cmd, unsigned long arg)
1170{
1171 switch (cmd) {
1172 case TIOCGLCKTRMIOS:
1173 case TIOCSLCKTRMIOS:
1174 return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg));
1175 default:
1176 return -ENOIOCTLCMD;
1177 }
1178}
1179EXPORT_SYMBOL(n_tty_compat_ioctl_helper);
1180#endif
1181