aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorAlan Cox <alan@redhat.com>2008-10-13 05:44:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-13 12:51:44 -0400
commit47afa7a5a8a8fb9e60cdb6a3bd612e07c37e9d90 (patch)
tree4f07d3aed0a08516162e529df75a014bd0798f8f /drivers/char
parentfe6e29fdb1a7b94891bbdd3c67358fe4ed14639d (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>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/n_hdlc.c2
-rw-r--r--drivers/char/n_tty.c53
-rw-r--r--drivers/char/tty_ioctl.c42
3 files changed, 54 insertions, 43 deletions
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
1012static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) 1012static 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
1588static 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
1607static 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
1576struct tty_ldisc_ops tty_ldisc_N_TTY = { 1625struct 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
490static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) 490static 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
680static 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}
1111EXPORT_SYMBOL_GPL(tty_perform_flush); 1080EXPORT_SYMBOL_GPL(tty_perform_flush);
1112 1081
1113int n_tty_ioctl(struct tty_struct *tty, struct file *file, 1082int 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}
1183EXPORT_SYMBOL(n_tty_ioctl); 1145EXPORT_SYMBOL(n_tty_ioctl_helper);