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

Commit ba2e68ac authored by Jiri Slaby's avatar Jiri Slaby Committed by Greg Kroah-Hartman
Browse files

TTY: move ldisc data from tty_struct: read_* and echo_* and canon_* stuff



All the ring-buffers...

Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
Acked-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3fe780b3
Loading
Loading
Loading
Loading
+137 −123
Original line number Original line Diff line number Diff line
@@ -83,6 +83,19 @@ struct n_tty_data {


	DECLARE_BITMAP(process_char_map, 256);
	DECLARE_BITMAP(process_char_map, 256);
	DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
	DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);

	char *read_buf;
	int read_head;
	int read_tail;
	int read_cnt;

	unsigned char *echo_buf;
	unsigned int echo_pos;
	unsigned int echo_cnt;

	int canon_data;
	unsigned long canon_head;
	unsigned int canon_column;
};
};


static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
@@ -110,14 +123,14 @@ static void n_tty_set_room(struct tty_struct *tty)
	int left;
	int left;
	int old_left;
	int old_left;


	/* tty->read_cnt is not read locked ? */
	/* ldata->read_cnt is not read locked ? */
	if (I_PARMRK(tty)) {
	if (I_PARMRK(tty)) {
		/* Multiply read_cnt by 3, since each byte might take up to
		/* Multiply read_cnt by 3, since each byte might take up to
		 * three times as many spaces when PARMRK is set (depending on
		 * three times as many spaces when PARMRK is set (depending on
		 * its flags, e.g. parity error). */
		 * its flags, e.g. parity error). */
		left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
		left = N_TTY_BUF_SIZE - ldata->read_cnt * 3 - 1;
	} else
	} else
		left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
		left = N_TTY_BUF_SIZE - ldata->read_cnt - 1;


	/*
	/*
	 * If we are doing input canonicalization, and there are no
	 * If we are doing input canonicalization, and there are no
@@ -126,7 +139,7 @@ static void n_tty_set_room(struct tty_struct *tty)
	 * characters will be beeped.
	 * characters will be beeped.
	 */
	 */
	if (left <= 0)
	if (left <= 0)
		left = ldata->icanon && !tty->canon_data;
		left = ldata->icanon && !ldata->canon_data;
	old_left = tty->receive_room;
	old_left = tty->receive_room;
	tty->receive_room = left;
	tty->receive_room = left;


@@ -137,10 +150,12 @@ static void n_tty_set_room(struct tty_struct *tty)


static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
{
{
	if (tty->read_cnt < N_TTY_BUF_SIZE) {
	struct n_tty_data *ldata = tty->disc_data;
		tty->read_buf[tty->read_head] = c;

		tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
	if (ldata->read_cnt < N_TTY_BUF_SIZE) {
		tty->read_cnt++;
		ldata->read_buf[ldata->read_head] = c;
		ldata->read_head = (ldata->read_head + 1) & (N_TTY_BUF_SIZE-1);
		ldata->read_cnt++;
	}
	}
}
}


@@ -198,14 +213,14 @@ static void reset_buffer_flags(struct tty_struct *tty)
	unsigned long flags;
	unsigned long flags;


	spin_lock_irqsave(&tty->read_lock, flags);
	spin_lock_irqsave(&tty->read_lock, flags);
	tty->read_head = tty->read_tail = tty->read_cnt = 0;
	ldata->read_head = ldata->read_tail = ldata->read_cnt = 0;
	spin_unlock_irqrestore(&tty->read_lock, flags);
	spin_unlock_irqrestore(&tty->read_lock, flags);


	mutex_lock(&tty->echo_lock);
	mutex_lock(&tty->echo_lock);
	tty->echo_pos = tty->echo_cnt = ldata->echo_overrun = 0;
	ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0;
	mutex_unlock(&tty->echo_lock);
	mutex_unlock(&tty->echo_lock);


	tty->canon_head = tty->canon_data = ldata->erasing = 0;
	ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
	n_tty_set_room(tty);
	n_tty_set_room(tty);
}
}
@@ -257,11 +272,11 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)


	spin_lock_irqsave(&tty->read_lock, flags);
	spin_lock_irqsave(&tty->read_lock, flags);
	if (!ldata->icanon) {
	if (!ldata->icanon) {
		n = tty->read_cnt;
		n = ldata->read_cnt;
	} else if (tty->canon_data) {
	} else if (ldata->canon_data) {
		n = (tty->canon_head > tty->read_tail) ?
		n = (ldata->canon_head > ldata->read_tail) ?
			tty->canon_head - tty->read_tail :
			ldata->canon_head - ldata->read_tail :
			tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
			ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail);
	}
	}
	spin_unlock_irqrestore(&tty->read_lock, flags);
	spin_unlock_irqrestore(&tty->read_lock, flags);
	return n;
	return n;
