summaryrefslogtreecommitdiff
path: root/drivers/char/n_tty.c
diff options
context:
space:
mode:
authorAlan Cox <alan@redhat.com>2008-10-13 13:44:17 +0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-13 20:51:44 +0400
commit47afa7a5a8a8fb9e60cdb6a3bd612e07c37e9d90 (patch)
tree4f07d3aed0a08516162e529df75a014bd0798f8f /drivers/char/n_tty.c
parentfe6e29fdb1a7b94891bbdd3c67358fe4ed14639d (diff)
downloadlinux-47afa7a5a8a8fb9e60cdb6a3bd612e07c37e9d90.tar.xz
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)
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- if (!tty)
- return;
+ int canon_change = 1;
+ BUG_ON(!tty);
+
+ if (old)
+ canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+ if (canon_change) {
+ memset(&tty->read_flags, 0, sizeof tty->read_flags);
+ tty->canon_head = tty->read_tail;
+ tty->canon_data = 0;
+ tty->erasing = 0;
+ }
+
+ if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+ wake_up_interruptible(&tty->read_wait);
tty->icanon = (L_ICANON(tty) != 0);
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,
return mask;
}
+static unsigned long inq_canon(struct tty_struct *tty)
+{
+ int nr, head, tail;
+
+ if (!tty->canon_data || !tty->read_buf)
+ return 0;
+ head = tty->canon_head;
+ tail = tty->read_tail;
+ nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+ /* Skip EOF-chars.. */
+ while (head != tail) {
+ if (test_bit(tail, tty->read_flags) &&
+ tty->read_buf[tail] == __DISABLED_CHAR)
+ nr--;
+ tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+ }
+ return nr;
+}
+
+static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int retval;
+
+ switch (cmd) {
+ case TIOCOUTQ:
+ return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
+ case TIOCINQ:
+ retval = tty->read_cnt;
+ if (L_ICANON(tty))
+ retval = inq_canon(tty);
+ return put_user(retval, (unsigned int __user *) arg);
+ default:
+ return n_tty_ioctl_helper(tty, file, cmd, arg);
+ }
+}
+
struct tty_ldisc_ops tty_ldisc_N_TTY = {
.magic = TTY_LDISC_MAGIC,
.name = "n_tty",