diff options
Diffstat (limited to 'drivers/char/tty_ioctl.c')
-rw-r--r-- | drivers/char/tty_ioctl.c | 212 |
1 files changed, 152 insertions, 60 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index bf34e4597421..a408c8e487ec 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -40,6 +40,15 @@ | |||
40 | #define TERMIOS_OLD 8 | 40 | #define TERMIOS_OLD 8 |
41 | 41 | ||
42 | 42 | ||
43 | /** | ||
44 | * tty_chars_in_buffer - characters pending | ||
45 | * @tty: terminal | ||
46 | * | ||
47 | * Return the number of bytes of data in the device private | ||
48 | * output queue. If no private method is supplied there is assumed | ||
49 | * to be no queue on the device. | ||
50 | */ | ||
51 | |||
43 | int tty_chars_in_buffer(struct tty_struct *tty) | 52 | int tty_chars_in_buffer(struct tty_struct *tty) |
44 | { | 53 | { |
45 | if (tty->ops->chars_in_buffer) | 54 | if (tty->ops->chars_in_buffer) |
@@ -47,26 +56,49 @@ int tty_chars_in_buffer(struct tty_struct *tty) | |||
47 | else | 56 | else |
48 | return 0; | 57 | return 0; |
49 | } | 58 | } |
50 | |||
51 | EXPORT_SYMBOL(tty_chars_in_buffer); | 59 | EXPORT_SYMBOL(tty_chars_in_buffer); |
52 | 60 | ||
61 | /** | ||
62 | * tty_write_room - write queue space | ||
63 | * @tty: terminal | ||
64 | * | ||
65 | * Return the number of bytes that can be queued to this device | ||
66 | * at the present time. The result should be treated as a guarantee | ||
67 | * and the driver cannot offer a value it later shrinks by more than | ||
68 | * the number of bytes written. If no method is provided 2K is always | ||
69 | * returned and data may be lost as there will be no flow control. | ||
70 | */ | ||
71 | |||
53 | int tty_write_room(struct tty_struct *tty) | 72 | int tty_write_room(struct tty_struct *tty) |
54 | { | 73 | { |
55 | if (tty->ops->write_room) | 74 | if (tty->ops->write_room) |
56 | return tty->ops->write_room(tty); | 75 | return tty->ops->write_room(tty); |
57 | return 2048; | 76 | return 2048; |
58 | } | 77 | } |
59 | |||
60 | EXPORT_SYMBOL(tty_write_room); | 78 | EXPORT_SYMBOL(tty_write_room); |
61 | 79 | ||
80 | /** | ||
81 | * tty_driver_flush_buffer - discard internal buffer | ||
82 | * @tty: terminal | ||
83 | * | ||
84 | * Discard the internal output buffer for this device. If no method | ||
85 | * is provided then either the buffer cannot be hardware flushed or | ||
86 | * there is no buffer driver side. | ||
87 | */ | ||
62 | void tty_driver_flush_buffer(struct tty_struct *tty) | 88 | void tty_driver_flush_buffer(struct tty_struct *tty) |
63 | { | 89 | { |
64 | if (tty->ops->flush_buffer) | 90 | if (tty->ops->flush_buffer) |
65 | tty->ops->flush_buffer(tty); | 91 | tty->ops->flush_buffer(tty); |
66 | } | 92 | } |
67 | |||
68 | EXPORT_SYMBOL(tty_driver_flush_buffer); | 93 | EXPORT_SYMBOL(tty_driver_flush_buffer); |
69 | 94 | ||
95 | /** | ||
96 | * tty_throttle - flow control | ||
97 | * @tty: terminal | ||
98 | * | ||
99 | * Indicate that a tty should stop transmitting data down the stack. | ||
100 | */ | ||
101 | |||
70 | void tty_throttle(struct tty_struct *tty) | 102 | void tty_throttle(struct tty_struct *tty) |
71 | { | 103 | { |
72 | /* check TTY_THROTTLED first so it indicates our state */ | 104 | /* check TTY_THROTTLED first so it indicates our state */ |
@@ -76,6 +108,13 @@ void tty_throttle(struct tty_struct *tty) | |||
76 | } | 108 | } |
77 | EXPORT_SYMBOL(tty_throttle); | 109 | EXPORT_SYMBOL(tty_throttle); |
78 | 110 | ||
111 | /** | ||
112 | * tty_unthrottle - flow control | ||
113 | * @tty: terminal | ||
114 | * | ||
115 | * Indicate that a tty may continue transmitting data down the stack. | ||
116 | */ | ||
117 | |||
79 | void tty_unthrottle(struct tty_struct *tty) | 118 | void tty_unthrottle(struct tty_struct *tty) |
80 | { | 119 | { |
81 | if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && | 120 | if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && |
@@ -112,6 +151,11 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout) | |||
112 | } | 151 | } |
113 | EXPORT_SYMBOL(tty_wait_until_sent); | 152 | EXPORT_SYMBOL(tty_wait_until_sent); |
114 | 153 | ||
154 | |||
155 | /* | ||
156 | * Termios Helper Methods | ||
157 | */ | ||
158 | |||
115 | static void unset_locked_termios(struct ktermios *termios, | 159 | static void unset_locked_termios(struct ktermios *termios, |
116 | struct ktermios *old, | 160 | struct ktermios *old, |
117 | struct ktermios *locked) | 161 | struct ktermios *locked) |
@@ -346,6 +390,16 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, | |||
346 | } | 390 | } |
347 | EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); | 391 | EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); |
348 | 392 | ||
393 | /** | ||
394 | * tty_encode_baud_rate - set baud rate of the tty | ||
395 | * @ibaud: input baud rate | ||
396 | * @obad: output baud rate | ||
397 | * | ||
398 | * Update the current termios data for the tty with the new speed | ||
399 | * settings. The caller must hold the termios_mutex for the tty in | ||
400 | * question. | ||
401 | */ | ||
402 | |||
349 | void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) | 403 | void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) |
350 | { | 404 | { |
351 | tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); | 405 | tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); |
@@ -430,12 +484,11 @@ EXPORT_SYMBOL(tty_termios_hw_change); | |||
430 | * is a bit of layering violation here with n_tty in terms of the | 484 | * is a bit of layering violation here with n_tty in terms of the |
431 | * internal knowledge of this function. | 485 | * internal knowledge of this function. |
432 | * | 486 | * |
433 | * Locking: termios_sem | 487 | * Locking: termios_mutex |
434 | */ | 488 | */ |
435 | 489 | ||
436 | static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | 490 | static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) |
437 | { | 491 | { |
438 | int canon_change; | ||
439 | struct ktermios old_termios; | 492 | struct ktermios old_termios; |
440 | struct tty_ldisc *ld; | 493 | struct tty_ldisc *ld; |
441 | unsigned long flags; | 494 | unsigned long flags; |
@@ -451,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
451 | old_termios = *tty->termios; | 504 | old_termios = *tty->termios; |
452 | *tty->termios = *new_termios; | 505 | *tty->termios = *new_termios; |
453 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); | 506 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); |
454 | canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; | ||
455 | if (canon_change) { | ||
456 | memset(&tty->read_flags, 0, sizeof tty->read_flags); | ||
457 | tty->canon_head = tty->read_tail; | ||
458 | tty->canon_data = 0; | ||
459 | tty->erasing = 0; | ||
460 | } | ||
461 | |||
462 | /* This bit should be in the ldisc code */ | ||
463 | if (canon_change && !L_ICANON(tty) && tty->read_cnt) | ||
464 | /* Get characters left over from canonical mode. */ | ||
465 | wake_up_interruptible(&tty->read_wait); | ||
466 | 507 | ||
467 | /* See if packet mode change of state. */ | 508 | /* See if packet mode change of state. */ |
468 | if (tty->link && tty->link->packet) { | 509 | if (tty->link && tty->link->packet) { |
@@ -508,7 +549,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
508 | * functions before using change_termios to do the actual changes. | 549 | * functions before using change_termios to do the actual changes. |
509 | * | 550 | * |
510 | * Locking: | 551 | * Locking: |
511 | * Called functions take ldisc and termios_sem locks | 552 | * Called functions take ldisc and termios_mutex locks |
512 | */ | 553 | */ |
513 | 554 | ||
514 | static int set_termios(struct tty_struct *tty, void __user *arg, int opt) | 555 | static int set_termios(struct tty_struct *tty, void __user *arg, int opt) |
@@ -579,25 +620,51 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio) | |||
579 | return 0; | 620 | return 0; |
580 | } | 621 | } |
581 | 622 | ||
582 | static unsigned long inq_canon(struct tty_struct *tty) | 623 | |
624 | #ifdef TCGETX | ||
625 | |||
626 | /** | ||
627 | * set_termiox - set termiox fields if possible | ||
628 | * @tty: terminal | ||
629 | * @arg: termiox structure from user | ||
630 | * @opt: option flags for ioctl type | ||
631 | * | ||
632 | * Implement the device calling points for the SYS5 termiox ioctl | ||
633 | * interface in Linux | ||
634 | */ | ||
635 | |||
636 | static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) | ||
583 | { | 637 | { |
584 | int nr, head, tail; | 638 | struct termiox tnew; |
639 | struct tty_ldisc *ld; | ||
585 | 640 | ||
586 | if (!tty->canon_data || !tty->read_buf) | 641 | if (tty->termiox == NULL) |
587 | return 0; | 642 | return -EINVAL; |
588 | head = tty->canon_head; | 643 | if (copy_from_user(&tnew, arg, sizeof(struct termiox))) |
589 | tail = tty->read_tail; | 644 | return -EFAULT; |
590 | nr = (head - tail) & (N_TTY_BUF_SIZE-1); | 645 | |
591 | /* Skip EOF-chars.. */ | 646 | ld = tty_ldisc_ref(tty); |
592 | while (head != tail) { | 647 | if (ld != NULL) { |
593 | if (test_bit(tail, tty->read_flags) && | 648 | if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) |
594 | tty->read_buf[tail] == __DISABLED_CHAR) | 649 | ld->ops->flush_buffer(tty); |
595 | nr--; | 650 | tty_ldisc_deref(ld); |
596 | tail = (tail+1) & (N_TTY_BUF_SIZE-1); | ||
597 | } | 651 | } |
598 | return nr; | 652 | if (opt & TERMIOS_WAIT) { |
653 | tty_wait_until_sent(tty, 0); | ||
654 | if (signal_pending(current)) | ||
655 | return -EINTR; | ||
656 | } | ||
657 | |||
658 | mutex_lock(&tty->termios_mutex); | ||
659 | if (tty->ops->set_termiox) | ||
660 | tty->ops->set_termiox(tty, &tnew); | ||
661 | mutex_unlock(&tty->termios_mutex); | ||
662 | return 0; | ||
599 | } | 663 | } |
600 | 664 | ||
665 | #endif | ||
666 | |||
667 | |||
601 | #ifdef TIOCGETP | 668 | #ifdef TIOCGETP |
602 | /* | 669 | /* |
603 | * These are deprecated, but there is limited support.. | 670 | * These are deprecated, but there is limited support.. |
@@ -671,7 +738,7 @@ static void set_sgflags(struct ktermios *termios, int flags) | |||
671 | * Updates a terminal from the legacy BSD style terminal information | 738 | * Updates a terminal from the legacy BSD style terminal information |
672 | * structure. | 739 | * structure. |
673 | * | 740 | * |
674 | * Locking: termios_sem | 741 | * Locking: termios_mutex |
675 | */ | 742 | */ |
676 | 743 | ||
677 | static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) | 744 | static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) |
@@ -849,6 +916,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
849 | { | 916 | { |
850 | struct tty_struct *real_tty; | 917 | struct tty_struct *real_tty; |
851 | void __user *p = (void __user *)arg; | 918 | void __user *p = (void __user *)arg; |
919 | int ret = 0; | ||
852 | 920 | ||
853 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 921 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
854 | tty->driver->subtype == PTY_TYPE_MASTER) | 922 | tty->driver->subtype == PTY_TYPE_MASTER) |
@@ -884,18 +952,24 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
884 | return set_termios(real_tty, p, TERMIOS_OLD); | 952 | return set_termios(real_tty, p, TERMIOS_OLD); |
885 | #ifndef TCGETS2 | 953 | #ifndef TCGETS2 |
886 | case TCGETS: | 954 | case TCGETS: |
955 | mutex_lock(&real_tty->termios_mutex); | ||
887 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) | 956 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) |
888 | return -EFAULT; | 957 | ret = -EFAULT; |
889 | return 0; | 958 | mutex_unlock(&real_tty->termios_mutex); |
959 | return ret; | ||
890 | #else | 960 | #else |
891 | case TCGETS: | 961 | case TCGETS: |
962 | mutex_lock(&real_tty->termios_mutex); | ||
892 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) | 963 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) |
893 | return -EFAULT; | 964 | ret = -EFAULT; |
894 | return 0; | 965 | mutex_unlock(&real_tty->termios_mutex); |
966 | return ret; | ||
895 | case TCGETS2: | 967 | case TCGETS2: |
968 | mutex_lock(&real_tty->termios_mutex); | ||
896 | if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) | 969 | if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) |
897 | return -EFAULT; | 970 | ret = -EFAULT; |
898 | return 0; | 971 | mutex_unlock(&real_tty->termios_mutex); |
972 | return ret; | ||
899 | case TCSETSF2: | 973 | case TCSETSF2: |
900 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); | 974 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); |
901 | case TCSETSW2: | 975 | case TCSETSW2: |
@@ -913,34 +987,59 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
913 | return set_termios(real_tty, p, TERMIOS_TERMIO); | 987 | return set_termios(real_tty, p, TERMIOS_TERMIO); |
914 | #ifndef TCGETS2 | 988 | #ifndef TCGETS2 |
915 | case TIOCGLCKTRMIOS: | 989 | case TIOCGLCKTRMIOS: |
990 | mutex_lock(&real_tty->termios_mutex); | ||
916 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) | 991 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) |
917 | return -EFAULT; | 992 | ret = -EFAULT; |
918 | return 0; | 993 | mutex_unlock(&real_tty->termios_mutex); |
994 | return ret; | ||
919 | case TIOCSLCKTRMIOS: | 995 | case TIOCSLCKTRMIOS: |
920 | if (!capable(CAP_SYS_ADMIN)) | 996 | if (!capable(CAP_SYS_ADMIN)) |
921 | return -EPERM; | 997 | return -EPERM; |
998 | mutex_lock(&real_tty->termios_mutex); | ||
922 | if (user_termios_to_kernel_termios(real_tty->termios_locked, | 999 | if (user_termios_to_kernel_termios(real_tty->termios_locked, |
923 | (struct termios __user *) arg)) | 1000 | (struct termios __user *) arg)) |
924 | return -EFAULT; | 1001 | ret = -EFAULT; |
925 | return 0; | 1002 | mutex_unlock(&real_tty->termios_mutex); |
1003 | return ret; | ||
926 | #else | 1004 | #else |
927 | case TIOCGLCKTRMIOS: | 1005 | case TIOCGLCKTRMIOS: |
1006 | mutex_lock(&real_tty->termios_mutex); | ||
928 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) | 1007 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) |
929 | return -EFAULT; | 1008 | ret = -EFAULT; |
930 | return 0; | 1009 | mutex_unlock(&real_tty->termios_mutex); |
1010 | return ret; | ||
931 | case TIOCSLCKTRMIOS: | 1011 | case TIOCSLCKTRMIOS: |
932 | if (!capable(CAP_SYS_ADMIN)) | 1012 | if (!capable(CAP_SYS_ADMIN)) |
933 | return -EPERM; | 1013 | ret = -EPERM; |
1014 | mutex_lock(&real_tty->termios_mutex); | ||
934 | if (user_termios_to_kernel_termios_1(real_tty->termios_locked, | 1015 | if (user_termios_to_kernel_termios_1(real_tty->termios_locked, |
935 | (struct termios __user *) arg)) | 1016 | (struct termios __user *) arg)) |
936 | return -EFAULT; | 1017 | ret = -EFAULT; |
937 | return 0; | 1018 | mutex_unlock(&real_tty->termios_mutex); |
1019 | return ret; | ||
938 | #endif | 1020 | #endif |
1021 | #ifdef TCGETX | ||
1022 | case TCGETX: | ||
1023 | if (real_tty->termiox == NULL) | ||
1024 | return -EINVAL; | ||
1025 | mutex_lock(&real_tty->termios_mutex); | ||
1026 | if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox))) | ||
1027 | ret = -EFAULT; | ||
1028 | mutex_unlock(&real_tty->termios_mutex); | ||
1029 | return ret; | ||
1030 | case TCSETX: | ||
1031 | return set_termiox(real_tty, p, 0); | ||
1032 | case TCSETXW: | ||
1033 | return set_termiox(real_tty, p, TERMIOS_WAIT); | ||
1034 | case TCSETXF: | ||
1035 | return set_termiox(real_tty, p, TERMIOS_FLUSH); | ||
1036 | #endif | ||
939 | case TIOCGSOFTCAR: | 1037 | case TIOCGSOFTCAR: |
940 | /* FIXME: for correctness we may need to take the termios | 1038 | mutex_lock(&real_tty->termios_mutex); |
941 | lock here - review */ | 1039 | ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, |
942 | return put_user(C_CLOCAL(real_tty) ? 1 : 0, | ||
943 | (int __user *)arg); | 1040 | (int __user *)arg); |
1041 | mutex_unlock(&real_tty->termios_mutex); | ||
1042 | return ret; | ||
944 | case TIOCSSOFTCAR: | 1043 | case TIOCSSOFTCAR: |
945 | if (get_user(arg, (unsigned int __user *) arg)) | 1044 | if (get_user(arg, (unsigned int __user *) arg)) |
946 | return -EFAULT; | 1045 | return -EFAULT; |
@@ -980,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) | |||
980 | } | 1079 | } |
981 | EXPORT_SYMBOL_GPL(tty_perform_flush); | 1080 | EXPORT_SYMBOL_GPL(tty_perform_flush); |
982 | 1081 | ||
983 | int n_tty_ioctl(struct tty_struct *tty, struct file *file, | 1082 | int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, |
984 | unsigned int cmd, unsigned long arg) | 1083 | unsigned int cmd, unsigned long arg) |
985 | { | 1084 | { |
986 | unsigned long flags; | 1085 | unsigned long flags; |
@@ -1018,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
1018 | return 0; | 1117 | return 0; |
1019 | case TCFLSH: | 1118 | case TCFLSH: |
1020 | return tty_perform_flush(tty, arg); | 1119 | return tty_perform_flush(tty, arg); |
1021 | case TIOCOUTQ: | ||
1022 | return put_user(tty_chars_in_buffer(tty), (int __user *) arg); | ||
1023 | case TIOCINQ: | ||
1024 | retval = tty->read_cnt; | ||
1025 | if (L_ICANON(tty)) | ||
1026 | retval = inq_canon(tty); | ||
1027 | return put_user(retval, (unsigned int __user *) arg); | ||
1028 | case TIOCPKT: | 1120 | case TIOCPKT: |
1029 | { | 1121 | { |
1030 | int pktmode; | 1122 | int pktmode; |
@@ -1050,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
1050 | return tty_mode_ioctl(tty, file, cmd, arg); | 1142 | return tty_mode_ioctl(tty, file, cmd, arg); |
1051 | } | 1143 | } |
1052 | } | 1144 | } |
1053 | EXPORT_SYMBOL(n_tty_ioctl); | 1145 | EXPORT_SYMBOL(n_tty_ioctl_helper); |