blob: d4b6d64e858b5e4ec18255a992ce0e57a0cbd92b [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
42/**
43 * tty_wait_until_sent - wait for I/O to finish
44 * @tty: tty we are waiting for
45 * @timeout: how long we will wait
46 *
47 * Wait for characters pending in a tty driver to hit the wire, or
48 * for a timeout to occur (eg due to flow control)
49 *
50 * Locking: none
51 */
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053void tty_wait_until_sent(struct tty_struct * tty, long timeout)
54{
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
56 char buf[64];
57
58 printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
59#endif
60 if (!tty->driver->chars_in_buffer)
61 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 if (!timeout)
63 timeout = MAX_SCHEDULE_TIMEOUT;
Jiri Slaby5a52bd42007-07-15 23:40:18 -070064 if (wait_event_interruptible_timeout(tty->write_wait,
Cory T. Tusardb992472007-12-23 12:34:51 -080065 !tty->driver->chars_in_buffer(tty), timeout) < 0)
Jiri Slaby5a52bd42007-07-15 23:40:18 -070066 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 if (tty->driver->wait_until_sent)
68 tty->driver->wait_until_sent(tty, timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
71EXPORT_SYMBOL(tty_wait_until_sent);
72
Alan Coxedc6afc2006-12-08 02:38:44 -080073static void unset_locked_termios(struct ktermios *termios,
74 struct ktermios *old,
75 struct ktermios *locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
77 int i;
78
79#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
80
81 if (!locked) {
82 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
83 return;
84 }
85
86 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
87 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
88 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
89 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
90 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
91 for (i=0; i < NCCS; i++)
92 termios->c_cc[i] = locked->c_cc[i] ?
93 old->c_cc[i] : termios->c_cc[i];
Alan Coxedc6afc2006-12-08 02:38:44 -080094 /* FIXME: What should we do for i/ospeed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96
Alan Coxedc6afc2006-12-08 02:38:44 -080097/*
98 * Routine which returns the baud rate of the tty
99 *
100 * Note that the baud_table needs to be kept in sync with the
101 * include/asm/termbits.h file.
102 */
103static const speed_t baud_table[] = {
104 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
105 9600, 19200, 38400, 57600, 115200, 230400, 460800,
106#ifdef __sparc__
107 76800, 153600, 307200, 614400, 921600
108#else
109 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
110 2500000, 3000000, 3500000, 4000000
111#endif
112};
113
114#ifndef __sparc__
115static const tcflag_t baud_bits[] = {
116 B0, B50, B75, B110, B134, B150, B200, B300, B600,
117 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
118 B57600, B115200, B230400, B460800, B500000, B576000,
119 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
120 B3000000, B3500000, B4000000
121};
122#else
123static const tcflag_t baud_bits[] = {
124 B0, B50, B75, B110, B134, B150, B200, B300, B600,
125 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
126 B57600, B115200, B230400, B460800, B76800, B153600,
127 B307200, B614400, B921600
128};
129#endif
130
131static int n_baud_table = ARRAY_SIZE(baud_table);
132
133/**
134 * tty_termios_baud_rate
135 * @termios: termios structure
136 *
137 * Convert termios baud rate data into a speed. This should be called
138 * with the termios lock held if this termios is a terminal termios
139 * structure. May change the termios data. Device drivers can call this
140 * function but should use ->c_[io]speed directly as they are updated.
141 *
142 * Locking: none
143 */
144
145speed_t tty_termios_baud_rate(struct ktermios *termios)
146{
147 unsigned int cbaud;
148
149 cbaud = termios->c_cflag & CBAUD;
150
151#ifdef BOTHER
152 /* Magic token for arbitary speed via c_ispeed/c_ospeed */
153 if (cbaud == BOTHER)
154 return termios->c_ospeed;
155#endif
156 if (cbaud & CBAUDEX) {
157 cbaud &= ~CBAUDEX;
158
159 if (cbaud < 1 || cbaud + 15 > n_baud_table)
160 termios->c_cflag &= ~CBAUDEX;
161 else
162 cbaud += 15;
163 }
164 return baud_table[cbaud];
165}
166
167EXPORT_SYMBOL(tty_termios_baud_rate);
168
169/**
170 * tty_termios_input_baud_rate
171 * @termios: termios structure
172 *
173 * Convert termios baud rate data into a speed. This should be called
174 * with the termios lock held if this termios is a terminal termios
175 * structure. May change the termios data. Device drivers can call this
176 * function but should use ->c_[io]speed directly as they are updated.
177 *
178 * Locking: none
179 */
180
181speed_t tty_termios_input_baud_rate(struct ktermios *termios)
182{
183#ifdef IBSHIFT
184 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
185
186 if (cbaud == B0)
187 return tty_termios_baud_rate(termios);
188
189 /* Magic token for arbitary speed via c_ispeed*/
190 if (cbaud == BOTHER)
191 return termios->c_ispeed;
192
193 if (cbaud & CBAUDEX) {
194 cbaud &= ~CBAUDEX;
195
196 if (cbaud < 1 || cbaud + 15 > n_baud_table)
197 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
198 else
199 cbaud += 15;
200 }
201 return baud_table[cbaud];
202#else
203 return tty_termios_baud_rate(termios);
204#endif
205}
206
207EXPORT_SYMBOL(tty_termios_input_baud_rate);
208
Alan Coxedc6afc2006-12-08 02:38:44 -0800209/**
210 * tty_termios_encode_baud_rate
Alan Cox78137e32007-02-10 01:45:57 -0800211 * @termios: ktermios structure holding user requested state
Alan Coxedc6afc2006-12-08 02:38:44 -0800212 * @ispeed: input speed
213 * @ospeed: output speed
214 *
215 * Encode the speeds set into the passed termios structure. This is
216 * used as a library helper for drivers os that they can report back
217 * the actual speed selected when it differs from the speed requested
218 *
Alan Cox78137e32007-02-10 01:45:57 -0800219 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
220 * we need to carefully set the bits when the user does not get the
221 * desired speed. We allow small margins and preserve as much of possible
222 * of the input intent to keep compatiblity.
Alan Coxedc6afc2006-12-08 02:38:44 -0800223 *
224 * Locking: Caller should hold termios lock. This is already held
225 * when calling this function from the driver termios handler.
Alan Cox5f519d72007-10-16 23:30:07 -0700226 *
227 * The ifdefs deal with platforms whose owners have yet to update them
228 * and will all go away once this is done.
Alan Coxedc6afc2006-12-08 02:38:44 -0800229 */
230
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700231void tty_termios_encode_baud_rate(struct ktermios *termios,
232 speed_t ibaud, speed_t obaud)
Alan Coxedc6afc2006-12-08 02:38:44 -0800233{
234 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800235 int ifound = -1, ofound = -1;
236 int iclose = ibaud/50, oclose = obaud/50;
237 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800238
Alan Cox5f519d72007-10-16 23:30:07 -0700239 if (obaud == 0) /* CD dropped */
240 ibaud = 0; /* Clear ibaud to be sure */
241
Alan Coxedc6afc2006-12-08 02:38:44 -0800242 termios->c_ispeed = ibaud;
243 termios->c_ospeed = obaud;
244
Alan Cox5f519d72007-10-16 23:30:07 -0700245#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800246 /* If the user asked for a precise weird speed give a precise weird
247 answer. If they asked for a Bfoo speed they many have problems
248 digesting non-exact replies so fuzz a bit */
249
250 if ((termios->c_cflag & CBAUD) == BOTHER)
251 oclose = 0;
252 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
253 iclose = 0;
254 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
255 ibinput = 1; /* An input speed was specified */
Alan Cox5f519d72007-10-16 23:30:07 -0700256#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800257 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800258
Alan Cox5f519d72007-10-16 23:30:07 -0700259 /*
260 * Our goal is to find a close match to the standard baud rate
261 * returned. Walk the baud rate table and if we get a very close
262 * match then report back the speed as a POSIX Bxxxx value by
263 * preference
264 */
265
Alan Coxedc6afc2006-12-08 02:38:44 -0800266 do {
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700267 if (obaud - oclose <= baud_table[i] &&
268 obaud + oclose >= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800269 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800270 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800271 }
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700272 if (ibaud - iclose <= baud_table[i] &&
273 ibaud + iclose >= baud_table[i]) {
274 /* For the case input == output don't set IBAUD bits
275 if the user didn't do so */
Alan Cox5f519d72007-10-16 23:30:07 -0700276 if (ofound == i && !ibinput)
277 ifound = i;
278#ifdef IBSHIFT
279 else {
280 ifound = i;
Alan Cox78137e32007-02-10 01:45:57 -0800281 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700282 }
283#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800284 }
Jiri Slaby68043962007-07-15 23:40:18 -0700285 } while (++i < n_baud_table);
Alan Cox5f519d72007-10-16 23:30:07 -0700286
287 /*
288 * If we found no match then use BOTHER if provided or warn
289 * the user their platform maintainer needs to wake up if not.
290 */
291#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800292 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800293 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800294 /* Set exact input bits only if the input and output differ or the
295 user already did */
Jiri Slaby68043962007-07-15 23:40:18 -0700296 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800297 termios->c_cflag |= (BOTHER << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700298#else
299 if (ifound == -1 || ofound == -1) {
300 static int warned;
301 if (!warned++)
302 printk(KERN_WARNING "tty: Unable to return correct "
303 "speed data as your architecture needs updating.\n");
304 }
305#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800306}
Alan Coxedc6afc2006-12-08 02:38:44 -0800307EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
308
Alan Cox5f519d72007-10-16 23:30:07 -0700309void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
310{
311 tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
312}
313EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
Alan Coxedc6afc2006-12-08 02:38:44 -0800314
315/**
316 * tty_get_baud_rate - get tty bit rates
317 * @tty: tty to query
318 *
319 * Returns the baud rate as an integer for this terminal. The
320 * termios lock must be held by the caller and the terminal bit
321 * flags may be updated.
322 *
323 * Locking: none
324 */
325
326speed_t tty_get_baud_rate(struct tty_struct *tty)
327{
328 speed_t baud = tty_termios_baud_rate(tty->termios);
329
330 if (baud == 38400 && tty->alt_speed) {
331 if (!tty->warned) {
332 printk(KERN_WARNING "Use of setserial/setrocket to "
333 "set SPD_* flags is deprecated\n");
334 tty->warned = 1;
335 }
336 baud = tty->alt_speed;
337 }
338
339 return baud;
340}
341
342EXPORT_SYMBOL(tty_get_baud_rate);
343
Alan Coxaf9b8972006-08-27 01:24:01 -0700344/**
Alan Cox5f519d72007-10-16 23:30:07 -0700345 * tty_termios_copy_hw - copy hardware settings
346 * @new: New termios
347 * @old: Old termios
348 *
349 * Propogate the hardware specific terminal setting bits from
350 * the old termios structure to the new one. This is used in cases
351 * where the hardware does not support reconfiguration or as a helper
352 * in some cases where only minimal reconfiguration is supported
353 */
354
355void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
356{
357 /* The bits a dumb device handles in software. Smart devices need
358 to always provide a set_termios method */
359 new->c_cflag &= HUPCL | CREAD | CLOCAL;
360 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
361 new->c_ispeed = old->c_ispeed;
362 new->c_ospeed = old->c_ospeed;
363}
364
365EXPORT_SYMBOL(tty_termios_copy_hw);
366
367/**
Alan Coxbf5e5832008-01-08 14:55:51 +0000368 * tty_termios_hw_change - check for setting change
369 * @a: termios
370 * @b: termios to compare
371 *
372 * Check if any of the bits that affect a dumb device have changed
373 * between the two termios structures, or a speed change is needed.
374 */
375
376int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
377{
378 if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
379 return 1;
380 if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
381 return 1;
382 return 0;
383}
384EXPORT_SYMBOL(tty_termios_hw_change);
385
386/**
Alan Coxaf9b8972006-08-27 01:24:01 -0700387 * change_termios - update termios values
388 * @tty: tty to update
389 * @new_termios: desired new value
390 *
391 * Perform updates to the termios values set on this terminal. There
392 * is a bit of layering violation here with n_tty in terms of the
393 * internal knowledge of this function.
394 *
395 * Locking: termios_sem
396 */
397
Alan Coxedc6afc2006-12-08 02:38:44 -0800398static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
400 int canon_change;
Alan Coxedc6afc2006-12-08 02:38:44 -0800401 struct ktermios old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 struct tty_ldisc *ld;
403
404 /*
405 * Perform the actual termios internal changes under lock.
406 */
407
408
409 /* FIXME: we need to decide on some locking/ordering semantics
410 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700411 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
413 *tty->termios = *new_termios;
414 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
415 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
416 if (canon_change) {
417 memset(&tty->read_flags, 0, sizeof tty->read_flags);
418 tty->canon_head = tty->read_tail;
419 tty->canon_data = 0;
420 tty->erasing = 0;
421 }
422
Alan Cox5f519d72007-10-16 23:30:07 -0700423 /* This bit should be in the ldisc code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
425 /* Get characters left over from canonical mode. */
426 wake_up_interruptible(&tty->read_wait);
427
428 /* See if packet mode change of state. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 if (tty->link && tty->link->packet) {
430 int old_flow = ((old_termios.c_iflag & IXON) &&
431 (old_termios.c_cc[VSTOP] == '\023') &&
432 (old_termios.c_cc[VSTART] == '\021'));
433 int new_flow = (I_IXON(tty) &&
434 STOP_CHAR(tty) == '\023' &&
435 START_CHAR(tty) == '\021');
436 if (old_flow != new_flow) {
437 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
438 if (new_flow)
439 tty->ctrl_status |= TIOCPKT_DOSTOP;
440 else
441 tty->ctrl_status |= TIOCPKT_NOSTOP;
442 wake_up_interruptible(&tty->link->read_wait);
443 }
444 }
445
446 if (tty->driver->set_termios)
447 (*tty->driver->set_termios)(tty, &old_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700448 else
449 tty_termios_copy_hw(tty->termios, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 ld = tty_ldisc_ref(tty);
452 if (ld != NULL) {
453 if (ld->set_termios)
454 (ld->set_termios)(tty, &old_termios);
455 tty_ldisc_deref(ld);
456 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700457 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
Alan Coxaf9b8972006-08-27 01:24:01 -0700460/**
461 * set_termios - set termios values for a tty
462 * @tty: terminal device
463 * @arg: user data
464 * @opt: option information
465 *
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200466 * Helper function to prepare termios data and run necessary other
Alan Coxaf9b8972006-08-27 01:24:01 -0700467 * functions before using change_termios to do the actual changes.
468 *
469 * Locking:
470 * Called functions take ldisc and termios_sem locks
471 */
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
474{
Alan Coxedc6afc2006-12-08 02:38:44 -0800475 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 struct tty_ldisc *ld;
477 int retval = tty_check_change(tty);
478
479 if (retval)
480 return retval;
481
Alan Cox64bb6c52006-12-08 02:38:47 -0800482 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 if (user_termio_to_kernel_termios(&tmp_termios,
486 (struct termio __user *)arg))
487 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800488#ifdef TCGETS2
489 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800490 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 (struct termios __user *)arg))
492 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800493 } else {
494 if (user_termios_to_kernel_termios(&tmp_termios,
495 (struct termios2 __user *)arg))
496 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800498#else
499 } else if (user_termios_to_kernel_termios(&tmp_termios,
500 (struct termios __user *)arg))
501 return -EFAULT;
502#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
Alan Coxedc6afc2006-12-08 02:38:44 -0800504 /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed
505 so its unconditionally usable */
506 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
507 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 ld = tty_ldisc_ref(tty);
510
511 if (ld != NULL) {
512 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
513 ld->flush_buffer(tty);
514 tty_ldisc_deref(ld);
515 }
516
517 if (opt & TERMIOS_WAIT) {
518 tty_wait_until_sent(tty, 0);
519 if (signal_pending(current))
520 return -EINTR;
521 }
522
523 change_termios(tty, &tmp_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700524
525 /* FIXME: Arguably if tmp_termios == tty->termios AND the
526 actual requested termios was not tmp_termios then we may
527 want to return an error as no user requested change has
528 succeeded */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 return 0;
530}
531
532static int get_termio(struct tty_struct * tty, struct termio __user * termio)
533{
534 if (kernel_termios_to_user_termio(termio, tty->termios))
535 return -EFAULT;
536 return 0;
537}
538
539static unsigned long inq_canon(struct tty_struct * tty)
540{
541 int nr, head, tail;
542
543 if (!tty->canon_data || !tty->read_buf)
544 return 0;
545 head = tty->canon_head;
546 tail = tty->read_tail;
547 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
548 /* Skip EOF-chars.. */
549 while (head != tail) {
550 if (test_bit(tail, tty->read_flags) &&
551 tty->read_buf[tail] == __DISABLED_CHAR)
552 nr--;
553 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
554 }
555 return nr;
556}
557
558#ifdef TIOCGETP
559/*
560 * These are deprecated, but there is limited support..
561 *
562 * The "sg_flags" translation is a joke..
563 */
564static int get_sgflags(struct tty_struct * tty)
565{
566 int flags = 0;
567
568 if (!(tty->termios->c_lflag & ICANON)) {
569 if (tty->termios->c_lflag & ISIG)
570 flags |= 0x02; /* cbreak */
571 else
572 flags |= 0x20; /* raw */
573 }
574 if (tty->termios->c_lflag & ECHO)
575 flags |= 0x08; /* echo */
576 if (tty->termios->c_oflag & OPOST)
577 if (tty->termios->c_oflag & ONLCR)
578 flags |= 0x10; /* crmod */
579 return flags;
580}
581
582static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
583{
584 struct sgttyb tmp;
585
Arjan van de Ven5785c952006-09-29 02:00:43 -0700586 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800587 tmp.sg_ispeed = tty->termios->c_ispeed;
588 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 tmp.sg_erase = tty->termios->c_cc[VERASE];
590 tmp.sg_kill = tty->termios->c_cc[VKILL];
591 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700592 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
595}
596
Alan Coxedc6afc2006-12-08 02:38:44 -0800597static void set_sgflags(struct ktermios * termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598{
599 termios->c_iflag = ICRNL | IXON;
600 termios->c_oflag = 0;
601 termios->c_lflag = ISIG | ICANON;
602 if (flags & 0x02) { /* cbreak */
603 termios->c_iflag = 0;
604 termios->c_lflag &= ~ICANON;
605 }
606 if (flags & 0x08) { /* echo */
607 termios->c_lflag |= ECHO | ECHOE | ECHOK |
608 ECHOCTL | ECHOKE | IEXTEN;
609 }
610 if (flags & 0x10) { /* crmod */
611 termios->c_oflag |= OPOST | ONLCR;
612 }
613 if (flags & 0x20) { /* raw */
614 termios->c_iflag = 0;
615 termios->c_lflag &= ~(ISIG | ICANON);
616 }
617 if (!(termios->c_lflag & ICANON)) {
618 termios->c_cc[VMIN] = 1;
619 termios->c_cc[VTIME] = 0;
620 }
621}
622
Alan Coxaf9b8972006-08-27 01:24:01 -0700623/**
624 * set_sgttyb - set legacy terminal values
625 * @tty: tty structure
626 * @sgttyb: pointer to old style terminal structure
627 *
628 * Updates a terminal from the legacy BSD style terminal information
629 * structure.
630 *
631 * Locking: termios_sem
632 */
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
635{
636 int retval;
637 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800638 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 retval = tty_check_change(tty);
641 if (retval)
642 return retval;
643
644 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
645 return -EFAULT;
646
Arjan van de Ven5785c952006-09-29 02:00:43 -0700647 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700648 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 termios.c_cc[VERASE] = tmp.sg_erase;
650 termios.c_cc[VKILL] = tmp.sg_kill;
651 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800652 /* Try and encode into Bfoo format */
653#ifdef BOTHER
654 tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
655#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700656 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 change_termios(tty, &termios);
658 return 0;
659}
660#endif
661
662#ifdef TIOCGETC
663static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars)
664{
665 struct tchars tmp;
666
667 tmp.t_intrc = tty->termios->c_cc[VINTR];
668 tmp.t_quitc = tty->termios->c_cc[VQUIT];
669 tmp.t_startc = tty->termios->c_cc[VSTART];
670 tmp.t_stopc = tty->termios->c_cc[VSTOP];
671 tmp.t_eofc = tty->termios->c_cc[VEOF];
672 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
673 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
674}
675
676static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars)
677{
678 struct tchars tmp;
679
680 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
681 return -EFAULT;
682 tty->termios->c_cc[VINTR] = tmp.t_intrc;
683 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
684 tty->termios->c_cc[VSTART] = tmp.t_startc;
685 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
686 tty->termios->c_cc[VEOF] = tmp.t_eofc;
687 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
688 return 0;
689}
690#endif
691
692#ifdef TIOCGLTC
693static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
694{
695 struct ltchars tmp;
696
697 tmp.t_suspc = tty->termios->c_cc[VSUSP];
698 tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */
699 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
700 tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */
701 tmp.t_werasc = tty->termios->c_cc[VWERASE];
702 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
703 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
704}
705
706static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
707{
708 struct ltchars tmp;
709
710 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
711 return -EFAULT;
712
713 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
714 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */
715 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
716 tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */
717 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
718 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
719 return 0;
720}
721#endif
722
Alan Coxaf9b8972006-08-27 01:24:01 -0700723/**
724 * send_prio_char - send priority character
725 *
726 * Send a high priority character to the tty even if stopped
727 *
Alan Cox5f412b22006-09-29 02:01:40 -0700728 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700730
Alan Cox5f412b22006-09-29 02:01:40 -0700731static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
733 int was_stopped = tty->stopped;
734
735 if (tty->driver->send_xchar) {
736 tty->driver->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700737 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 }
Alan Cox5f412b22006-09-29 02:01:40 -0700739
Alan Cox9c1729d2007-07-15 23:39:43 -0700740 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700741 return -ERESTARTSYS;
742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (was_stopped)
744 start_tty(tty);
745 tty->driver->write(tty, &ch, 1);
746 if (was_stopped)
747 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700748 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700749 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750}
751
Alan Cox0fc00e22007-11-07 01:24:56 -0800752/**
753 * tty_mode_ioctl - mode related ioctls
754 * @tty: tty for the ioctl
755 * @file: file pointer for the tty
756 * @cmd: command
757 * @arg: ioctl argument
758 *
759 * Perform non line discipline specific mode control ioctls. This
760 * is designed to be called by line disciplines to ensure they provide
761 * consistent mode setting.
762 */
763
764int tty_mode_ioctl(struct tty_struct * tty, struct file *file,
765 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
767 struct tty_struct * real_tty;
768 void __user *p = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
771 tty->driver->subtype == PTY_TYPE_MASTER)
772 real_tty = tty->link;
773 else
774 real_tty = tty;
775
776 switch (cmd) {
777#ifdef TIOCGETP
778 case TIOCGETP:
779 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
780 case TIOCSETP:
781 case TIOCSETN:
782 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
783#endif
784#ifdef TIOCGETC
785 case TIOCGETC:
786 return get_tchars(real_tty, p);
787 case TIOCSETC:
788 return set_tchars(real_tty, p);
789#endif
790#ifdef TIOCGLTC
791 case TIOCGLTC:
792 return get_ltchars(real_tty, p);
793 case TIOCSLTC:
794 return set_ltchars(real_tty, p);
795#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800796 case TCSETSF:
797 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
798 case TCSETSW:
799 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
800 case TCSETS:
801 return set_termios(real_tty, p, TERMIOS_OLD);
802#ifndef TCGETS2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 case TCGETS:
804 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
805 return -EFAULT;
806 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800807#else
808 case TCGETS:
Alan Cox64bb6c52006-12-08 02:38:47 -0800809 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800810 return -EFAULT;
811 return 0;
812 case TCGETS2:
Alan Cox64bb6c52006-12-08 02:38:47 -0800813 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800814 return -EFAULT;
815 return 0;
816 case TCSETSF2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800818 case TCSETSW2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return set_termios(real_tty, p, TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800820 case TCSETS2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800822#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 case TCGETA:
824 return get_termio(real_tty, p);
825 case TCSETAF:
826 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
827 case TCSETAW:
828 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
829 case TCSETA:
830 return set_termios(real_tty, p, TERMIOS_TERMIO);
Alan Cox0fc00e22007-11-07 01:24:56 -0800831#ifndef TCGETS2
832 case TIOCGLCKTRMIOS:
833 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
834 return -EFAULT;
835 return 0;
836
837 case TIOCSLCKTRMIOS:
838 if (!capable(CAP_SYS_ADMIN))
839 return -EPERM;
840 if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
841 return -EFAULT;
842 return 0;
843#else
844 case TIOCGLCKTRMIOS:
845 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
846 return -EFAULT;
847 return 0;
848
849 case TIOCSLCKTRMIOS:
850 if (!capable(CAP_SYS_ADMIN))
851 return -EPERM;
852 if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
853 return -EFAULT;
854 return 0;
855#endif
856 case TIOCGSOFTCAR:
857 return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
858 case TIOCSSOFTCAR:
859 if (get_user(arg, (unsigned int __user *) arg))
860 return -EFAULT;
861 mutex_lock(&tty->termios_mutex);
862 tty->termios->c_cflag =
863 ((tty->termios->c_cflag & ~CLOCAL) |
864 (arg ? CLOCAL : 0));
865 mutex_unlock(&tty->termios_mutex);
866 return 0;
867 default:
868 return -ENOIOCTLCMD;
869 }
870}
871
872EXPORT_SYMBOL_GPL(tty_mode_ioctl);
873
874int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
875{
876 struct tty_ldisc *ld;
877 int retval = tty_check_change(tty);
878 if (retval)
879 return retval;
880
881 ld = tty_ldisc_ref(tty);
882 switch (arg) {
883 case TCIFLUSH:
884 if (ld && ld->flush_buffer)
885 ld->flush_buffer(tty);
886 break;
887 case TCIOFLUSH:
888 if (ld && ld->flush_buffer)
889 ld->flush_buffer(tty);
890 /* fall through */
891 case TCOFLUSH:
892 if (tty->driver->flush_buffer)
893 tty->driver->flush_buffer(tty);
894 break;
895 default:
896 tty_ldisc_deref(ld);
897 return -EINVAL;
898 }
899 tty_ldisc_deref(ld);
900 return 0;
901}
902
903EXPORT_SYMBOL_GPL(tty_perform_flush);
904
905int n_tty_ioctl(struct tty_struct * tty, struct file * file,
906 unsigned int cmd, unsigned long arg)
907{
908 struct tty_struct * real_tty;
909 int retval;
910
911 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
912 tty->driver->subtype == PTY_TYPE_MASTER)
913 real_tty = tty->link;
914 else
915 real_tty = tty;
916
917 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 case TCXONC:
919 retval = tty_check_change(tty);
920 if (retval)
921 return retval;
922 switch (arg) {
923 case TCOOFF:
924 if (!tty->flow_stopped) {
925 tty->flow_stopped = 1;
926 stop_tty(tty);
927 }
928 break;
929 case TCOON:
930 if (tty->flow_stopped) {
931 tty->flow_stopped = 0;
932 start_tty(tty);
933 }
934 break;
935 case TCIOFF:
936 if (STOP_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700937 return send_prio_char(tty, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 break;
939 case TCION:
940 if (START_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700941 return send_prio_char(tty, START_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 break;
943 default:
944 return -EINVAL;
945 }
946 return 0;
947 case TCFLSH:
Alan Cox0fc00e22007-11-07 01:24:56 -0800948 return tty_perform_flush(tty, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 case TIOCOUTQ:
950 return put_user(tty->driver->chars_in_buffer ?
951 tty->driver->chars_in_buffer(tty) : 0,
952 (int __user *) arg);
953 case TIOCINQ:
954 retval = tty->read_cnt;
955 if (L_ICANON(tty))
956 retval = inq_canon(tty);
957 return put_user(retval, (unsigned int __user *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 case TIOCPKT:
959 {
960 int pktmode;
961
962 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
963 tty->driver->subtype != PTY_TYPE_MASTER)
964 return -ENOTTY;
965 if (get_user(pktmode, (int __user *) arg))
966 return -EFAULT;
967 if (pktmode) {
968 if (!tty->packet) {
969 tty->packet = 1;
970 tty->link->ctrl_status = 0;
971 }
972 } else
973 tty->packet = 0;
974 return 0;
975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 default:
Alan Cox0fc00e22007-11-07 01:24:56 -0800977 /* Try the mode commands */
978 return tty_mode_ioctl(tty, file, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 }
980}
981
982EXPORT_SYMBOL(n_tty_ioctl);