Remove CONFIG_VT_UNICODE
[linux-2.6-block.git] / drivers / char / tty_ioctl.c
CommitLineData
1da177e4
LT
1/*
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>
5785c95b 23#include <linux/mutex.h>
1da177e4
LT
24
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
edc6afc5 39#define TERMIOS_OLD 8
1da177e4 40
af9b897e
AC
41
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
1da177e4
LT
53void tty_wait_until_sent(struct tty_struct * tty, long timeout)
54{
1da177e4
LT
55#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;
1da177e4
LT
62 if (!timeout)
63 timeout = MAX_SCHEDULE_TIMEOUT;
5a52bd4a
JS
64 if (wait_event_interruptible_timeout(tty->write_wait,
65 !tty->driver->chars_in_buffer(tty), timeout))
66 return;
1da177e4
LT
67 if (tty->driver->wait_until_sent)
68 tty->driver->wait_until_sent(tty, timeout);
1da177e4
LT
69}
70
71EXPORT_SYMBOL(tty_wait_until_sent);
72
edc6afc5
AC
73static void unset_locked_termios(struct ktermios *termios,
74 struct ktermios *old,
75 struct ktermios *locked)
1da177e4
LT
76{
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];
edc6afc5 94 /* FIXME: What should we do for i/ospeed */
1da177e4
LT
95}
96
edc6afc5
AC
97/*
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
edc6afc5
AC
209/**
210 * tty_termios_encode_baud_rate
78137e3b 211 * @termios: ktermios structure holding user requested state
edc6afc5
AC
212 * @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 *
78137e3b
AC
219 * 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.
edc6afc5
AC
223 *
224 * Locking: Caller should hold termios lock. This is already held
225 * when calling this function from the driver termios handler.
5f519d72
AC
226 *
227 * The ifdefs deal with platforms whose owners have yet to update them
228 * and will all go away once this is done.
edc6afc5
AC
229 */
230
231void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
232{
233 int i = 0;
78137e3b
AC
234 int ifound = -1, ofound = -1;
235 int iclose = ibaud/50, oclose = obaud/50;
236 int ibinput = 0;
edc6afc5 237
5f519d72
AC
238 if (obaud == 0) /* CD dropped */
239 ibaud = 0; /* Clear ibaud to be sure */
240
edc6afc5
AC
241 termios->c_ispeed = ibaud;
242 termios->c_ospeed = obaud;
243
5f519d72 244#ifdef BOTHER
78137e3b
AC
245 /* 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 */
5f519d72 255#endif
edc6afc5 256 termios->c_cflag &= ~CBAUD;
edc6afc5 257
5f519d72
AC
258 /*
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
edc6afc5 265 do {
78137e3b 266 if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
edc6afc5 267 termios->c_cflag |= baud_bits[i];
78137e3b 268 ofound = i;
edc6afc5 269 }
78137e3b 270 if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
5f519d72
AC
271 if (ofound == i && !ibinput)
272 ifound = i;
273#ifdef IBSHIFT
274 else {
275 ifound = i;
78137e3b 276 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
5f519d72
AC
277 }
278#endif
edc6afc5 279 }
6804396f 280 } while (++i < n_baud_table);
5f519d72
AC
281
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
78137e3b 287 if (ofound == -1)
edc6afc5 288 termios->c_cflag |= BOTHER;
78137e3b
AC
289 /* Set exact input bits only if the input and output differ or the
290 user already did */
6804396f 291 if (ifound == -1 && (ibaud != obaud || ibinput))
edc6afc5 292 termios->c_cflag |= (BOTHER << IBSHIFT);
5f519d72
AC
293#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
edc6afc5 301}
edc6afc5
AC
302EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
303
5f519d72
AC
304void 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);
edc6afc5
AC
309
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
5f519d72
AC
339/**
340 * 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
af9b897e
AC
362/**
363 * 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
edc6afc5 374static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
1da177e4
LT
375{
376 int canon_change;
edc6afc5 377 struct ktermios old_termios = *tty->termios;
1da177e4
LT
378 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 */
5785c95b 387 mutex_lock(&tty->termios_mutex);
1da177e4
LT
388
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
5f519d72 399 /* This bit should be in the ldisc code */
1da177e4
LT
400 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. */
1da177e4
LT
405 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);
5f519d72
AC
424 else
425 tty_termios_copy_hw(tty->termios, &old_termios);
1da177e4
LT
426
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 }
5785c95b 433 mutex_unlock(&tty->termios_mutex);
1da177e4
LT
434}
435
af9b897e
AC
436/**
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
1da177e4
LT
449static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
450{
edc6afc5 451 struct ktermios tmp_termios;
1da177e4
LT
452 struct tty_ldisc *ld;
453 int retval = tty_check_change(tty);
454
455 if (retval)
456 return retval;
457
64bb6c5e
AC
458 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
459
1da177e4 460 if (opt & TERMIOS_TERMIO) {
1da177e4
LT
461 if (user_termio_to_kernel_termios(&tmp_termios,
462 (struct termio __user *)arg))
463 return -EFAULT;
edc6afc5
AC
464#ifdef TCGETS2
465 } else if (opt & TERMIOS_OLD) {
edc6afc5 466 if (user_termios_to_kernel_termios_1(&tmp_termios,
64bb6c5e 467 (struct termios __user *)arg))
edc6afc5 468 return -EFAULT;
1da177e4
LT
469 } else {
470 if (user_termios_to_kernel_termios(&tmp_termios,
64bb6c5e 471 (struct termios2 __user *)arg))
1da177e4
LT
472 return -EFAULT;
473 }
64bb6c5e
AC
474#else
475 } else if (user_termios_to_kernel_termios(&tmp_termios,
476 (struct termios __user *)arg))
477 return -EFAULT;
478#endif
1da177e4 479
edc6afc5
AC
480 /* 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
1da177e4
LT
485 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);
5f519d72
AC
500
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 */
1da177e4
LT
505 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
5785c95b 562 mutex_lock(&tty->termios_mutex);
606d099c
AC
563 tmp.sg_ispeed = tty->termios->c_ispeed;
564 tmp.sg_ospeed = tty->termios->c_ospeed;
1da177e4
LT
565 tmp.sg_erase = tty->termios->c_cc[VERASE];
566 tmp.sg_kill = tty->termios->c_cc[VKILL];
567 tmp.sg_flags = get_sgflags(tty);
5785c95b 568 mutex_unlock(&tty->termios_mutex);
1da177e4
LT
569
570 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
571}
572
edc6afc5 573static void set_sgflags(struct ktermios * termios, int flags)
1da177e4
LT
574{
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
af9b897e
AC
599/**
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
1da177e4
LT
610static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
611{
612 int retval;
613 struct sgttyb tmp;
edc6afc5 614 struct ktermios termios;
1da177e4
LT
615
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
5785c95b 623 mutex_lock(&tty->termios_mutex);
6804396f 624 termios = *tty->termios;
1da177e4
LT
625 termios.c_cc[VERASE] = tmp.sg_erase;
626 termios.c_cc[VKILL] = tmp.sg_kill;
627 set_sgflags(&termios, tmp.sg_flags);
edc6afc5
AC
628 /* Try and encode into Bfoo format */
629#ifdef BOTHER
630 tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
631#endif
5785c95b 632 mutex_unlock(&tty->termios_mutex);
1da177e4
LT
633 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
af9b897e
AC
699/**
700 * send_prio_char - send priority character
701 *
702 * Send a high priority character to the tty even if stopped
703 *
5f412b24 704 * Locking: none for xchar method, write ordering for write method.
1da177e4 705 */
af9b897e 706
5f412b24 707static int send_prio_char(struct tty_struct *tty, char ch)
1da177e4
LT
708{
709 int was_stopped = tty->stopped;
710
711 if (tty->driver->send_xchar) {
712 tty->driver->send_xchar(tty, ch);
5f412b24 713 return 0;
1da177e4 714 }
5f412b24 715
9c1729db 716 if (tty_write_lock(tty, 0) < 0)
5f412b24
AC
717 return -ERESTARTSYS;
718
1da177e4
LT
719 if (was_stopped)
720 start_tty(tty);
721 tty->driver->write(tty, &ch, 1);
722 if (was_stopped)
723 stop_tty(tty);
9c1729db 724 tty_write_unlock(tty);
5f412b24 725 return 0;
1da177e4
LT
726}
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
edc6afc5
AC
762 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
1da177e4
LT
769 case TCGETS:
770 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
771 return -EFAULT;
772 return 0;
edc6afc5
AC
773#else
774 case TCGETS:
64bb6c5e 775 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
edc6afc5
AC
776 return -EFAULT;
777 return 0;
778 case TCGETS2:
64bb6c5e 779 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
edc6afc5
AC
780 return -EFAULT;
781 return 0;
782 case TCSETSF2:
1da177e4 783 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
edc6afc5 784 case TCSETSW2:
1da177e4 785 return set_termios(real_tty, p, TERMIOS_WAIT);
edc6afc5 786 case TCSETS2:
1da177e4 787 return set_termios(real_tty, p, 0);
edc6afc5 788#endif
1da177e4
LT
789 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)
5f412b24 816 return send_prio_char(tty, STOP_CHAR(tty));
1da177e4
LT
817 break;
818 case TCION:
819 if (START_CHAR(tty) != __DISABLED_CHAR)
5f412b24 820 return send_prio_char(tty, START_CHAR(tty));
1da177e4
LT
821 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:
69f63c5c 834 if (ld && ld->flush_buffer)
1da177e4
LT
835 ld->flush_buffer(tty);
836 break;
837 case TCIOFLUSH:
69f63c5c 838 if (ld && ld->flush_buffer)
1da177e4
LT
839 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);
bb8bd3a5
TB
860#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
1da177e4 873 case TIOCGLCKTRMIOS:
f629307c 874 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
1da177e4
LT
875 return -EFAULT;
876 return 0;
877
878 case TIOCSLCKTRMIOS:
879 if (!capable(CAP_SYS_ADMIN))
880 return -EPERM;
f629307c 881 if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
1da177e4
LT
882 return -EFAULT;
883 return 0;
bb8bd3a5 884#endif
1da177e4
LT
885
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;
5785c95b 909 mutex_lock(&tty->termios_mutex);
1da177e4
LT
910 tty->termios->c_cflag =
911 ((tty->termios->c_cflag & ~CLOCAL) |
912 (arg ? CLOCAL : 0));
5785c95b 913 mutex_unlock(&tty->termios_mutex);
1da177e4
LT
914 return 0;
915 default:
916 return -ENOIOCTLCMD;
917 }
918}
919
920EXPORT_SYMBOL(n_tty_ioctl);