diff options
author | Alan Cox <alan@redhat.com> | 2008-10-13 05:44:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-13 12:51:44 -0400 |
commit | 47afa7a5a8a8fb9e60cdb6a3bd612e07c37e9d90 (patch) | |
tree | 4f07d3aed0a08516162e529df75a014bd0798f8f | |
parent | fe6e29fdb1a7b94891bbdd3c67358fe4ed14639d (diff) |
tty: some ICANON magic is in the wrong places
Move the set up on ldisc change into the ldisc
Move the INQ/OUTQ cases into the driver not in shared ioctl code where it
gives bogus answers for other ldisc values
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 2 | ||||
-rw-r--r-- | drivers/char/n_hdlc.c | 2 | ||||
-rw-r--r-- | drivers/char/n_tty.c | 53 | ||||
-rw-r--r-- | drivers/char/tty_ioctl.c | 42 | ||||
-rw-r--r-- | include/linux/tty.h | 2 |
5 files changed, 56 insertions, 45 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 8dfcf77cb717..4426bb552bd9 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c | |||
@@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, | |||
484 | return -EUNATCH; | 484 | return -EUNATCH; |
485 | 485 | ||
486 | default: | 486 | default: |
487 | err = n_tty_ioctl(tty, file, cmd, arg); | 487 | err = n_tty_ioctl_helper(tty, file, cmd, arg); |
488 | break; | 488 | break; |
489 | }; | 489 | }; |
490 | 490 | ||
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 69ec6399c714..bacb3e2872ae 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c | |||
@@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
764 | break; | 764 | break; |
765 | 765 | ||
766 | default: | 766 | default: |
767 | error = n_tty_ioctl (tty, file, cmd, arg); | 767 | error = n_tty_ioctl_helper(tty, file, cmd, arg); |
768 | break; | 768 | break; |
769 | } | 769 | } |
770 | return error; | 770 | return error; |
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 708c2b1dbe51..b4f5dccad2a6 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c | |||
@@ -1011,8 +1011,20 @@ int is_ignored(int sig) | |||
1011 | 1011 | ||
1012 | static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) | 1012 | static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) |
1013 | { | 1013 | { |
1014 | if (!tty) | 1014 | int canon_change = 1; |
1015 | return; | 1015 | BUG_ON(!tty); |
1016 | |||
1017 | if (old) | ||
1018 | canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON; | ||
1019 | if (canon_change) { | ||
1020 | memset(&tty->read_flags, 0, sizeof tty->read_flags); | ||
1021 | tty->canon_head = tty->read_tail; | ||
1022 | tty->canon_data = 0; | ||
1023 | tty->erasing = 0; | ||
1024 | } | ||
1025 | |||
1026 | if (canon_change && !L_ICANON(tty) && tty->read_cnt) | ||
1027 | wake_up_interruptible(&tty->read_wait); | ||
1016 | 1028 | ||
1017 | tty->icanon = (L_ICANON(tty) != 0); | 1029 | tty->icanon = (L_ICANON(tty) != 0); |
1018 | if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { | 1030 | if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { |
@@ -1573,6 +1585,43 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file, | |||
1573 | return mask; | 1585 | return mask; |
1574 | } | 1586 | } |
1575 | 1587 | ||
1588 | static unsigned long inq_canon(struct tty_struct *tty) | ||
1589 | { | ||
1590 | int nr, head, tail; | ||
1591 | |||
1592 | if (!tty->canon_data || !tty->read_buf) | ||
1593 | return 0; | ||
1594 | head = tty->canon_head; | ||
1595 | tail = tty->read_tail; | ||
1596 | nr = (head - tail) & (N_TTY_BUF_SIZE-1); | ||
1597 | /* Skip EOF-chars.. */ | ||
1598 | while (head != tail) { | ||
1599 | if (test_bit(tail, tty->read_flags) && | ||
1600 | tty->read_buf[tail] == __DISABLED_CHAR) | ||
1601 | nr--; | ||
1602 | tail = (tail+1) & (N_TTY_BUF_SIZE-1); | ||
1603 | } | ||
1604 | return nr; | ||
1605 | } | ||
1606 | |||
1607 | static int n_tty_ioctl(struct tty_struct *tty, struct file *file, | ||
1608 | unsigned int cmd, unsigned long arg) | ||
1609 | { | ||
1610 | int retval; | ||
1611 | |||
1612 | switch (cmd) { | ||
1613 | case TIOCOUTQ: | ||
1614 | return put_user(tty_chars_in_buffer(tty), (int __user *) arg); | ||
1615 | case TIOCINQ: | ||
1616 | retval = tty->read_cnt; | ||
1617 | if (L_ICANON(tty)) | ||
1618 | retval = inq_canon(tty); | ||
1619 | return put_user(retval, (unsigned int __user *) arg); | ||
1620 | default: | ||
1621 | return n_tty_ioctl_helper(tty, file, cmd, arg); | ||
1622 | } | ||
1623 | } | ||
1624 | |||
1576 | struct tty_ldisc_ops tty_ldisc_N_TTY = { | 1625 | struct tty_ldisc_ops tty_ldisc_N_TTY = { |
1577 | .magic = TTY_LDISC_MAGIC, | 1626 | .magic = TTY_LDISC_MAGIC, |
1578 | .name = "n_tty", | 1627 | .name = "n_tty", |
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 14cc19c344cc..a408c8e487ec 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -489,7 +489,6 @@ EXPORT_SYMBOL(tty_termios_hw_change); | |||
489 | 489 | ||
490 | 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) |
491 | { | 491 | { |
492 | int canon_change; | ||
493 | struct ktermios old_termios; | 492 | struct ktermios old_termios; |
494 | struct tty_ldisc *ld; | 493 | struct tty_ldisc *ld; |
495 | unsigned long flags; | 494 | unsigned long flags; |
@@ -505,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
505 | old_termios = *tty->termios; | 504 | old_termios = *tty->termios; |
506 | *tty->termios = *new_termios; | 505 | *tty->termios = *new_termios; |
507 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); | 506 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); |
508 | canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; | ||
509 | if (canon_change) { | ||
510 | memset(&tty->read_flags, 0, sizeof tty->read_flags); | ||
511 | tty->canon_head = tty->read_tail; | ||
512 | tty->canon_data = 0; | ||
513 | tty->erasing = 0; | ||
514 | } | ||
515 | |||
516 | /* This bit should be in the ldisc code */ | ||
517 | if (canon_change && !L_ICANON(tty) && tty->read_cnt) | ||
518 | /* Get characters left over from canonical mode. */ | ||
519 | wake_up_interruptible(&tty->read_wait); | ||
520 | 507 | ||
521 | /* See if packet mode change of state. */ | 508 | /* See if packet mode change of state. */ |
522 | if (tty->link && tty->link->packet) { | 509 | if (tty->link && tty->link->packet) { |
@@ -677,24 +664,6 @@ static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) | |||
677 | 664 | ||
678 | #endif | 665 | #endif |
679 | 666 | ||
680 | static unsigned long inq_canon(struct tty_struct *tty) | ||
681 | { | ||
682 | int nr, head, tail; | ||
683 | |||
684 | if (!tty->canon_data || !tty->read_buf) | ||
685 | return 0; | ||
686 | head = tty->canon_head; | ||
687 | tail = tty->read_tail; | ||
688 | nr = (head - tail) & (N_TTY_BUF_SIZE-1); | ||
689 | /* Skip EOF-chars.. */ | ||
690 | while (head != tail) { | ||
691 | if (test_bit(tail, tty->read_flags) && | ||
692 | tty->read_buf[tail] == __DISABLED_CHAR) | ||
693 | nr--; | ||
694 | tail = (tail+1) & (N_TTY_BUF_SIZE-1); | ||
695 | } | ||
696 | return nr; | ||
697 | } | ||
698 | 667 | ||
699 | #ifdef TIOCGETP | 668 | #ifdef TIOCGETP |
700 | /* | 669 | /* |
@@ -1110,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) | |||
1110 | } | 1079 | } |
1111 | EXPORT_SYMBOL_GPL(tty_perform_flush); | 1080 | EXPORT_SYMBOL_GPL(tty_perform_flush); |
1112 | 1081 | ||
1113 | int n_tty_ioctl(struct tty_struct *tty, struct file *file, | 1082 | int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, |
1114 | unsigned int cmd, unsigned long arg) | 1083 | unsigned int cmd, unsigned long arg) |
1115 | { | 1084 | { |
1116 | unsigned long flags; | 1085 | unsigned long flags; |
@@ -1148,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
1148 | return 0; | 1117 | return 0; |
1149 | case TCFLSH: | 1118 | case TCFLSH: |
1150 | return tty_perform_flush(tty, arg); | 1119 | return tty_perform_flush(tty, arg); |
1151 | case TIOCOUTQ: | ||
1152 | return put_user(tty_chars_in_buffer(tty), (int __user *) arg); | ||
1153 | case TIOCINQ: | ||
1154 | retval = tty->read_cnt; | ||
1155 | if (L_ICANON(tty)) | ||
1156 | retval = inq_canon(tty); | ||
1157 | return put_user(retval, (unsigned int __user *) arg); | ||
1158 | case TIOCPKT: | 1120 | case TIOCPKT: |
1159 | { | 1121 | { |
1160 | int pktmode; | 1122 | int pktmode; |
@@ -1180,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
1180 | return tty_mode_ioctl(tty, file, cmd, arg); | 1142 | return tty_mode_ioctl(tty, file, cmd, arg); |
1181 | } | 1143 | } |
1182 | } | 1144 | } |
1183 | EXPORT_SYMBOL(n_tty_ioctl); | 1145 | EXPORT_SYMBOL(n_tty_ioctl_helper); |
diff --git a/include/linux/tty.h b/include/linux/tty.h index 3c7c75794a4a..3b8121d4e36f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
@@ -466,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk, | |||
466 | #endif | 466 | #endif |
467 | 467 | ||
468 | /* tty_ioctl.c */ | 468 | /* tty_ioctl.c */ |
469 | extern int n_tty_ioctl(struct tty_struct *tty, struct file *file, | 469 | extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, |
470 | unsigned int cmd, unsigned long arg); | 470 | unsigned int cmd, unsigned long arg); |
471 | 471 | ||
472 | /* serial.c */ | 472 | /* serial.c */ |