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 /drivers/char/n_tty.c | |
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>
Diffstat (limited to 'drivers/char/n_tty.c')
-rw-r--r-- | drivers/char/n_tty.c | 53 |
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 | ||
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", |