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>
This commit is contained in:
parent
fe6e29fdb1
commit
47afa7a5a8
5 changed files with 56 additions and 45 deletions
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue