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;
|
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,
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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);
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
#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)
|
||||||
}
|
}
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
#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 */
|
||||||
|
|
Loading…
Reference in a new issue