Skip to content

Commit

Permalink
tty: some ICANON magic is in the wrong places
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alan Cox authored and Linus Torvalds committed Oct 13, 2008
1 parent fe6e29f commit 47afa7a
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 45 deletions.
2 changes: 1 addition & 1 deletion drivers/bluetooth/hci_ldisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
return -EUNATCH;

default:
err = n_tty_ioctl(tty, file, cmd, arg);
err = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/char/n_hdlc.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
break;

default:
error = n_tty_ioctl (tty, file, cmd, arg);
error = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
}
return error;
Expand Down
53 changes: 51 additions & 2 deletions drivers/char/n_tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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",
Expand Down
42 changes: 2 additions & 40 deletions drivers/char/tty_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,6 @@ EXPORT_SYMBOL(tty_termios_hw_change);

static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
int canon_change;
struct ktermios old_termios;
struct tty_ldisc *ld;
unsigned long flags;
Expand All @@ -505,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
old_termios = *tty->termios;
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.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;
}

/* This bit should be in the ldisc code */
if (canon_change && !L_ICANON(tty) && tty->read_cnt)
/* Get characters left over from canonical mode. */
wake_up_interruptible(&tty->read_wait);

/* See if packet mode change of state. */
if (tty->link && tty->link->packet) {
Expand Down Expand Up @@ -677,24 +664,6 @@ static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)

#endif

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;
}

#ifdef TIOCGETP
/*
Expand Down Expand Up @@ -1110,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
}
EXPORT_SYMBOL_GPL(tty_perform_flush);

int n_tty_ioctl(struct tty_struct *tty, struct file *file,
int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned long flags;
Expand Down Expand Up @@ -1148,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return 0;
case TCFLSH:
return tty_perform_flush(tty, arg);
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);
case TIOCPKT:
{
int pktmode;
Expand All @@ -1180,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return tty_mode_ioctl(tty, file, cmd, arg);
}
}
EXPORT_SYMBOL(n_tty_ioctl);
EXPORT_SYMBOL(n_tty_ioctl_helper);
2 changes: 1 addition & 1 deletion include/linux/tty.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk,
#endif

/* tty_ioctl.c */
extern int n_tty_ioctl(struct tty_struct *tty, struct file *file,
extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);

/* serial.c */
Expand Down

0 comments on commit 47afa7a

Please sign in to comment.