blob: c10d40c4c5cac49739dc7dd842023976acf553cc [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 Coxf34d7a52008-04-30 00:54:13 -070043int tty_chars_in_buffer(struct tty_struct *tty)
44{
45 if (tty->ops->chars_in_buffer)
46 return tty->ops->chars_in_buffer(tty);
47 else
48 return 0;
49}
50
51EXPORT_SYMBOL(tty_chars_in_buffer);
52
53int tty_write_room(struct tty_struct *tty)
54{
55 if (tty->ops->write_room)
56 return tty->ops->write_room(tty);
57 return 2048;
58}
59
60EXPORT_SYMBOL(tty_write_room);
61
62void tty_driver_flush_buffer(struct tty_struct *tty)
63{
64 if (tty->ops->flush_buffer)
65 tty->ops->flush_buffer(tty);
66}
67
68EXPORT_SYMBOL(tty_driver_flush_buffer);
69
70
Alan Coxaf9b8972006-08-27 01:24:01 -070071/**
72 * tty_wait_until_sent - wait for I/O to finish
73 * @tty: tty we are waiting for
74 * @timeout: how long we will wait
75 *
76 * Wait for characters pending in a tty driver to hit the wire, or
77 * for a timeout to occur (eg due to flow control)
78 *
79 * Locking: none
80 */
81
Alan Cox355d95a2008-02-08 04:18:48 -080082void tty_wait_until_sent(struct tty_struct *tty, long timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083{
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
85 char buf[64];
Alan Cox355d95a2008-02-08 04:18:48 -080086
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
88#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 if (!timeout)
90 timeout = MAX_SCHEDULE_TIMEOUT;
Jiri Slaby5a52bd42007-07-15 23:40:18 -070091 if (wait_event_interruptible_timeout(tty->write_wait,
Alan Coxf34d7a52008-04-30 00:54:13 -070092 !tty_chars_in_buffer(tty), timeout) >= 0) {
93 if (tty->ops->wait_until_sent)
94 tty->ops->wait_until_sent(tty, timeout);
Alan Cox0ee9cbb2008-04-30 00:53:32 -070095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
Linus Torvalds1da177e2005-04-16 15:20:36 -070097EXPORT_SYMBOL(tty_wait_until_sent);
98
Alan Coxedc6afc2006-12-08 02:38:44 -080099static void unset_locked_termios(struct ktermios *termios,
100 struct ktermios *old,
101 struct ktermios *locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
103 int i;
Alan Cox355d95a2008-02-08 04:18:48 -0800104
105#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107 if (!locked) {
108 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
109 return;
110 }
111
112 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
113 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
114 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
115 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
116 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
Alan Cox355d95a2008-02-08 04:18:48 -0800117 for (i = 0; i < NCCS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 termios->c_cc[i] = locked->c_cc[i] ?
119 old->c_cc[i] : termios->c_cc[i];
Alan Coxedc6afc2006-12-08 02:38:44 -0800120 /* FIXME: What should we do for i/ospeed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121}
122
Alan Coxedc6afc2006-12-08 02:38:44 -0800123/*
124 * Routine which returns the baud rate of the tty
125 *
126 * Note that the baud_table needs to be kept in sync with the
127 * include/asm/termbits.h file.
128 */
129static const speed_t baud_table[] = {
130 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
131 9600, 19200, 38400, 57600, 115200, 230400, 460800,
132#ifdef __sparc__
133 76800, 153600, 307200, 614400, 921600
134#else
135 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
136 2500000, 3000000, 3500000, 4000000
137#endif
138};
139
140#ifndef __sparc__
141static const tcflag_t baud_bits[] = {
142 B0, B50, B75, B110, B134, B150, B200, B300, B600,
143 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
144 B57600, B115200, B230400, B460800, B500000, B576000,
145 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
146 B3000000, B3500000, B4000000
147};
148#else
149static const tcflag_t baud_bits[] = {
150 B0, B50, B75, B110, B134, B150, B200, B300, B600,
151 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
152 B57600, B115200, B230400, B460800, B76800, B153600,
153 B307200, B614400, B921600
154};
155#endif
156
157static int n_baud_table = ARRAY_SIZE(baud_table);
158
159/**
160 * tty_termios_baud_rate
161 * @termios: termios structure
162 *
163 * Convert termios baud rate data into a speed. This should be called
164 * with the termios lock held if this termios is a terminal termios
165 * structure. May change the termios data. Device drivers can call this
166 * function but should use ->c_[io]speed directly as they are updated.
167 *
168 * Locking: none
169 */
170
171speed_t tty_termios_baud_rate(struct ktermios *termios)
172{
173 unsigned int cbaud;
174
175 cbaud = termios->c_cflag & CBAUD;
176
177#ifdef BOTHER
178 /* Magic token for arbitary speed via c_ispeed/c_ospeed */
179 if (cbaud == BOTHER)
180 return termios->c_ospeed;
181#endif
182 if (cbaud & CBAUDEX) {
183 cbaud &= ~CBAUDEX;
184
185 if (cbaud < 1 || cbaud + 15 > n_baud_table)
186 termios->c_cflag &= ~CBAUDEX;
187 else
188 cbaud += 15;
189 }
190 return baud_table[cbaud];
191}
Alan Coxedc6afc2006-12-08 02:38:44 -0800192EXPORT_SYMBOL(tty_termios_baud_rate);
193
194/**
195 * tty_termios_input_baud_rate
196 * @termios: termios structure
197 *
198 * Convert termios baud rate data into a speed. This should be called
199 * with the termios lock held if this termios is a terminal termios
200 * structure. May change the termios data. Device drivers can call this
201 * function but should use ->c_[io]speed directly as they are updated.
202 *
203 * Locking: none
204 */
205
206speed_t tty_termios_input_baud_rate(struct ktermios *termios)
207{
208#ifdef IBSHIFT
209 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
210
211 if (cbaud == B0)
212 return tty_termios_baud_rate(termios);
213
214 /* Magic token for arbitary speed via c_ispeed*/
215 if (cbaud == BOTHER)
216 return termios->c_ispeed;
217
218 if (cbaud & CBAUDEX) {
219 cbaud &= ~CBAUDEX;
220
221 if (cbaud < 1 || cbaud + 15 > n_baud_table)
222 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
223 else
224 cbaud += 15;
225 }
226 return baud_table[cbaud];
227#else
228 return tty_termios_baud_rate(termios);
229#endif
230}
Alan Coxedc6afc2006-12-08 02:38:44 -0800231EXPORT_SYMBOL(tty_termios_input_baud_rate);
232
Alan Coxedc6afc2006-12-08 02:38:44 -0800233/**
234 * tty_termios_encode_baud_rate
Alan Cox78137e32007-02-10 01:45:57 -0800235 * @termios: ktermios structure holding user requested state
Alan Coxedc6afc2006-12-08 02:38:44 -0800236 * @ispeed: input speed
237 * @ospeed: output speed
238 *
239 * Encode the speeds set into the passed termios structure. This is
240 * used as a library helper for drivers os that they can report back
241 * the actual speed selected when it differs from the speed requested
242 *
Alan Cox78137e32007-02-10 01:45:57 -0800243 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
244 * we need to carefully set the bits when the user does not get the
245 * desired speed. We allow small margins and preserve as much of possible
246 * of the input intent to keep compatiblity.
Alan Coxedc6afc2006-12-08 02:38:44 -0800247 *
248 * Locking: Caller should hold termios lock. This is already held
249 * when calling this function from the driver termios handler.
Alan Cox5f519d72007-10-16 23:30:07 -0700250 *
251 * The ifdefs deal with platforms whose owners have yet to update them
252 * and will all go away once this is done.
Alan Coxedc6afc2006-12-08 02:38:44 -0800253 */
254
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700255void tty_termios_encode_baud_rate(struct ktermios *termios,
256 speed_t ibaud, speed_t obaud)
Alan Coxedc6afc2006-12-08 02:38:44 -0800257{
258 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800259 int ifound = -1, ofound = -1;
260 int iclose = ibaud/50, oclose = obaud/50;
261 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800262
Alan Cox5f519d72007-10-16 23:30:07 -0700263 if (obaud == 0) /* CD dropped */
264 ibaud = 0; /* Clear ibaud to be sure */
265
Alan Coxedc6afc2006-12-08 02:38:44 -0800266 termios->c_ispeed = ibaud;
267 termios->c_ospeed = obaud;
268
Alan Cox5f519d72007-10-16 23:30:07 -0700269#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800270 /* If the user asked for a precise weird speed give a precise weird
271 answer. If they asked for a Bfoo speed they many have problems
272 digesting non-exact replies so fuzz a bit */
273
274 if ((termios->c_cflag & CBAUD) == BOTHER)
275 oclose = 0;
276 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
277 iclose = 0;
278 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
279 ibinput = 1; /* An input speed was specified */
Alan Cox5f519d72007-10-16 23:30:07 -0700280#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800281 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800282
Alan Cox5f519d72007-10-16 23:30:07 -0700283 /*
284 * Our goal is to find a close match to the standard baud rate
285 * returned. Walk the baud rate table and if we get a very close
286 * match then report back the speed as a POSIX Bxxxx value by
287 * preference
288 */
289
Alan Coxedc6afc2006-12-08 02:38:44 -0800290 do {
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700291 if (obaud - oclose <= baud_table[i] &&
292 obaud + oclose >= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800293 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800294 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800295 }
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700296 if (ibaud - iclose <= baud_table[i] &&
297 ibaud + iclose >= baud_table[i]) {
298 /* For the case input == output don't set IBAUD bits
299 if the user didn't do so */
Alan Cox5f519d72007-10-16 23:30:07 -0700300 if (ofound == i && !ibinput)
301 ifound = i;
302#ifdef IBSHIFT
303 else {
304 ifound = i;
Alan Cox78137e32007-02-10 01:45:57 -0800305 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700306 }
307#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800308 }
Jiri Slaby68043962007-07-15 23:40:18 -0700309 } while (++i < n_baud_table);
Alan Cox5f519d72007-10-16 23:30:07 -0700310
311 /*
312 * If we found no match then use BOTHER if provided or warn
313 * the user their platform maintainer needs to wake up if not.
314 */
315#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800316 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800317 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800318 /* Set exact input bits only if the input and output differ or the
319 user already did */
Jiri Slaby68043962007-07-15 23:40:18 -0700320 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800321 termios->c_cflag |= (BOTHER << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700322#else
323 if (ifound == -1 || ofound == -1) {
324 static int warned;
325 if (!warned++)
326 printk(KERN_WARNING "tty: Unable to return correct "
327 "speed data as your architecture needs updating.\n");
328 }
329#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800330}
Alan Coxedc6afc2006-12-08 02:38:44 -0800331EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
332
Alan Cox5f519d72007-10-16 23:30:07 -0700333void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
334{
335 tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
336}
337EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
Alan Coxedc6afc2006-12-08 02:38:44 -0800338
339/**
340 * tty_get_baud_rate - get tty bit rates
341 * @tty: tty to query
342 *
343 * Returns the baud rate as an integer for this terminal. The
344 * termios lock must be held by the caller and the terminal bit
345 * flags may be updated.
346 *
347 * Locking: none
348 */
349
350speed_t tty_get_baud_rate(struct tty_struct *tty)
351{
352 speed_t baud = tty_termios_baud_rate(tty->termios);
353
354 if (baud == 38400 && tty->alt_speed) {
355 if (!tty->warned) {
356 printk(KERN_WARNING "Use of setserial/setrocket to "
357 "set SPD_* flags is deprecated\n");
358 tty->warned = 1;
359 }
360 baud = tty->alt_speed;
361 }
362
363 return baud;
364}
Alan Coxedc6afc2006-12-08 02:38:44 -0800365EXPORT_SYMBOL(tty_get_baud_rate);
366
Alan Coxaf9b8972006-08-27 01:24:01 -0700367/**
Alan Cox5f519d72007-10-16 23:30:07 -0700368 * tty_termios_copy_hw - copy hardware settings
369 * @new: New termios
370 * @old: Old termios
371 *
372 * Propogate the hardware specific terminal setting bits from
373 * the old termios structure to the new one. This is used in cases
374 * where the hardware does not support reconfiguration or as a helper
375 * in some cases where only minimal reconfiguration is supported
376 */
377
378void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
379{
380 /* The bits a dumb device handles in software. Smart devices need
381 to always provide a set_termios method */
382 new->c_cflag &= HUPCL | CREAD | CLOCAL;
383 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
384 new->c_ispeed = old->c_ispeed;
385 new->c_ospeed = old->c_ospeed;
386}
Alan Cox5f519d72007-10-16 23:30:07 -0700387EXPORT_SYMBOL(tty_termios_copy_hw);
388
389/**
Alan Coxbf5e5832008-01-08 14:55:51 +0000390 * tty_termios_hw_change - check for setting change
391 * @a: termios
392 * @b: termios to compare
393 *
394 * Check if any of the bits that affect a dumb device have changed
395 * between the two termios structures, or a speed change is needed.
396 */
397
398int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
399{
400 if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
401 return 1;
402 if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
403 return 1;
404 return 0;
405}
406EXPORT_SYMBOL(tty_termios_hw_change);
407
408/**
Alan Coxaf9b8972006-08-27 01:24:01 -0700409 * change_termios - update termios values
410 * @tty: tty to update
411 * @new_termios: desired new value
412 *
413 * Perform updates to the termios values set on this terminal. There
414 * is a bit of layering violation here with n_tty in terms of the
415 * internal knowledge of this function.
416 *
417 * Locking: termios_sem
418 */
419
Alan Cox355d95a2008-02-08 04:18:48 -0800420static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
422 int canon_change;
Alan Cox978e5952008-04-30 00:53:59 -0700423 struct ktermios old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 struct tty_ldisc *ld;
Alan Cox04f378b2008-04-30 00:53:29 -0700425 unsigned long flags;
Alan Cox355d95a2008-02-08 04:18:48 -0800426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 /*
428 * Perform the actual termios internal changes under lock.
429 */
Alan Cox355d95a2008-02-08 04:18:48 -0800430
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
432 /* FIXME: we need to decide on some locking/ordering semantics
433 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700434 mutex_lock(&tty->termios_mutex);
Alan Cox978e5952008-04-30 00:53:59 -0700435 old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 *tty->termios = *new_termios;
437 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
438 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
439 if (canon_change) {
440 memset(&tty->read_flags, 0, sizeof tty->read_flags);
441 tty->canon_head = tty->read_tail;
442 tty->canon_data = 0;
443 tty->erasing = 0;
444 }
Alan Cox355d95a2008-02-08 04:18:48 -0800445
Alan Cox5f519d72007-10-16 23:30:07 -0700446 /* This bit should be in the ldisc code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
448 /* Get characters left over from canonical mode. */
449 wake_up_interruptible(&tty->read_wait);
450
451 /* See if packet mode change of state. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (tty->link && tty->link->packet) {
453 int old_flow = ((old_termios.c_iflag & IXON) &&
454 (old_termios.c_cc[VSTOP] == '\023') &&
455 (old_termios.c_cc[VSTART] == '\021'));
456 int new_flow = (I_IXON(tty) &&
457 STOP_CHAR(tty) == '\023' &&
458 START_CHAR(tty) == '\021');
459 if (old_flow != new_flow) {
Alan Cox04f378b2008-04-30 00:53:29 -0700460 spin_lock_irqsave(&tty->ctrl_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
462 if (new_flow)
463 tty->ctrl_status |= TIOCPKT_DOSTOP;
464 else
465 tty->ctrl_status |= TIOCPKT_NOSTOP;
Alan Cox04f378b2008-04-30 00:53:29 -0700466 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 wake_up_interruptible(&tty->link->read_wait);
468 }
469 }
Alan Cox355d95a2008-02-08 04:18:48 -0800470
Alan Coxf34d7a52008-04-30 00:54:13 -0700471 if (tty->ops->set_termios)
472 (*tty->ops->set_termios)(tty, &old_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700473 else
474 tty_termios_copy_hw(tty->termios, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476 ld = tty_ldisc_ref(tty);
477 if (ld != NULL) {
478 if (ld->set_termios)
479 (ld->set_termios)(tty, &old_termios);
480 tty_ldisc_deref(ld);
481 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700482 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Alan Coxaf9b8972006-08-27 01:24:01 -0700485/**
486 * set_termios - set termios values for a tty
487 * @tty: terminal device
488 * @arg: user data
489 * @opt: option information
490 *
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200491 * Helper function to prepare termios data and run necessary other
Alan Coxaf9b8972006-08-27 01:24:01 -0700492 * functions before using change_termios to do the actual changes.
493 *
494 * Locking:
495 * Called functions take ldisc and termios_sem locks
496 */
497
Alan Cox355d95a2008-02-08 04:18:48 -0800498static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Alan Coxedc6afc2006-12-08 02:38:44 -0800500 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 struct tty_ldisc *ld;
502 int retval = tty_check_change(tty);
503
504 if (retval)
505 return retval;
506
Alan Cox978e5952008-04-30 00:53:59 -0700507 mutex_lock(&tty->termios_mutex);
Alan Cox64bb6c52006-12-08 02:38:47 -0800508 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
Alan Cox978e5952008-04-30 00:53:59 -0700509 mutex_unlock(&tty->termios_mutex);
Alan Cox64bb6c52006-12-08 02:38:47 -0800510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (user_termio_to_kernel_termios(&tmp_termios,
513 (struct termio __user *)arg))
514 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800515#ifdef TCGETS2
516 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800517 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 (struct termios __user *)arg))
519 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800520 } else {
521 if (user_termios_to_kernel_termios(&tmp_termios,
522 (struct termios2 __user *)arg))
523 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800525#else
526 } else if (user_termios_to_kernel_termios(&tmp_termios,
527 (struct termios __user *)arg))
528 return -EFAULT;
529#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Alan Cox355d95a2008-02-08 04:18:48 -0800531 /* If old style Bfoo values are used then load c_ispeed/c_ospeed
532 * with the real speed so its unconditionally usable */
Alan Coxedc6afc2006-12-08 02:38:44 -0800533 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
534 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 ld = tty_ldisc_ref(tty);
Alan Cox355d95a2008-02-08 04:18:48 -0800537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if (ld != NULL) {
539 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
540 ld->flush_buffer(tty);
541 tty_ldisc_deref(ld);
542 }
Alan Cox355d95a2008-02-08 04:18:48 -0800543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (opt & TERMIOS_WAIT) {
545 tty_wait_until_sent(tty, 0);
546 if (signal_pending(current))
547 return -EINTR;
548 }
549
550 change_termios(tty, &tmp_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700551
552 /* FIXME: Arguably if tmp_termios == tty->termios AND the
553 actual requested termios was not tmp_termios then we may
554 want to return an error as no user requested change has
555 succeeded */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 return 0;
557}
558
Alan Cox355d95a2008-02-08 04:18:48 -0800559static int get_termio(struct tty_struct *tty, struct termio __user *termio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
561 if (kernel_termios_to_user_termio(termio, tty->termios))
562 return -EFAULT;
563 return 0;
564}
565
Alan Cox355d95a2008-02-08 04:18:48 -0800566static unsigned long inq_canon(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
568 int nr, head, tail;
569
570 if (!tty->canon_data || !tty->read_buf)
571 return 0;
572 head = tty->canon_head;
573 tail = tty->read_tail;
574 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
575 /* Skip EOF-chars.. */
576 while (head != tail) {
577 if (test_bit(tail, tty->read_flags) &&
578 tty->read_buf[tail] == __DISABLED_CHAR)
579 nr--;
580 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
581 }
582 return nr;
583}
584
585#ifdef TIOCGETP
586/*
587 * These are deprecated, but there is limited support..
588 *
589 * The "sg_flags" translation is a joke..
590 */
Alan Cox355d95a2008-02-08 04:18:48 -0800591static int get_sgflags(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
593 int flags = 0;
594
595 if (!(tty->termios->c_lflag & ICANON)) {
596 if (tty->termios->c_lflag & ISIG)
597 flags |= 0x02; /* cbreak */
598 else
599 flags |= 0x20; /* raw */
600 }
601 if (tty->termios->c_lflag & ECHO)
602 flags |= 0x08; /* echo */
603 if (tty->termios->c_oflag & OPOST)
604 if (tty->termios->c_oflag & ONLCR)
605 flags |= 0x10; /* crmod */
606 return flags;
607}
608
Alan Cox355d95a2008-02-08 04:18:48 -0800609static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
611 struct sgttyb tmp;
612
Arjan van de Ven5785c952006-09-29 02:00:43 -0700613 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800614 tmp.sg_ispeed = tty->termios->c_ispeed;
615 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 tmp.sg_erase = tty->termios->c_cc[VERASE];
617 tmp.sg_kill = tty->termios->c_cc[VKILL];
618 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700619 mutex_unlock(&tty->termios_mutex);
Alan Cox355d95a2008-02-08 04:18:48 -0800620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
622}
623
Alan Cox355d95a2008-02-08 04:18:48 -0800624static void set_sgflags(struct ktermios *termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 termios->c_iflag = ICRNL | IXON;
627 termios->c_oflag = 0;
628 termios->c_lflag = ISIG | ICANON;
629 if (flags & 0x02) { /* cbreak */
630 termios->c_iflag = 0;
631 termios->c_lflag &= ~ICANON;
632 }
633 if (flags & 0x08) { /* echo */
634 termios->c_lflag |= ECHO | ECHOE | ECHOK |
635 ECHOCTL | ECHOKE | IEXTEN;
636 }
637 if (flags & 0x10) { /* crmod */
638 termios->c_oflag |= OPOST | ONLCR;
639 }
640 if (flags & 0x20) { /* raw */
641 termios->c_iflag = 0;
642 termios->c_lflag &= ~(ISIG | ICANON);
643 }
644 if (!(termios->c_lflag & ICANON)) {
645 termios->c_cc[VMIN] = 1;
646 termios->c_cc[VTIME] = 0;
647 }
648}
649
Alan Coxaf9b8972006-08-27 01:24:01 -0700650/**
651 * set_sgttyb - set legacy terminal values
652 * @tty: tty structure
653 * @sgttyb: pointer to old style terminal structure
654 *
655 * Updates a terminal from the legacy BSD style terminal information
656 * structure.
657 *
658 * Locking: termios_sem
659 */
660
Alan Cox355d95a2008-02-08 04:18:48 -0800661static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
663 int retval;
664 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800665 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 retval = tty_check_change(tty);
668 if (retval)
669 return retval;
Alan Cox355d95a2008-02-08 04:18:48 -0800670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
672 return -EFAULT;
673
Arjan van de Ven5785c952006-09-29 02:00:43 -0700674 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700675 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 termios.c_cc[VERASE] = tmp.sg_erase;
677 termios.c_cc[VKILL] = tmp.sg_kill;
678 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800679 /* Try and encode into Bfoo format */
680#ifdef BOTHER
Alan Cox355d95a2008-02-08 04:18:48 -0800681 tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
682 termios.c_ospeed);
Alan Coxedc6afc2006-12-08 02:38:44 -0800683#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700684 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 change_termios(tty, &termios);
686 return 0;
687}
688#endif
689
690#ifdef TIOCGETC
Alan Cox355d95a2008-02-08 04:18:48 -0800691static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
693 struct tchars tmp;
694
Alan Cox978e5952008-04-30 00:53:59 -0700695 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 tmp.t_intrc = tty->termios->c_cc[VINTR];
697 tmp.t_quitc = tty->termios->c_cc[VQUIT];
698 tmp.t_startc = tty->termios->c_cc[VSTART];
699 tmp.t_stopc = tty->termios->c_cc[VSTOP];
700 tmp.t_eofc = tty->termios->c_cc[VEOF];
701 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
Alan Cox978e5952008-04-30 00:53:59 -0700702 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
704}
705
Alan Cox355d95a2008-02-08 04:18:48 -0800706static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
708 struct tchars tmp;
709
710 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
711 return -EFAULT;
Alan Cox978e5952008-04-30 00:53:59 -0700712 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 tty->termios->c_cc[VINTR] = tmp.t_intrc;
714 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
715 tty->termios->c_cc[VSTART] = tmp.t_startc;
716 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
717 tty->termios->c_cc[VEOF] = tmp.t_eofc;
718 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
Alan Cox978e5952008-04-30 00:53:59 -0700719 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return 0;
721}
722#endif
723
724#ifdef TIOCGLTC
Alan Cox355d95a2008-02-08 04:18:48 -0800725static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726{
727 struct ltchars tmp;
728
Alan Cox978e5952008-04-30 00:53:59 -0700729 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 tmp.t_suspc = tty->termios->c_cc[VSUSP];
Alan Cox355d95a2008-02-08 04:18:48 -0800731 /* what is dsuspc anyway? */
732 tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
Alan Cox355d95a2008-02-08 04:18:48 -0800734 /* what is flushc anyway? */
735 tmp.t_flushc = tty->termios->c_cc[VEOL2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 tmp.t_werasc = tty->termios->c_cc[VWERASE];
737 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
Alan Cox978e5952008-04-30 00:53:59 -0700738 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
740}
741
Alan Cox355d95a2008-02-08 04:18:48 -0800742static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
744 struct ltchars tmp;
745
746 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
747 return -EFAULT;
748
Alan Cox978e5952008-04-30 00:53:59 -0700749 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
Alan Cox355d95a2008-02-08 04:18:48 -0800751 /* what is dsuspc anyway? */
752 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
Alan Cox355d95a2008-02-08 04:18:48 -0800754 /* what is flushc anyway? */
755 tty->termios->c_cc[VEOL2] = tmp.t_flushc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
757 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
Alan Cox978e5952008-04-30 00:53:59 -0700758 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return 0;
760}
761#endif
762
Alan Coxaf9b8972006-08-27 01:24:01 -0700763/**
764 * send_prio_char - send priority character
765 *
766 * Send a high priority character to the tty even if stopped
767 *
Alan Cox5f412b22006-09-29 02:01:40 -0700768 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700770
Alan Cox5f412b22006-09-29 02:01:40 -0700771static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772{
773 int was_stopped = tty->stopped;
774
Alan Coxf34d7a52008-04-30 00:54:13 -0700775 if (tty->ops->send_xchar) {
776 tty->ops->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700777 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
Alan Cox5f412b22006-09-29 02:01:40 -0700779
Alan Cox9c1729d2007-07-15 23:39:43 -0700780 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700781 return -ERESTARTSYS;
782
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (was_stopped)
784 start_tty(tty);
Alan Coxf34d7a52008-04-30 00:54:13 -0700785 tty->ops->write(tty, &ch, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (was_stopped)
787 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700788 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700789 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790}
791
Alan Cox0fc00e22007-11-07 01:24:56 -0800792/**
Alan Cox1c2630c2008-04-30 00:53:34 -0700793 * tty_change_softcar - carrier change ioctl helper
794 * @tty: tty to update
795 * @arg: enable/disable CLOCAL
796 *
797 * Perform a change to the CLOCAL state and call into the driver
798 * layer to make it visible. All done with the termios mutex
799 */
800
801static int tty_change_softcar(struct tty_struct *tty, int arg)
802{
803 int ret = 0;
804 int bit = arg ? CLOCAL : 0;
Alan Coxf34d7a52008-04-30 00:54:13 -0700805 struct ktermios old;
Alan Cox1c2630c2008-04-30 00:53:34 -0700806
807 mutex_lock(&tty->termios_mutex);
Alan Coxf34d7a52008-04-30 00:54:13 -0700808 old = *tty->termios;
Alan Cox1c2630c2008-04-30 00:53:34 -0700809 tty->termios->c_cflag &= ~CLOCAL;
810 tty->termios->c_cflag |= bit;
Alan Coxf34d7a52008-04-30 00:54:13 -0700811 if (tty->ops->set_termios)
812 tty->ops->set_termios(tty, &old);
Alan Cox1c2630c2008-04-30 00:53:34 -0700813 if ((tty->termios->c_cflag & CLOCAL) != bit)
814 ret = -EINVAL;
815 mutex_unlock(&tty->termios_mutex);
816 return ret;
817}
818
819/**
Alan Cox0fc00e22007-11-07 01:24:56 -0800820 * tty_mode_ioctl - mode related ioctls
821 * @tty: tty for the ioctl
822 * @file: file pointer for the tty
823 * @cmd: command
824 * @arg: ioctl argument
825 *
826 * Perform non line discipline specific mode control ioctls. This
827 * is designed to be called by line disciplines to ensure they provide
828 * consistent mode setting.
829 */
830
Alan Cox355d95a2008-02-08 04:18:48 -0800831int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -0800832 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
Alan Cox355d95a2008-02-08 04:18:48 -0800834 struct tty_struct *real_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 void __user *p = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
838 tty->driver->subtype == PTY_TYPE_MASTER)
839 real_tty = tty->link;
840 else
841 real_tty = tty;
842
843 switch (cmd) {
844#ifdef TIOCGETP
Alan Cox355d95a2008-02-08 04:18:48 -0800845 case TIOCGETP:
846 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
847 case TIOCSETP:
848 case TIOCSETN:
849 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850#endif
851#ifdef TIOCGETC
Alan Cox355d95a2008-02-08 04:18:48 -0800852 case TIOCGETC:
853 return get_tchars(real_tty, p);
854 case TIOCSETC:
855 return set_tchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856#endif
857#ifdef TIOCGLTC
Alan Cox355d95a2008-02-08 04:18:48 -0800858 case TIOCGLTC:
859 return get_ltchars(real_tty, p);
860 case TIOCSLTC:
861 return set_ltchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862#endif
Alan Cox355d95a2008-02-08 04:18:48 -0800863 case TCSETSF:
864 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
865 case TCSETSW:
866 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
867 case TCSETS:
868 return set_termios(real_tty, p, TERMIOS_OLD);
Alan Coxedc6afc2006-12-08 02:38:44 -0800869#ifndef TCGETS2
Alan Cox355d95a2008-02-08 04:18:48 -0800870 case TCGETS:
871 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
872 return -EFAULT;
873 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800874#else
Alan Cox355d95a2008-02-08 04:18:48 -0800875 case TCGETS:
876 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
877 return -EFAULT;
878 return 0;
879 case TCGETS2:
880 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
881 return -EFAULT;
882 return 0;
883 case TCSETSF2:
884 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
885 case TCSETSW2:
886 return set_termios(real_tty, p, TERMIOS_WAIT);
887 case TCSETS2:
888 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800889#endif
Alan Cox355d95a2008-02-08 04:18:48 -0800890 case TCGETA:
891 return get_termio(real_tty, p);
892 case TCSETAF:
893 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
894 case TCSETAW:
895 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
896 case TCSETA:
897 return set_termios(real_tty, p, TERMIOS_TERMIO);
Alan Cox0fc00e22007-11-07 01:24:56 -0800898#ifndef TCGETS2
Alan Cox355d95a2008-02-08 04:18:48 -0800899 case TIOCGLCKTRMIOS:
900 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
901 return -EFAULT;
902 return 0;
903 case TIOCSLCKTRMIOS:
904 if (!capable(CAP_SYS_ADMIN))
905 return -EPERM;
906 if (user_termios_to_kernel_termios(real_tty->termios_locked,
907 (struct termios __user *) arg))
908 return -EFAULT;
909 return 0;
Alan Cox0fc00e22007-11-07 01:24:56 -0800910#else
Alan Cox355d95a2008-02-08 04:18:48 -0800911 case TIOCGLCKTRMIOS:
912 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
913 return -EFAULT;
914 return 0;
915 case TIOCSLCKTRMIOS:
916 if (!capable(CAP_SYS_ADMIN))
917 return -EPERM;
918 if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
919 (struct termios __user *) arg))
920 return -EFAULT;
Alan Cox0fc00e22007-11-07 01:24:56 -0800921 return 0;
922#endif
Alan Cox355d95a2008-02-08 04:18:48 -0800923 case TIOCGSOFTCAR:
924 return put_user(C_CLOCAL(tty) ? 1 : 0,
925 (int __user *)arg);
926 case TIOCSSOFTCAR:
927 if (get_user(arg, (unsigned int __user *) arg))
928 return -EFAULT;
Alan Cox1c2630c2008-04-30 00:53:34 -0700929 return tty_change_softcar(tty, arg);
Alan Cox355d95a2008-02-08 04:18:48 -0800930 default:
931 return -ENOIOCTLCMD;
Alan Cox0fc00e22007-11-07 01:24:56 -0800932 }
933}
Alan Cox0fc00e22007-11-07 01:24:56 -0800934EXPORT_SYMBOL_GPL(tty_mode_ioctl);
935
936int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
937{
938 struct tty_ldisc *ld;
939 int retval = tty_check_change(tty);
940 if (retval)
941 return retval;
942
943 ld = tty_ldisc_ref(tty);
944 switch (arg) {
945 case TCIFLUSH:
946 if (ld && ld->flush_buffer)
947 ld->flush_buffer(tty);
948 break;
949 case TCIOFLUSH:
950 if (ld && ld->flush_buffer)
951 ld->flush_buffer(tty);
952 /* fall through */
953 case TCOFLUSH:
Alan Coxf34d7a52008-04-30 00:54:13 -0700954 tty_driver_flush_buffer(tty);
Alan Cox0fc00e22007-11-07 01:24:56 -0800955 break;
956 default:
957 tty_ldisc_deref(ld);
958 return -EINVAL;
959 }
960 tty_ldisc_deref(ld);
961 return 0;
962}
Alan Cox0fc00e22007-11-07 01:24:56 -0800963EXPORT_SYMBOL_GPL(tty_perform_flush);
964
Alan Cox355d95a2008-02-08 04:18:48 -0800965int n_tty_ioctl(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -0800966 unsigned int cmd, unsigned long arg)
967{
Alan Cox355d95a2008-02-08 04:18:48 -0800968 struct tty_struct *real_tty;
Alan Cox04f378b2008-04-30 00:53:29 -0700969 unsigned long flags;
Alan Cox0fc00e22007-11-07 01:24:56 -0800970 int retval;
971
972 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
973 tty->driver->subtype == PTY_TYPE_MASTER)
974 real_tty = tty->link;
975 else
976 real_tty = tty;
977
978 switch (cmd) {
Alan Cox355d95a2008-02-08 04:18:48 -0800979 case TCXONC:
980 retval = tty_check_change(tty);
981 if (retval)
982 return retval;
983 switch (arg) {
984 case TCOOFF:
985 if (!tty->flow_stopped) {
986 tty->flow_stopped = 1;
987 stop_tty(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 }
Alan Cox355d95a2008-02-08 04:18:48 -0800989 break;
990 case TCOON:
991 if (tty->flow_stopped) {
992 tty->flow_stopped = 0;
993 start_tty(tty);
994 }
995 break;
996 case TCIOFF:
997 if (STOP_CHAR(tty) != __DISABLED_CHAR)
998 return send_prio_char(tty, STOP_CHAR(tty));
999 break;
1000 case TCION:
1001 if (START_CHAR(tty) != __DISABLED_CHAR)
1002 return send_prio_char(tty, START_CHAR(tty));
1003 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 default:
Alan Cox355d95a2008-02-08 04:18:48 -08001005 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 }
Alan Cox355d95a2008-02-08 04:18:48 -08001007 return 0;
1008 case TCFLSH:
1009 return tty_perform_flush(tty, arg);
1010 case TIOCOUTQ:
Alan Coxf34d7a52008-04-30 00:54:13 -07001011 return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
Alan Cox355d95a2008-02-08 04:18:48 -08001012 case TIOCINQ:
1013 retval = tty->read_cnt;
1014 if (L_ICANON(tty))
1015 retval = inq_canon(tty);
1016 return put_user(retval, (unsigned int __user *) arg);
1017 case TIOCPKT:
1018 {
1019 int pktmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Alan Cox355d95a2008-02-08 04:18:48 -08001021 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
1022 tty->driver->subtype != PTY_TYPE_MASTER)
1023 return -ENOTTY;
1024 if (get_user(pktmode, (int __user *) arg))
1025 return -EFAULT;
Alan Cox04f378b2008-04-30 00:53:29 -07001026 spin_lock_irqsave(&tty->ctrl_lock, flags);
Alan Cox355d95a2008-02-08 04:18:48 -08001027 if (pktmode) {
1028 if (!tty->packet) {
1029 tty->packet = 1;
1030 tty->link->ctrl_status = 0;
1031 }
1032 } else
1033 tty->packet = 0;
Alan Cox04f378b2008-04-30 00:53:29 -07001034 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
Alan Cox355d95a2008-02-08 04:18:48 -08001035 return 0;
1036 }
1037 default:
1038 /* Try the mode commands */
1039 return tty_mode_ioctl(tty, file, cmd, arg);
1040 }
1041}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042EXPORT_SYMBOL(n_tty_ioctl);