@@ -331,11 +346,11 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
		if (O_ONLCR(tty)) {
		if (O_ONLCR(tty)) {
			if (space < 2)
			if (space < 2)
				return -1;
				return -1;
			tty->canon_column = ldata->column = 0;
			ldata->canon_column = ldata->column = 0;
			tty->ops->write(tty, "\r\n", 2);
			tty->ops->write(tty, "\r\n", 2);
			return 2;
			return 2;
		}
		}
		tty->canon_column = ldata->column;
		ldata->canon_column = ldata->column;
		break;
		break;
	case '\r':
	case '\r':
		if (O_ONOCR(tty) && ldata->column == 0)
		if (O_ONOCR(tty) && ldata->column == 0)
@@ -343,10 +358,10 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
		if (O_OCRNL(tty)) {
		if (O_OCRNL(tty)) {
			c = '\n';
			c = '\n';
			if (O_ONLRET(tty))
			if (O_ONLRET(tty))
				tty->canon_column = ldata->column = 0;
				ldata->canon_column = ldata->column = 0;
			break;
			break;
		}
		}
		tty->canon_column = ldata->column = 0;
		ldata->canon_column = ldata->column = 0;
		break;
		break;
	case '\t':
	case '\t':
		spaces = 8 - (ldata->column & 7);
		spaces = 8 - (ldata->column & 7);
