blob: dee47f40c6a3878656f5bcacddcabd98c34da676 [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
228 * @termios: termios structure
229 * @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 *
236 * For now input and output speed must agree.
237 *
238 * Locking: Caller should hold termios lock. This is already held
239 * when calling this function from the driver termios handler.
240 */
241
242void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
243{
244 int i = 0;
245 int ifound = 0, ofound = 0;
246
247 termios->c_ispeed = ibaud;
248 termios->c_ospeed = obaud;
249
250 termios->c_cflag &= ~CBAUD;
251 /* Identical speed means no input encoding (ie B0 << IBSHIFT)*/
252 if (termios->c_ispeed == termios->c_ospeed)
253 ifound = 1;
254
255 do {
256 if (obaud == baud_table[i]) {
257 termios->c_cflag |= baud_bits[i];
258 ofound = 1;
259 /* So that if ibaud == obaud we don't set it */
260 continue;
261 }
262 if (ibaud == baud_table[i]) {
263 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
264 ifound = 1;
265 }
266 }
267 while(++i < n_baud_table);
268 if (!ofound)
269 termios->c_cflag |= BOTHER;
270 if (!ifound)
271 termios->c_cflag |= (BOTHER << IBSHIFT);
272}
273
274EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
275
276#endif
277
278/**
279 * tty_get_baud_rate - get tty bit rates
280 * @tty: tty to query
281 *
282 * Returns the baud rate as an integer for this terminal. The
283 * termios lock must be held by the caller and the terminal bit
284 * flags may be updated.
285 *
286 * Locking: none
287 */
288
289speed_t tty_get_baud_rate(struct tty_struct *tty)
290{
291 speed_t baud = tty_termios_baud_rate(tty->termios);
292
293 if (baud == 38400 && tty->alt_speed) {
294 if (!tty->warned) {
295 printk(KERN_WARNING "Use of setserial/setrocket to "
296 "set SPD_* flags is deprecated\n");
297 tty->warned = 1;
298 }
299 baud = tty->alt_speed;
300 }
301
302 return baud;
303}
304
305EXPORT_SYMBOL(tty_get_baud_rate);
306
Alan Coxaf9b8972006-08-27 01:24:01 -0700307/**
308 * change_termios - update termios values
309 * @tty: tty to update
310 * @new_termios: desired new value
311 *
312 * Perform updates to the termios values set on this terminal. There
313 * is a bit of layering violation here with n_tty in terms of the
314 * internal knowledge of this function.
315 *
316 * Locking: termios_sem
317 */
318
Alan Coxedc6afc2006-12-08 02:38:44 -0800319static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 int canon_change;
Alan Coxedc6afc2006-12-08 02:38:44 -0800322 struct ktermios old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 struct tty_ldisc *ld;
324
325 /*
326 * Perform the actual termios internal changes under lock.
327 */
328
329
330 /* FIXME: we need to decide on some locking/ordering semantics
331 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700332 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
334 *tty->termios = *new_termios;
335 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
336 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
337 if (canon_change) {
338 memset(&tty->read_flags, 0, sizeof tty->read_flags);
339 tty->canon_head = tty->read_tail;
340 tty->canon_data = 0;
341 tty->erasing = 0;
342 }
343
344
345 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
346 /* Get characters left over from canonical mode. */
347 wake_up_interruptible(&tty->read_wait);
348
349 /* See if packet mode change of state. */
350
351 if (tty->link && tty->link->packet) {
352 int old_flow = ((old_termios.c_iflag & IXON) &&
353 (old_termios.c_cc[VSTOP] == '\023') &&
354 (old_termios.c_cc[VSTART] == '\021'));
355 int new_flow = (I_IXON(tty) &&
356 STOP_CHAR(tty) == '\023' &&
357 START_CHAR(tty) == '\021');
358 if (old_flow != new_flow) {
359 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
360 if (new_flow)
361 tty->ctrl_status |= TIOCPKT_DOSTOP;
362 else
363 tty->ctrl_status |= TIOCPKT_NOSTOP;
364 wake_up_interruptible(&tty->link->read_wait);
365 }
366 }
367
368 if (tty->driver->set_termios)
369 (*tty->driver->set_termios)(tty, &old_termios);
370
371 ld = tty_ldisc_ref(tty);
372 if (ld != NULL) {
373 if (ld->set_termios)
374 (ld->set_termios)(tty, &old_termios);
375 tty_ldisc_deref(ld);
376 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700377 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378}
379
Alan Coxaf9b8972006-08-27 01:24:01 -0700380/**
381 * set_termios - set termios values for a tty
382 * @tty: terminal device
383 * @arg: user data
384 * @opt: option information
385 *
386 * Helper function to prepare termios data and run neccessary other
387 * functions before using change_termios to do the actual changes.
388 *
389 * Locking:
390 * Called functions take ldisc and termios_sem locks
391 */
392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
394{
Alan Coxedc6afc2006-12-08 02:38:44 -0800395 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 struct tty_ldisc *ld;
397 int retval = tty_check_change(tty);
398
399 if (retval)
400 return retval;
401
Alan Cox64bb6c52006-12-08 02:38:47 -0800402 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
403
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (user_termio_to_kernel_termios(&tmp_termios,
406 (struct termio __user *)arg))
407 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800408#ifdef TCGETS2
409 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800410 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 (struct termios __user *)arg))
412 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800413 } else {
414 if (user_termios_to_kernel_termios(&tmp_termios,
415 (struct termios2 __user *)arg))
416 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800418#else
419 } else if (user_termios_to_kernel_termios(&tmp_termios,
420 (struct termios __user *)arg))
421 return -EFAULT;
422#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Alan Coxedc6afc2006-12-08 02:38:44 -0800424 /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed
425 so its unconditionally usable */
426 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
427 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
428
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 ld = tty_ldisc_ref(tty);
430
431 if (ld != NULL) {
432 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
433 ld->flush_buffer(tty);
434 tty_ldisc_deref(ld);
435 }
436
437 if (opt & TERMIOS_WAIT) {
438 tty_wait_until_sent(tty, 0);
439 if (signal_pending(current))
440 return -EINTR;
441 }
442
443 change_termios(tty, &tmp_termios);
444 return 0;
445}
446
447static int get_termio(struct tty_struct * tty, struct termio __user * termio)
448{
449 if (kernel_termios_to_user_termio(termio, tty->termios))
450 return -EFAULT;
451 return 0;
452}
453
454static unsigned long inq_canon(struct tty_struct * tty)
455{
456 int nr, head, tail;
457
458 if (!tty->canon_data || !tty->read_buf)
459 return 0;
460 head = tty->canon_head;
461 tail = tty->read_tail;
462 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
463 /* Skip EOF-chars.. */
464 while (head != tail) {
465 if (test_bit(tail, tty->read_flags) &&
466 tty->read_buf[tail] == __DISABLED_CHAR)
467 nr--;
468 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
469 }
470 return nr;
471}
472
473#ifdef TIOCGETP
474/*
475 * These are deprecated, but there is limited support..
476 *
477 * The "sg_flags" translation is a joke..
478 */
479static int get_sgflags(struct tty_struct * tty)
480{
481 int flags = 0;
482
483 if (!(tty->termios->c_lflag & ICANON)) {
484 if (tty->termios->c_lflag & ISIG)
485 flags |= 0x02; /* cbreak */
486 else
487 flags |= 0x20; /* raw */
488 }
489 if (tty->termios->c_lflag & ECHO)
490 flags |= 0x08; /* echo */
491 if (tty->termios->c_oflag & OPOST)
492 if (tty->termios->c_oflag & ONLCR)
493 flags |= 0x10; /* crmod */
494 return flags;
495}
496
497static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
498{
499 struct sgttyb tmp;
500
Arjan van de Ven5785c952006-09-29 02:00:43 -0700501 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800502 tmp.sg_ispeed = tty->termios->c_ispeed;
503 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 tmp.sg_erase = tty->termios->c_cc[VERASE];
505 tmp.sg_kill = tty->termios->c_cc[VKILL];
506 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700507 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
510}
511
Alan Coxedc6afc2006-12-08 02:38:44 -0800512static void set_sgflags(struct ktermios * termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 termios->c_iflag = ICRNL | IXON;
515 termios->c_oflag = 0;
516 termios->c_lflag = ISIG | ICANON;
517 if (flags & 0x02) { /* cbreak */
518 termios->c_iflag = 0;
519 termios->c_lflag &= ~ICANON;
520 }
521 if (flags & 0x08) { /* echo */
522 termios->c_lflag |= ECHO | ECHOE | ECHOK |
523 ECHOCTL | ECHOKE | IEXTEN;
524 }
525 if (flags & 0x10) { /* crmod */
526 termios->c_oflag |= OPOST | ONLCR;
527 }
528 if (flags & 0x20) { /* raw */
529 termios->c_iflag = 0;
530 termios->c_lflag &= ~(ISIG | ICANON);
531 }
532 if (!(termios->c_lflag & ICANON)) {
533 termios->c_cc[VMIN] = 1;
534 termios->c_cc[VTIME] = 0;
535 }
536}
537
Alan Coxaf9b8972006-08-27 01:24:01 -0700538/**
539 * set_sgttyb - set legacy terminal values
540 * @tty: tty structure
541 * @sgttyb: pointer to old style terminal structure
542 *
543 * Updates a terminal from the legacy BSD style terminal information
544 * structure.
545 *
546 * Locking: termios_sem
547 */
548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
550{
551 int retval;
552 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800553 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 retval = tty_check_change(tty);
556 if (retval)
557 return retval;
558
559 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
560 return -EFAULT;
561
Arjan van de Ven5785c952006-09-29 02:00:43 -0700562 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 termios = *tty->termios;
564 termios.c_cc[VERASE] = tmp.sg_erase;
565 termios.c_cc[VKILL] = tmp.sg_kill;
566 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800567 /* Try and encode into Bfoo format */
568#ifdef BOTHER
569 tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
570#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700571 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 change_termios(tty, &termios);
573 return 0;
574}
575#endif
576
577#ifdef TIOCGETC
578static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars)
579{
580 struct tchars tmp;
581
582 tmp.t_intrc = tty->termios->c_cc[VINTR];
583 tmp.t_quitc = tty->termios->c_cc[VQUIT];
584 tmp.t_startc = tty->termios->c_cc[VSTART];
585 tmp.t_stopc = tty->termios->c_cc[VSTOP];
586 tmp.t_eofc = tty->termios->c_cc[VEOF];
587 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
588 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
589}
590
591static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars)
592{
593 struct tchars tmp;
594
595 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
596 return -EFAULT;
597 tty->termios->c_cc[VINTR] = tmp.t_intrc;
598 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
599 tty->termios->c_cc[VSTART] = tmp.t_startc;
600 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
601 tty->termios->c_cc[VEOF] = tmp.t_eofc;
602 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
603 return 0;
604}
605#endif
606
607#ifdef TIOCGLTC
608static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
609{
610 struct ltchars tmp;
611
612 tmp.t_suspc = tty->termios->c_cc[VSUSP];
613 tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */
614 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
615 tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */
616 tmp.t_werasc = tty->termios->c_cc[VWERASE];
617 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
618 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
619}
620
621static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
622{
623 struct ltchars tmp;
624
625 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
626 return -EFAULT;
627
628 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
629 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */
630 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
631 tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */
632 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
633 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
634 return 0;
635}
636#endif
637
Alan Coxaf9b8972006-08-27 01:24:01 -0700638/**
639 * send_prio_char - send priority character
640 *
641 * Send a high priority character to the tty even if stopped
642 *
Alan Cox5f412b22006-09-29 02:01:40 -0700643 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700645
Alan Cox5f412b22006-09-29 02:01:40 -0700646static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
648 int was_stopped = tty->stopped;
649
650 if (tty->driver->send_xchar) {
651 tty->driver->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700652 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Alan Cox5f412b22006-09-29 02:01:40 -0700654
655 if (mutex_lock_interruptible(&tty->atomic_write_lock))
656 return -ERESTARTSYS;
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 if (was_stopped)
659 start_tty(tty);
660 tty->driver->write(tty, &ch, 1);
661 if (was_stopped)
662 stop_tty(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700663 mutex_unlock(&tty->atomic_write_lock);
664 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665}
666
667int n_tty_ioctl(struct tty_struct * tty, struct file * file,
668 unsigned int cmd, unsigned long arg)
669{
670 struct tty_struct * real_tty;
671 void __user *p = (void __user *)arg;
672 int retval;
673 struct tty_ldisc *ld;
674
675 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
676 tty->driver->subtype == PTY_TYPE_MASTER)
677 real_tty = tty->link;
678 else
679 real_tty = tty;
680
681 switch (cmd) {
682#ifdef TIOCGETP
683 case TIOCGETP:
684 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
685 case TIOCSETP:
686 case TIOCSETN:
687 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
688#endif
689#ifdef TIOCGETC
690 case TIOCGETC:
691 return get_tchars(real_tty, p);
692 case TIOCSETC:
693 return set_tchars(real_tty, p);
694#endif
695#ifdef TIOCGLTC
696 case TIOCGLTC:
697 return get_ltchars(real_tty, p);
698 case TIOCSLTC:
699 return set_ltchars(real_tty, p);
700#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800701 case TCSETSF:
702 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
703 case TCSETSW:
704 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
705 case TCSETS:
706 return set_termios(real_tty, p, TERMIOS_OLD);
707#ifndef TCGETS2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 case TCGETS:
709 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
710 return -EFAULT;
711 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800712#else
713 case TCGETS:
Alan Cox64bb6c52006-12-08 02:38:47 -0800714 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800715 return -EFAULT;
716 return 0;
717 case TCGETS2:
Alan Cox64bb6c52006-12-08 02:38:47 -0800718 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800719 return -EFAULT;
720 return 0;
721 case TCSETSF2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800723 case TCSETSW2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return set_termios(real_tty, p, TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800725 case TCSETS2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800727#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 case TCGETA:
729 return get_termio(real_tty, p);
730 case TCSETAF:
731 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
732 case TCSETAW:
733 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
734 case TCSETA:
735 return set_termios(real_tty, p, TERMIOS_TERMIO);
736 case TCXONC:
737 retval = tty_check_change(tty);
738 if (retval)
739 return retval;
740 switch (arg) {
741 case TCOOFF:
742 if (!tty->flow_stopped) {
743 tty->flow_stopped = 1;
744 stop_tty(tty);
745 }
746 break;
747 case TCOON:
748 if (tty->flow_stopped) {
749 tty->flow_stopped = 0;
750 start_tty(tty);
751 }
752 break;
753 case TCIOFF:
754 if (STOP_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700755 return send_prio_char(tty, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 break;
757 case TCION:
758 if (START_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700759 return send_prio_char(tty, START_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 break;
761 default:
762 return -EINVAL;
763 }
764 return 0;
765 case TCFLSH:
766 retval = tty_check_change(tty);
767 if (retval)
768 return retval;
769
770 ld = tty_ldisc_ref(tty);
771 switch (arg) {
772 case TCIFLUSH:
KAMBAROV, ZAUR69f63c52005-06-28 20:45:12 -0700773 if (ld && ld->flush_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 ld->flush_buffer(tty);
775 break;
776 case TCIOFLUSH:
KAMBAROV, ZAUR69f63c52005-06-28 20:45:12 -0700777 if (ld && ld->flush_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 ld->flush_buffer(tty);
779 /* fall through */
780 case TCOFLUSH:
781 if (tty->driver->flush_buffer)
782 tty->driver->flush_buffer(tty);
783 break;
784 default:
785 tty_ldisc_deref(ld);
786 return -EINVAL;
787 }
788 tty_ldisc_deref(ld);
789 return 0;
790 case TIOCOUTQ:
791 return put_user(tty->driver->chars_in_buffer ?
792 tty->driver->chars_in_buffer(tty) : 0,
793 (int __user *) arg);
794 case TIOCINQ:
795 retval = tty->read_cnt;
796 if (L_ICANON(tty))
797 retval = inq_canon(tty);
798 return put_user(retval, (unsigned int __user *) arg);
799 case TIOCGLCKTRMIOS:
800 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
801 return -EFAULT;
802 return 0;
803
804 case TIOCSLCKTRMIOS:
805 if (!capable(CAP_SYS_ADMIN))
806 return -EPERM;
807 if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
808 return -EFAULT;
809 return 0;
810
811 case TIOCPKT:
812 {
813 int pktmode;
814
815 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
816 tty->driver->subtype != PTY_TYPE_MASTER)
817 return -ENOTTY;
818 if (get_user(pktmode, (int __user *) arg))
819 return -EFAULT;
820 if (pktmode) {
821 if (!tty->packet) {
822 tty->packet = 1;
823 tty->link->ctrl_status = 0;
824 }
825 } else
826 tty->packet = 0;
827 return 0;
828 }
829 case TIOCGSOFTCAR:
830 return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
831 case TIOCSSOFTCAR:
832 if (get_user(arg, (unsigned int __user *) arg))
833 return -EFAULT;
Arjan van de Ven5785c952006-09-29 02:00:43 -0700834 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 tty->termios->c_cflag =
836 ((tty->termios->c_cflag & ~CLOCAL) |
837 (arg ? CLOCAL : 0));
Arjan van de Ven5785c952006-09-29 02:00:43 -0700838 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 return 0;
840 default:
841 return -ENOIOCTLCMD;
842 }
843}
844
845EXPORT_SYMBOL(n_tty_ioctl);