Commit 47afa7a5 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

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: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fe6e29fd
...@@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, ...@@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
return -EUNATCH; return -EUNATCH;
default: default:
err = n_tty_ioctl(tty, file, cmd, arg); err = n_tty_ioctl_helper(tty, file, cmd, arg);
break; break;
}; };
......
...@@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, ...@@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
break; break;
default: default:
error = n_tty_ioctl (tty, file, cmd, arg); error = n_tty_ioctl_helper(tty, file, cmd, arg);
break; break;
} }
return error; return error;
......
...@@ -1011,8 +1011,20 @@ int is_ignored(int sig) ...@@ -1011,8 +1011,20 @@ int is_ignored(int sig)
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{ {
if (!tty) int canon_change = 1;
return; 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); tty->icanon = (L_ICANON(tty) != 0);
if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { 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,6 +1585,43 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
return mask; 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 = { struct tty_ldisc_ops tty_ldisc_N_TTY = {
.magic = TTY_LDISC_MAGIC, .magic = TTY_LDISC_MAGIC,
.name = "n_tty", .name = "n_tty",
......
...@@ -489,7 +489,6 @@ EXPORT_SYMBOL(tty_termios_hw_change); ...@@ -489,7 +489,6 @@ EXPORT_SYMBOL(tty_termios_hw_change);
static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
{ {
int canon_change;
struct ktermios old_termios; struct ktermios old_termios;
struct tty_ldisc *ld; struct tty_ldisc *ld;
unsigned long flags; unsigned long flags;
...@@ -505,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) ...@@ -505,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
old_termios = *tty->termios; old_termios = *tty->termios;
*tty->termios = *new_termios; *tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); 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. */ /* See if packet mode change of state. */
if (tty->link && tty->link->packet) { if (tty->link && tty->link->packet) {
...@@ -677,24 +664,6 @@ static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) ...@@ -677,24 +664,6 @@ static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
#endif #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 #ifdef TIOCGETP
/* /*
...@@ -1110,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) ...@@ -1110,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
} }
EXPORT_SYMBOL_GPL(tty_perform_flush); 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 int cmd, unsigned long arg)
{ {
unsigned long flags; unsigned long flags;
...@@ -1148,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, ...@@ -1148,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return 0; return 0;
case TCFLSH: case TCFLSH:
return tty_perform_flush(tty, arg); 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: case TIOCPKT:
{ {
int pktmode; int pktmode;
...@@ -1180,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, ...@@ -1180,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return tty_mode_ioctl(tty, file, cmd, arg); return tty_mode_ioctl(tty, file, cmd, arg);
} }
} }
EXPORT_SYMBOL(n_tty_ioctl); EXPORT_SYMBOL(n_tty_ioctl_helper);
...@@ -466,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk, ...@@ -466,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk,
#endif #endif
/* tty_ioctl.c */ /* 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); unsigned int cmd, unsigned long arg);
/* serial.c */ /* serial.c */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment