blob: a408c8e487ec006147078f2f7d22b6bce88925bb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/char/tty_ioctl.c
3 *
4 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
5 *
6 * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
7 * which can be dynamically activated and de-activated by the line
8 * discipline handling modules (like SLIP).
9 */
10
11#include <linux/types.h>
12#include <linux/termios.h>
13#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/kernel.h>
16#include <linux/major.h>
17#include <linux/tty.h>
18#include <linux/fcntl.h>
19#include <linux/string.h>
20#include <linux/mm.h>
21#include <linux/module.h>
22#include <linux/bitops.h>
Arjan van de Ven5785c952006-09-29 02:00:43 -070023#include <linux/mutex.h>
Alan Cox0ee9cbb2008-04-30 00:53:32 -070024#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#include <asm/io.h>
27#include <asm/uaccess.h>
28#include <asm/system.h>
29
30#undef TTY_DEBUG_WAIT_UNTIL_SENT
31
32#undef DEBUG
33
34/*
35 * Internal flag options for termios setting behavior
36 */
37#define TERMIOS_FLUSH 1
38#define TERMIOS_WAIT 2
39#define TERMIOS_TERMIO 4
Alan Coxedc6afc2006-12-08 02:38:44 -080040#define TERMIOS_OLD 8
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Alan Coxaf9b8972006-08-27 01:24:01 -070042
Alan Coxd81ed102008-10-13 10:41:42 +010043/**
44 * tty_chars_in_buffer - characters pending
45 * @tty: terminal
46 *
47 * Return the number of bytes of data in the device private
48 * output queue. If no private method is supplied there is assumed
49 * to be no queue on the device.
50 */
51
Alan Coxf34d7a52008-04-30 00:54:13 -070052int tty_chars_in_buffer(struct tty_struct *tty)
53{
54 if (tty->ops->chars_in_buffer)
55 return tty->ops->chars_in_buffer(tty);
56 else
57 return 0;
58}
Alan Coxf34d7a52008-04-30 00:54:13 -070059EXPORT_SYMBOL(tty_chars_in_buffer);
60
Alan Coxd81ed102008-10-13 10:41:42 +010061/**
62 * tty_write_room - write queue space
63 * @tty: terminal
64 *
65 * Return the number of bytes that can be queued to this device
66 * at the present time. The result should be treated as a guarantee
67 * and the driver cannot offer a value it later shrinks by more than
68 * the number of bytes written. If no method is provided 2K is always
69 * returned and data may be lost as there will be no flow control.
70 */
71
Alan Coxf34d7a52008-04-30 00:54:13 -070072int tty_write_room(struct tty_struct *tty)
73{
74 if (tty->ops->write_room)
75 return tty->ops->write_room(tty);
76 return 2048;
77}
Alan Coxf34d7a52008-04-30 00:54:13 -070078EXPORT_SYMBOL(tty_write_room);
79
Alan Coxd81ed102008-10-13 10:41:42 +010080/**
81 * tty_driver_flush_buffer - discard internal buffer
82 * @tty: terminal
83 *
84 * Discard the internal output buffer for this device. If no method
85 * is provided then either the buffer cannot be hardware flushed or
86 * there is no buffer driver side.
87 */
Alan Coxf34d7a52008-04-30 00:54:13 -070088void tty_driver_flush_buffer(struct tty_struct *tty)
89{
90 if (tty->ops->flush_buffer)
91 tty->ops->flush_buffer(tty);
92}
Alan Coxf34d7a52008-04-30 00:54:13 -070093EXPORT_SYMBOL(tty_driver_flush_buffer);
94
Alan Coxd81ed102008-10-13 10:41:42 +010095/**
96 * tty_throttle - flow control
97 * @tty: terminal
98 *
99 * Indicate that a tty should stop transmitting data down the stack.
100 */
101
Alan Cox39c2e602008-04-30 00:54:18 -0700102void tty_throttle(struct tty_struct *tty)
103{
104 /* check TTY_THROTTLED first so it indicates our state */
105 if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
106 tty->ops->throttle)
107 tty->ops->throttle(tty);
108}
109EXPORT_SYMBOL(tty_throttle);
110
Alan Coxd81ed102008-10-13 10:41:42 +0100111/**
112 * tty_unthrottle - flow control
113 * @tty: terminal
114 *
115 * Indicate that a tty may continue transmitting data down the stack.
116 */
117
Alan Cox39c2e602008-04-30 00:54:18 -0700118void tty_unthrottle(struct tty_struct *tty)
119{
120 if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
121 tty->ops->unthrottle)
122 tty->ops->unthrottle(tty);
123}
124EXPORT_SYMBOL(tty_unthrottle);
Alan Coxf34d7a52008-04-30 00:54:13 -0700125
Alan Coxaf9b8972006-08-27 01:24:01 -0700126/**
127 * tty_wait_until_sent - wait for I/O to finish
128 * @tty: tty we are waiting for
129 * @timeout: how long we will wait
130 *
131 * Wait for characters pending in a tty driver to hit the wire, or
132 * for a timeout to occur (eg due to flow control)
133 *
134 * Locking: none
135 */
136
Alan Cox355d95a12008-02-08 04:18:48 -0800137void tty_wait_until_sent(struct tty_struct *tty, long timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
140 char buf[64];
Alan Cox355d95a12008-02-08 04:18:48 -0800141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
143#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 if (!timeout)
145 timeout = MAX_SCHEDULE_TIMEOUT;
Jiri Slaby5a52bd42007-07-15 23:40:18 -0700146 if (wait_event_interruptible_timeout(tty->write_wait,
Alan Coxf34d7a52008-04-30 00:54:13 -0700147 !tty_chars_in_buffer(tty), timeout) >= 0) {
148 if (tty->ops->wait_until_sent)
149 tty->ops->wait_until_sent(tty, timeout);
Alan Cox0ee9cbb2008-04-30 00:53:32 -0700150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152EXPORT_SYMBOL(tty_wait_until_sent);
153
Alan Coxd81ed102008-10-13 10:41:42 +0100154
155/*
156 * Termios Helper Methods
157 */
158
Alan Coxedc6afc2006-12-08 02:38:44 -0800159static void unset_locked_termios(struct ktermios *termios,
160 struct ktermios *old,
161 struct ktermios *locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
163 int i;
Alan Cox355d95a12008-02-08 04:18:48 -0800164
165#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 if (!locked) {
168 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
169 return;
170 }
171
172 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
173 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
174 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
175 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
176 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
Alan Cox355d95a12008-02-08 04:18:48 -0800177 for (i = 0; i < NCCS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 termios->c_cc[i] = locked->c_cc[i] ?
179 old->c_cc[i] : termios->c_cc[i];
Alan Coxedc6afc2006-12-08 02:38:44 -0800180 /* FIXME: What should we do for i/ospeed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181}
182
Alan Coxedc6afc2006-12-08 02:38:44 -0800183/*
184 * Routine which returns the baud rate of the tty
185 *
186 * Note that the baud_table needs to be kept in sync with the
187 * include/asm/termbits.h file.
188 */
189static const speed_t baud_table[] = {
190 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
191 9600, 19200, 38400, 57600, 115200, 230400, 460800,
192#ifdef __sparc__
193 76800, 153600, 307200, 614400, 921600
194#else
195 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
196 2500000, 3000000, 3500000, 4000000
197#endif
198};
199
200#ifndef __sparc__
201static const tcflag_t baud_bits[] = {
202 B0, B50, B75, B110, B134, B150, B200, B300, B600,
203 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
204 B57600, B115200, B230400, B460800, B500000, B576000,
205 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
206 B3000000, B3500000, B4000000
207};
208#else
209static const tcflag_t baud_bits[] = {
210 B0, B50, B75, B110, B134, B150, B200, B300, B600,
211 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
212 B57600, B115200, B230400, B460800, B76800, B153600,
213 B307200, B614400, B921600
214};
215#endif
216
217static int n_baud_table = ARRAY_SIZE(baud_table);
218
219/**
220 * tty_termios_baud_rate
221 * @termios: termios structure
222 *
223 * Convert termios baud rate data into a speed. This should be called
224 * with the termios lock held if this termios is a terminal termios
225 * structure. May change the termios data. Device drivers can call this
226 * function but should use ->c_[io]speed directly as they are updated.
227 *
228 * Locking: none
229 */
230
231speed_t tty_termios_baud_rate(struct ktermios *termios)
232{
233 unsigned int cbaud;
234
235 cbaud = termios->c_cflag & CBAUD;
236
237#ifdef BOTHER
238 /* Magic token for arbitary speed via c_ispeed/c_ospeed */
239 if (cbaud == BOTHER)
240 return termios->c_ospeed;
241#endif
242 if (cbaud & CBAUDEX) {
243 cbaud &= ~CBAUDEX;
244
245 if (cbaud < 1 || cbaud + 15 > n_baud_table)
246 termios->c_cflag &= ~CBAUDEX;
247 else
248 cbaud += 15;
249 }
250 return baud_table[cbaud];
251}
Alan Coxedc6afc2006-12-08 02:38:44 -0800252EXPORT_SYMBOL(tty_termios_baud_rate);
253
254/**
255 * tty_termios_input_baud_rate
256 * @termios: termios structure
257 *
258 * Convert termios baud rate data into a speed. This should be called
259 * with the termios lock held if this termios is a terminal termios
260 * structure. May change the termios data. Device drivers can call this
261 * function but should use ->c_[io]speed directly as they are updated.
262 *
263 * Locking: none
264 */
265
266speed_t tty_termios_input_baud_rate(struct ktermios *termios)
267{
268#ifdef IBSHIFT
269 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
270
271 if (cbaud == B0)
272 return tty_termios_baud_rate(termios);
273
274 /* Magic token for arbitary speed via c_ispeed*/
275 if (cbaud == BOTHER)
276 return termios->c_ispeed;
277
278 if (cbaud & CBAUDEX) {
279 cbaud &= ~CBAUDEX;
280
281 if (cbaud < 1 || cbaud + 15 > n_baud_table)
282 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
283 else
284 cbaud += 15;
285 }
286 return baud_table[cbaud];
287#else
288 return tty_termios_baud_rate(termios);
289#endif
290}
Alan Coxedc6afc2006-12-08 02:38:44 -0800291EXPORT_SYMBOL(tty_termios_input_baud_rate);
292
Alan Coxedc6afc2006-12-08 02:38:44 -0800293/**
294 * tty_termios_encode_baud_rate
Alan Cox78137e32007-02-10 01:45:57 -0800295 * @termios: ktermios structure holding user requested state
Alan Coxedc6afc2006-12-08 02:38:44 -0800296 * @ispeed: input speed
297 * @ospeed: output speed
298 *
299 * Encode the speeds set into the passed termios structure. This is
300 * used as a library helper for drivers os that they can report back
301 * the actual speed selected when it differs from the speed requested
302 *
Alan Cox78137e32007-02-10 01:45:57 -0800303 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
304 * we need to carefully set the bits when the user does not get the
305 * desired speed. We allow small margins and preserve as much of possible
306 * of the input intent to keep compatiblity.
Alan Coxedc6afc2006-12-08 02:38:44 -0800307 *
308 * Locking: Caller should hold termios lock. This is already held
309 * when calling this function from the driver termios handler.
Alan Cox5f519d72007-10-16 23:30:07 -0700310 *
311 * The ifdefs deal with platforms whose owners have yet to update them
312 * and will all go away once this is done.
Alan Coxedc6afc2006-12-08 02:38:44 -0800313 */
314
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700315void tty_termios_encode_baud_rate(struct ktermios *termios,
316 speed_t ibaud, speed_t obaud)
Alan Coxedc6afc2006-12-08 02:38:44 -0800317{
318 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800319 int ifound = -1, ofound = -1;
320 int iclose = ibaud/50, oclose = obaud/50;
321 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800322
Alan Cox5f519d72007-10-16 23:30:07 -0700323 if (obaud == 0) /* CD dropped */
324 ibaud = 0; /* Clear ibaud to be sure */
325
Alan Coxedc6afc2006-12-08 02:38:44 -0800326 termios->c_ispeed = ibaud;
327 termios->c_ospeed = obaud;
328
Alan Cox5f519d72007-10-16 23:30:07 -0700329#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800330 /* If the user asked for a precise weird speed give a precise weird
331 answer. If they asked for a Bfoo speed they many have problems
332 digesting non-exact replies so fuzz a bit */
333
334 if ((termios->c_cflag & CBAUD) == BOTHER)
335 oclose = 0;
336 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
337 iclose = 0;
338 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
339 ibinput = 1; /* An input speed was specified */
Alan Cox5f519d72007-10-16 23:30:07 -0700340#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800341 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800342
Alan Cox5f519d72007-10-16 23:30:07 -0700343 /*
344 * Our goal is to find a close match to the standard baud rate
345 * returned. Walk the baud rate table and if we get a very close
346 * match then report back the speed as a POSIX Bxxxx value by
347 * preference
348 */
349
Alan Coxedc6afc2006-12-08 02:38:44 -0800350 do {
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700351 if (obaud - oclose <= baud_table[i] &&
352 obaud + oclose >= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800353 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800354 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800355 }
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700356 if (ibaud - iclose <= baud_table[i] &&
357 ibaud + iclose >= baud_table[i]) {
358 /* For the case input == output don't set IBAUD bits
359 if the user didn't do so */
Alan Cox5f519d72007-10-16 23:30:07 -0700360 if (ofound == i && !ibinput)
361 ifound = i;
362#ifdef IBSHIFT
363 else {
364 ifound = i;
Alan Cox78137e32007-02-10 01:45:57 -0800365 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700366 }
367#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800368 }
Jiri Slaby68043962007-07-15 23:40:18 -0700369 } while (++i < n_baud_table);
Alan Cox5f519d72007-10-16 23:30:07 -0700370
371 /*
372 * If we found no match then use BOTHER if provided or warn
373 * the user their platform maintainer needs to wake up if not.
374 */
375#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800376 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800377 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800378 /* Set exact input bits only if the input and output differ or the
379 user already did */
Jiri Slaby68043962007-07-15 23:40:18 -0700380 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800381 termios->c_cflag |= (BOTHER << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700382#else
383 if (ifound == -1 || ofound == -1) {
384 static int warned;
385 if (!warned++)
386 printk(KERN_WARNING "tty: Unable to return correct "
387 "speed data as your architecture needs updating.\n");
388 }
389#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800390}
Alan Coxedc6afc2006-12-08 02:38:44 -0800391EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
392
Alan Coxd81ed102008-10-13 10:41:42 +0100393/**
394 * tty_encode_baud_rate - set baud rate of the tty
395 * @ibaud: input baud rate
396 * @obad: output baud rate
397 *
398 * Update the current termios data for the tty with the new speed
399 * settings. The caller must hold the termios_mutex for the tty in
400 * question.
401 */
402
Alan Cox5f519d72007-10-16 23:30:07 -0700403void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
404{
405 tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
406}
407EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
Alan Coxedc6afc2006-12-08 02:38:44 -0800408
409/**
410 * tty_get_baud_rate - get tty bit rates
411 * @tty: tty to query
412 *
413 * Returns the baud rate as an integer for this terminal. The
414 * termios lock must be held by the caller and the terminal bit
415 * flags may be updated.
416 *
417 * Locking: none
418 */
419
420speed_t tty_get_baud_rate(struct tty_struct *tty)
421{
422 speed_t baud = tty_termios_baud_rate(tty->termios);
423
424 if (baud == 38400 && tty->alt_speed) {
425 if (!tty->warned) {
426 printk(KERN_WARNING "Use of setserial/setrocket to "
427 "set SPD_* flags is deprecated\n");
428 tty->warned = 1;
429 }
430 baud = tty->alt_speed;
431 }
432
433 return baud;
434}
Alan Coxedc6afc2006-12-08 02:38:44 -0800435EXPORT_SYMBOL(tty_get_baud_rate);
436
Alan Coxaf9b8972006-08-27 01:24:01 -0700437/**
Alan Cox5f519d72007-10-16 23:30:07 -0700438 * tty_termios_copy_hw - copy hardware settings
439 * @new: New termios
440 * @old: Old termios
441 *
442 * Propogate the hardware specific terminal setting bits from
443 * the old termios structure to the new one. This is used in cases
444 * where the hardware does not support reconfiguration or as a helper
445 * in some cases where only minimal reconfiguration is supported
446 */
447
448void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
449{
450 /* The bits a dumb device handles in software. Smart devices need
451 to always provide a set_termios method */
452 new->c_cflag &= HUPCL | CREAD | CLOCAL;
453 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
454 new->c_ispeed = old->c_ispeed;
455 new->c_ospeed = old->c_ospeed;
456}
Alan Cox5f519d72007-10-16 23:30:07 -0700457EXPORT_SYMBOL(tty_termios_copy_hw);
458
459/**
Alan Coxbf5e5832008-01-08 14:55:51 +0000460 * tty_termios_hw_change - check for setting change
461 * @a: termios
462 * @b: termios to compare
463 *
464 * Check if any of the bits that affect a dumb device have changed
465 * between the two termios structures, or a speed change is needed.
466 */
467
468int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
469{
470 if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
471 return 1;
472 if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
473 return 1;
474 return 0;
475}
476EXPORT_SYMBOL(tty_termios_hw_change);
477
478/**
Alan Coxaf9b8972006-08-27 01:24:01 -0700479 * change_termios - update termios values
480 * @tty: tty to update
481 * @new_termios: desired new value
482 *
483 * Perform updates to the termios values set on this terminal. There
484 * is a bit of layering violation here with n_tty in terms of the
485 * internal knowledge of this function.
486 *
Alan Coxd81ed102008-10-13 10:41:42 +0100487 * Locking: termios_mutex
Alan Coxaf9b8972006-08-27 01:24:01 -0700488 */
489
Alan Cox355d95a12008-02-08 04:18:48 -0800490static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Alan Cox978e5952008-04-30 00:53:59 -0700492 struct ktermios old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 struct tty_ldisc *ld;
Alan Cox04f378b2008-04-30 00:53:29 -0700494 unsigned long flags;
Alan Cox355d95a12008-02-08 04:18:48 -0800495
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 /*
497 * Perform the actual termios internal changes under lock.
498 */
Alan Cox355d95a12008-02-08 04:18:48 -0800499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
501 /* FIXME: we need to decide on some locking/ordering semantics
502 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700503 mutex_lock(&tty->termios_mutex);
Alan Cox978e5952008-04-30 00:53:59 -0700504 old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 *tty->termios = *new_termios;
506 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 /* See if packet mode change of state. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (tty->link && tty->link->packet) {
510 int old_flow = ((old_termios.c_iflag & IXON) &&
511 (old_termios.c_cc[VSTOP] == '\023') &&
512 (old_termios.c_cc[VSTART] == '\021'));
513 int new_flow = (I_IXON(tty) &&
514 STOP_CHAR(tty) == '\023' &&
515 START_CHAR(tty) == '\021');
516 if (old_flow != new_flow) {
Alan Cox04f378b2008-04-30 00:53:29 -0700517 spin_lock_irqsave(&tty->ctrl_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
519 if (new_flow)
520 tty->ctrl_status |= TIOCPKT_DOSTOP;
521 else
522 tty->ctrl_status |= TIOCPKT_NOSTOP;
Alan Cox04f378b2008-04-30 00:53:29 -0700523 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 wake_up_interruptible(&tty->link->read_wait);
525 }
526 }
Alan Cox355d95a12008-02-08 04:18:48 -0800527
Alan Coxf34d7a52008-04-30 00:54:13 -0700528 if (tty->ops->set_termios)
529 (*tty->ops->set_termios)(tty, &old_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700530 else
531 tty_termios_copy_hw(tty->termios, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 ld = tty_ldisc_ref(tty);
534 if (ld != NULL) {
Alan Coxa352def2008-07-16 21:53:12 +0100535 if (ld->ops->set_termios)
536 (ld->ops->set_termios)(tty, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 tty_ldisc_deref(ld);
538 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700539 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540}
541
Alan Coxaf9b8972006-08-27 01:24:01 -0700542/**
543 * set_termios - set termios values for a tty
544 * @tty: terminal device
545 * @arg: user data
546 * @opt: option information
547 *
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200548 * Helper function to prepare termios data and run necessary other
Alan Coxaf9b8972006-08-27 01:24:01 -0700549 * functions before using change_termios to do the actual changes.
550 *
551 * Locking:
Alan Coxd81ed102008-10-13 10:41:42 +0100552 * Called functions take ldisc and termios_mutex locks
Alan Coxaf9b8972006-08-27 01:24:01 -0700553 */
554
Alan Cox355d95a12008-02-08 04:18:48 -0800555static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
Alan Coxedc6afc2006-12-08 02:38:44 -0800557 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 struct tty_ldisc *ld;
559 int retval = tty_check_change(tty);
560
561 if (retval)
562 return retval;
563
Alan Cox978e5952008-04-30 00:53:59 -0700564 mutex_lock(&tty->termios_mutex);
Alan Cox64bb6c52006-12-08 02:38:47 -0800565 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
Alan Cox978e5952008-04-30 00:53:59 -0700566 mutex_unlock(&tty->termios_mutex);
Alan Cox64bb6c52006-12-08 02:38:47 -0800567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (user_termio_to_kernel_termios(&tmp_termios,
570 (struct termio __user *)arg))
571 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800572#ifdef TCGETS2
573 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800574 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 (struct termios __user *)arg))
576 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800577 } else {
578 if (user_termios_to_kernel_termios(&tmp_termios,
579 (struct termios2 __user *)arg))
580 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800582#else
583 } else if (user_termios_to_kernel_termios(&tmp_termios,
584 (struct termios __user *)arg))
585 return -EFAULT;
586#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Alan Cox355d95a12008-02-08 04:18:48 -0800588 /* If old style Bfoo values are used then load c_ispeed/c_ospeed
589 * with the real speed so its unconditionally usable */
Alan Coxedc6afc2006-12-08 02:38:44 -0800590 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
591 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 ld = tty_ldisc_ref(tty);
Alan Cox355d95a12008-02-08 04:18:48 -0800594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 if (ld != NULL) {
Alan Coxa352def2008-07-16 21:53:12 +0100596 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
597 ld->ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 tty_ldisc_deref(ld);
599 }
Alan Cox355d95a12008-02-08 04:18:48 -0800600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 if (opt & TERMIOS_WAIT) {
602 tty_wait_until_sent(tty, 0);
603 if (signal_pending(current))
604 return -EINTR;
605 }
606
607 change_termios(tty, &tmp_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700608
609 /* FIXME: Arguably if tmp_termios == tty->termios AND the
610 actual requested termios was not tmp_termios then we may
611 want to return an error as no user requested change has
612 succeeded */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return 0;
614}
615
Alan Cox355d95a12008-02-08 04:18:48 -0800616static int get_termio(struct tty_struct *tty, struct termio __user *termio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
618 if (kernel_termios_to_user_termio(termio, tty->termios))
619 return -EFAULT;
620 return 0;
621}
622
Alan Cox1d65b4a2008-10-13 10:38:18 +0100623
624#ifdef TCGETX
625
626/**
627 * set_termiox - set termiox fields if possible
628 * @tty: terminal
629 * @arg: termiox structure from user
630 * @opt: option flags for ioctl type
631 *
632 * Implement the device calling points for the SYS5 termiox ioctl
633 * interface in Linux
634 */
635
636static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
637{
638 struct termiox tnew;
639 struct tty_ldisc *ld;
640
641 if (tty->termiox == NULL)
642 return -EINVAL;
643 if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
644 return -EFAULT;
645
646 ld = tty_ldisc_ref(tty);
647 if (ld != NULL) {
648 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
649 ld->ops->flush_buffer(tty);
650 tty_ldisc_deref(ld);
651 }
652 if (opt & TERMIOS_WAIT) {
653 tty_wait_until_sent(tty, 0);
654 if (signal_pending(current))
655 return -EINTR;
656 }
657
658 mutex_lock(&tty->termios_mutex);
659 if (tty->ops->set_termiox)
660 tty->ops->set_termiox(tty, &tnew);
661 mutex_unlock(&tty->termios_mutex);
662 return 0;
663}
664
665#endif
666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668#ifdef TIOCGETP
669/*
670 * These are deprecated, but there is limited support..
671 *
672 * The "sg_flags" translation is a joke..
673 */
Alan Cox355d95a12008-02-08 04:18:48 -0800674static int get_sgflags(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 int flags = 0;
677
678 if (!(tty->termios->c_lflag & ICANON)) {
679 if (tty->termios->c_lflag & ISIG)
680 flags |= 0x02; /* cbreak */
681 else
682 flags |= 0x20; /* raw */
683 }
684 if (tty->termios->c_lflag & ECHO)
685 flags |= 0x08; /* echo */
686 if (tty->termios->c_oflag & OPOST)
687 if (tty->termios->c_oflag & ONLCR)
688 flags |= 0x10; /* crmod */
689 return flags;
690}
691
Alan Cox355d95a12008-02-08 04:18:48 -0800692static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
694 struct sgttyb tmp;
695
Arjan van de Ven5785c952006-09-29 02:00:43 -0700696 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800697 tmp.sg_ispeed = tty->termios->c_ispeed;
698 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 tmp.sg_erase = tty->termios->c_cc[VERASE];
700 tmp.sg_kill = tty->termios->c_cc[VKILL];
701 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700702 mutex_unlock(&tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -0800703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
705}
706
Alan Cox355d95a12008-02-08 04:18:48 -0800707static void set_sgflags(struct ktermios *termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 termios->c_iflag = ICRNL | IXON;
710 termios->c_oflag = 0;
711 termios->c_lflag = ISIG | ICANON;
712 if (flags & 0x02) { /* cbreak */
713 termios->c_iflag = 0;
714 termios->c_lflag &= ~ICANON;
715 }
716 if (flags & 0x08) { /* echo */
717 termios->c_lflag |= ECHO | ECHOE | ECHOK |
718 ECHOCTL | ECHOKE | IEXTEN;
719 }
720 if (flags & 0x10) { /* crmod */
721 termios->c_oflag |= OPOST | ONLCR;
722 }
723 if (flags & 0x20) { /* raw */
724 termios->c_iflag = 0;
725 termios->c_lflag &= ~(ISIG | ICANON);
726 }
727 if (!(termios->c_lflag & ICANON)) {
728 termios->c_cc[VMIN] = 1;
729 termios->c_cc[VTIME] = 0;
730 }
731}
732
Alan Coxaf9b8972006-08-27 01:24:01 -0700733/**
734 * set_sgttyb - set legacy terminal values
735 * @tty: tty structure
736 * @sgttyb: pointer to old style terminal structure
737 *
738 * Updates a terminal from the legacy BSD style terminal information
739 * structure.
740 *
Alan Coxd81ed102008-10-13 10:41:42 +0100741 * Locking: termios_mutex
Alan Coxaf9b8972006-08-27 01:24:01 -0700742 */
743
Alan Cox355d95a12008-02-08 04:18:48 -0800744static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
746 int retval;
747 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800748 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 retval = tty_check_change(tty);
751 if (retval)
752 return retval;
Alan Cox355d95a12008-02-08 04:18:48 -0800753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
755 return -EFAULT;
756
Arjan van de Ven5785c952006-09-29 02:00:43 -0700757 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700758 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 termios.c_cc[VERASE] = tmp.sg_erase;
760 termios.c_cc[VKILL] = tmp.sg_kill;
761 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800762 /* Try and encode into Bfoo format */
763#ifdef BOTHER
Alan Cox355d95a12008-02-08 04:18:48 -0800764 tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
765 termios.c_ospeed);
Alan Coxedc6afc2006-12-08 02:38:44 -0800766#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700767 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 change_termios(tty, &termios);
769 return 0;
770}
771#endif
772
773#ifdef TIOCGETC
Alan Cox355d95a12008-02-08 04:18:48 -0800774static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 struct tchars tmp;
777
Alan Cox978e5952008-04-30 00:53:59 -0700778 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 tmp.t_intrc = tty->termios->c_cc[VINTR];
780 tmp.t_quitc = tty->termios->c_cc[VQUIT];
781 tmp.t_startc = tty->termios->c_cc[VSTART];
782 tmp.t_stopc = tty->termios->c_cc[VSTOP];
783 tmp.t_eofc = tty->termios->c_cc[VEOF];
784 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
Alan Cox978e5952008-04-30 00:53:59 -0700785 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
787}
788
Alan Cox355d95a12008-02-08 04:18:48 -0800789static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
791 struct tchars tmp;
792
793 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
794 return -EFAULT;
Alan Cox978e5952008-04-30 00:53:59 -0700795 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 tty->termios->c_cc[VINTR] = tmp.t_intrc;
797 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
798 tty->termios->c_cc[VSTART] = tmp.t_startc;
799 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
800 tty->termios->c_cc[VEOF] = tmp.t_eofc;
801 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
Alan Cox978e5952008-04-30 00:53:59 -0700802 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return 0;
804}
805#endif
806
807#ifdef TIOCGLTC
Alan Cox355d95a12008-02-08 04:18:48 -0800808static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
810 struct ltchars tmp;
811
Alan Cox978e5952008-04-30 00:53:59 -0700812 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 tmp.t_suspc = tty->termios->c_cc[VSUSP];
Alan Cox355d95a12008-02-08 04:18:48 -0800814 /* what is dsuspc anyway? */
815 tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
Alan Cox355d95a12008-02-08 04:18:48 -0800817 /* what is flushc anyway? */
818 tmp.t_flushc = tty->termios->c_cc[VEOL2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 tmp.t_werasc = tty->termios->c_cc[VWERASE];
820 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
Alan Cox978e5952008-04-30 00:53:59 -0700821 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
823}
824
Alan Cox355d95a12008-02-08 04:18:48 -0800825static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826{
827 struct ltchars tmp;
828
829 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
830 return -EFAULT;
831
Alan Cox978e5952008-04-30 00:53:59 -0700832 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
Alan Cox355d95a12008-02-08 04:18:48 -0800834 /* what is dsuspc anyway? */
835 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
Alan Cox355d95a12008-02-08 04:18:48 -0800837 /* what is flushc anyway? */
838 tty->termios->c_cc[VEOL2] = tmp.t_flushc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
840 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
Alan Cox978e5952008-04-30 00:53:59 -0700841 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 return 0;
843}
844#endif
845
Alan Coxaf9b8972006-08-27 01:24:01 -0700846/**
847 * send_prio_char - send priority character
848 *
849 * Send a high priority character to the tty even if stopped
850 *
Alan Cox5f412b22006-09-29 02:01:40 -0700851 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700853
Alan Cox5f412b22006-09-29 02:01:40 -0700854static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855{
856 int was_stopped = tty->stopped;
857
Alan Coxf34d7a52008-04-30 00:54:13 -0700858 if (tty->ops->send_xchar) {
859 tty->ops->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700860 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 }
Alan Cox5f412b22006-09-29 02:01:40 -0700862
Alan Cox9c1729d2007-07-15 23:39:43 -0700863 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700864 return -ERESTARTSYS;
865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 if (was_stopped)
867 start_tty(tty);
Alan Coxf34d7a52008-04-30 00:54:13 -0700868 tty->ops->write(tty, &ch, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (was_stopped)
870 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700871 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700872 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873}
874
Alan Cox0fc00e22007-11-07 01:24:56 -0800875/**
Alan Cox1c2630c2008-04-30 00:53:34 -0700876 * tty_change_softcar - carrier change ioctl helper
877 * @tty: tty to update
878 * @arg: enable/disable CLOCAL
879 *
880 * Perform a change to the CLOCAL state and call into the driver
881 * layer to make it visible. All done with the termios mutex
882 */
883
884static int tty_change_softcar(struct tty_struct *tty, int arg)
885{
886 int ret = 0;
887 int bit = arg ? CLOCAL : 0;
Alan Coxf34d7a52008-04-30 00:54:13 -0700888 struct ktermios old;
Alan Cox1c2630c2008-04-30 00:53:34 -0700889
890 mutex_lock(&tty->termios_mutex);
Alan Coxf34d7a52008-04-30 00:54:13 -0700891 old = *tty->termios;
Alan Cox1c2630c2008-04-30 00:53:34 -0700892 tty->termios->c_cflag &= ~CLOCAL;
893 tty->termios->c_cflag |= bit;
Alan Coxf34d7a52008-04-30 00:54:13 -0700894 if (tty->ops->set_termios)
895 tty->ops->set_termios(tty, &old);
Alan Cox1c2630c2008-04-30 00:53:34 -0700896 if ((tty->termios->c_cflag & CLOCAL) != bit)
897 ret = -EINVAL;
898 mutex_unlock(&tty->termios_mutex);
899 return ret;
900}
901
902/**
Alan Cox0fc00e22007-11-07 01:24:56 -0800903 * tty_mode_ioctl - mode related ioctls
904 * @tty: tty for the ioctl
905 * @file: file pointer for the tty
906 * @cmd: command
907 * @arg: ioctl argument
908 *
909 * Perform non line discipline specific mode control ioctls. This
910 * is designed to be called by line disciplines to ensure they provide
911 * consistent mode setting.
912 */
913
Alan Cox355d95a12008-02-08 04:18:48 -0800914int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -0800915 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
Alan Cox355d95a12008-02-08 04:18:48 -0800917 struct tty_struct *real_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 void __user *p = (void __user *)arg;
Alan Cox8f520022008-10-13 10:38:46 +0100919 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
922 tty->driver->subtype == PTY_TYPE_MASTER)
923 real_tty = tty->link;
924 else
925 real_tty = tty;
926
927 switch (cmd) {
928#ifdef TIOCGETP
Alan Cox355d95a12008-02-08 04:18:48 -0800929 case TIOCGETP:
930 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
931 case TIOCSETP:
932 case TIOCSETN:
933 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934#endif
935#ifdef TIOCGETC
Alan Cox355d95a12008-02-08 04:18:48 -0800936 case TIOCGETC:
937 return get_tchars(real_tty, p);
938 case TIOCSETC:
939 return set_tchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940#endif
941#ifdef TIOCGLTC
Alan Cox355d95a12008-02-08 04:18:48 -0800942 case TIOCGLTC:
943 return get_ltchars(real_tty, p);
944 case TIOCSLTC:
945 return set_ltchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946#endif
Alan Cox355d95a12008-02-08 04:18:48 -0800947 case TCSETSF:
948 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
949 case TCSETSW:
950 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
951 case TCSETS:
952 return set_termios(real_tty, p, TERMIOS_OLD);
Alan Coxedc6afc2006-12-08 02:38:44 -0800953#ifndef TCGETS2
Alan Cox355d95a12008-02-08 04:18:48 -0800954 case TCGETS:
Alan Cox8f520022008-10-13 10:38:46 +0100955 mutex_lock(&real_tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -0800956 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
Alan Cox8f520022008-10-13 10:38:46 +0100957 ret = -EFAULT;
958 mutex_unlock(&real_tty->termios_mutex);
959 return ret;
Alan Coxedc6afc2006-12-08 02:38:44 -0800960#else
Alan Cox355d95a12008-02-08 04:18:48 -0800961 case TCGETS:
Alan Cox8f520022008-10-13 10:38:46 +0100962 mutex_lock(&real_tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -0800963 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
Alan Cox8f520022008-10-13 10:38:46 +0100964 ret = -EFAULT;
965 mutex_unlock(&real_tty->termios_mutex);
966 return ret;
Alan Cox355d95a12008-02-08 04:18:48 -0800967 case TCGETS2:
Alan Cox8f520022008-10-13 10:38:46 +0100968 mutex_lock(&real_tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -0800969 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
Alan Cox8f520022008-10-13 10:38:46 +0100970 ret = -EFAULT;
971 mutex_unlock(&real_tty->termios_mutex);
972 return ret;
Alan Cox355d95a12008-02-08 04:18:48 -0800973 case TCSETSF2:
974 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
975 case TCSETSW2:
976 return set_termios(real_tty, p, TERMIOS_WAIT);
977 case TCSETS2:
978 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800979#endif
Alan Cox355d95a12008-02-08 04:18:48 -0800980 case TCGETA:
981 return get_termio(real_tty, p);
982 case TCSETAF:
983 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
984 case TCSETAW:
985 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
986 case TCSETA:
987 return set_termios(real_tty, p, TERMIOS_TERMIO);
Alan Cox0fc00e22007-11-07 01:24:56 -0800988#ifndef TCGETS2
Alan Cox355d95a12008-02-08 04:18:48 -0800989 case TIOCGLCKTRMIOS:
Alan Cox8f520022008-10-13 10:38:46 +0100990 mutex_lock(&real_tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -0800991 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
Alan Cox8f520022008-10-13 10:38:46 +0100992 ret = -EFAULT;
993 mutex_unlock(&real_tty->termios_mutex);
994 return ret;
Alan Cox355d95a12008-02-08 04:18:48 -0800995 case TIOCSLCKTRMIOS:
996 if (!capable(CAP_SYS_ADMIN))
997 return -EPERM;
Alan Cox8f520022008-10-13 10:38:46 +0100998 mutex_lock(&real_tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -0800999 if (user_termios_to_kernel_termios(real_tty->termios_locked,
1000 (struct termios __user *) arg))
Alan Cox8f520022008-10-13 10:38:46 +01001001 ret = -EFAULT;
1002 mutex_unlock(&real_tty->termios_mutex);
1003 return ret;
Alan Cox0fc00e22007-11-07 01:24:56 -08001004#else
Alan Cox355d95a12008-02-08 04:18:48 -08001005 case TIOCGLCKTRMIOS:
Alan Cox8f520022008-10-13 10:38:46 +01001006 mutex_lock(&real_tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -08001007 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
Alan Cox8f520022008-10-13 10:38:46 +01001008 ret = -EFAULT;
1009 mutex_unlock(&real_tty->termios_mutex);
1010 return ret;
Alan Cox355d95a12008-02-08 04:18:48 -08001011 case TIOCSLCKTRMIOS:
1012 if (!capable(CAP_SYS_ADMIN))
Alan Cox8f520022008-10-13 10:38:46 +01001013 ret = -EPERM;
1014 mutex_lock(&real_tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -08001015 if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
1016 (struct termios __user *) arg))
Alan Cox8f520022008-10-13 10:38:46 +01001017 ret = -EFAULT;
1018 mutex_unlock(&real_tty->termios_mutex);
1019 return ret;
Alan Cox0fc00e22007-11-07 01:24:56 -08001020#endif
Alan Cox1d65b4a2008-10-13 10:38:18 +01001021#ifdef TCGETX
1022 case TCGETX:
1023 if (real_tty->termiox == NULL)
1024 return -EINVAL;
Alan Cox8f520022008-10-13 10:38:46 +01001025 mutex_lock(&real_tty->termios_mutex);
Alan Cox1d65b4a2008-10-13 10:38:18 +01001026 if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
Alan Cox8f520022008-10-13 10:38:46 +01001027 ret = -EFAULT;
1028 mutex_unlock(&real_tty->termios_mutex);
1029 return ret;
Alan Cox1d65b4a2008-10-13 10:38:18 +01001030 case TCSETX:
1031 return set_termiox(real_tty, p, 0);
1032 case TCSETXW:
1033 return set_termiox(real_tty, p, TERMIOS_WAIT);
1034 case TCSETXF:
1035 return set_termiox(real_tty, p, TERMIOS_FLUSH);
1036#endif
Alan Cox355d95a12008-02-08 04:18:48 -08001037 case TIOCGSOFTCAR:
Alan Cox8f520022008-10-13 10:38:46 +01001038 mutex_lock(&real_tty->termios_mutex);
1039 ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
Alan Cox355d95a12008-02-08 04:18:48 -08001040 (int __user *)arg);
Alan Cox8f520022008-10-13 10:38:46 +01001041 mutex_unlock(&real_tty->termios_mutex);
1042 return ret;
Alan Cox355d95a12008-02-08 04:18:48 -08001043 case TIOCSSOFTCAR:
1044 if (get_user(arg, (unsigned int __user *) arg))
1045 return -EFAULT;
Alan Coxf753f322008-08-26 19:52:47 +01001046 return tty_change_softcar(real_tty, arg);
Alan Cox355d95a12008-02-08 04:18:48 -08001047 default:
1048 return -ENOIOCTLCMD;
Alan Cox0fc00e22007-11-07 01:24:56 -08001049 }
1050}
Alan Cox0fc00e22007-11-07 01:24:56 -08001051EXPORT_SYMBOL_GPL(tty_mode_ioctl);
1052
1053int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
1054{
1055 struct tty_ldisc *ld;
1056 int retval = tty_check_change(tty);
1057 if (retval)
1058 return retval;
1059
1060 ld = tty_ldisc_ref(tty);
1061 switch (arg) {
1062 case TCIFLUSH:
Alan Coxa352def2008-07-16 21:53:12 +01001063 if (ld && ld->ops->flush_buffer)
1064 ld->ops->flush_buffer(tty);
Alan Cox0fc00e22007-11-07 01:24:56 -08001065 break;
1066 case TCIOFLUSH:
Alan Coxa352def2008-07-16 21:53:12 +01001067 if (ld && ld->ops->flush_buffer)
1068 ld->ops->flush_buffer(tty);
Alan Cox0fc00e22007-11-07 01:24:56 -08001069 /* fall through */
1070 case TCOFLUSH:
Alan Coxf34d7a52008-04-30 00:54:13 -07001071 tty_driver_flush_buffer(tty);
Alan Cox0fc00e22007-11-07 01:24:56 -08001072 break;
1073 default:
1074 tty_ldisc_deref(ld);
1075 return -EINVAL;
1076 }
1077 tty_ldisc_deref(ld);
1078 return 0;
1079}
Alan Cox0fc00e22007-11-07 01:24:56 -08001080EXPORT_SYMBOL_GPL(tty_perform_flush);
1081
Alan Cox47afa7a2008-10-13 10:44:17 +01001082int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -08001083 unsigned int cmd, unsigned long arg)
1084{
Alan Cox04f378b2008-04-30 00:53:29 -07001085 unsigned long flags;
Alan Cox0fc00e22007-11-07 01:24:56 -08001086 int retval;
1087
Alan Cox0fc00e22007-11-07 01:24:56 -08001088 switch (cmd) {
Alan Cox355d95a12008-02-08 04:18:48 -08001089 case TCXONC:
1090 retval = tty_check_change(tty);
1091 if (retval)
1092 return retval;
1093 switch (arg) {
1094 case TCOOFF:
1095 if (!tty->flow_stopped) {
1096 tty->flow_stopped = 1;
1097 stop_tty(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 }
Alan Cox355d95a12008-02-08 04:18:48 -08001099 break;
1100 case TCOON:
1101 if (tty->flow_stopped) {
1102 tty->flow_stopped = 0;
1103 start_tty(tty);
1104 }
1105 break;
1106 case TCIOFF:
1107 if (STOP_CHAR(tty) != __DISABLED_CHAR)
1108 return send_prio_char(tty, STOP_CHAR(tty));
1109 break;
1110 case TCION:
1111 if (START_CHAR(tty) != __DISABLED_CHAR)
1112 return send_prio_char(tty, START_CHAR(tty));
1113 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 default:
Alan Cox355d95a12008-02-08 04:18:48 -08001115 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 }
Alan Cox355d95a12008-02-08 04:18:48 -08001117 return 0;
1118 case TCFLSH:
1119 return tty_perform_flush(tty, arg);
Alan Cox355d95a12008-02-08 04:18:48 -08001120 case TIOCPKT:
1121 {
1122 int pktmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Alan Cox355d95a12008-02-08 04:18:48 -08001124 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
1125 tty->driver->subtype != PTY_TYPE_MASTER)
1126 return -ENOTTY;
1127 if (get_user(pktmode, (int __user *) arg))
1128 return -EFAULT;
Alan Cox04f378b2008-04-30 00:53:29 -07001129 spin_lock_irqsave(&tty->ctrl_lock, flags);
Alan Cox355d95a12008-02-08 04:18:48 -08001130 if (pktmode) {
1131 if (!tty->packet) {
1132 tty->packet = 1;
1133 tty->link->ctrl_status = 0;
1134 }
1135 } else
1136 tty->packet = 0;
Alan Cox04f378b2008-04-30 00:53:29 -07001137 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
Alan Cox355d95a12008-02-08 04:18:48 -08001138 return 0;
1139 }
1140 default:
1141 /* Try the mode commands */
1142 return tty_mode_ioctl(tty, file, cmd, arg);
1143 }
1144}
Alan Cox47afa7a2008-10-13 10:44:17 +01001145EXPORT_SYMBOL(n_tty_ioctl_helper);