@@ -453,14 +468,14 @@ static ssize_t process_output_block(struct tty_struct *tty,
				ldata->column = 0;
				ldata->column = 0;
			if (O_ONLCR(tty))
			if (O_ONLCR(tty))
				goto break_out;
				goto break_out;
			tty->canon_column = ldata->column;
			ldata->canon_column = ldata->column;
			break;
			break;
		case '\r':
		case '\r':
			if (O_ONOCR(tty) && ldata->column == 0)
			if (O_ONOCR(tty) && ldata->column == 0)
				goto break_out;
				goto break_out;
			if (O_OCRNL(tty))
			if (O_OCRNL(tty))
				goto break_out;
				goto break_out;
			tty->canon_column = ldata->column = 0;
			ldata->canon_column = ldata->column = 0;
			break;
			break;
		case '\t':
		case '\t':
			goto break_out;
			goto break_out;
@@ -518,7 +533,7 @@ static void process_echoes(struct tty_struct *tty)
	unsigned char c;
	unsigned char c;
	unsigned char *cp, *buf_end;
	unsigned char *cp, *buf_end;


	if (!tty->echo_cnt)
	if (!ldata->echo_cnt)
		return;
		return;


	mutex_lock(&tty->output_lock);
	mutex_lock(&tty->output_lock);
@@ -526,9 +541,9 @@ static void process_echoes(struct tty_struct *tty)


	space = tty_write_room(tty);
	space = tty_write_room(tty);


	buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
	buf_end = ldata->echo_buf + N_TTY_BUF_SIZE;
	cp = tty->echo_buf + tty->echo_pos;
	cp = ldata->echo_buf + ldata->echo_pos;
	nr = tty->echo_cnt;
	nr = ldata->echo_cnt;
	while (nr > 0) {
	while (nr > 0) {
		c = *cp;
		c = *cp;
		if (c == ECHO_OP_START) {
		if (c == ECHO_OP_START) {
@@ -565,7 +580,7 @@ static void process_echoes(struct tty_struct *tty)
				 * Otherwise, tab spacing is normal.
				 * Otherwise, tab spacing is normal.
				 */
				 */
				if (!(num_chars & 0x80))
				if (!(num_chars & 0x80))
					num_chars += tty->canon_column;
					num_chars += ldata->canon_column;
				num_bs = 8 - (num_chars & 7);
				num_bs = 8 - (num_chars & 7);


				if (num_bs > space) {
				if (num_bs > space) {
@@ -583,7 +598,7 @@ static void process_echoes(struct tty_struct *tty)
				break;
				break;


			case ECHO_OP_SET_CANON_COL:
			case ECHO_OP_SET_CANON_COL:
				tty->canon_column = ldata->column;
				ldata->canon_column = ldata->column;
				cp += 2;
				cp += 2;
				nr -= 2;
				nr -= 2;
				break;
				break;
@@ -655,14 +670,14 @@ static void process_echoes(struct tty_struct *tty)
	}
	}


	if (nr == 0) {
	if (nr == 0) {
		tty->echo_pos = 0;
		ldata->echo_pos = 0;
		tty->echo_cnt = 0;
		ldata->echo_cnt = 0;
		ldata->echo_overrun = 0;
		ldata->echo_overrun = 0;
	} else {
	} else {
		int num_processed = tty->echo_cnt - nr;
		int num_processed = ldata->echo_cnt - nr;
		tty->echo_pos += num_processed;
		ldata->echo_pos += num_processed;
		tty->echo_pos &= N_TTY_BUF_SIZE - 1;
		ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
		tty->echo_cnt = nr;
		ldata->echo_cnt = nr;
		if (num_processed > 0)
		if (num_processed > 0)
			ldata->echo_overrun = 0;
			ldata->echo_overrun = 0;
	}
	}
@@ -689,37 +704,37 @@ static void add_echo_byte(unsigned char c, struct tty_struct *tty)
	struct n_tty_data *ldata = tty->disc_data;
	struct n_tty_data *ldata = tty->disc_data;
	int	new_byte_pos;
	int	new_byte_pos;


	if (tty->echo_cnt == N_TTY_BUF_SIZE) {
	if (ldata->echo_cnt == N_TTY_BUF_SIZE) {
		/* Circular buffer is already at capacity */
		/* Circular buffer is already at capacity */
		new_byte_pos = tty->echo_pos;
		new_byte_pos = ldata->echo_pos;


		/*
		/*
		 * Since the buffer start position needs to be advanced,
		 * Since the buffer start position needs to be advanced,
		 * be sure to step by a whole operation byte group.
		 * be sure to step by a whole operation byte group.
		 */
		 */
		if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
		if (ldata->echo_buf[ldata->echo_pos] == ECHO_OP_START) {
			if (tty->echo_buf[(tty->echo_pos + 1) &
			if (ldata->echo_buf[(ldata->echo_pos + 1) &
					  (N_TTY_BUF_SIZE - 1)] ==
					  (N_TTY_BUF_SIZE - 1)] ==
						ECHO_OP_ERASE_TAB) {
						ECHO_OP_ERASE_TAB) {
				tty->echo_pos += 3;
				ldata->echo_pos += 3;
				tty->echo_cnt -= 2;
				ldata->echo_cnt -= 2;
			} else {
			} else {
				tty->echo_pos += 2;
				ldata->echo_pos += 2;
				tty->echo_cnt -= 1;
				ldata->echo_cnt -= 1;
			}
			}
		} else {
		} else {
			tty->echo_pos++;
			ldata->echo_pos++;
		}
		}
		tty->echo_pos &= N_TTY_BUF_SIZE - 1;
		ldata->echo_pos &= N_TTY_BUF_SIZE - 1;


		ldata->echo_overrun = 1;
		ldata->echo_overrun = 1;
	} else {
	} else {
		new_byte_pos = tty->echo_pos + tty->echo_cnt;
		new_byte_pos = ldata->echo_pos + ldata->echo_cnt;
		new_byte_pos &= N_TTY_BUF_SIZE - 1;
		new_byte_pos &= N_TTY_BUF_SIZE - 1;
		tty->echo_cnt++;
		ldata->echo_cnt++;
	}
	}


	tty->echo_buf[new_byte_pos] = c;
	ldata->echo_buf[new_byte_pos] = c;
}
}


/**
/**
@@ -889,7 +904,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
	unsigned long flags;
	unsigned long flags;


	/* FIXME: locking needed ? */
	/* FIXME: locking needed ? */
	if (tty->read_head == tty->canon_head) {
	if (ldata->read_head == ldata->canon_head) {
		/* process_output('\a', tty); */ /* what do you think? */
		/* process_output('\a', tty); */ /* what do you think? */
		return;
		return;
	}
	}
@@ -900,17 +915,17 @@ static void eraser(unsigned char c, struct tty_struct *tty)
	else {
	else {
		if (!L_ECHO(tty)) {
		if (!L_ECHO(tty)) {
			spin_lock_irqsave(&tty->read_lock, flags);
			spin_lock_irqsave(&tty->read_lock, flags);
			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
			ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
					  (N_TTY_BUF_SIZE - 1));
					  (N_TTY_BUF_SIZE - 1));
			tty->read_head = tty->canon_head;
			ldata->read_head = ldata->canon_head;
			spin_unlock_irqrestore(&tty->read_lock, flags);
			spin_unlock_irqrestore(&tty->read_lock, flags);
			return;
			return;
		}
		}
		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
			spin_lock_irqsave(&tty->read_lock, flags);
			spin_lock_irqsave(&tty->read_lock, flags);
			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
			ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
					  (N_TTY_BUF_SIZE - 1));
					  (N_TTY_BUF_SIZE - 1));
			tty->read_head = tty->canon_head;
			ldata->read_head = ldata->canon_head;
			spin_unlock_irqrestore(&tty->read_lock, flags);
			spin_unlock_irqrestore(&tty->read_lock, flags);
			finish_erasing(tty);
			finish_erasing(tty);
			echo_char(KILL_CHAR(tty), tty);
			echo_char(KILL_CHAR(tty), tty);
