aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/n_tty.c
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/n_tty.c
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/n_tty.c')
-rw-r--r--drivers/char/n_tty.c53
1 files changed, 51 insertions, 2 deletions
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",