blob: 918e24c885f122944529f0e04702e5159b8c0a94 [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{
55 DECLARE_WAITQUEUE(wait, current);
56
57#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
58 char buf[64];
59
60 printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
61#endif
62 if (!tty->driver->chars_in_buffer)
63 return;
64 add_wait_queue(&tty->write_wait, &wait);
65 if (!timeout)
66 timeout = MAX_SCHEDULE_TIMEOUT;
67 do {
68#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
69 printk(KERN_DEBUG "waiting %s...(%d)\n", tty_name(tty, buf),
70 tty->driver->chars_in_buffer(tty));
71#endif
72 set_current_state(TASK_INTERRUPTIBLE);
73 if (signal_pending(current))
74 goto stop_waiting;
75 if (!tty->driver->chars_in_buffer(tty))
76 break;
77 timeout = schedule_timeout(timeout);
78 } while (timeout);
79 if (tty->driver->wait_until_sent)
80 tty->driver->wait_until_sent(tty, timeout);
81stop_waiting:
82 set_current_state(TASK_RUNNING);
83 remove_wait_queue(&tty->write_wait, &wait);
84}
85
86EXPORT_SYMBOL(tty_wait_until_sent);
87
Alan Coxedc6afc2006-12-08 02:38:44 -080088static void unset_locked_termios(struct ktermios *termios,
89 struct ktermios *old,
90 struct ktermios *locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -070091{
92 int i;
93
94#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
95
96 if (!locked) {
97 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
98 return;
99 }
100
101 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
102 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
103 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
104 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
105 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
106 for (i=0; i < NCCS; i++)
107 termios->c_cc[i] = locked->c_cc[i] ?
108 old->c_cc[i] : termios->c_cc[i];
Alan Coxedc6afc2006-12-08 02:38:44 -0800109 /* FIXME: What should we do for i/ospeed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110}
111
Alan Coxedc6afc2006-12-08 02:38:44 -0800112/*
113 * Routine which returns the baud rate of the tty
114 *
115 * Note that the baud_table needs to be kept in sync with the
116 * include/asm/termbits.h file.
117 */
118static const speed_t baud_table[] = {
119 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
120 9600, 19200, 38400, 57600, 115200, 230400, 460800,
121#ifdef __sparc__
122 76800, 153600, 307200, 614400, 921600
123#else
124 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
125 2500000, 3000000, 3500000, 4000000
126#endif
127};
128
129#ifndef __sparc__
130static const tcflag_t baud_bits[] = {
131 B0, B50, B75, B110, B134, B150, B200, B300, B600,
132 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
133 B57600, B115200, B230400, B460800, B500000, B576000,
134 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
135 B3000000, B3500000, B4000000
136};
137#else
138static const tcflag_t baud_bits[] = {
139 B0, B50, B75, B110, B134, B150, B200, B300, B600,
140 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
141 B57600, B115200, B230400, B460800, B76800, B153600,
142 B307200, B614400, B921600
143};
144#endif
145
146static int n_baud_table = ARRAY_SIZE(baud_table);
147
148/**
149 * tty_termios_baud_rate
150 * @termios: termios structure
151 *
152 * Convert termios baud rate data into a speed. This should be called
153 * with the termios lock held if this termios is a terminal termios
154 * structure. May change the termios data. Device drivers can call this
155 * function but should use ->c_[io]speed directly as they are updated.
156 *
157 * Locking: none
158 */
159
160speed_t tty_termios_baud_rate(struct ktermios *termios)
161{
162 unsigned int cbaud;
163
164 cbaud = termios->c_cflag & CBAUD;
165
166#ifdef BOTHER
167 /* Magic token for arbitary speed via c_ispeed/c_ospeed */
168 if (cbaud == BOTHER)
169 return termios->c_ospeed;
170#endif
171 if (cbaud & CBAUDEX) {
172 cbaud &= ~CBAUDEX;
173
174 if (cbaud < 1 || cbaud + 15 > n_baud_table)
175 termios->c_cflag &= ~CBAUDEX;
176 else
177 cbaud += 15;
178 }
179 return baud_table[cbaud];
180}
181
182EXPORT_SYMBOL(tty_termios_baud_rate);
183
184/**
185 * tty_termios_input_baud_rate
186 * @termios: termios structure
187 *
188 * Convert termios baud rate data into a speed. This should be called
189 * with the termios lock held if this termios is a terminal termios
190 * structure. May change the termios data. Device drivers can call this
191 * function but should use ->c_[io]speed directly as they are updated.
192 *
193 * Locking: none
194 */
195
196speed_t tty_termios_input_baud_rate(struct ktermios *termios)
197{
198#ifdef IBSHIFT
199 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
200
201 if (cbaud == B0)
202 return tty_termios_baud_rate(termios);
203
204 /* Magic token for arbitary speed via c_ispeed*/
205 if (cbaud == BOTHER)
206 return termios->c_ispeed;
207
208 if (cbaud & CBAUDEX) {
209 cbaud &= ~CBAUDEX;
210
211 if (cbaud < 1 || cbaud + 15 > n_baud_table)
212 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
213 else
214 cbaud += 15;
215 }
216 return baud_table[cbaud];
217#else
218 return tty_termios_baud_rate(termios);
219#endif
220}
221
222EXPORT_SYMBOL(tty_termios_input_baud_rate);
223
224#ifdef BOTHER
225
226/**
227 * tty_termios_encode_baud_rate
Alan Cox78137e32007-02-10 01:45:57 -0800228 * @termios: ktermios structure holding user requested state
Alan Coxedc6afc2006-12-08 02:38:44 -0800229 * @ispeed: input speed
230 * @ospeed: output speed
231 *
232 * Encode the speeds set into the passed termios structure. This is
233 * used as a library helper for drivers os that they can report back
234 * the actual speed selected when it differs from the speed requested
235 *
Alan Cox78137e32007-02-10 01:45:57 -0800236 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
237 * we need to carefully set the bits when the user does not get the
238 * desired speed. We allow small margins and preserve as much of possible
239 * of the input intent to keep compatiblity.
Alan Coxedc6afc2006-12-08 02:38:44 -0800240 *
241 * Locking: Caller should hold termios lock. This is already held
242 * when calling this function from the driver termios handler.
243 */
244
245void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
246{
247 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800248 int ifound = -1, ofound = -1;
249 int iclose = ibaud/50, oclose = obaud/50;
250 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800251
252 termios->c_ispeed = ibaud;
253 termios->c_ospeed = obaud;
254
Alan Cox78137e32007-02-10 01:45:57 -0800255 /* If the user asked for a precise weird speed give a precise weird
256 answer. If they asked for a Bfoo speed they many have problems
257 digesting non-exact replies so fuzz a bit */
258
259 if ((termios->c_cflag & CBAUD) == BOTHER)
260 oclose = 0;
261 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
262 iclose = 0;
263 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
264 ibinput = 1; /* An input speed was specified */
265
Alan Coxedc6afc2006-12-08 02:38:44 -0800266 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800267
268 do {
Alan Cox78137e32007-02-10 01:45:57 -0800269 if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800270 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800271 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800272 }
Alan Cox78137e32007-02-10 01:45:57 -0800273 if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
274 /* For the case input == output don't set IBAUD bits if the user didn't do so */
275 if (ofound != i || ibinput)
276 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
277 ifound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800278 }
279 }
280 while(++i < n_baud_table);
Alan Cox78137e32007-02-10 01:45:57 -0800281 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800282 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800283 /* Set exact input bits only if the input and output differ or the
284 user already did */
285 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800286 termios->c_cflag |= (BOTHER << IBSHIFT);
287}
288
289EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
290
291#endif
292
293/**
294 * tty_get_baud_rate - get tty bit rates
295 * @tty: tty to query
296 *
297 * Returns the baud rate as an integer for this terminal. The
298 * termios lock must be held by the caller and the terminal bit
299 * flags may be updated.
300 *
301 * Locking: none
302 */
303
304speed_t tty_get_baud_rate(struct tty_struct *tty)
305{
306 speed_t baud = tty_termios_baud_rate(tty->termios);
307
308 if (baud == 38400 && tty->alt_speed) {
309 if (!tty->warned) {
310 printk(KERN_WARNING "Use of setserial/setrocket to "
311 "set SPD_* flags is deprecated\n");
312 tty->warned = 1;
313 }
314 baud = tty->alt_speed;
315 }
316
317 return baud;
318}
319
320EXPORT_SYMBOL(tty_get_baud_rate);
321
Alan Coxaf9b8972006-08-27 01:24:01 -0700322/**
323 * change_termios - update termios values
324 * @tty: tty to update
325 * @new_termios: desired new value
326 *
327 * Perform updates to the termios values set on this terminal. There
328 * is a bit of layering violation here with n_tty in terms of the
329 * internal knowledge of this function.
330 *
331 * Locking: termios_sem
332 */
333
Alan Coxedc6afc2006-12-08 02:38:44 -0800334static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336 int canon_change;
Alan Coxedc6afc2006-12-08 02:38:44 -0800337 struct ktermios old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 struct tty_ldisc *ld;
339
340 /*
341 * Perform the actual termios internal changes under lock.
342 */
343
344
345 /* FIXME: we need to decide on some locking/ordering semantics
346 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700347 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 *tty->termios = *new_termios;
350 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
351 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
352 if (canon_change) {
353 memset(&tty->read_flags, 0, sizeof tty->read_flags);
354 tty->canon_head = tty->read_tail;
355 tty->canon_data = 0;
356 tty->erasing = 0;
357 }
358
359
360 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
361 /* Get characters left over from canonical mode. */
362 wake_up_interruptible(&tty->read_wait);
363
364 /* See if packet mode change of state. */
365
366 if (tty->link && tty->link->packet) {
367 int old_flow = ((old_termios.c_iflag & IXON) &&
368 (old_termios.c_cc[VSTOP] == '\023') &&
369 (old_termios.c_cc[VSTART] == '\021'));
370 int new_flow = (I_IXON(tty) &&
371 STOP_CHAR(tty) == '\023' &&
372 START_CHAR(tty) == '\021');
373 if (old_flow != new_flow) {
374 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
375 if (new_flow)
376 tty->ctrl_status |= TIOCPKT_DOSTOP;
377 else
378 tty->ctrl_status |= TIOCPKT_NOSTOP;
379 wake_up_interruptible(&tty->link->read_wait);
380 }
381 }
382
383 if (tty->driver->set_termios)
384 (*tty->driver->set_termios)(tty, &old_termios);
385
386 ld = tty_ldisc_ref(tty);
387 if (ld != NULL) {
388 if (ld->set_termios)
389 (ld->set_termios)(tty, &old_termios);
390 tty_ldisc_deref(ld);
391 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700392 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393}
394
Alan Coxaf9b8972006-08-27 01:24:01 -0700395/**
396 * set_termios - set termios values for a tty
397 * @tty: terminal device
398 * @arg: user data
399 * @opt: option information
400 *
401 * Helper function to prepare termios data and run neccessary other
402 * functions before using change_termios to do the actual changes.
403 *
404 * Locking:
405 * Called functions take ldisc and termios_sem locks
406 */
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
409{
Alan Coxedc6afc2006-12-08 02:38:44 -0800410 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 struct tty_ldisc *ld;
412 int retval = tty_check_change(tty);
413
414 if (retval)
415 return retval;
416
Alan Cox64bb6c52006-12-08 02:38:47 -0800417 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 if (user_termio_to_kernel_termios(&tmp_termios,
421 (struct termio __user *)arg))
422 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800423#ifdef TCGETS2
424 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800425 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 (struct termios __user *)arg))
427 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800428 } else {
429 if (user_termios_to_kernel_termios(&tmp_termios,
430 (struct termios2 __user *)arg))
431 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800433#else
434 } else if (user_termios_to_kernel_termios(&tmp_termios,
435 (struct termios __user *)arg))
436 return -EFAULT;
437#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Alan Coxedc6afc2006-12-08 02:38:44 -0800439 /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed
440 so its unconditionally usable */
441 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
442 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 ld = tty_ldisc_ref(tty);
445
446 if (ld != NULL) {
447 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
448 ld->flush_buffer(tty);
449 tty_ldisc_deref(ld);
450 }
451
452 if (opt & TERMIOS_WAIT) {
453 tty_wait_until_sent(tty, 0);
454 if (signal_pending(current))
455 return -EINTR;
456 }
457
458 change_termios(tty, &tmp_termios);
459 return 0;
460}
461
462static int get_termio(struct tty_struct * tty, struct termio __user * termio)
463{
464 if (kernel_termios_to_user_termio(termio, tty->termios))
465 return -EFAULT;
466 return 0;
467}
468
469static unsigned long inq_canon(struct tty_struct * tty)
470{
471 int nr, head, tail;
472
473 if (!tty->canon_data || !tty->read_buf)
474 return 0;
475 head = tty->canon_head;
476 tail = tty->read_tail;
477 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
478 /* Skip EOF-chars.. */
479 while (head != tail) {
480 if (test_bit(tail, tty->read_flags) &&
481 tty->read_buf[tail] == __DISABLED_CHAR)
482 nr--;
483 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
484 }
485 return nr;
486}
487
488#ifdef TIOCGETP
489/*
490 * These are deprecated, but there is limited support..
491 *
492 * The "sg_flags" translation is a joke..
493 */
494static int get_sgflags(struct tty_struct * tty)
495{
496 int flags = 0;
497
498 if (!(tty->termios->c_lflag & ICANON)) {
499 if (tty->termios->c_lflag & ISIG)
500 flags |= 0x02; /* cbreak */
501 else
502 flags |= 0x20; /* raw */
503 }
504 if (tty->termios->c_lflag & ECHO)
505 flags |= 0x08; /* echo */
506 if (tty->termios->c_oflag & OPOST)
507 if (tty->termios->c_oflag & ONLCR)
508 flags |= 0x10; /* crmod */
509 return flags;
510}
511
512static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
513{
514 struct sgttyb tmp;
515
Arjan van de Ven5785c952006-09-29 02:00:43 -0700516 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800517 tmp.sg_ispeed = tty->termios->c_ispeed;
518 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 tmp.sg_erase = tty->termios->c_cc[VERASE];
520 tmp.sg_kill = tty->termios->c_cc[VKILL];
521 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700522 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
525}
526
Alan Coxedc6afc2006-12-08 02:38:44 -0800527static void set_sgflags(struct ktermios * termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
529 termios->c_iflag = ICRNL | IXON;
530 termios->c_oflag = 0;
531 termios->c_lflag = ISIG | ICANON;
532 if (flags & 0x02) { /* cbreak */
533 termios->c_iflag = 0;
534 termios->c_lflag &= ~ICANON;
535 }
536 if (flags & 0x08) { /* echo */
537 termios->c_lflag |= ECHO | ECHOE | ECHOK |
538 ECHOCTL | ECHOKE | IEXTEN;
539 }
540 if (flags & 0x10) { /* crmod */
541 termios->c_oflag |= OPOST | ONLCR;
542 }
543 if (flags & 0x20) { /* raw */
544 termios->c_iflag = 0;
545 termios->c_lflag &= ~(ISIG | ICANON);
546 }
547 if (!(termios->c_lflag & ICANON)) {
548 termios->c_cc[VMIN] = 1;
549 termios->c_cc[VTIME] = 0;
550 }
551}
552
Alan Coxaf9b8972006-08-27 01:24:01 -0700553/**
554 * set_sgttyb - set legacy terminal values
555 * @tty: tty structure
556 * @sgttyb: pointer to old style terminal structure
557 *
558 * Updates a terminal from the legacy BSD style terminal information
559 * structure.
560 *
561 * Locking: termios_sem
562 */
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
565{
566 int retval;
567 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800568 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
570 retval = tty_check_change(tty);
571 if (retval)
572 return retval;
573
574 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
575 return -EFAULT;
576
Arjan van de Ven5785c952006-09-29 02:00:43 -0700577 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 termios = *tty->termios;
579 termios.c_cc[VERASE] = tmp.sg_erase;
580 termios.c_cc[VKILL] = tmp.sg_kill;
581 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800582 /* Try and encode into Bfoo format */
583#ifdef BOTHER
584 tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
585#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700586 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 change_termios(tty, &termios);
588 return 0;
589}
590#endif
591
592#ifdef TIOCGETC
593static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars)
594{
595 struct tchars tmp;
596
597 tmp.t_intrc = tty->termios->c_cc[VINTR];
598 tmp.t_quitc = tty->termios->c_cc[VQUIT];
599 tmp.t_startc = tty->termios->c_cc[VSTART];
600 tmp.t_stopc = tty->termios->c_cc[VSTOP];
601 tmp.t_eofc = tty->termios->c_cc[VEOF];
602 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
603 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
604}
605
606static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars)
607{
608 struct tchars tmp;
609
610 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
611 return -EFAULT;
612 tty->termios->c_cc[VINTR] = tmp.t_intrc;
613 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
614 tty->termios->c_cc[VSTART] = tmp.t_startc;
615 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
616 tty->termios->c_cc[VEOF] = tmp.t_eofc;
617 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
618 return 0;
619}
620#endif
621
622#ifdef TIOCGLTC
623static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
624{
625 struct ltchars tmp;
626
627 tmp.t_suspc = tty->termios->c_cc[VSUSP];
628 tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */
629 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
630 tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */
631 tmp.t_werasc = tty->termios->c_cc[VWERASE];
632 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
633 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
634}
635
636static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
637{
638 struct ltchars tmp;
639
640 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
641 return -EFAULT;
642
643 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
644 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */
645 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
646 tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */
647 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
648 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
649 return 0;
650}
651#endif
652
Alan Coxaf9b8972006-08-27 01:24:01 -0700653/**
654 * send_prio_char - send priority character
655 *
656 * Send a high priority character to the tty even if stopped
657 *
Alan Cox5f412b22006-09-29 02:01:40 -0700658 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700660
Alan Cox5f412b22006-09-29 02:01:40 -0700661static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
663 int was_stopped = tty->stopped;
664
665 if (tty->driver->send_xchar) {
666 tty->driver->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700667 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
Alan Cox5f412b22006-09-29 02:01:40 -0700669
Alan Cox9c1729d2007-07-15 23:39:43 -0700670 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700671 return -ERESTARTSYS;
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (was_stopped)
674 start_tty(tty);
675 tty->driver->write(tty, &ch, 1);
676 if (was_stopped)
677 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700678 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700679 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
682int n_tty_ioctl(struct tty_struct * tty, struct file * file,
683 unsigned int cmd, unsigned long arg)
684{
685 struct tty_struct * real_tty;
686 void __user *p = (void __user *)arg;
687 int retval;
688 struct tty_ldisc *ld;
689
690 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
691 tty->driver->subtype == PTY_TYPE_MASTER)
692 real_tty = tty->link;
693 else
694 real_tty = tty;
695
696 switch (cmd) {
697#ifdef TIOCGETP
698 case TIOCGETP:
699 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
700 case TIOCSETP:
701 case TIOCSETN:
702 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
703#endif
704#ifdef TIOCGETC
705 case TIOCGETC:
706 return get_tchars(real_tty, p);
707 case TIOCSETC:
708 return set_tchars(real_tty, p);
709#endif
710#ifdef TIOCGLTC
711 case TIOCGLTC:
712 return get_ltchars(real_tty, p);
713 case TIOCSLTC:
714 return set_ltchars(real_tty, p);
715#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800716 case TCSETSF:
717 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
718 case TCSETSW:
719 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
720 case TCSETS:
721 return set_termios(real_tty, p, TERMIOS_OLD);
722#ifndef TCGETS2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 case TCGETS:
724 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
725 return -EFAULT;
726 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800727#else
728 case TCGETS:
Alan Cox64bb6c52006-12-08 02:38:47 -0800729 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800730 return -EFAULT;
731 return 0;
732 case TCGETS2:
Alan Cox64bb6c52006-12-08 02:38:47 -0800733 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800734 return -EFAULT;
735 return 0;
736 case TCSETSF2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800738 case TCSETSW2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return set_termios(real_tty, p, TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800740 case TCSETS2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800742#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 case TCGETA:
744 return get_termio(real_tty, p);
745 case TCSETAF:
746 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
747 case TCSETAW:
748 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
749 case TCSETA:
750 return set_termios(real_tty, p, TERMIOS_TERMIO);
751 case TCXONC:
752 retval = tty_check_change(tty);
753 if (retval)
754 return retval;
755 switch (arg) {
756 case TCOOFF:
757 if (!tty->flow_stopped) {
758 tty->flow_stopped = 1;
759 stop_tty(tty);
760 }
761 break;
762 case TCOON:
763 if (tty->flow_stopped) {
764 tty->flow_stopped = 0;
765 start_tty(tty);
766 }
767 break;
768 case TCIOFF:
769 if (STOP_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700770 return send_prio_char(tty, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 break;
772 case TCION:
773 if (START_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700774 return send_prio_char(tty, START_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 break;
776 default:
777 return -EINVAL;
778 }
779 return 0;
780 case TCFLSH:
781 retval = tty_check_change(tty);
782 if (retval)
783 return retval;
784
785 ld = tty_ldisc_ref(tty);
786 switch (arg) {
787 case TCIFLUSH:
KAMBAROV, ZAUR69f63c52005-06-28 20:45:12 -0700788 if (ld && ld->flush_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 ld->flush_buffer(tty);
790 break;
791 case TCIOFLUSH:
KAMBAROV, ZAUR69f63c52005-06-28 20:45:12 -0700792 if (ld && ld->flush_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 ld->flush_buffer(tty);
794 /* fall through */
795 case TCOFLUSH:
796 if (tty->driver->flush_buffer)
797 tty->driver->flush_buffer(tty);
798 break;
799 default:
800 tty_ldisc_deref(ld);
801 return -EINVAL;
802 }
803 tty_ldisc_deref(ld);
804 return 0;
805 case TIOCOUTQ:
806 return put_user(tty->driver->chars_in_buffer ?
807 tty->driver->chars_in_buffer(tty) : 0,
808 (int __user *) arg);
809 case TIOCINQ:
810 retval = tty->read_cnt;
811 if (L_ICANON(tty))
812 retval = inq_canon(tty);
813 return put_user(retval, (unsigned int __user *) arg);
814 case TIOCGLCKTRMIOS:
815 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
816 return -EFAULT;
817 return 0;
818
819 case TIOCSLCKTRMIOS:
820 if (!capable(CAP_SYS_ADMIN))
821 return -EPERM;
822 if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
823 return -EFAULT;
824 return 0;
825
826 case TIOCPKT:
827 {
828 int pktmode;
829
830 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
831 tty->driver->subtype != PTY_TYPE_MASTER)
832 return -ENOTTY;
833 if (get_user(pktmode, (int __user *) arg))
834 return -EFAULT;
835 if (pktmode) {
836 if (!tty->packet) {
837 tty->packet = 1;
838 tty->link->ctrl_status = 0;
839 }
840 } else
841 tty->packet = 0;
842 return 0;
843 }
844 case TIOCGSOFTCAR:
845 return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
846 case TIOCSSOFTCAR:
847 if (get_user(arg, (unsigned int __user *) arg))
848 return -EFAULT;
Arjan van de Ven5785c952006-09-29 02:00:43 -0700849 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 tty->termios->c_cflag =
851 ((tty->termios->c_cflag & ~CLOCAL) |
852 (arg ? CLOCAL : 0));
Arjan van de Ven5785c952006-09-29 02:00:43 -0700853 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 return 0;
855 default:
856 return -ENOIOCTLCMD;
857 }
858}
859
860EXPORT_SYMBOL(n_tty_ioctl);