blob: ad6ba4ed280853bce299b8bf6aab4d3d53b7c68e [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
25#include <asm/io.h>
26#include <asm/uaccess.h>
27#include <asm/system.h>
28
29#undef TTY_DEBUG_WAIT_UNTIL_SENT
30
31#undef DEBUG
32
33/*
34 * Internal flag options for termios setting behavior
35 */
36#define TERMIOS_FLUSH 1
37#define TERMIOS_WAIT 2
38#define TERMIOS_TERMIO 4
Alan Coxedc6afc2006-12-08 02:38:44 -080039#define TERMIOS_OLD 8
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Alan Coxaf9b8972006-08-27 01:24:01 -070041
Alan Coxd81ed102008-10-13 10:41:42 +010042/**
43 * tty_chars_in_buffer - characters pending
44 * @tty: terminal
45 *
46 * Return the number of bytes of data in the device private
47 * output queue. If no private method is supplied there is assumed
48 * to be no queue on the device.
49 */
50
Alan Coxf34d7a52008-04-30 00:54:13 -070051int tty_chars_in_buffer(struct tty_struct *tty)
52{
53 if (tty->ops->chars_in_buffer)
54 return tty->ops->chars_in_buffer(tty);
55 else
56 return 0;
57}
Alan Coxf34d7a52008-04-30 00:54:13 -070058EXPORT_SYMBOL(tty_chars_in_buffer);
59
Alan Coxd81ed102008-10-13 10:41:42 +010060/**
61 * tty_write_room - write queue space
62 * @tty: terminal
63 *
64 * Return the number of bytes that can be queued to this device
65 * at the present time. The result should be treated as a guarantee
66 * and the driver cannot offer a value it later shrinks by more than
67 * the number of bytes written. If no method is provided 2K is always
68 * returned and data may be lost as there will be no flow control.
69 */
70
Alan Coxf34d7a52008-04-30 00:54:13 -070071int tty_write_room(struct tty_struct *tty)
72{
73 if (tty->ops->write_room)
74 return tty->ops->write_room(tty);
75 return 2048;
76}
Alan Coxf34d7a52008-04-30 00:54:13 -070077EXPORT_SYMBOL(tty_write_room);
78
Alan Coxd81ed102008-10-13 10:41:42 +010079/**
80 * tty_driver_flush_buffer - discard internal buffer
81 * @tty: terminal
82 *
83 * Discard the internal output buffer for this device. If no method
84 * is provided then either the buffer cannot be hardware flushed or
85 * there is no buffer driver side.
86 */
Alan Coxf34d7a52008-04-30 00:54:13 -070087void tty_driver_flush_buffer(struct tty_struct *tty)
88{
89 if (tty->ops->flush_buffer)
90 tty->ops->flush_buffer(tty);
91}
Alan Coxf34d7a52008-04-30 00:54:13 -070092EXPORT_SYMBOL(tty_driver_flush_buffer);
93
Alan Coxd81ed102008-10-13 10:41:42 +010094/**
95 * tty_throttle - flow control
96 * @tty: terminal
97 *
98 * Indicate that a tty should stop transmitting data down the stack.
Alan Cox38db8972009-06-11 12:44:17 +010099 * Takes the termios mutex to protect against parallel throttle/unthrottle
100 * and also to ensure the driver can consistently reference its own
101 * termios data at this point when implementing software flow control.
Alan Coxd81ed102008-10-13 10:41:42 +0100102 */
103
Alan Cox39c2e602008-04-30 00:54:18 -0700104void tty_throttle(struct tty_struct *tty)
105{
Alan Cox38db8972009-06-11 12:44:17 +0100106 mutex_lock(&tty->termios_mutex);
Alan Cox39c2e602008-04-30 00:54:18 -0700107 /* check TTY_THROTTLED first so it indicates our state */
108 if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
109 tty->ops->throttle)
110 tty->ops->throttle(tty);
Alan Cox38db8972009-06-11 12:44:17 +0100111 mutex_unlock(&tty->termios_mutex);
Alan Cox39c2e602008-04-30 00:54:18 -0700112}
113EXPORT_SYMBOL(tty_throttle);
114
Alan Coxd81ed102008-10-13 10:41:42 +0100115/**
116 * tty_unthrottle - flow control
117 * @tty: terminal
118 *
119 * Indicate that a tty may continue transmitting data down the stack.
Alan Cox38db8972009-06-11 12:44:17 +0100120 * Takes the termios mutex to protect against parallel throttle/unthrottle
121 * and also to ensure the driver can consistently reference its own
122 * termios data at this point when implementing software flow control.
123 *
124 * Drivers should however remember that the stack can issue a throttle,
125 * then change flow control method, then unthrottle.
Alan Coxd81ed102008-10-13 10:41:42 +0100126 */
127
Alan Cox39c2e602008-04-30 00:54:18 -0700128void tty_unthrottle(struct tty_struct *tty)
129{
Alan Cox38db8972009-06-11 12:44:17 +0100130 mutex_lock(&tty->termios_mutex);
Alan Cox39c2e602008-04-30 00:54:18 -0700131 if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
132 tty->ops->unthrottle)
133 tty->ops->unthrottle(tty);
Alan Cox38db8972009-06-11 12:44:17 +0100134 mutex_unlock(&tty->termios_mutex);
Alan Cox39c2e602008-04-30 00:54:18 -0700135}
136EXPORT_SYMBOL(tty_unthrottle);
Alan Coxf34d7a52008-04-30 00:54:13 -0700137
Alan Coxaf9b8972006-08-27 01:24:01 -0700138/**
139 * tty_wait_until_sent - wait for I/O to finish
140 * @tty: tty we are waiting for
141 * @timeout: how long we will wait
142 *
143 * Wait for characters pending in a tty driver to hit the wire, or
144 * for a timeout to occur (eg due to flow control)
145 *
146 * Locking: none
147 */
148
Alan Cox355d95a2008-02-08 04:18:48 -0800149void tty_wait_until_sent(struct tty_struct *tty, long timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
152 char buf[64];
Alan Cox355d95a2008-02-08 04:18:48 -0800153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
155#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 if (!timeout)
157 timeout = MAX_SCHEDULE_TIMEOUT;
Jiri Slaby5a52bd42007-07-15 23:40:18 -0700158 if (wait_event_interruptible_timeout(tty->write_wait,
Alan Coxf34d7a52008-04-30 00:54:13 -0700159 !tty_chars_in_buffer(tty), timeout) >= 0) {
160 if (tty->ops->wait_until_sent)
161 tty->ops->wait_until_sent(tty, timeout);
Alan Cox0ee9cbb2008-04-30 00:53:32 -0700162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164EXPORT_SYMBOL(tty_wait_until_sent);
165
Alan Coxd81ed102008-10-13 10:41:42 +0100166
167/*
168 * Termios Helper Methods
169 */
170
Alan Coxedc6afc2006-12-08 02:38:44 -0800171static void unset_locked_termios(struct ktermios *termios,
172 struct ktermios *old,
173 struct ktermios *locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
175 int i;
Alan Cox355d95a2008-02-08 04:18:48 -0800176
177#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179 if (!locked) {
180 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
181 return;
182 }
183
184 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
185 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
186 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
187 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
188 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
Alan Cox355d95a2008-02-08 04:18:48 -0800189 for (i = 0; i < NCCS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 termios->c_cc[i] = locked->c_cc[i] ?
191 old->c_cc[i] : termios->c_cc[i];
Alan Coxedc6afc2006-12-08 02:38:44 -0800192 /* FIXME: What should we do for i/ospeed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
Alan Coxedc6afc2006-12-08 02:38:44 -0800195/*
196 * Routine which returns the baud rate of the tty
197 *
198 * Note that the baud_table needs to be kept in sync with the
199 * include/asm/termbits.h file.
200 */
201static const speed_t baud_table[] = {
202 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
203 9600, 19200, 38400, 57600, 115200, 230400, 460800,
204#ifdef __sparc__
205 76800, 153600, 307200, 614400, 921600
206#else
207 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
208 2500000, 3000000, 3500000, 4000000
209#endif
210};
211
212#ifndef __sparc__
213static const tcflag_t baud_bits[] = {
214 B0, B50, B75, B110, B134, B150, B200, B300, B600,
215 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
216 B57600, B115200, B230400, B460800, B500000, B576000,
217 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
218 B3000000, B3500000, B4000000
219};
220#else
221static const tcflag_t baud_bits[] = {
222 B0, B50, B75, B110, B134, B150, B200, B300, B600,
223 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
224 B57600, B115200, B230400, B460800, B76800, B153600,
225 B307200, B614400, B921600
226};
227#endif
228
229static int n_baud_table = ARRAY_SIZE(baud_table);
230
231/**
232 * tty_termios_baud_rate
233 * @termios: termios structure
234 *
235 * Convert termios baud rate data into a speed. This should be called
236 * with the termios lock held if this termios is a terminal termios
237 * structure. May change the termios data. Device drivers can call this
238 * function but should use ->c_[io]speed directly as they are updated.
239 *
240 * Locking: none
241 */
242
243speed_t tty_termios_baud_rate(struct ktermios *termios)
244{
245 unsigned int cbaud;
246
247 cbaud = termios->c_cflag & CBAUD;
248
249#ifdef BOTHER
250 /* Magic token for arbitary speed via c_ispeed/c_ospeed */
251 if (cbaud == BOTHER)
252 return termios->c_ospeed;
253#endif
254 if (cbaud & CBAUDEX) {
255 cbaud &= ~CBAUDEX;
256
257 if (cbaud < 1 || cbaud + 15 > n_baud_table)
258 termios->c_cflag &= ~CBAUDEX;
259 else
260 cbaud += 15;
261 }
262 return baud_table[cbaud];
263}
Alan Coxedc6afc2006-12-08 02:38:44 -0800264EXPORT_SYMBOL(tty_termios_baud_rate);
265
266/**
267 * tty_termios_input_baud_rate
268 * @termios: termios structure
269 *
270 * Convert termios baud rate data into a speed. This should be called
271 * with the termios lock held if this termios is a terminal termios
272 * structure. May change the termios data. Device drivers can call this
273 * function but should use ->c_[io]speed directly as they are updated.
274 *
275 * Locking: none
276 */
277
278speed_t tty_termios_input_baud_rate(struct ktermios *termios)
279{
280#ifdef IBSHIFT
281 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
282
283 if (cbaud == B0)
284 return tty_termios_baud_rate(termios);
285
286 /* Magic token for arbitary speed via c_ispeed*/
287 if (cbaud == BOTHER)
288 return termios->c_ispeed;
289
290 if (cbaud & CBAUDEX) {
291 cbaud &= ~CBAUDEX;
292
293 if (cbaud < 1 || cbaud + 15 > n_baud_table)
294 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
295 else
296 cbaud += 15;
297 }
298 return baud_table[cbaud];
299#else
300 return tty_termios_baud_rate(termios);
301#endif
302}
Alan Coxedc6afc2006-12-08 02:38:44 -0800303EXPORT_SYMBOL(tty_termios_input_baud_rate);
304
Alan Coxedc6afc2006-12-08 02:38:44 -0800305/**
306 * tty_termios_encode_baud_rate
Alan Cox78137e32007-02-10 01:45:57 -0800307 * @termios: ktermios structure holding user requested state
Alan Coxedc6afc2006-12-08 02:38:44 -0800308 * @ispeed: input speed
309 * @ospeed: output speed
310 *
311 * Encode the speeds set into the passed termios structure. This is
312 * used as a library helper for drivers os that they can report back
313 * the actual speed selected when it differs from the speed requested
314 *
Alan Cox78137e32007-02-10 01:45:57 -0800315 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
316 * we need to carefully set the bits when the user does not get the
317 * desired speed. We allow small margins and preserve as much of possible
318 * of the input intent to keep compatiblity.
Alan Coxedc6afc2006-12-08 02:38:44 -0800319 *
320 * Locking: Caller should hold termios lock. This is already held
321 * when calling this function from the driver termios handler.
Alan Cox5f519d72007-10-16 23:30:07 -0700322 *
323 * The ifdefs deal with platforms whose owners have yet to update them
324 * and will all go away once this is done.
Alan Coxedc6afc2006-12-08 02:38:44 -0800325 */
326
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700327void tty_termios_encode_baud_rate(struct ktermios *termios,
328 speed_t ibaud, speed_t obaud)
Alan Coxedc6afc2006-12-08 02:38:44 -0800329{
330 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800331 int ifound = -1, ofound = -1;
332 int iclose = ibaud/50, oclose = obaud/50;
333 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800334
Alan Cox5f519d72007-10-16 23:30:07 -0700335 if (obaud == 0) /* CD dropped */
336 ibaud = 0; /* Clear ibaud to be sure */
337
Alan Coxedc6afc2006-12-08 02:38:44 -0800338 termios->c_ispeed = ibaud;
339 termios->c_ospeed = obaud;
340
Alan Cox5f519d72007-10-16 23:30:07 -0700341#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800342 /* If the user asked for a precise weird speed give a precise weird
343 answer. If they asked for a Bfoo speed they many have problems
344 digesting non-exact replies so fuzz a bit */
345
346 if ((termios->c_cflag & CBAUD) == BOTHER)
347 oclose = 0;
348 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
349 iclose = 0;
350 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
351 ibinput = 1; /* An input speed was specified */
Alan Cox5f519d72007-10-16 23:30:07 -0700352#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800353 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800354
Alan Cox5f519d72007-10-16 23:30:07 -0700355 /*
356 * Our goal is to find a close match to the standard baud rate
357 * returned. Walk the baud rate table and if we get a very close
358 * match then report back the speed as a POSIX Bxxxx value by
359 * preference
360 */
361
Alan Coxedc6afc2006-12-08 02:38:44 -0800362 do {
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700363 if (obaud - oclose <= baud_table[i] &&
364 obaud + oclose >= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800365 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800366 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800367 }
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700368 if (ibaud - iclose <= baud_table[i] &&
369 ibaud + iclose >= baud_table[i]) {
370 /* For the case input == output don't set IBAUD bits
371 if the user didn't do so */
Alan Cox5f519d72007-10-16 23:30:07 -0700372 if (ofound == i && !ibinput)
373 ifound = i;
374#ifdef IBSHIFT
375 else {
376 ifound = i;
Alan Cox78137e32007-02-10 01:45:57 -0800377 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700378 }
379#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800380 }
Jiri Slaby68043962007-07-15 23:40:18 -0700381 } while (++i < n_baud_table);
Alan Cox5f519d72007-10-16 23:30:07 -0700382
383 /*
384 * If we found no match then use BOTHER if provided or warn
385 * the user their platform maintainer needs to wake up if not.
386 */
387#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800388 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800389 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800390 /* Set exact input bits only if the input and output differ or the
391 user already did */
Jiri Slaby68043962007-07-15 23:40:18 -0700392 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800393 termios->c_cflag |= (BOTHER << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700394#else
395 if (ifound == -1 || ofound == -1) {
396 static int warned;
397 if (!warned++)
398 printk(KERN_WARNING "tty: Unable to return correct "
399 "speed data as your architecture needs updating.\n");
400 }
401#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800402}
Alan Coxedc6afc2006-12-08 02:38:44 -0800403EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
404
Alan Coxd81ed102008-10-13 10:41:42 +0100405/**
406 * tty_encode_baud_rate - set baud rate of the tty
407 * @ibaud: input baud rate
408 * @obad: output baud rate
409 *
410 * Update the current termios data for the tty with the new speed
411 * settings. The caller must hold the termios_mutex for the tty in
412 * question.
413 */
414
Alan Cox5f519d72007-10-16 23:30:07 -0700415void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
416{
417 tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
418}
419EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
Alan Coxedc6afc2006-12-08 02:38:44 -0800420
421/**
422 * tty_get_baud_rate - get tty bit rates
423 * @tty: tty to query
424 *
425 * Returns the baud rate as an integer for this terminal. The
426 * termios lock must be held by the caller and the terminal bit
427 * flags may be updated.
428 *
429 * Locking: none
430 */
431
432speed_t tty_get_baud_rate(struct tty_struct *tty)
433{
434 speed_t baud = tty_termios_baud_rate(tty->termios);
435
436 if (baud == 38400 && tty->alt_speed) {
437 if (!tty->warned) {
438 printk(KERN_WARNING "Use of setserial/setrocket to "
439 "set SPD_* flags is deprecated\n");
440 tty->warned = 1;
441 }
442 baud = tty->alt_speed;
443 }
444
445 return baud;
446}
Alan Coxedc6afc2006-12-08 02:38:44 -0800447EXPORT_SYMBOL(tty_get_baud_rate);
448
Alan Coxaf9b8972006-08-27 01:24:01 -0700449/**
Alan Cox5f519d72007-10-16 23:30:07 -0700450 * tty_termios_copy_hw - copy hardware settings
451 * @new: New termios
452 * @old: Old termios
453 *
454 * Propogate the hardware specific terminal setting bits from
455 * the old termios structure to the new one. This is used in cases
456 * where the hardware does not support reconfiguration or as a helper
457 * in some cases where only minimal reconfiguration is supported
458 */
459
460void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
461{
462 /* The bits a dumb device handles in software. Smart devices need
463 to always provide a set_termios method */
464 new->c_cflag &= HUPCL | CREAD | CLOCAL;
465 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
466 new->c_ispeed = old->c_ispeed;
467 new->c_ospeed = old->c_ospeed;
468}
Alan Cox5f519d72007-10-16 23:30:07 -0700469EXPORT_SYMBOL(tty_termios_copy_hw);
470
471/**
Alan Coxbf5e5832008-01-08 14:55:51 +0000472 * tty_termios_hw_change - check for setting change
473 * @a: termios
474 * @b: termios to compare
475 *
476 * Check if any of the bits that affect a dumb device have changed
477 * between the two termios structures, or a speed change is needed.
478 */
479
480int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
481{
482 if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
483 return 1;
484 if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
485 return 1;
486 return 0;
487}
488EXPORT_SYMBOL(tty_termios_hw_change);
489
490/**
Alan Coxaf9b8972006-08-27 01:24:01 -0700491 * change_termios - update termios values
492 * @tty: tty to update
493 * @new_termios: desired new value
494 *
495 * Perform updates to the termios values set on this terminal. There
496 * is a bit of layering violation here with n_tty in terms of the
497 * internal knowledge of this function.
498 *
Alan Coxd81ed102008-10-13 10:41:42 +0100499 * Locking: termios_mutex
Alan Coxaf9b8972006-08-27 01:24:01 -0700500 */
501
Alan Cox355d95a2008-02-08 04:18:48 -0800502static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
Alan Cox978e5952008-04-30 00:53:59 -0700504 struct ktermios old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 struct tty_ldisc *ld;
Alan Cox04f378b2008-04-30 00:53:29 -0700506 unsigned long flags;
Alan Cox355d95a2008-02-08 04:18:48 -0800507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 /*
509 * Perform the actual termios internal changes under lock.
510 */
Alan Cox355d95a2008-02-08 04:18:48 -0800511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 /* FIXME: we need to decide on some locking/ordering semantics
514 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700515 mutex_lock(&tty->termios_mutex);
Alan Cox978e5952008-04-30 00:53:59 -0700516 old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 *tty->termios = *new_termios;
518 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520 /* See if packet mode change of state. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 if (tty->link && tty->link->packet) {
522 int old_flow = ((old_termios.c_iflag & IXON) &&
523 (old_termios.c_cc[VSTOP] == '\023') &&
524 (old_termios.c_cc[VSTART] == '\021'));
525 int new_flow = (I_IXON(tty) &&
526 STOP_CHAR(tty) == '\023' &&
527 START_CHAR(tty) == '\021');
528 if (old_flow != new_flow) {
Alan Cox04f378b2008-04-30 00:53:29 -0700529 spin_lock_irqsave(&tty->ctrl_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
531 if (new_flow)
532 tty->ctrl_status |= TIOCPKT_DOSTOP;
533 else
534 tty->ctrl_status |= TIOCPKT_NOSTOP;
Alan Cox04f378b2008-04-30 00:53:29 -0700535 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 wake_up_interruptible(&tty->link->read_wait);
537 }
538 }
Alan Cox355d95a2008-02-08 04:18:48 -0800539
Alan Coxf34d7a52008-04-30 00:54:13 -0700540 if (tty->ops->set_termios)
541 (*tty->ops->set_termios)(tty, &old_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700542 else
543 tty_termios_copy_hw(tty->termios, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 ld = tty_ldisc_ref(tty);
546 if (ld != NULL) {
Alan Coxa352def2008-07-16 21:53:12 +0100547 if (ld->ops->set_termios)
548 (ld->ops->set_termios)(tty, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 tty_ldisc_deref(ld);
550 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700551 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552}
553
Alan Coxaf9b8972006-08-27 01:24:01 -0700554/**
555 * set_termios - set termios values for a tty
556 * @tty: terminal device
557 * @arg: user data
558 * @opt: option information
559 *
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200560 * Helper function to prepare termios data and run necessary other
Alan Coxaf9b8972006-08-27 01:24:01 -0700561 * functions before using change_termios to do the actual changes.
562 *
563 * Locking:
Alan Coxd81ed102008-10-13 10:41:42 +0100564 * Called functions take ldisc and termios_mutex locks
Alan Coxaf9b8972006-08-27 01:24:01 -0700565 */
566
Alan Cox355d95a2008-02-08 04:18:48 -0800567static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
Alan Coxedc6afc2006-12-08 02:38:44 -0800569 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 struct tty_ldisc *ld;
571 int retval = tty_check_change(tty);
572
573 if (retval)
574 return retval;
575
Alan Cox978e5952008-04-30 00:53:59 -0700576 mutex_lock(&tty->termios_mutex);
Alan Cox64bb6c52006-12-08 02:38:47 -0800577 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
Alan Cox978e5952008-04-30 00:53:59 -0700578 mutex_unlock(&tty->termios_mutex);
Alan Cox64bb6c52006-12-08 02:38:47 -0800579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 if (user_termio_to_kernel_termios(&tmp_termios,
582 (struct termio __user *)arg))
583 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800584#ifdef TCGETS2
585 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800586 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 (struct termios __user *)arg))
588 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800589 } else {
590 if (user_termios_to_kernel_termios(&tmp_termios,
591 (struct termios2 __user *)arg))
592 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800594#else
595 } else if (user_termios_to_kernel_termios(&tmp_termios,
596 (struct termios __user *)arg))
597 return -EFAULT;
598#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Alan Cox355d95a2008-02-08 04:18:48 -0800600 /* If old style Bfoo values are used then load c_ispeed/c_ospeed
601 * with the real speed so its unconditionally usable */
Alan Coxedc6afc2006-12-08 02:38:44 -0800602 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
603 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 ld = tty_ldisc_ref(tty);
Alan Cox355d95a2008-02-08 04:18:48 -0800606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 if (ld != NULL) {
Alan Coxa352def2008-07-16 21:53:12 +0100608 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
609 ld->ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 tty_ldisc_deref(ld);
611 }
Alan Cox355d95a2008-02-08 04:18:48 -0800612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 if (opt & TERMIOS_WAIT) {
614 tty_wait_until_sent(tty, 0);
615 if (signal_pending(current))
616 return -EINTR;
617 }
618
619 change_termios(tty, &tmp_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700620
621 /* FIXME: Arguably if tmp_termios == tty->termios AND the
622 actual requested termios was not tmp_termios then we may
623 want to return an error as no user requested change has
624 succeeded */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return 0;
626}
627
Alan Cox26a2e202009-06-11 14:03:13 +0100628static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
629{
630 mutex_lock(&tty->termios_mutex);
631 memcpy(kterm, tty->termios, sizeof(struct ktermios));
632 mutex_unlock(&tty->termios_mutex);
633}
634
635static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
636{
637 mutex_lock(&tty->termios_mutex);
638 memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
639 mutex_unlock(&tty->termios_mutex);
640}
641
Alan Cox355d95a2008-02-08 04:18:48 -0800642static int get_termio(struct tty_struct *tty, struct termio __user *termio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643{
Alan Cox26a2e202009-06-11 14:03:13 +0100644 struct ktermios kterm;
645 copy_termios(tty, &kterm);
646 if (kernel_termios_to_user_termio(termio, &kterm))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return -EFAULT;
648 return 0;
649}
650
Alan Cox1d65b4a2008-10-13 10:38:18 +0100651
652#ifdef TCGETX
653
654/**
655 * set_termiox - set termiox fields if possible
656 * @tty: terminal
657 * @arg: termiox structure from user
658 * @opt: option flags for ioctl type
659 *
660 * Implement the device calling points for the SYS5 termiox ioctl
661 * interface in Linux
662 */
663
664static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
665{
666 struct termiox tnew;
667 struct tty_ldisc *ld;
668
669 if (tty->termiox == NULL)
670 return -EINVAL;
671 if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
672 return -EFAULT;
673
674 ld = tty_ldisc_ref(tty);
675 if (ld != NULL) {
676 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
677 ld->ops->flush_buffer(tty);
678 tty_ldisc_deref(ld);
679 }
680 if (opt & TERMIOS_WAIT) {
681 tty_wait_until_sent(tty, 0);
682 if (signal_pending(current))
683 return -EINTR;
684 }
685
686 mutex_lock(&tty->termios_mutex);
687 if (tty->ops->set_termiox)
688 tty->ops->set_termiox(tty, &tnew);
689 mutex_unlock(&tty->termios_mutex);
690 return 0;
691}
692
693#endif
694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696#ifdef TIOCGETP
697/*
698 * These are deprecated, but there is limited support..
699 *
700 * The "sg_flags" translation is a joke..
701 */
Alan Cox355d95a2008-02-08 04:18:48 -0800702static int get_sgflags(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 int flags = 0;
705
706 if (!(tty->termios->c_lflag & ICANON)) {
707 if (tty->termios->c_lflag & ISIG)
708 flags |= 0x02; /* cbreak */
709 else
710 flags |= 0x20; /* raw */
711 }
712 if (tty->termios->c_lflag & ECHO)
713 flags |= 0x08; /* echo */
714 if (tty->termios->c_oflag & OPOST)
715 if (tty->termios->c_oflag & ONLCR)
716 flags |= 0x10; /* crmod */
717 return flags;
718}
719
Alan Cox355d95a2008-02-08 04:18:48 -0800720static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
722 struct sgttyb tmp;
723
Arjan van de Ven5785c952006-09-29 02:00:43 -0700724 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800725 tmp.sg_ispeed = tty->termios->c_ispeed;
726 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 tmp.sg_erase = tty->termios->c_cc[VERASE];
728 tmp.sg_kill = tty->termios->c_cc[VKILL];
729 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700730 mutex_unlock(&tty->termios_mutex);
Alan Cox355d95a2008-02-08 04:18:48 -0800731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
733}
734
Alan Cox355d95a2008-02-08 04:18:48 -0800735static void set_sgflags(struct ktermios *termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
737 termios->c_iflag = ICRNL | IXON;
738 termios->c_oflag = 0;
739 termios->c_lflag = ISIG | ICANON;
740 if (flags & 0x02) { /* cbreak */
741 termios->c_iflag = 0;
742 termios->c_lflag &= ~ICANON;
743 }
744 if (flags & 0x08) { /* echo */
745 termios->c_lflag |= ECHO | ECHOE | ECHOK |
746 ECHOCTL | ECHOKE | IEXTEN;
747 }
748 if (flags & 0x10) { /* crmod */
749 termios->c_oflag |= OPOST | ONLCR;
750 }
751 if (flags & 0x20) { /* raw */
752 termios->c_iflag = 0;
753 termios->c_lflag &= ~(ISIG | ICANON);
754 }
755 if (!(termios->c_lflag & ICANON)) {
756 termios->c_cc[VMIN] = 1;
757 termios->c_cc[VTIME] = 0;
758 }
759}
760
Alan Coxaf9b8972006-08-27 01:24:01 -0700761/**
762 * set_sgttyb - set legacy terminal values
763 * @tty: tty structure
764 * @sgttyb: pointer to old style terminal structure
765 *
766 * Updates a terminal from the legacy BSD style terminal information
767 * structure.
768 *
Alan Coxd81ed102008-10-13 10:41:42 +0100769 * Locking: termios_mutex
Alan Coxaf9b8972006-08-27 01:24:01 -0700770 */
771
Alan Cox355d95a2008-02-08 04:18:48 -0800772static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
774 int retval;
775 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800776 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
778 retval = tty_check_change(tty);
779 if (retval)
780 return retval;
Alan Cox355d95a2008-02-08 04:18:48 -0800781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
783 return -EFAULT;
784
Arjan van de Ven5785c952006-09-29 02:00:43 -0700785 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700786 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 termios.c_cc[VERASE] = tmp.sg_erase;
788 termios.c_cc[VKILL] = tmp.sg_kill;
789 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800790 /* Try and encode into Bfoo format */
791#ifdef BOTHER
Alan Cox355d95a2008-02-08 04:18:48 -0800792 tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
793 termios.c_ospeed);
Alan Coxedc6afc2006-12-08 02:38:44 -0800794#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700795 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 change_termios(tty, &termios);
797 return 0;
798}
799#endif
800
801#ifdef TIOCGETC
Alan Cox355d95a2008-02-08 04:18:48 -0800802static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
804 struct tchars tmp;
805
Alan Cox978e5952008-04-30 00:53:59 -0700806 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 tmp.t_intrc = tty->termios->c_cc[VINTR];
808 tmp.t_quitc = tty->termios->c_cc[VQUIT];
809 tmp.t_startc = tty->termios->c_cc[VSTART];
810 tmp.t_stopc = tty->termios->c_cc[VSTOP];
811 tmp.t_eofc = tty->termios->c_cc[VEOF];
812 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
Alan Cox978e5952008-04-30 00:53:59 -0700813 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
815}
816
Alan Cox355d95a2008-02-08 04:18:48 -0800817static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 struct tchars tmp;
820
821 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
822 return -EFAULT;
Alan Cox978e5952008-04-30 00:53:59 -0700823 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 tty->termios->c_cc[VINTR] = tmp.t_intrc;
825 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
826 tty->termios->c_cc[VSTART] = tmp.t_startc;
827 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
828 tty->termios->c_cc[VEOF] = tmp.t_eofc;
829 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
Alan Cox978e5952008-04-30 00:53:59 -0700830 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 return 0;
832}
833#endif
834
835#ifdef TIOCGLTC
Alan Cox355d95a2008-02-08 04:18:48 -0800836static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837{
838 struct ltchars tmp;
839
Alan Cox978e5952008-04-30 00:53:59 -0700840 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 tmp.t_suspc = tty->termios->c_cc[VSUSP];
Alan Cox355d95a2008-02-08 04:18:48 -0800842 /* what is dsuspc anyway? */
843 tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
Alan Cox355d95a2008-02-08 04:18:48 -0800845 /* what is flushc anyway? */
846 tmp.t_flushc = tty->termios->c_cc[VEOL2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 tmp.t_werasc = tty->termios->c_cc[VWERASE];
848 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
Alan Cox978e5952008-04-30 00:53:59 -0700849 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
851}
852
Alan Cox355d95a2008-02-08 04:18:48 -0800853static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854{
855 struct ltchars tmp;
856
857 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
858 return -EFAULT;
859
Alan Cox978e5952008-04-30 00:53:59 -0700860 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
Alan Cox355d95a2008-02-08 04:18:48 -0800862 /* what is dsuspc anyway? */
863 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
Alan Cox355d95a2008-02-08 04:18:48 -0800865 /* what is flushc anyway? */
866 tty->termios->c_cc[VEOL2] = tmp.t_flushc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
868 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
Alan Cox978e5952008-04-30 00:53:59 -0700869 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 return 0;
871}
872#endif
873
Alan Coxaf9b8972006-08-27 01:24:01 -0700874/**
875 * send_prio_char - send priority character
876 *
877 * Send a high priority character to the tty even if stopped
878 *
Alan Cox5f412b22006-09-29 02:01:40 -0700879 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700881
Alan Cox5f412b22006-09-29 02:01:40 -0700882static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 int was_stopped = tty->stopped;
885
Alan Coxf34d7a52008-04-30 00:54:13 -0700886 if (tty->ops->send_xchar) {
887 tty->ops->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700888 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 }
Alan Cox5f412b22006-09-29 02:01:40 -0700890
Alan Cox9c1729d2007-07-15 23:39:43 -0700891 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700892 return -ERESTARTSYS;
893
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 if (was_stopped)
895 start_tty(tty);
Alan Coxf34d7a52008-04-30 00:54:13 -0700896 tty->ops->write(tty, &ch, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 if (was_stopped)
898 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700899 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700900 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901}
902
Alan Cox0fc00e22007-11-07 01:24:56 -0800903/**
Alan Cox1c2630c2008-04-30 00:53:34 -0700904 * tty_change_softcar - carrier change ioctl helper
905 * @tty: tty to update
906 * @arg: enable/disable CLOCAL
907 *
908 * Perform a change to the CLOCAL state and call into the driver
909 * layer to make it visible. All done with the termios mutex
910 */
911
912static int tty_change_softcar(struct tty_struct *tty, int arg)
913{
914 int ret = 0;
915 int bit = arg ? CLOCAL : 0;
Alan Coxf34d7a52008-04-30 00:54:13 -0700916 struct ktermios old;
Alan Cox1c2630c2008-04-30 00:53:34 -0700917
918 mutex_lock(&tty->termios_mutex);
Alan Coxf34d7a52008-04-30 00:54:13 -0700919 old = *tty->termios;
Alan Cox1c2630c2008-04-30 00:53:34 -0700920 tty->termios->c_cflag &= ~CLOCAL;
921 tty->termios->c_cflag |= bit;
Alan Coxf34d7a52008-04-30 00:54:13 -0700922 if (tty->ops->set_termios)
923 tty->ops->set_termios(tty, &old);
Alan Cox1c2630c2008-04-30 00:53:34 -0700924 if ((tty->termios->c_cflag & CLOCAL) != bit)
925 ret = -EINVAL;
926 mutex_unlock(&tty->termios_mutex);
927 return ret;
928}
929
930/**
Alan Cox0fc00e22007-11-07 01:24:56 -0800931 * tty_mode_ioctl - mode related ioctls
932 * @tty: tty for the ioctl
933 * @file: file pointer for the tty
934 * @cmd: command
935 * @arg: ioctl argument
936 *
937 * Perform non line discipline specific mode control ioctls. This
938 * is designed to be called by line disciplines to ensure they provide
939 * consistent mode setting.
940 */
941
Alan Cox355d95a2008-02-08 04:18:48 -0800942int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -0800943 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
Alan Cox355d95a2008-02-08 04:18:48 -0800945 struct tty_struct *real_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 void __user *p = (void __user *)arg;
Alan Cox8f520022008-10-13 10:38:46 +0100947 int ret = 0;
Alan Cox26a2e202009-06-11 14:03:13 +0100948 struct ktermios kterm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
951 tty->driver->subtype == PTY_TYPE_MASTER)
952 real_tty = tty->link;
953 else
954 real_tty = tty;
955
956 switch (cmd) {
957#ifdef TIOCGETP
Alan Cox355d95a2008-02-08 04:18:48 -0800958 case TIOCGETP:
959 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
960 case TIOCSETP:
961 case TIOCSETN:
962 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963#endif
964#ifdef TIOCGETC
Alan Cox355d95a2008-02-08 04:18:48 -0800965 case TIOCGETC:
966 return get_tchars(real_tty, p);
967 case TIOCSETC:
968 return set_tchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969#endif
970#ifdef TIOCGLTC
Alan Cox355d95a2008-02-08 04:18:48 -0800971 case TIOCGLTC:
972 return get_ltchars(real_tty, p);
973 case TIOCSLTC:
974 return set_ltchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975#endif
Alan Cox355d95a2008-02-08 04:18:48 -0800976 case TCSETSF:
977 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
978 case TCSETSW:
979 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
980 case TCSETS:
981 return set_termios(real_tty, p, TERMIOS_OLD);
Alan Coxedc6afc2006-12-08 02:38:44 -0800982#ifndef TCGETS2
Alan Cox355d95a2008-02-08 04:18:48 -0800983 case TCGETS:
Alan Cox26a2e202009-06-11 14:03:13 +0100984 copy_termios(real_tty, &kterm);
985 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
Alan Cox8f520022008-10-13 10:38:46 +0100986 ret = -EFAULT;
Alan Cox8f520022008-10-13 10:38:46 +0100987 return ret;
Alan Coxedc6afc2006-12-08 02:38:44 -0800988#else
Alan Cox355d95a2008-02-08 04:18:48 -0800989 case TCGETS:
Alan Cox26a2e202009-06-11 14:03:13 +0100990 copy_termios(real_tty, &kterm);
991 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
Alan Cox8f520022008-10-13 10:38:46 +0100992 ret = -EFAULT;
Alan Cox8f520022008-10-13 10:38:46 +0100993 return ret;
Alan Cox355d95a2008-02-08 04:18:48 -0800994 case TCGETS2:
Alan Cox26a2e202009-06-11 14:03:13 +0100995 copy_termios(real_tty, &kterm);
996 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
Alan Cox8f520022008-10-13 10:38:46 +0100997 ret = -EFAULT;
Alan Cox8f520022008-10-13 10:38:46 +0100998 return ret;
Alan Cox355d95a2008-02-08 04:18:48 -0800999 case TCSETSF2:
1000 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
1001 case TCSETSW2:
1002 return set_termios(real_tty, p, TERMIOS_WAIT);
1003 case TCSETS2:
1004 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -08001005#endif
Alan Cox355d95a2008-02-08 04:18:48 -08001006 case TCGETA:
1007 return get_termio(real_tty, p);
1008 case TCSETAF:
1009 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
1010 case TCSETAW:
1011 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
1012 case TCSETA:
1013 return set_termios(real_tty, p, TERMIOS_TERMIO);
Alan Cox0fc00e22007-11-07 01:24:56 -08001014#ifndef TCGETS2
Alan Cox355d95a2008-02-08 04:18:48 -08001015 case TIOCGLCKTRMIOS:
Alan Cox26a2e202009-06-11 14:03:13 +01001016 copy_termios_locked(real_tty, &kterm);
1017 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
Alan Cox8f520022008-10-13 10:38:46 +01001018 ret = -EFAULT;
Alan Cox8f520022008-10-13 10:38:46 +01001019 return ret;
Alan Cox355d95a2008-02-08 04:18:48 -08001020 case TIOCSLCKTRMIOS:
1021 if (!capable(CAP_SYS_ADMIN))
1022 return -EPERM;
Alan Cox26a2e202009-06-11 14:03:13 +01001023 copy_termios_locked(real_tty, &kterm);
1024 if (user_termios_to_kernel_termios(&kterm,
Alan Cox355d95a2008-02-08 04:18:48 -08001025 (struct termios __user *) arg))
Alan Cox26a2e202009-06-11 14:03:13 +01001026 return -EFAULT;
1027 mutex_lock(&real_tty->termios_mutex);
1028 memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
Alan Cox8f520022008-10-13 10:38:46 +01001029 mutex_unlock(&real_tty->termios_mutex);
Alan Cox26a2e202009-06-11 14:03:13 +01001030 return 0;
Alan Cox0fc00e22007-11-07 01:24:56 -08001031#else
Alan Cox355d95a2008-02-08 04:18:48 -08001032 case TIOCGLCKTRMIOS:
Alan Cox26a2e202009-06-11 14:03:13 +01001033 copy_termios_locked(real_tty, &kterm);
1034 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
Alan Cox8f520022008-10-13 10:38:46 +01001035 ret = -EFAULT;
Alan Cox8f520022008-10-13 10:38:46 +01001036 return ret;
Alan Cox355d95a2008-02-08 04:18:48 -08001037 case TIOCSLCKTRMIOS:
1038 if (!capable(CAP_SYS_ADMIN))
Alan Cox26a2e202009-06-11 14:03:13 +01001039 return -EPERM;
1040 copy_termios_locked(real_tty, &kterm);
1041 if (user_termios_to_kernel_termios_1(&kterm,
Alan Cox355d95a2008-02-08 04:18:48 -08001042 (struct termios __user *) arg))
Alan Cox26a2e202009-06-11 14:03:13 +01001043 return -EFAULT;
1044 mutex_lock(&real_tty->termios_mutex);
1045 memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
Alan Cox8f520022008-10-13 10:38:46 +01001046 mutex_unlock(&real_tty->termios_mutex);
1047 return ret;
Alan Cox0fc00e22007-11-07 01:24:56 -08001048#endif
Alan Cox1d65b4a2008-10-13 10:38:18 +01001049#ifdef TCGETX
Mike Frysinger5dca6072009-06-16 17:01:02 +01001050 case TCGETX: {
1051 struct termiox ktermx;
Alan Cox1d65b4a2008-10-13 10:38:18 +01001052 if (real_tty->termiox == NULL)
1053 return -EINVAL;
Alan Cox8f520022008-10-13 10:38:46 +01001054 mutex_lock(&real_tty->termios_mutex);
Alan Cox26a2e202009-06-11 14:03:13 +01001055 memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
Alan Cox8f520022008-10-13 10:38:46 +01001056 mutex_unlock(&real_tty->termios_mutex);
Alan Cox26a2e202009-06-11 14:03:13 +01001057 if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
1058 ret = -EFAULT;
Alan Cox8f520022008-10-13 10:38:46 +01001059 return ret;
Mike Frysinger5dca6072009-06-16 17:01:02 +01001060 }
Alan Cox1d65b4a2008-10-13 10:38:18 +01001061 case TCSETX:
1062 return set_termiox(real_tty, p, 0);
1063 case TCSETXW:
1064 return set_termiox(real_tty, p, TERMIOS_WAIT);
1065 case TCSETXF:
1066 return set_termiox(real_tty, p, TERMIOS_FLUSH);
1067#endif
Alan Cox355d95a2008-02-08 04:18:48 -08001068 case TIOCGSOFTCAR:
Alan Cox26a2e202009-06-11 14:03:13 +01001069 copy_termios(real_tty, &kterm);
1070 ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
Alan Cox355d95a2008-02-08 04:18:48 -08001071 (int __user *)arg);
Alan Cox8f520022008-10-13 10:38:46 +01001072 return ret;
Alan Cox355d95a2008-02-08 04:18:48 -08001073 case TIOCSSOFTCAR:
1074 if (get_user(arg, (unsigned int __user *) arg))
1075 return -EFAULT;
Alan Coxf753f322008-08-26 19:52:47 +01001076 return tty_change_softcar(real_tty, arg);
Alan Cox355d95a2008-02-08 04:18:48 -08001077 default:
1078 return -ENOIOCTLCMD;
Alan Cox0fc00e22007-11-07 01:24:56 -08001079 }
1080}
Alan Cox0fc00e22007-11-07 01:24:56 -08001081EXPORT_SYMBOL_GPL(tty_mode_ioctl);
1082
1083int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
1084{
1085 struct tty_ldisc *ld;
1086 int retval = tty_check_change(tty);
1087 if (retval)
1088 return retval;
1089
Alan Coxc0253ee2009-01-15 13:30:25 +00001090 ld = tty_ldisc_ref_wait(tty);
Alan Cox0fc00e22007-11-07 01:24:56 -08001091 switch (arg) {
1092 case TCIFLUSH:
Alan Coxa352def2008-07-16 21:53:12 +01001093 if (ld && ld->ops->flush_buffer)
1094 ld->ops->flush_buffer(tty);
Alan Cox0fc00e22007-11-07 01:24:56 -08001095 break;
1096 case TCIOFLUSH:
Alan Coxa352def2008-07-16 21:53:12 +01001097 if (ld && ld->ops->flush_buffer)
1098 ld->ops->flush_buffer(tty);
Alan Cox0fc00e22007-11-07 01:24:56 -08001099 /* fall through */
1100 case TCOFLUSH:
Alan Coxf34d7a52008-04-30 00:54:13 -07001101 tty_driver_flush_buffer(tty);
Alan Cox0fc00e22007-11-07 01:24:56 -08001102 break;
1103 default:
1104 tty_ldisc_deref(ld);
1105 return -EINVAL;
1106 }
1107 tty_ldisc_deref(ld);
1108 return 0;
1109}
Alan Cox0fc00e22007-11-07 01:24:56 -08001110EXPORT_SYMBOL_GPL(tty_perform_flush);
1111
Alan Cox47afa7a2008-10-13 10:44:17 +01001112int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -08001113 unsigned int cmd, unsigned long arg)
1114{
Alan Cox04f378b2008-04-30 00:53:29 -07001115 unsigned long flags;
Alan Cox0fc00e22007-11-07 01:24:56 -08001116 int retval;
1117
Alan Cox0fc00e22007-11-07 01:24:56 -08001118 switch (cmd) {
Alan Cox355d95a2008-02-08 04:18:48 -08001119 case TCXONC:
1120 retval = tty_check_change(tty);
1121 if (retval)
1122 return retval;
1123 switch (arg) {
1124 case TCOOFF:
1125 if (!tty->flow_stopped) {
1126 tty->flow_stopped = 1;
1127 stop_tty(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 }
Alan Cox355d95a2008-02-08 04:18:48 -08001129 break;
1130 case TCOON:
1131 if (tty->flow_stopped) {
1132 tty->flow_stopped = 0;
1133 start_tty(tty);
1134 }
1135 break;
1136 case TCIOFF:
1137 if (STOP_CHAR(tty) != __DISABLED_CHAR)
1138 return send_prio_char(tty, STOP_CHAR(tty));
1139 break;
1140 case TCION:
1141 if (START_CHAR(tty) != __DISABLED_CHAR)
1142 return send_prio_char(tty, START_CHAR(tty));
1143 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 default:
Alan Cox355d95a2008-02-08 04:18:48 -08001145 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 }
Alan Cox355d95a2008-02-08 04:18:48 -08001147 return 0;
1148 case TCFLSH:
1149 return tty_perform_flush(tty, arg);
Alan Cox355d95a2008-02-08 04:18:48 -08001150 case TIOCPKT:
1151 {
1152 int pktmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Alan Cox355d95a2008-02-08 04:18:48 -08001154 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
1155 tty->driver->subtype != PTY_TYPE_MASTER)
1156 return -ENOTTY;
1157 if (get_user(pktmode, (int __user *) arg))
1158 return -EFAULT;
Alan Cox04f378b2008-04-30 00:53:29 -07001159 spin_lock_irqsave(&tty->ctrl_lock, flags);
Alan Cox355d95a2008-02-08 04:18:48 -08001160 if (pktmode) {
1161 if (!tty->packet) {
1162 tty->packet = 1;
1163 tty->link->ctrl_status = 0;
1164 }
1165 } else
1166 tty->packet = 0;
Alan Cox04f378b2008-04-30 00:53:29 -07001167 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
Alan Cox355d95a2008-02-08 04:18:48 -08001168 return 0;
1169 }
1170 default:
1171 /* Try the mode commands */
1172 return tty_mode_ioctl(tty, file, cmd, arg);
1173 }
1174}
Alan Cox47afa7a2008-10-13 10:44:17 +01001175EXPORT_SYMBOL(n_tty_ioctl_helper);