Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
	};

+1 −1
Original line number Diff line number Diff line
@@ -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;
+51 −2
Original line number Diff line number Diff line
@@ -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",
+2 −40
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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 */