@@ -924,14 +939,14 @@ static void eraser(unsigned char c, struct tty_struct *tty)


	seen_alnums = 0;
	seen_alnums = 0;
	/* FIXME: Locking ?? */
	/* FIXME: Locking ?? */
	while (tty->read_head != tty->canon_head) {
	while (ldata->read_head != ldata->canon_head) {
		head = tty->read_head;
		head = ldata->read_head;


		/* erase a single possibly multibyte character */
		/* erase a single possibly multibyte character */
		do {
		do {
			head = (head - 1) & (N_TTY_BUF_SIZE-1);
			head = (head - 1) & (N_TTY_BUF_SIZE-1);
			c = tty->read_buf[head];
			c = ldata->read_buf[head];
		} while (is_continuation(c, tty) && head != tty->canon_head);
		} while (is_continuation(c, tty) && head != ldata->canon_head);


		/* do not partially erase */
		/* do not partially erase */
		if (is_continuation(c, tty))
		if (is_continuation(c, tty))
@@ -944,10 +959,10 @@ static void eraser(unsigned char c, struct tty_struct *tty)
			else if (seen_alnums)
			else if (seen_alnums)
				break;
				break;
		}
		}
		cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
		cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1);
		spin_lock_irqsave(&tty->read_lock, flags);
		spin_lock_irqsave(&tty->read_lock, flags);
		tty->read_head = head;
		ldata->read_head = head;
		tty->read_cnt -= cnt;
		ldata->read_cnt -= cnt;
		spin_unlock_irqrestore(&tty->read_lock, flags);
		spin_unlock_irqrestore(&tty->read_lock, flags);
		if (L_ECHO(tty)) {
		if (L_ECHO(tty)) {
			if (L_ECHOPRT(tty)) {
			if (L_ECHOPRT(tty)) {
@@ -959,7 +974,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
				echo_char(c, tty);
				echo_char(c, tty);
				while (--cnt > 0) {
				while (--cnt > 0) {
					head = (head+1) & (N_TTY_BUF_SIZE-1);
					head = (head+1) & (N_TTY_BUF_SIZE-1);
					echo_char_raw(tty->read_buf[head], tty);
					echo_char_raw(ldata->read_buf[head], tty);
					echo_move_back_col(tty);
					echo_move_back_col(tty);
				}
				}
			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
@@ -967,7 +982,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
			} else if (c == '\t') {
			} else if (c == '\t') {
				unsigned int num_chars = 0;
				unsigned int num_chars = 0;
				int after_tab = 0;
				int after_tab = 0;
				unsigned long tail = tty->read_head;
				unsigned long tail = ldata->read_head;


				/*
				/*
				 * Count the columns used for characters
				 * Count the columns used for characters
@@ -976,9 +991,9 @@ static void eraser(unsigned char c, struct tty_struct *tty)
				 * This info is used to go back the correct
				 * This info is used to go back the correct
				 * number of columns.
				 * number of columns.
				 */
				 */
				while (tail != tty->canon_head) {
				while (tail != ldata->canon_head) {
					tail = (tail-1) & (N_TTY_BUF_SIZE-1);
					tail = (tail-1) & (N_TTY_BUF_SIZE-1);
					c = tty->read_buf[tail];
					c = ldata->read_buf[tail];
					if (c == '\t') {
					if (c == '\t') {
						after_tab = 1;
						after_tab = 1;
						break;
						break;
@@ -1006,7 +1021,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
		if (kill_type == ERASE)
		if (kill_type == ERASE)
			break;
			break;
	}
	}
	if (tty->read_head == tty->canon_head && L_ECHO(tty))
	if (ldata->read_head == ldata->canon_head && L_ECHO(tty))
		finish_erasing(tty);
		finish_erasing(tty);
}
}


@@ -1171,7 +1186,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
	if (!test_bit(c, ldata->process_char_map) || ldata->lnext) {
	if (!test_bit(c, ldata->process_char_map) || ldata->lnext) {
		ldata->lnext = 0;
		ldata->lnext = 0;
		parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
		parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
		if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
		if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
			/* beep if no space */
			/* beep if no space */
			if (L_ECHO(tty))
			if (L_ECHO(tty))
				process_output('\a', tty);
				process_output('\a', tty);
@@ -1180,7 +1195,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
		if (L_ECHO(tty)) {
		if (L_ECHO(tty)) {
			finish_erasing(tty);
			finish_erasing(tty);
			/* Record the column of first canon char. */
			/* Record the column of first canon char. */
			if (tty->canon_head == tty->read_head)
			if (ldata->canon_head == ldata->read_head)
				echo_set_canon_col(tty);
				echo_set_canon_col(tty);
			echo_char(c, tty);
			echo_char(c, tty);
			process_echoes(tty);
			process_echoes(tty);
@@ -1264,20 +1279,20 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
		}
		}
		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
		    L_IEXTEN(tty)) {
		    L_IEXTEN(tty)) {
			unsigned long tail = tty->canon_head;
			unsigned long tail = ldata->canon_head;


			finish_erasing(tty);
			finish_erasing(tty);
			echo_char(c, tty);
			echo_char(c, tty);
			echo_char_raw('\n', tty);
			echo_char_raw('\n', tty);
			while (tail != tty->read_head) {
			while (tail != ldata->read_head) {
				echo_char(tty->read_buf[tail], tty);
				echo_char(ldata->read_buf[tail], tty);
				tail = (tail+1) & (N_TTY_BUF_SIZE-1);
				tail = (tail+1) & (N_TTY_BUF_SIZE-1);
			}
			}
			process_echoes(tty);
			process_echoes(tty);
			return;
			return;
		}
		}
		if (c == '\n') {
		if (c == '\n') {
			if (tty->read_cnt >= N_TTY_BUF_SIZE) {
			if (ldata->read_cnt >= N_TTY_BUF_SIZE) {
				if (L_ECHO(tty))
				if (L_ECHO(tty))
					process_output('\a', tty);
					process_output('\a', tty);
				return;
				return;
@@ -1289,9 +1304,9 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
			goto handle_newline;
			goto handle_newline;
		}
		}
		if (c == EOF_CHAR(tty)) {
		if (c == EOF_CHAR(tty)) {
			if (tty->read_cnt >= N_TTY_BUF_SIZE)
			if (ldata->read_cnt >= N_TTY_BUF_SIZE)
				return;
				return;
			if (tty->canon_head != tty->read_head)
			if (ldata->canon_head != ldata->read_head)
				set_bit(TTY_PUSH, &tty->flags);
				set_bit(TTY_PUSH, &tty->flags);
			c = __DISABLED_CHAR;
			c = __DISABLED_CHAR;
			goto handle_newline;
			goto handle_newline;
@@ -1300,7 +1315,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
			parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
			parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
				 ? 1 : 0;
				 ? 1 : 0;
			if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
			if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
				if (L_ECHO(tty))
				if (L_ECHO(tty))
					process_output('\a', tty);
					process_output('\a', tty);
				return;
				return;
@@ -1310,7 +1325,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
			 */
			 */
			if (L_ECHO(tty)) {
			if (L_ECHO(tty)) {
				/* Record the column of first canon char. */
				/* Record the column of first canon char. */
				if (tty->canon_head == tty->read_head)
				if (ldata->canon_head == ldata->read_head)
					echo_set_canon_col(tty);
					echo_set_canon_col(tty);
				echo_char(c, tty);
				echo_char(c, tty);
				process_echoes(tty);
				process_echoes(tty);
@@ -1324,10 +1339,10 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)


handle_newline:
handle_newline:
			spin_lock_irqsave(&tty->read_lock, flags);
			spin_lock_irqsave(&tty->read_lock, flags);
			set_bit(tty->read_head, ldata->read_flags);
			set_bit(ldata->read_head, ldata->read_flags);
			put_tty_queue_nolock(c, tty);
			put_tty_queue_nolock(c, tty);
			tty->canon_head = tty->read_head;
			ldata->canon_head = ldata->read_head;
			tty->canon_data++;
			ldata->canon_data++;
			spin_unlock_irqrestore(&tty->read_lock, flags);
			spin_unlock_irqrestore(&tty->read_lock, flags);
			kill_fasync(&tty->fasync, SIGIO, POLL_IN);
			kill_fasync(&tty->fasync, SIGIO, POLL_IN);
			if (waitqueue_active(&tty->read_wait))
			if (waitqueue_active(&tty->read_wait))
@@ -1337,7 +1352,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
	}
	}


	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
	if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
	if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
		/* beep if no space */
		/* beep if no space */
		if (L_ECHO(tty))
		if (L_ECHO(tty))
			process_output('\a', tty);
			process_output('\a', tty);
@@ -1349,7 +1364,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
			echo_char_raw('\n', tty);
			echo_char_raw('\n', tty);
		else {
		else {
			/* Record the column of first canon char. */
			/* Record the column of first canon char. */
			if (tty->canon_head == tty->read_head)
			if (ldata->canon_head == ldata->read_head)
				echo_set_canon_col(tty);
				echo_set_canon_col(tty);
			echo_char(c, tty);
			echo_char(c, tty);
		}
		}
@@ -1403,21 +1418,21 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,


	if (ldata->real_raw) {
	if (ldata->real_raw) {
		spin_lock_irqsave(&tty->read_lock, cpuflags);
		spin_lock_irqsave(&tty->read_lock, cpuflags);
		i = min(N_TTY_BUF_SIZE - tty->read_cnt,
		i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
			N_TTY_BUF_SIZE - tty->read_head);
			N_TTY_BUF_SIZE - ldata->read_head);
		i = min(count, i);
		i = min(count, i);
		memcpy(tty->read_buf + tty->read_head, cp, i);
		memcpy(ldata->read_buf + ldata->read_head, cp, i);
		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
		ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
		tty->read_cnt += i;
		ldata->read_cnt += i;
		cp += i;
		cp += i;
		count -= i;
		count -= i;


		i = min(N_TTY_BUF_SIZE - tty->read_cnt,
		i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
			N_TTY_BUF_SIZE - tty->read_head);
			N_TTY_BUF_SIZE - ldata->read_head);
		i = min(count, i);
		i = min(count, i);
		memcpy(tty->read_buf + tty->read_head, cp, i);
		memcpy(ldata->read_buf + ldata->read_head, cp, i);
		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
		ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
		tty->read_cnt += i;
		ldata->read_cnt += i;
		spin_unlock_irqrestore(&tty->read_lock, cpuflags);
		spin_unlock_irqrestore(&tty->read_lock, cpuflags);
	} else {
	} else {
		for (i = count, p = cp, f = fp; i; i--, p++) {
		for (i = count, p = cp, f = fp; i; i--, p++) {
@@ -1449,7 +1464,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,


	n_tty_set_room(tty);
	n_tty_set_room(tty);


	if ((!ldata->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
	if ((!ldata->icanon && (ldata->read_cnt >= tty->minimum_to_wake)) ||
		L_EXTPROC(tty)) {
		L_EXTPROC(tty)) {
		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
		if (waitqueue_active(&tty->read_wait))
		if (waitqueue_active(&tty->read_wait))
@@ -1500,12 +1515,12 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
		canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
		canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
	if (canon_change) {
	if (canon_change) {
		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
		tty->canon_head = tty->read_tail;
		ldata->canon_head = ldata->read_tail;
		tty->canon_data = 0;
		ldata->canon_data = 0;
		ldata->erasing = 0;
		ldata->erasing = 0;
	}
	}


	if (canon_change && !L_ICANON(tty) && tty->read_cnt)
	if (canon_change && !L_ICANON(tty) && ldata->read_cnt)
		wake_up_interruptible(&tty->read_wait);
		wake_up_interruptible(&tty->read_wait);


	ldata->icanon = (L_ICANON(tty) != 0);
	ldata->icanon = (L_ICANON(tty) != 0);
@@ -1586,11 +1601,9 @@ static void n_tty_close(struct tty_struct *tty)
	struct n_tty_data *ldata = tty->disc_data;
	struct n_tty_data *ldata = tty->disc_data;


	n_tty_flush_buffer(tty);
	n_tty_flush_buffer(tty);
	kfree(tty->read_buf);
	kfree(ldata->read_buf);
	kfree(tty->echo_buf);
	kfree(ldata->echo_buf);
	kfree(ldata);
	kfree(ldata);
	tty->read_buf = NULL;
	tty->echo_buf = NULL;
	tty->disc_data = NULL;
	tty->disc_data = NULL;
}
}


@@ -1615,9 +1628,9 @@ static int n_tty_open(struct tty_struct *tty)
	ldata->overrun_time = jiffies;
	ldata->overrun_time = jiffies;


	/* These are ugly. Currently a malloc failure here can panic */
	/* These are ugly. Currently a malloc failure here can panic */
	tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
	ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
	tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
	ldata->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
	if (!tty->read_buf || !tty->echo_buf)
	if (!ldata->read_buf || !ldata->echo_buf)
		goto err_free_bufs;
		goto err_free_bufs;


	tty->disc_data = ldata;
	tty->disc_data = ldata;
@@ -1630,8 +1643,8 @@ static int n_tty_open(struct tty_struct *tty)


	return 0;
	return 0;
err_free_bufs:
err_free_bufs:
	kfree(tty->read_buf);
	kfree(ldata->read_buf);
	kfree(tty->echo_buf);
	kfree(ldata->echo_buf);
	kfree(ldata);
	kfree(ldata);
err:
err:
	return -ENOMEM;
	return -ENOMEM;
@@ -1643,9 +1656,9 @@ static inline int input_available_p(struct tty_struct *tty, int amt)


	tty_flush_to_ldisc(tty);
	tty_flush_to_ldisc(tty);
	if (ldata->icanon && !L_EXTPROC(tty)) {
	if (ldata->icanon && !L_EXTPROC(tty)) {
		if (tty->canon_data)
		if (ldata->canon_data)
			return 1;
			return 1;
	} else if (tty->read_cnt >= (amt ? amt : 1))
	} else if (ldata->read_cnt >= (amt ? amt : 1))
		return 1;
		return 1;


	return 0;
	return 0;
@@ -1681,21 +1694,21 @@ static int copy_from_read_buf(struct tty_struct *tty,


	retval = 0;
	retval = 0;
	spin_lock_irqsave(&tty->read_lock, flags);
	spin_lock_irqsave(&tty->read_lock, flags);
	n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
	n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);
	n = min(*nr, n);
	n = min(*nr, n);
	spin_unlock_irqrestore(&tty->read_lock, flags);
	spin_unlock_irqrestore(&tty->read_lock, flags);
	if (n) {
	if (n) {
		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
		retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);
		n -= retval;
		n -= retval;
		is_eof = n == 1 &&
		is_eof = n == 1 &&
			tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
			ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty);
		tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n,
		tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n,
				ldata->icanon);
				ldata->icanon);
		spin_lock_irqsave(&tty->read_lock, flags);
		spin_lock_irqsave(&tty->read_lock, flags);
		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
		ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1);
		tty->read_cnt -= n;
		ldata->read_cnt -= n;
		/* Turn single EOF into zero-length read */
		/* Turn single EOF into zero-length read */
		if (L_EXTPROC(tty) && ldata->icanon && is_eof && !tty->read_cnt)
		if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt)
			n = 0;
			n = 0;
		spin_unlock_irqrestore(&tty->read_lock, flags);
		spin_unlock_irqrestore(&tty->read_lock, flags);
		*b += n;
		*b += n;
@@ -1878,22 +1891,22 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
		if (ldata->icanon && !L_EXTPROC(tty)) {
		if (ldata->icanon && !L_EXTPROC(tty)) {
			/* N.B. avoid overrun if nr == 0 */
			/* N.B. avoid overrun if nr == 0 */
			spin_lock_irqsave(&tty->read_lock, flags);
			spin_lock_irqsave(&tty->read_lock, flags);
			while (nr && tty->read_cnt) {
			while (nr && ldata->read_cnt) {
				int eol;
				int eol;


				eol = test_and_clear_bit(tty->read_tail,
				eol = test_and_clear_bit(ldata->read_tail,
						ldata->read_flags);
						ldata->read_flags);
				c = tty->read_buf[tty->read_tail];
				c = ldata->read_buf[ldata->read_tail];
				tty->read_tail = ((tty->read_tail+1) &
				ldata->read_tail = ((ldata->read_tail+1) &
						  (N_TTY_BUF_SIZE-1));
						  (N_TTY_BUF_SIZE-1));
				tty->read_cnt--;
				ldata->read_cnt--;
				if (eol) {
				if (eol) {
					/* this test should be redundant:
					/* this test should be redundant:
					 * we shouldn't be reading data if
					 * we shouldn't be reading data if
					 * canon_data is 0
					 * canon_data is 0
					 */
					 */
					if (--tty->canon_data < 0)
					if (--ldata->canon_data < 0)
						tty->canon_data = 0;
						ldata->canon_data = 0;
				}
				}
				spin_unlock_irqrestore(&tty->read_lock, flags);
				spin_unlock_irqrestore(&tty->read_lock, flags);


@@ -2111,15 +2124,15 @@ static unsigned long inq_canon(struct tty_struct *tty)
	struct n_tty_data *ldata = tty->disc_data;
	struct n_tty_data *ldata = tty->disc_data;
	int nr, head, tail;
	int nr, head, tail;


	if (!tty->canon_data)
	if (!ldata->canon_data)
		return 0;
		return 0;
	head = tty->canon_head;
	head = ldata->canon_head;
	tail = tty->read_tail;
	tail = ldata->read_tail;
	nr = (head - tail) & (N_TTY_BUF_SIZE-1);
	nr = (head - tail) & (N_TTY_BUF_SIZE-1);
	/* Skip EOF-chars.. */
	/* Skip EOF-chars.. */
	while (head != tail) {
	while (head != tail) {
		if (test_bit(tail, ldata->read_flags) &&
		if (test_bit(tail, ldata->read_flags) &&
		    tty->read_buf[tail] == __DISABLED_CHAR)
		    ldata->read_buf[tail] == __DISABLED_CHAR)
			nr--;
			nr--;
		tail = (tail+1) & (N_TTY_BUF_SIZE-1);
		tail = (tail+1) & (N_TTY_BUF_SIZE-1);
	}
	}
@@ -2129,6 +2142,7 @@ static unsigned long inq_canon(struct tty_struct *tty)
static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
		       unsigned int cmd, unsigned long arg)
		       unsigned int cmd, unsigned long arg)
{
{
	struct n_tty_data *ldata = tty->disc_data;
	int retval;
	int retval;


	switch (cmd) {
	switch (cmd) {
@@ -2136,7 +2150,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
	case TIOCINQ:
	case TIOCINQ:
		/* FIXME: Locking */
		/* FIXME: Locking */
		retval = tty->read_cnt;
		retval = ldata->read_cnt;
		if (L_ICANON(tty))
		if (L_ICANON(tty))
			retval = inq_canon(tty);
			retval = inq_canon(tty);
		return put_user(retval, (unsigned int __user *) arg);
		return put_user(retval, (unsigned int __user *) arg);
+0 −10
Original line number Original line Diff line number Diff line
@@ -272,16 +272,6 @@ struct tty_struct {
	 */
	 */
	unsigned char closing:1;
	unsigned char closing:1;
	unsigned short minimum_to_wake;
	unsigned short minimum_to_wake;
	char *read_buf;
	int read_head;
	int read_tail;
	int read_cnt;
	unsigned char *echo_buf;
	unsigned int echo_pos;
	unsigned int echo_cnt;
	int canon_data;
	unsigned long canon_head;
	unsigned int canon_column;
	struct mutex atomic_read_lock;
	struct mutex atomic_read_lock;
	struct mutex atomic_write_lock;
	struct mutex atomic_write_lock;
	struct mutex output_lock;
	struct mutex output_lock;