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