blob: 3423e9ee6481c1874898e448dc7e9712b3b33195 [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
209#ifdef BOTHER
210
211/**
212 * tty_termios_encode_baud_rate
Alan Cox78137e32007-02-10 01:45:57 -0800213 * @termios: ktermios structure holding user requested state
Alan Coxedc6afc2006-12-08 02:38:44 -0800214 * @ispeed: input speed
215 * @ospeed: output speed
216 *
217 * Encode the speeds set into the passed termios structure. This is
218 * used as a library helper for drivers os that they can report back
219 * the actual speed selected when it differs from the speed requested
220 *
Alan Cox78137e32007-02-10 01:45:57 -0800221 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
222 * we need to carefully set the bits when the user does not get the
223 * desired speed. We allow small margins and preserve as much of possible
224 * of the input intent to keep compatiblity.
Alan Coxedc6afc2006-12-08 02:38:44 -0800225 *
226 * Locking: Caller should hold termios lock. This is already held
227 * when calling this function from the driver termios handler.
228 */
229
230void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
231{
232 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800233 int ifound = -1, ofound = -1;
234 int iclose = ibaud/50, oclose = obaud/50;
235 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800236
237 termios->c_ispeed = ibaud;
238 termios->c_ospeed = obaud;
239
Alan Cox78137e32007-02-10 01:45:57 -0800240 /* If the user asked for a precise weird speed give a precise weird
241 answer. If they asked for a Bfoo speed they many have problems
242 digesting non-exact replies so fuzz a bit */
243
244 if ((termios->c_cflag & CBAUD) == BOTHER)
245 oclose = 0;
246 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
247 iclose = 0;
248 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
249 ibinput = 1; /* An input speed was specified */
250
Alan Coxedc6afc2006-12-08 02:38:44 -0800251 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800252
253 do {
Alan Cox78137e32007-02-10 01:45:57 -0800254 if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800255 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800256 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800257 }
Alan Cox78137e32007-02-10 01:45:57 -0800258 if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
259 /* For the case input == output don't set IBAUD bits if the user didn't do so */
260 if (ofound != i || ibinput)
261 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
262 ifound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800263 }
Jiri Slaby68043962007-07-15 23:40:18 -0700264 } while (++i < n_baud_table);
Alan Cox78137e32007-02-10 01:45:57 -0800265 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800266 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800267 /* Set exact input bits only if the input and output differ or the
268 user already did */
Jiri Slaby68043962007-07-15 23:40:18 -0700269 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800270 termios->c_cflag |= (BOTHER << IBSHIFT);
271}
272
273EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
274
275#endif
276
277/**
278 * tty_get_baud_rate - get tty bit rates
279 * @tty: tty to query
280 *
281 * Returns the baud rate as an integer for this terminal. The
282 * termios lock must be held by the caller and the terminal bit
283 * flags may be updated.
284 *
285 * Locking: none
286 */
287
288speed_t tty_get_baud_rate(struct tty_struct *tty)
289{
290 speed_t baud = tty_termios_baud_rate(tty->termios);
291
292 if (baud == 38400 && tty->alt_speed) {
293 if (!tty->warned) {
294 printk(KERN_WARNING "Use of setserial/setrocket to "
295 "set SPD_* flags is deprecated\n");
296 tty->warned = 1;
297 }
298 baud = tty->alt_speed;
299 }
300
301 return baud;
302}
303
304EXPORT_SYMBOL(tty_get_baud_rate);
305
Alan Coxaf9b8972006-08-27 01:24:01 -0700306/**
307 * change_termios - update termios values
308 * @tty: tty to update
309 * @new_termios: desired new value
310 *
311 * Perform updates to the termios values set on this terminal. There
312 * is a bit of layering violation here with n_tty in terms of the
313 * internal knowledge of this function.
314 *
315 * Locking: termios_sem
316 */
317
Alan Coxedc6afc2006-12-08 02:38:44 -0800318static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
320 int canon_change;
Alan Coxedc6afc2006-12-08 02:38:44 -0800321 struct ktermios old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 struct tty_ldisc *ld;
323
324 /*
325 * Perform the actual termios internal changes under lock.
326 */
327
328
329 /* FIXME: we need to decide on some locking/ordering semantics
330 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700331 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333 *tty->termios = *new_termios;
334 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
335 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
336 if (canon_change) {
337 memset(&tty->read_flags, 0, sizeof tty->read_flags);
338 tty->canon_head = tty->read_tail;
339 tty->canon_data = 0;
340 tty->erasing = 0;
341 }
342
343
344 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
345 /* Get characters left over from canonical mode. */
346 wake_up_interruptible(&tty->read_wait);
347
348 /* See if packet mode change of state. */
349
350 if (tty->link && tty->link->packet) {
351 int old_flow = ((old_termios.c_iflag & IXON) &&
352 (old_termios.c_cc[VSTOP] == '\023') &&
353 (old_termios.c_cc[VSTART] == '\021'));
354 int new_flow = (I_IXON(tty) &&
355 STOP_CHAR(tty) == '\023' &&
356 START_CHAR(tty) == '\021');
357 if (old_flow != new_flow) {
358 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
359 if (new_flow)
360 tty->ctrl_status |= TIOCPKT_DOSTOP;
361 else
362 tty->ctrl_status |= TIOCPKT_NOSTOP;
363 wake_up_interruptible(&tty->link->read_wait);
364 }
365 }
366
367 if (tty->driver->set_termios)
368 (*tty->driver->set_termios)(tty, &old_termios);
369
370 ld = tty_ldisc_ref(tty);
371 if (ld != NULL) {
372 if (ld->set_termios)
373 (ld->set_termios)(tty, &old_termios);
374 tty_ldisc_deref(ld);
375 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700376 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
Alan Coxaf9b8972006-08-27 01:24:01 -0700379/**
380 * set_termios - set termios values for a tty
381 * @tty: terminal device
382 * @arg: user data
383 * @opt: option information
384 *
385 * Helper function to prepare termios data and run neccessary other
386 * functions before using change_termios to do the actual changes.
387 *
388 * Locking:
389 * Called functions take ldisc and termios_sem locks
390 */
391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
393{
Alan Coxedc6afc2006-12-08 02:38:44 -0800394 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 struct tty_ldisc *ld;
396 int retval = tty_check_change(tty);
397
398 if (retval)
399 return retval;
400
Alan Cox64bb6c52006-12-08 02:38:47 -0800401 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 if (user_termio_to_kernel_termios(&tmp_termios,
405 (struct termio __user *)arg))
406 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800407#ifdef TCGETS2
408 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800409 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 (struct termios __user *)arg))
411 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800412 } else {
413 if (user_termios_to_kernel_termios(&tmp_termios,
414 (struct termios2 __user *)arg))
415 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800417#else
418 } else if (user_termios_to_kernel_termios(&tmp_termios,
419 (struct termios __user *)arg))
420 return -EFAULT;
421#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Alan Coxedc6afc2006-12-08 02:38:44 -0800423 /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed
424 so its unconditionally usable */
425 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
426 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 ld = tty_ldisc_ref(tty);
429
430 if (ld != NULL) {
431 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
432 ld->flush_buffer(tty);
433 tty_ldisc_deref(ld);
434 }
435
436 if (opt & TERMIOS_WAIT) {
437 tty_wait_until_sent(tty, 0);
438 if (signal_pending(current))
439 return -EINTR;
440 }
441
442 change_termios(tty, &tmp_termios);
443 return 0;
444}
445
446static int get_termio(struct tty_struct * tty, struct termio __user * termio)
447{
448 if (kernel_termios_to_user_termio(termio, tty->termios))
449 return -EFAULT;
450 return 0;
451}
452
453static unsigned long inq_canon(struct tty_struct * tty)
454{
455 int nr, head, tail;
456
457 if (!tty->canon_data || !tty->read_buf)
458 return 0;
459 head = tty->canon_head;
460 tail = tty->read_tail;
461 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
462 /* Skip EOF-chars.. */
463 while (head != tail) {
464 if (test_bit(tail, tty->read_flags) &&
465 tty->read_buf[tail] == __DISABLED_CHAR)
466 nr--;
467 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
468 }
469 return nr;
470}
471
472#ifdef TIOCGETP
473/*
474 * These are deprecated, but there is limited support..
475 *
476 * The "sg_flags" translation is a joke..
477 */
478static int get_sgflags(struct tty_struct * tty)
479{
480 int flags = 0;
481
482 if (!(tty->termios->c_lflag & ICANON)) {
483 if (tty->termios->c_lflag & ISIG)
484 flags |= 0x02; /* cbreak */
485 else
486 flags |= 0x20; /* raw */
487 }
488 if (tty->termios->c_lflag & ECHO)
489 flags |= 0x08; /* echo */
490 if (tty->termios->c_oflag & OPOST)
491 if (tty->termios->c_oflag & ONLCR)
492 flags |= 0x10; /* crmod */
493 return flags;
494}
495
496static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
497{
498 struct sgttyb tmp;
499
Arjan van de Ven5785c952006-09-29 02:00:43 -0700500 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800501 tmp.sg_ispeed = tty->termios->c_ispeed;
502 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 tmp.sg_erase = tty->termios->c_cc[VERASE];
504 tmp.sg_kill = tty->termios->c_cc[VKILL];
505 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700506 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
509}
510
Alan Coxedc6afc2006-12-08 02:38:44 -0800511static void set_sgflags(struct ktermios * termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
513 termios->c_iflag = ICRNL | IXON;
514 termios->c_oflag = 0;
515 termios->c_lflag = ISIG | ICANON;
516 if (flags & 0x02) { /* cbreak */
517 termios->c_iflag = 0;
518 termios->c_lflag &= ~ICANON;
519 }
520 if (flags & 0x08) { /* echo */
521 termios->c_lflag |= ECHO | ECHOE | ECHOK |
522 ECHOCTL | ECHOKE | IEXTEN;
523 }
524 if (flags & 0x10) { /* crmod */
525 termios->c_oflag |= OPOST | ONLCR;
526 }
527 if (flags & 0x20) { /* raw */
528 termios->c_iflag = 0;
529 termios->c_lflag &= ~(ISIG | ICANON);
530 }
531 if (!(termios->c_lflag & ICANON)) {
532 termios->c_cc[VMIN] = 1;
533 termios->c_cc[VTIME] = 0;
534 }
535}
536
Alan Coxaf9b8972006-08-27 01:24:01 -0700537/**
538 * set_sgttyb - set legacy terminal values
539 * @tty: tty structure
540 * @sgttyb: pointer to old style terminal structure
541 *
542 * Updates a terminal from the legacy BSD style terminal information
543 * structure.
544 *
545 * Locking: termios_sem
546 */
547
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
549{
550 int retval;
551 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800552 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 retval = tty_check_change(tty);
555 if (retval)
556 return retval;
557
558 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
559 return -EFAULT;
560
Arjan van de Ven5785c952006-09-29 02:00:43 -0700561 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700562 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 termios.c_cc[VERASE] = tmp.sg_erase;
564 termios.c_cc[VKILL] = tmp.sg_kill;
565 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800566 /* Try and encode into Bfoo format */
567#ifdef BOTHER
568 tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
569#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700570 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 change_termios(tty, &termios);
572 return 0;
573}
574#endif
575
576#ifdef TIOCGETC
577static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars)
578{
579 struct tchars tmp;
580
581 tmp.t_intrc = tty->termios->c_cc[VINTR];
582 tmp.t_quitc = tty->termios->c_cc[VQUIT];
583 tmp.t_startc = tty->termios->c_cc[VSTART];
584 tmp.t_stopc = tty->termios->c_cc[VSTOP];
585 tmp.t_eofc = tty->termios->c_cc[VEOF];
586 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
587 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
588}
589
590static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars)
591{
592 struct tchars tmp;
593
594 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
595 return -EFAULT;
596 tty->termios->c_cc[VINTR] = tmp.t_intrc;
597 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
598 tty->termios->c_cc[VSTART] = tmp.t_startc;
599 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
600 tty->termios->c_cc[VEOF] = tmp.t_eofc;
601 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
602 return 0;
603}
604#endif
605
606#ifdef TIOCGLTC
607static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
608{
609 struct ltchars tmp;
610
611 tmp.t_suspc = tty->termios->c_cc[VSUSP];
612 tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */
613 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
614 tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */
615 tmp.t_werasc = tty->termios->c_cc[VWERASE];
616 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
617 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
618}
619
620static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
621{
622 struct ltchars tmp;
623
624 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
625 return -EFAULT;
626
627 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
628 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */
629 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
630 tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */
631 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
632 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
633 return 0;
634}
635#endif
636
Alan Coxaf9b8972006-08-27 01:24:01 -0700637/**
638 * send_prio_char - send priority character
639 *
640 * Send a high priority character to the tty even if stopped
641 *
Alan Cox5f412b22006-09-29 02:01:40 -0700642 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700644
Alan Cox5f412b22006-09-29 02:01:40 -0700645static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
647 int was_stopped = tty->stopped;
648
649 if (tty->driver->send_xchar) {
650 tty->driver->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700651 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
Alan Cox5f412b22006-09-29 02:01:40 -0700653
Alan Cox9c1729d2007-07-15 23:39:43 -0700654 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700655 return -ERESTARTSYS;
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (was_stopped)
658 start_tty(tty);
659 tty->driver->write(tty, &ch, 1);
660 if (was_stopped)
661 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700662 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700663 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664}
665
666int n_tty_ioctl(struct tty_struct * tty, struct file * file,
667 unsigned int cmd, unsigned long arg)
668{
669 struct tty_struct * real_tty;
670 void __user *p = (void __user *)arg;
671 int retval;
672 struct tty_ldisc *ld;
673
674 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
675 tty->driver->subtype == PTY_TYPE_MASTER)
676 real_tty = tty->link;
677 else
678 real_tty = tty;
679
680 switch (cmd) {
681#ifdef TIOCGETP
682 case TIOCGETP:
683 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
684 case TIOCSETP:
685 case TIOCSETN:
686 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
687#endif
688#ifdef TIOCGETC
689 case TIOCGETC:
690 return get_tchars(real_tty, p);
691 case TIOCSETC:
692 return set_tchars(real_tty, p);
693#endif
694#ifdef TIOCGLTC
695 case TIOCGLTC:
696 return get_ltchars(real_tty, p);
697 case TIOCSLTC:
698 return set_ltchars(real_tty, p);
699#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800700 case TCSETSF:
701 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
702 case TCSETSW:
703 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
704 case TCSETS:
705 return set_termios(real_tty, p, TERMIOS_OLD);
706#ifndef TCGETS2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 case TCGETS:
708 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
709 return -EFAULT;
710 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800711#else
712 case TCGETS:
Alan Cox64bb6c52006-12-08 02:38:47 -0800713 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800714 return -EFAULT;
715 return 0;
716 case TCGETS2:
Alan Cox64bb6c52006-12-08 02:38:47 -0800717 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800718 return -EFAULT;
719 return 0;
720 case TCSETSF2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800722 case TCSETSW2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return set_termios(real_tty, p, TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800724 case TCSETS2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800726#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 case TCGETA:
728 return get_termio(real_tty, p);
729 case TCSETAF:
730 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
731 case TCSETAW:
732 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
733 case TCSETA:
734 return set_termios(real_tty, p, TERMIOS_TERMIO);
735 case TCXONC:
736 retval = tty_check_change(tty);
737 if (retval)
738 return retval;
739 switch (arg) {
740 case TCOOFF:
741 if (!tty->flow_stopped) {
742 tty->flow_stopped = 1;
743 stop_tty(tty);
744 }
745 break;
746 case TCOON:
747 if (tty->flow_stopped) {
748 tty->flow_stopped = 0;
749 start_tty(tty);
750 }
751 break;
752 case TCIOFF:
753 if (STOP_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700754 return send_prio_char(tty, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 break;
756 case TCION:
757 if (START_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700758 return send_prio_char(tty, START_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 break;
760 default:
761 return -EINVAL;
762 }
763 return 0;
764 case TCFLSH:
765 retval = tty_check_change(tty);
766 if (retval)
767 return retval;
768
769 ld = tty_ldisc_ref(tty);
770 switch (arg) {
771 case TCIFLUSH:
KAMBAROV, ZAUR69f63c52005-06-28 20:45:12 -0700772 if (ld && ld->flush_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 ld->flush_buffer(tty);
774 break;
775 case TCIOFLUSH:
KAMBAROV, ZAUR69f63c52005-06-28 20:45:12 -0700776 if (ld && ld->flush_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 ld->flush_buffer(tty);
778 /* fall through */
779 case TCOFLUSH:
780 if (tty->driver->flush_buffer)
781 tty->driver->flush_buffer(tty);
782 break;
783 default:
784 tty_ldisc_deref(ld);
785 return -EINVAL;
786 }
787 tty_ldisc_deref(ld);
788 return 0;
789 case TIOCOUTQ:
790 return put_user(tty->driver->chars_in_buffer ?
791 tty->driver->chars_in_buffer(tty) : 0,
792 (int __user *) arg);
793 case TIOCINQ:
794 retval = tty->read_cnt;
795 if (L_ICANON(tty))
796 retval = inq_canon(tty);
797 return put_user(retval, (unsigned int __user *) arg);
798 case TIOCGLCKTRMIOS:
799 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
800 return -EFAULT;
801 return 0;
802
803 case TIOCSLCKTRMIOS:
804 if (!capable(CAP_SYS_ADMIN))
805 return -EPERM;
806 if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
807 return -EFAULT;
808 return 0;
809
810 case TIOCPKT:
811 {
812 int pktmode;
813
814 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
815 tty->driver->subtype != PTY_TYPE_MASTER)
816 return -ENOTTY;
817 if (get_user(pktmode, (int __user *) arg))
818 return -EFAULT;
819 if (pktmode) {
820 if (!tty->packet) {
821 tty->packet = 1;
822 tty->link->ctrl_status = 0;
823 }
824 } else
825 tty->packet = 0;
826 return 0;
827 }
828 case TIOCGSOFTCAR:
829 return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
830 case TIOCSSOFTCAR:
831 if (get_user(arg, (unsigned int __user *) arg))
832 return -EFAULT;
Arjan van de Ven5785c952006-09-29 02:00:43 -0700833 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 tty->termios->c_cflag =
835 ((tty->termios->c_cflag & ~CLOCAL) |
836 (arg ? CLOCAL : 0));
Arjan van de Ven5785c952006-09-29 02:00:43 -0700837 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 return 0;
839 default:
840 return -ENOIOCTLCMD;
841 }
842}
843
844EXPORT_SYMBOL(n_tty_ioctl);