blob: 745d552620bfc21229d286a8bc40827fd7811d3b [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,
65 !tty->driver->chars_in_buffer(tty), timeout))
66 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
231void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
232{
233 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800234 int ifound = -1, ofound = -1;
235 int iclose = ibaud/50, oclose = obaud/50;
236 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800237
Alan Cox5f519d72007-10-16 23:30:07 -0700238 if (obaud == 0) /* CD dropped */
239 ibaud = 0; /* Clear ibaud to be sure */
240
Alan Coxedc6afc2006-12-08 02:38:44 -0800241 termios->c_ispeed = ibaud;
242 termios->c_ospeed = obaud;
243
Alan Cox5f519d72007-10-16 23:30:07 -0700244#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800245 /* If the user asked for a precise weird speed give a precise weird
246 answer. If they asked for a Bfoo speed they many have problems
247 digesting non-exact replies so fuzz a bit */
248
249 if ((termios->c_cflag & CBAUD) == BOTHER)
250 oclose = 0;
251 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
252 iclose = 0;
253 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
254 ibinput = 1; /* An input speed was specified */
Alan Cox5f519d72007-10-16 23:30:07 -0700255#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800256 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800257
Alan Cox5f519d72007-10-16 23:30:07 -0700258 /*
259 * Our goal is to find a close match to the standard baud rate
260 * returned. Walk the baud rate table and if we get a very close
261 * match then report back the speed as a POSIX Bxxxx value by
262 * preference
263 */
264
Alan Coxedc6afc2006-12-08 02:38:44 -0800265 do {
Alan Cox78137e32007-02-10 01:45:57 -0800266 if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800267 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800268 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800269 }
Alan Cox78137e32007-02-10 01:45:57 -0800270 if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
Alan Cox5f519d72007-10-16 23:30:07 -0700271 if (ofound == i && !ibinput)
272 ifound = i;
273#ifdef IBSHIFT
274 else {
275 ifound = i;
Alan Cox78137e32007-02-10 01:45:57 -0800276 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700277 }
278#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800279 }
Jiri Slaby68043962007-07-15 23:40:18 -0700280 } while (++i < n_baud_table);
Alan Cox5f519d72007-10-16 23:30:07 -0700281
282 /*
283 * If we found no match then use BOTHER if provided or warn
284 * the user their platform maintainer needs to wake up if not.
285 */
286#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800287 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800288 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800289 /* Set exact input bits only if the input and output differ or the
290 user already did */
Jiri Slaby68043962007-07-15 23:40:18 -0700291 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800292 termios->c_cflag |= (BOTHER << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700293#else
294 if (ifound == -1 || ofound == -1) {
295 static int warned;
296 if (!warned++)
297 printk(KERN_WARNING "tty: Unable to return correct "
298 "speed data as your architecture needs updating.\n");
299 }
300#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800301}
Alan Coxedc6afc2006-12-08 02:38:44 -0800302EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
303
Alan Cox5f519d72007-10-16 23:30:07 -0700304void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
305{
306 tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
307}
308EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
Alan Coxedc6afc2006-12-08 02:38:44 -0800309
310/**
311 * tty_get_baud_rate - get tty bit rates
312 * @tty: tty to query
313 *
314 * Returns the baud rate as an integer for this terminal. The
315 * termios lock must be held by the caller and the terminal bit
316 * flags may be updated.
317 *
318 * Locking: none
319 */
320
321speed_t tty_get_baud_rate(struct tty_struct *tty)
322{
323 speed_t baud = tty_termios_baud_rate(tty->termios);
324
325 if (baud == 38400 && tty->alt_speed) {
326 if (!tty->warned) {
327 printk(KERN_WARNING "Use of setserial/setrocket to "
328 "set SPD_* flags is deprecated\n");
329 tty->warned = 1;
330 }
331 baud = tty->alt_speed;
332 }
333
334 return baud;
335}
336
337EXPORT_SYMBOL(tty_get_baud_rate);
338
Alan Coxaf9b8972006-08-27 01:24:01 -0700339/**
Alan Cox5f519d72007-10-16 23:30:07 -0700340 * tty_termios_copy_hw - copy hardware settings
341 * @new: New termios
342 * @old: Old termios
343 *
344 * Propogate the hardware specific terminal setting bits from
345 * the old termios structure to the new one. This is used in cases
346 * where the hardware does not support reconfiguration or as a helper
347 * in some cases where only minimal reconfiguration is supported
348 */
349
350void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
351{
352 /* The bits a dumb device handles in software. Smart devices need
353 to always provide a set_termios method */
354 new->c_cflag &= HUPCL | CREAD | CLOCAL;
355 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
356 new->c_ispeed = old->c_ispeed;
357 new->c_ospeed = old->c_ospeed;
358}
359
360EXPORT_SYMBOL(tty_termios_copy_hw);
361
362/**
Alan Coxaf9b8972006-08-27 01:24:01 -0700363 * change_termios - update termios values
364 * @tty: tty to update
365 * @new_termios: desired new value
366 *
367 * Perform updates to the termios values set on this terminal. There
368 * is a bit of layering violation here with n_tty in terms of the
369 * internal knowledge of this function.
370 *
371 * Locking: termios_sem
372 */
373
Alan Coxedc6afc2006-12-08 02:38:44 -0800374static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 int canon_change;
Alan Coxedc6afc2006-12-08 02:38:44 -0800377 struct ktermios old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 struct tty_ldisc *ld;
379
380 /*
381 * Perform the actual termios internal changes under lock.
382 */
383
384
385 /* FIXME: we need to decide on some locking/ordering semantics
386 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700387 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 *tty->termios = *new_termios;
390 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
391 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
392 if (canon_change) {
393 memset(&tty->read_flags, 0, sizeof tty->read_flags);
394 tty->canon_head = tty->read_tail;
395 tty->canon_data = 0;
396 tty->erasing = 0;
397 }
398
Alan Cox5f519d72007-10-16 23:30:07 -0700399 /* This bit should be in the ldisc code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
401 /* Get characters left over from canonical mode. */
402 wake_up_interruptible(&tty->read_wait);
403
404 /* See if packet mode change of state. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (tty->link && tty->link->packet) {
406 int old_flow = ((old_termios.c_iflag & IXON) &&
407 (old_termios.c_cc[VSTOP] == '\023') &&
408 (old_termios.c_cc[VSTART] == '\021'));
409 int new_flow = (I_IXON(tty) &&
410 STOP_CHAR(tty) == '\023' &&
411 START_CHAR(tty) == '\021');
412 if (old_flow != new_flow) {
413 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
414 if (new_flow)
415 tty->ctrl_status |= TIOCPKT_DOSTOP;
416 else
417 tty->ctrl_status |= TIOCPKT_NOSTOP;
418 wake_up_interruptible(&tty->link->read_wait);
419 }
420 }
421
422 if (tty->driver->set_termios)
423 (*tty->driver->set_termios)(tty, &old_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700424 else
425 tty_termios_copy_hw(tty->termios, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 ld = tty_ldisc_ref(tty);
428 if (ld != NULL) {
429 if (ld->set_termios)
430 (ld->set_termios)(tty, &old_termios);
431 tty_ldisc_deref(ld);
432 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700433 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
Alan Coxaf9b8972006-08-27 01:24:01 -0700436/**
437 * set_termios - set termios values for a tty
438 * @tty: terminal device
439 * @arg: user data
440 * @opt: option information
441 *
442 * Helper function to prepare termios data and run neccessary other
443 * functions before using change_termios to do the actual changes.
444 *
445 * Locking:
446 * Called functions take ldisc and termios_sem locks
447 */
448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
450{
Alan Coxedc6afc2006-12-08 02:38:44 -0800451 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 struct tty_ldisc *ld;
453 int retval = tty_check_change(tty);
454
455 if (retval)
456 return retval;
457
Alan Cox64bb6c52006-12-08 02:38:47 -0800458 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (user_termio_to_kernel_termios(&tmp_termios,
462 (struct termio __user *)arg))
463 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800464#ifdef TCGETS2
465 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800466 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 (struct termios __user *)arg))
468 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800469 } else {
470 if (user_termios_to_kernel_termios(&tmp_termios,
471 (struct termios2 __user *)arg))
472 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800474#else
475 } else if (user_termios_to_kernel_termios(&tmp_termios,
476 (struct termios __user *)arg))
477 return -EFAULT;
478#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Alan Coxedc6afc2006-12-08 02:38:44 -0800480 /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed
481 so its unconditionally usable */
482 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
483 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 ld = tty_ldisc_ref(tty);
486
487 if (ld != NULL) {
488 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
489 ld->flush_buffer(tty);
490 tty_ldisc_deref(ld);
491 }
492
493 if (opt & TERMIOS_WAIT) {
494 tty_wait_until_sent(tty, 0);
495 if (signal_pending(current))
496 return -EINTR;
497 }
498
499 change_termios(tty, &tmp_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700500
501 /* FIXME: Arguably if tmp_termios == tty->termios AND the
502 actual requested termios was not tmp_termios then we may
503 want to return an error as no user requested change has
504 succeeded */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return 0;
506}
507
508static int get_termio(struct tty_struct * tty, struct termio __user * termio)
509{
510 if (kernel_termios_to_user_termio(termio, tty->termios))
511 return -EFAULT;
512 return 0;
513}
514
515static unsigned long inq_canon(struct tty_struct * tty)
516{
517 int nr, head, tail;
518
519 if (!tty->canon_data || !tty->read_buf)
520 return 0;
521 head = tty->canon_head;
522 tail = tty->read_tail;
523 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
524 /* Skip EOF-chars.. */
525 while (head != tail) {
526 if (test_bit(tail, tty->read_flags) &&
527 tty->read_buf[tail] == __DISABLED_CHAR)
528 nr--;
529 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
530 }
531 return nr;
532}
533
534#ifdef TIOCGETP
535/*
536 * These are deprecated, but there is limited support..
537 *
538 * The "sg_flags" translation is a joke..
539 */
540static int get_sgflags(struct tty_struct * tty)
541{
542 int flags = 0;
543
544 if (!(tty->termios->c_lflag & ICANON)) {
545 if (tty->termios->c_lflag & ISIG)
546 flags |= 0x02; /* cbreak */
547 else
548 flags |= 0x20; /* raw */
549 }
550 if (tty->termios->c_lflag & ECHO)
551 flags |= 0x08; /* echo */
552 if (tty->termios->c_oflag & OPOST)
553 if (tty->termios->c_oflag & ONLCR)
554 flags |= 0x10; /* crmod */
555 return flags;
556}
557
558static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
559{
560 struct sgttyb tmp;
561
Arjan van de Ven5785c952006-09-29 02:00:43 -0700562 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800563 tmp.sg_ispeed = tty->termios->c_ispeed;
564 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 tmp.sg_erase = tty->termios->c_cc[VERASE];
566 tmp.sg_kill = tty->termios->c_cc[VKILL];
567 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700568 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
570 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
571}
572
Alan Coxedc6afc2006-12-08 02:38:44 -0800573static void set_sgflags(struct ktermios * termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
575 termios->c_iflag = ICRNL | IXON;
576 termios->c_oflag = 0;
577 termios->c_lflag = ISIG | ICANON;
578 if (flags & 0x02) { /* cbreak */
579 termios->c_iflag = 0;
580 termios->c_lflag &= ~ICANON;
581 }
582 if (flags & 0x08) { /* echo */
583 termios->c_lflag |= ECHO | ECHOE | ECHOK |
584 ECHOCTL | ECHOKE | IEXTEN;
585 }
586 if (flags & 0x10) { /* crmod */
587 termios->c_oflag |= OPOST | ONLCR;
588 }
589 if (flags & 0x20) { /* raw */
590 termios->c_iflag = 0;
591 termios->c_lflag &= ~(ISIG | ICANON);
592 }
593 if (!(termios->c_lflag & ICANON)) {
594 termios->c_cc[VMIN] = 1;
595 termios->c_cc[VTIME] = 0;
596 }
597}
598
Alan Coxaf9b8972006-08-27 01:24:01 -0700599/**
600 * set_sgttyb - set legacy terminal values
601 * @tty: tty structure
602 * @sgttyb: pointer to old style terminal structure
603 *
604 * Updates a terminal from the legacy BSD style terminal information
605 * structure.
606 *
607 * Locking: termios_sem
608 */
609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
611{
612 int retval;
613 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800614 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 retval = tty_check_change(tty);
617 if (retval)
618 return retval;
619
620 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
621 return -EFAULT;
622
Arjan van de Ven5785c952006-09-29 02:00:43 -0700623 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700624 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 termios.c_cc[VERASE] = tmp.sg_erase;
626 termios.c_cc[VKILL] = tmp.sg_kill;
627 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800628 /* Try and encode into Bfoo format */
629#ifdef BOTHER
630 tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
631#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700632 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 change_termios(tty, &termios);
634 return 0;
635}
636#endif
637
638#ifdef TIOCGETC
639static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars)
640{
641 struct tchars tmp;
642
643 tmp.t_intrc = tty->termios->c_cc[VINTR];
644 tmp.t_quitc = tty->termios->c_cc[VQUIT];
645 tmp.t_startc = tty->termios->c_cc[VSTART];
646 tmp.t_stopc = tty->termios->c_cc[VSTOP];
647 tmp.t_eofc = tty->termios->c_cc[VEOF];
648 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
649 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
650}
651
652static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars)
653{
654 struct tchars tmp;
655
656 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
657 return -EFAULT;
658 tty->termios->c_cc[VINTR] = tmp.t_intrc;
659 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
660 tty->termios->c_cc[VSTART] = tmp.t_startc;
661 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
662 tty->termios->c_cc[VEOF] = tmp.t_eofc;
663 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
664 return 0;
665}
666#endif
667
668#ifdef TIOCGLTC
669static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
670{
671 struct ltchars tmp;
672
673 tmp.t_suspc = tty->termios->c_cc[VSUSP];
674 tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */
675 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
676 tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */
677 tmp.t_werasc = tty->termios->c_cc[VWERASE];
678 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
679 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
680}
681
682static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
683{
684 struct ltchars tmp;
685
686 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
687 return -EFAULT;
688
689 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
690 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */
691 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
692 tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */
693 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
694 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
695 return 0;
696}
697#endif
698
Alan Coxaf9b8972006-08-27 01:24:01 -0700699/**
700 * send_prio_char - send priority character
701 *
702 * Send a high priority character to the tty even if stopped
703 *
Alan Cox5f412b22006-09-29 02:01:40 -0700704 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700706
Alan Cox5f412b22006-09-29 02:01:40 -0700707static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 int was_stopped = tty->stopped;
710
711 if (tty->driver->send_xchar) {
712 tty->driver->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700713 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 }
Alan Cox5f412b22006-09-29 02:01:40 -0700715
Alan Cox9c1729d2007-07-15 23:39:43 -0700716 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700717 return -ERESTARTSYS;
718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 if (was_stopped)
720 start_tty(tty);
721 tty->driver->write(tty, &ch, 1);
722 if (was_stopped)
723 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700724 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700725 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726}
727
728int n_tty_ioctl(struct tty_struct * tty, struct file * file,
729 unsigned int cmd, unsigned long arg)
730{
731 struct tty_struct * real_tty;
732 void __user *p = (void __user *)arg;
733 int retval;
734 struct tty_ldisc *ld;
735
736 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
737 tty->driver->subtype == PTY_TYPE_MASTER)
738 real_tty = tty->link;
739 else
740 real_tty = tty;
741
742 switch (cmd) {
743#ifdef TIOCGETP
744 case TIOCGETP:
745 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
746 case TIOCSETP:
747 case TIOCSETN:
748 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
749#endif
750#ifdef TIOCGETC
751 case TIOCGETC:
752 return get_tchars(real_tty, p);
753 case TIOCSETC:
754 return set_tchars(real_tty, p);
755#endif
756#ifdef TIOCGLTC
757 case TIOCGLTC:
758 return get_ltchars(real_tty, p);
759 case TIOCSLTC:
760 return set_ltchars(real_tty, p);
761#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800762 case TCSETSF:
763 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
764 case TCSETSW:
765 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
766 case TCSETS:
767 return set_termios(real_tty, p, TERMIOS_OLD);
768#ifndef TCGETS2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 case TCGETS:
770 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
771 return -EFAULT;
772 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800773#else
774 case TCGETS:
Alan Cox64bb6c52006-12-08 02:38:47 -0800775 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800776 return -EFAULT;
777 return 0;
778 case TCGETS2:
Alan Cox64bb6c52006-12-08 02:38:47 -0800779 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800780 return -EFAULT;
781 return 0;
782 case TCSETSF2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800784 case TCSETSW2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return set_termios(real_tty, p, TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800786 case TCSETS2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800788#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 case TCGETA:
790 return get_termio(real_tty, p);
791 case TCSETAF:
792 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
793 case TCSETAW:
794 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
795 case TCSETA:
796 return set_termios(real_tty, p, TERMIOS_TERMIO);
797 case TCXONC:
798 retval = tty_check_change(tty);
799 if (retval)
800 return retval;
801 switch (arg) {
802 case TCOOFF:
803 if (!tty->flow_stopped) {
804 tty->flow_stopped = 1;
805 stop_tty(tty);
806 }
807 break;
808 case TCOON:
809 if (tty->flow_stopped) {
810 tty->flow_stopped = 0;
811 start_tty(tty);
812 }
813 break;
814 case TCIOFF:
815 if (STOP_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700816 return send_prio_char(tty, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 break;
818 case TCION:
819 if (START_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700820 return send_prio_char(tty, START_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 break;
822 default:
823 return -EINVAL;
824 }
825 return 0;
826 case TCFLSH:
827 retval = tty_check_change(tty);
828 if (retval)
829 return retval;
830
831 ld = tty_ldisc_ref(tty);
832 switch (arg) {
833 case TCIFLUSH:
KAMBAROV, ZAUR69f63c52005-06-28 20:45:12 -0700834 if (ld && ld->flush_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 ld->flush_buffer(tty);
836 break;
837 case TCIOFLUSH:
KAMBAROV, ZAUR69f63c52005-06-28 20:45:12 -0700838 if (ld && ld->flush_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 ld->flush_buffer(tty);
840 /* fall through */
841 case TCOFLUSH:
842 if (tty->driver->flush_buffer)
843 tty->driver->flush_buffer(tty);
844 break;
845 default:
846 tty_ldisc_deref(ld);
847 return -EINVAL;
848 }
849 tty_ldisc_deref(ld);
850 return 0;
851 case TIOCOUTQ:
852 return put_user(tty->driver->chars_in_buffer ?
853 tty->driver->chars_in_buffer(tty) : 0,
854 (int __user *) arg);
855 case TIOCINQ:
856 retval = tty->read_cnt;
857 if (L_ICANON(tty))
858 retval = inq_canon(tty);
859 return put_user(retval, (unsigned int __user *) arg);
Tony Breedsbb8bd3a2007-09-14 17:03:01 -0700860#ifndef TCGETS2
861 case TIOCGLCKTRMIOS:
862 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
863 return -EFAULT;
864 return 0;
865
866 case TIOCSLCKTRMIOS:
867 if (!capable(CAP_SYS_ADMIN))
868 return -EPERM;
869 if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
870 return -EFAULT;
871 return 0;
872#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 case TIOCGLCKTRMIOS:
David Millerf6293072007-09-11 15:23:50 -0700874 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 return -EFAULT;
876 return 0;
877
878 case TIOCSLCKTRMIOS:
879 if (!capable(CAP_SYS_ADMIN))
880 return -EPERM;
David Millerf6293072007-09-11 15:23:50 -0700881 if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return -EFAULT;
883 return 0;
Tony Breedsbb8bd3a2007-09-14 17:03:01 -0700884#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886 case TIOCPKT:
887 {
888 int pktmode;
889
890 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
891 tty->driver->subtype != PTY_TYPE_MASTER)
892 return -ENOTTY;
893 if (get_user(pktmode, (int __user *) arg))
894 return -EFAULT;
895 if (pktmode) {
896 if (!tty->packet) {
897 tty->packet = 1;
898 tty->link->ctrl_status = 0;
899 }
900 } else
901 tty->packet = 0;
902 return 0;
903 }
904 case TIOCGSOFTCAR:
905 return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
906 case TIOCSSOFTCAR:
907 if (get_user(arg, (unsigned int __user *) arg))
908 return -EFAULT;
Arjan van de Ven5785c952006-09-29 02:00:43 -0700909 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 tty->termios->c_cflag =
911 ((tty->termios->c_cflag & ~CLOCAL) |
912 (arg ? CLOCAL : 0));
Arjan van de Ven5785c952006-09-29 02:00:43 -0700913 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 return 0;
915 default:
916 return -ENOIOCTLCMD;
917 }
918}
919
920EXPORT_SYMBOL(n_tty_ioctl);